use std::error; use std::fmt; use std::result; use crate::header; use crate::method; use crate::status; use crate::uri; /// A generic "error" for HTTP connections /// /// This error type is less specific than the error returned from other /// functions in this crate, but all other errors can be converted to this /// error. Consumers of this crate can typically consume and work with this form /// of error for conversions with the `?` operator. pub struct Error { inner: ErrorKind, } /// A `Result` typedef to use with the `http::Error` type pub type Result = result::Result; enum ErrorKind { StatusCode(status::InvalidStatusCode), Method(method::InvalidMethod), Uri(uri::InvalidUri), UriParts(uri::InvalidUriParts), HeaderName(header::InvalidHeaderName), HeaderValue(header::InvalidHeaderValue), } impl fmt::Debug for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("http::Error") // Skip the noise of the ErrorKind enum .field(&self.get_ref()) .finish() } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(self.get_ref(), f) } } impl Error { /// Return true if the underlying error has the same type as T. pub fn is(&self) -> bool { self.get_ref().is::() } /// Return a reference to the lower level, inner error. pub fn get_ref(&self) -> &(dyn error::Error + 'static) { use self::ErrorKind::*; match self.inner { StatusCode(ref e) => e, Method(ref e) => e, Uri(ref e) => e, UriParts(ref e) => e, HeaderName(ref e) => e, HeaderValue(ref e) => e, } } } impl error::Error for Error { // Return any available cause from the inner error. Note the inner error is // not itself the cause. fn source(&self) -> Option<&(dyn error::Error + 'static)> { self.get_ref().source() } } impl From for Error { fn from(err: status::InvalidStatusCode) -> Error { Error { inner: ErrorKind::StatusCode(err), } } } impl From for Error { fn from(err: method::InvalidMethod) -> Error { Error { inner: ErrorKind::Method(err), } } } impl From for Error { fn from(err: uri::InvalidUri) -> Error { Error { inner: ErrorKind::Uri(err), } } } impl From for Error { fn from(err: uri::InvalidUriParts) -> Error { Error { inner: ErrorKind::UriParts(err), } } } impl From for Error { fn from(err: header::InvalidHeaderName) -> Error { Error { inner: ErrorKind::HeaderName(err), } } } impl From for Error { fn from(err: header::InvalidHeaderValue) -> Error { Error { inner: ErrorKind::HeaderValue(err), } } } impl From for Error { fn from(err: std::convert::Infallible) -> Error { match err {} } } #[cfg(test)] mod tests { use super::*; #[test] fn inner_error_is_invalid_status_code() { if let Err(e) = status::StatusCode::from_u16(6666) { let err: Error = e.into(); let ie = err.get_ref(); assert!(!ie.is::()); assert!(ie.is::()); ie.downcast_ref::().unwrap(); assert!(!err.is::()); assert!(err.is::()); } else { panic!("Bad status allowed!"); } } }