]> git.proxmox.com Git - cargo.git/blob - vendor/openssl-0.9.23/src/error.rs
New upstream version 0.24.0
[cargo.git] / vendor / openssl-0.9.23 / src / error.rs
1 //! Errors returned by OpenSSL library.
2 //!
3 //! OpenSSL errors are stored in an `ErrorStack`. Most methods in the crate
4 //! returns a `Result<T, ErrorStack>` type.
5 //!
6 //! # Examples
7 //!
8 //! ```
9 //! use openssl::error::ErrorStack;
10 //! use openssl::bn::BigNum;
11 //!
12 //! let an_error = BigNum::from_dec_str("Cannot parse letters");
13 //! match an_error {
14 //! Ok(_) => (),
15 //! Err(e) => println!("Parsing Error: {:?}", e),
16 //! }
17 //! ```
18 use libc::{c_ulong, c_char, c_int};
19 use std::fmt;
20 use std::error;
21 use std::ffi::CStr;
22 use std::io;
23 use std::str;
24 use std::ptr;
25 use std::borrow::Cow;
26
27 use ffi;
28
29 /// Collection of [`Error`]s from OpenSSL.
30 ///
31 /// [`Error`]: struct.Error.html
32 #[derive(Debug, Clone)]
33 pub struct ErrorStack(Vec<Error>);
34
35 impl ErrorStack {
36 /// Returns the contents of the OpenSSL error stack.
37 pub fn get() -> ErrorStack {
38 let mut vec = vec![];
39 while let Some(err) = Error::get() {
40 vec.push(err);
41 }
42 ErrorStack(vec)
43 }
44 }
45
46 impl ErrorStack {
47 /// Returns the errors in the stack.
48 pub fn errors(&self) -> &[Error] {
49 &self.0
50 }
51 }
52
53 impl fmt::Display for ErrorStack {
54 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
55 let mut first = true;
56 for err in &self.0 {
57 if !first {
58 fmt.write_str(", ")?;
59 }
60 write!(fmt, "{}", err)?;
61 first = false;
62 }
63 Ok(())
64 }
65 }
66
67 impl error::Error for ErrorStack {
68 fn description(&self) -> &str {
69 "An OpenSSL error stack"
70 }
71 }
72
73 impl From<ErrorStack> for io::Error {
74 fn from(e: ErrorStack) -> io::Error {
75 io::Error::new(io::ErrorKind::Other, e)
76 }
77 }
78
79 impl From<ErrorStack> for fmt::Error {
80 fn from(_: ErrorStack) -> fmt::Error {
81 fmt::Error
82 }
83 }
84
85 /// An error reported from OpenSSL.
86 #[derive(Clone)]
87 pub struct Error {
88 code: c_ulong,
89 file: *const c_char,
90 line: c_int,
91 data: Option<Cow<'static, str>>,
92 }
93
94 unsafe impl Sync for Error {}
95 unsafe impl Send for Error {}
96
97 impl Error {
98 /// Returns the first error on the OpenSSL error stack.
99 pub fn get() -> Option<Error> {
100 unsafe {
101 ffi::init();
102
103 let mut file = ptr::null();
104 let mut line = 0;
105 let mut data = ptr::null();
106 let mut flags = 0;
107 match ffi::ERR_get_error_line_data(&mut file, &mut line, &mut data, &mut flags) {
108 0 => None,
109 code => {
110 // The memory referenced by data is only valid until that slot is overwritten
111 // in the error stack, so we'll need to copy it off if it's dynamic
112 let data = if flags & ffi::ERR_TXT_STRING != 0 {
113 let bytes = CStr::from_ptr(data as *const _).to_bytes();
114 let data = str::from_utf8(bytes).unwrap();
115 let data = if flags & ffi::ERR_TXT_MALLOCED != 0 {
116 Cow::Owned(data.to_string())
117 } else {
118 Cow::Borrowed(data)
119 };
120 Some(data)
121 } else {
122 None
123 };
124 Some(Error {
125 code: code,
126 file: file,
127 line: line,
128 data: data,
129 })
130 }
131 }
132 }
133 }
134
135 /// Returns the raw OpenSSL error code for this error.
136 pub fn code(&self) -> c_ulong {
137 self.code
138 }
139
140 /// Returns the name of the library reporting the error, if available.
141 pub fn library(&self) -> Option<&'static str> {
142 unsafe {
143 let cstr = ffi::ERR_lib_error_string(self.code);
144 if cstr.is_null() {
145 return None;
146 }
147 let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
148 Some(str::from_utf8(bytes).unwrap())
149 }
150 }
151
152 /// Returns the name of the function reporting the error.
153 pub fn function(&self) -> Option<&'static str> {
154 unsafe {
155 let cstr = ffi::ERR_func_error_string(self.code);
156 if cstr.is_null() {
157 return None;
158 }
159 let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
160 Some(str::from_utf8(bytes).unwrap())
161 }
162 }
163
164 /// Returns the reason for the error.
165 pub fn reason(&self) -> Option<&'static str> {
166 unsafe {
167 let cstr = ffi::ERR_reason_error_string(self.code);
168 if cstr.is_null() {
169 return None;
170 }
171 let bytes = CStr::from_ptr(cstr as *const _).to_bytes();
172 Some(str::from_utf8(bytes).unwrap())
173 }
174 }
175
176 /// Returns the name of the source file which encountered the error.
177 pub fn file(&self) -> &'static str {
178 unsafe {
179 assert!(!self.file.is_null());
180 let bytes = CStr::from_ptr(self.file as *const _).to_bytes();
181 str::from_utf8(bytes).unwrap()
182 }
183 }
184
185 /// Returns the line in the source file which encountered the error.
186 pub fn line(&self) -> c_int {
187 self.line
188 }
189
190 /// Returns additional data describing the error.
191 pub fn data(&self) -> Option<&str> {
192 self.data.as_ref().map(|s| &**s)
193 }
194 }
195
196 impl fmt::Debug for Error {
197 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
198 let mut builder = fmt.debug_struct("Error");
199 builder.field("code", &self.code());
200 if let Some(library) = self.library() {
201 builder.field("library", &library);
202 }
203 if let Some(function) = self.function() {
204 builder.field("function", &function);
205 }
206 if let Some(reason) = self.reason() {
207 builder.field("reason", &reason);
208 }
209 builder.field("file", &self.file());
210 builder.field("line", &self.line());
211 if let Some(data) = self.data() {
212 builder.field("data", &data);
213 }
214 builder.finish()
215 }
216 }
217
218 impl fmt::Display for Error {
219 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
220 write!(fmt, "error:{:08X}", self.code())?;
221 match self.library() {
222 Some(l) => write!(fmt, ":{}", l)?,
223 None => write!(fmt, ":lib({})", ffi::ERR_GET_LIB(self.code()))?,
224 }
225 match self.function() {
226 Some(f) => write!(fmt, ":{}", f)?,
227 None => write!(fmt, ":func({})", ffi::ERR_GET_FUNC(self.code()))?,
228 }
229 match self.reason() {
230 Some(r) => write!(fmt, ":{}", r)?,
231 None => write!(fmt, ":reason({})", ffi::ERR_GET_FUNC(self.code()))?,
232 }
233 write!(
234 fmt,
235 ":{}:{}:{}",
236 self.file(),
237 self.line(),
238 self.data().unwrap_or("")
239 )
240 }
241 }
242
243 impl error::Error for Error {
244 fn description(&self) -> &str {
245 "an OpenSSL error"
246 }
247 }