Expose more error information
This commit is contained in:
parent
618cc70d19
commit
268288337b
|
|
@ -143,6 +143,9 @@ pub const BIO_FLAGS_SHOULD_RETRY: c_int = 0x08;
|
||||||
|
|
||||||
pub const CRYPTO_LOCK: c_int = 1;
|
pub const CRYPTO_LOCK: c_int = 1;
|
||||||
|
|
||||||
|
pub const ERR_TXT_MALLOCED: c_int = 0x01;
|
||||||
|
pub const ERR_TXT_STRING: c_int = 0x02;
|
||||||
|
|
||||||
pub const ERR_LIB_PEM: c_int = 9;
|
pub const ERR_LIB_PEM: c_int = 9;
|
||||||
pub const PEM_R_NO_START_LINE: c_int = 108;
|
pub const PEM_R_NO_START_LINE: c_int = 108;
|
||||||
|
|
||||||
|
|
@ -1542,6 +1545,7 @@ extern {
|
||||||
|
|
||||||
pub fn ERR_peek_last_error() -> c_ulong;
|
pub fn ERR_peek_last_error() -> c_ulong;
|
||||||
pub fn ERR_get_error() -> c_ulong;
|
pub fn ERR_get_error() -> c_ulong;
|
||||||
|
pub fn ERR_get_error_line_data(file: *mut *const c_char, line: *mut c_int, data: *mut *const c_char, flags: *mut c_int) -> c_ulong;
|
||||||
pub fn ERR_lib_error_string(err: c_ulong) -> *const c_char;
|
pub fn ERR_lib_error_string(err: c_ulong) -> *const c_char;
|
||||||
pub fn ERR_func_error_string(err: c_ulong) -> *const c_char;
|
pub fn ERR_func_error_string(err: c_ulong) -> *const c_char;
|
||||||
pub fn ERR_reason_error_string(err: c_ulong) -> *const c_char;
|
pub fn ERR_reason_error_string(err: c_ulong) -> *const c_char;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
use libc::c_ulong;
|
use libc::{c_ulong, c_char, c_int};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::error;
|
use std::error;
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
use std::ptr;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use ffi;
|
use ffi;
|
||||||
|
|
||||||
|
|
@ -62,28 +64,63 @@ impl From<ErrorStack> for fmt::Error {
|
||||||
|
|
||||||
/// An error reported from OpenSSL.
|
/// An error reported from OpenSSL.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Error(c_ulong);
|
pub struct Error {
|
||||||
|
code: c_ulong,
|
||||||
|
file: *const c_char,
|
||||||
|
line: c_int,
|
||||||
|
data: Option<Cow<'static, str>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Sync for Error {}
|
||||||
|
unsafe impl Send for Error {}
|
||||||
|
|
||||||
impl Error {
|
impl Error {
|
||||||
/// Returns the first error on the OpenSSL error stack.
|
/// Returns the first error on the OpenSSL error stack.
|
||||||
pub fn get() -> Option<Error> {
|
pub fn get() -> Option<Error> {
|
||||||
ffi::init();
|
unsafe {
|
||||||
|
ffi::init();
|
||||||
|
|
||||||
match unsafe { ffi::ERR_get_error() } {
|
let mut file = ptr::null();
|
||||||
0 => None,
|
let mut line = 0;
|
||||||
err => Some(Error(err)),
|
let mut data = ptr::null();
|
||||||
|
let mut flags = 0;
|
||||||
|
match ffi::ERR_get_error_line_data(&mut file, &mut line, &mut data, &mut flags) {
|
||||||
|
0 => None,
|
||||||
|
code => {
|
||||||
|
// The memory referenced by data is only valid until that slot is overwritten
|
||||||
|
// in the error stack, so we'll need to copy it off if it's dynamic
|
||||||
|
let data = if flags & ffi::ERR_TXT_STRING != 0 {
|
||||||
|
let bytes = CStr::from_ptr(data as *const _).to_bytes();
|
||||||
|
let data = str::from_utf8(bytes).unwrap();
|
||||||
|
let data = if flags & ffi::ERR_TXT_MALLOCED != 0 {
|
||||||
|
Cow::Owned(data.to_string())
|
||||||
|
} else {
|
||||||
|
Cow::Borrowed(data)
|
||||||
|
};
|
||||||
|
Some(data)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
Some(Error {
|
||||||
|
code: code,
|
||||||
|
file: file,
|
||||||
|
line: line,
|
||||||
|
data: data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the raw OpenSSL error code for this error.
|
/// Returns the raw OpenSSL error code for this error.
|
||||||
pub fn code(&self) -> c_ulong {
|
pub fn code(&self) -> c_ulong {
|
||||||
self.0
|
self.code
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the name of the library reporting the error, if available.
|
/// Returns the name of the library reporting the error, if available.
|
||||||
pub fn library(&self) -> Option<&'static str> {
|
pub fn library(&self) -> Option<&'static str> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let cstr = ffi::ERR_lib_error_string(self.0);
|
let cstr = ffi::ERR_lib_error_string(self.code);
|
||||||
if cstr.is_null() {
|
if cstr.is_null() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
@ -95,7 +132,7 @@ impl Error {
|
||||||
/// Returns the name of the function reporting the error.
|
/// Returns the name of the function reporting the error.
|
||||||
pub fn function(&self) -> Option<&'static str> {
|
pub fn function(&self) -> Option<&'static str> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let cstr = ffi::ERR_func_error_string(self.0);
|
let cstr = ffi::ERR_func_error_string(self.code);
|
||||||
if cstr.is_null() {
|
if cstr.is_null() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
@ -107,7 +144,7 @@ impl Error {
|
||||||
/// Returns the reason for the error.
|
/// Returns the reason for the error.
|
||||||
pub fn reason(&self) -> Option<&'static str> {
|
pub fn reason(&self) -> Option<&'static str> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let cstr = ffi::ERR_reason_error_string(self.0);
|
let cstr = ffi::ERR_reason_error_string(self.code);
|
||||||
if cstr.is_null() {
|
if cstr.is_null() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
@ -115,6 +152,25 @@ impl Error {
|
||||||
Some(str::from_utf8(bytes).unwrap())
|
Some(str::from_utf8(bytes).unwrap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the name of the source file which encountered the error.
|
||||||
|
pub fn file(&self) -> &'static str {
|
||||||
|
unsafe {
|
||||||
|
assert!(!self.file.is_null());
|
||||||
|
let bytes = CStr::from_ptr(self.file as *const _).to_bytes();
|
||||||
|
str::from_utf8(bytes).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the line in the source file which encountered the error.
|
||||||
|
pub fn line(&self) -> c_int {
|
||||||
|
self.line
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns additional data describing the error.
|
||||||
|
pub fn data(&self) -> Option<&str> {
|
||||||
|
self.data.as_ref().map(|s| &**s)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Error {
|
impl fmt::Debug for Error {
|
||||||
|
|
@ -130,30 +186,36 @@ impl fmt::Debug for Error {
|
||||||
if let Some(reason) = self.reason() {
|
if let Some(reason) = self.reason() {
|
||||||
builder.field("reason", &reason);
|
builder.field("reason", &reason);
|
||||||
}
|
}
|
||||||
|
builder.field("file", &self.file());
|
||||||
|
builder.field("line", &self.line());
|
||||||
|
if let Some(data) = self.data() {
|
||||||
|
builder.field("data", &data);
|
||||||
|
}
|
||||||
builder.finish()
|
builder.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
try!(write!(fmt, "error:{:08X}", self.0));
|
try!(write!(fmt, "error:{:08X}", self.code()));
|
||||||
match self.library() {
|
match self.library() {
|
||||||
Some(l) => try!(write!(fmt, ":{}", l)),
|
Some(l) => try!(write!(fmt, ":{}", l)),
|
||||||
None => try!(write!(fmt, ":lib({})", ffi::ERR_GET_LIB(self.0))),
|
None => try!(write!(fmt, ":lib({})", ffi::ERR_GET_LIB(self.code()))),
|
||||||
}
|
}
|
||||||
match self.function() {
|
match self.function() {
|
||||||
Some(f) => try!(write!(fmt, ":{}", f)),
|
Some(f) => try!(write!(fmt, ":{}", f)),
|
||||||
None => try!(write!(fmt, ":func({})", ffi::ERR_GET_FUNC(self.0))),
|
None => try!(write!(fmt, ":func({})", ffi::ERR_GET_FUNC(self.code()))),
|
||||||
}
|
}
|
||||||
match self.reason() {
|
match self.reason() {
|
||||||
Some(r) => write!(fmt, ":{}", r),
|
Some(r) => try!(write!(fmt, ":{}", r)),
|
||||||
None => write!(fmt, ":reason({})", ffi::ERR_GET_FUNC(self.0)),
|
None => try!(write!(fmt, ":reason({})", ffi::ERR_GET_FUNC(self.code()))),
|
||||||
}
|
}
|
||||||
|
write!(fmt, ":{}:{}:{}", self.file(), self.line(), self.data().unwrap_or(""))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl error::Error for Error {
|
impl error::Error for Error {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str {
|
||||||
"An OpenSSL error"
|
"an OpenSSL error"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue