1 use std::error; 2 use std::fmt; 3 use std::result; 4 5 use crate::header; 6 use crate::method; 7 use crate::status; 8 use crate::uri; 9 10 /// A generic "error" for HTTP connections 11 /// 12 /// This error type is less specific than the error returned from other 13 /// functions in this crate, but all other errors can be converted to this 14 /// error. Consumers of this crate can typically consume and work with this form 15 /// of error for conversions with the `?` operator. 16 pub struct Error { 17 inner: ErrorKind, 18 } 19 20 /// A `Result` typedef to use with the `http::Error` type 21 pub type Result<T> = result::Result<T, Error>; 22 23 enum ErrorKind { 24 StatusCode(status::InvalidStatusCode), 25 Method(method::InvalidMethod), 26 Uri(uri::InvalidUri), 27 UriParts(uri::InvalidUriParts), 28 HeaderName(header::InvalidHeaderName), 29 HeaderValue(header::InvalidHeaderValue), 30 } 31 32 impl fmt::Debug for Error { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result33 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 34 f.debug_tuple("http::Error") 35 // Skip the noise of the ErrorKind enum 36 .field(&self.get_ref()) 37 .finish() 38 } 39 } 40 41 impl fmt::Display for Error { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result42 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 43 fmt::Display::fmt(self.get_ref(), f) 44 } 45 } 46 47 impl Error { 48 /// Return true if the underlying error has the same type as T. is<T: error::Error + 'static>(&self) -> bool49 pub fn is<T: error::Error + 'static>(&self) -> bool { 50 self.get_ref().is::<T>() 51 } 52 53 /// Return a reference to the lower level, inner error. get_ref(&self) -> &(dyn error::Error + 'static)54 pub fn get_ref(&self) -> &(dyn error::Error + 'static) { 55 use self::ErrorKind::*; 56 57 match self.inner { 58 StatusCode(ref e) => e, 59 Method(ref e) => e, 60 Uri(ref e) => e, 61 UriParts(ref e) => e, 62 HeaderName(ref e) => e, 63 HeaderValue(ref e) => e, 64 } 65 } 66 } 67 68 impl error::Error for Error { 69 // Return any available cause from the inner error. Note the inner error is 70 // not itself the cause. source(&self) -> Option<&(dyn error::Error + 'static)>71 fn source(&self) -> Option<&(dyn error::Error + 'static)> { 72 self.get_ref().source() 73 } 74 } 75 76 impl From<status::InvalidStatusCode> for Error { from(err: status::InvalidStatusCode) -> Error77 fn from(err: status::InvalidStatusCode) -> Error { 78 Error { 79 inner: ErrorKind::StatusCode(err), 80 } 81 } 82 } 83 84 impl From<method::InvalidMethod> for Error { from(err: method::InvalidMethod) -> Error85 fn from(err: method::InvalidMethod) -> Error { 86 Error { 87 inner: ErrorKind::Method(err), 88 } 89 } 90 } 91 92 impl From<uri::InvalidUri> for Error { from(err: uri::InvalidUri) -> Error93 fn from(err: uri::InvalidUri) -> Error { 94 Error { 95 inner: ErrorKind::Uri(err), 96 } 97 } 98 } 99 100 impl From<uri::InvalidUriParts> for Error { from(err: uri::InvalidUriParts) -> Error101 fn from(err: uri::InvalidUriParts) -> Error { 102 Error { 103 inner: ErrorKind::UriParts(err), 104 } 105 } 106 } 107 108 impl From<header::InvalidHeaderName> for Error { from(err: header::InvalidHeaderName) -> Error109 fn from(err: header::InvalidHeaderName) -> Error { 110 Error { 111 inner: ErrorKind::HeaderName(err), 112 } 113 } 114 } 115 116 impl From<header::InvalidHeaderValue> for Error { from(err: header::InvalidHeaderValue) -> Error117 fn from(err: header::InvalidHeaderValue) -> Error { 118 Error { 119 inner: ErrorKind::HeaderValue(err), 120 } 121 } 122 } 123 124 impl From<std::convert::Infallible> for Error { from(err: std::convert::Infallible) -> Error125 fn from(err: std::convert::Infallible) -> Error { 126 match err {} 127 } 128 } 129 130 #[cfg(test)] 131 mod tests { 132 use super::*; 133 134 #[test] inner_error_is_invalid_status_code()135 fn inner_error_is_invalid_status_code() { 136 if let Err(e) = status::StatusCode::from_u16(6666) { 137 let err: Error = e.into(); 138 let ie = err.get_ref(); 139 assert!(!ie.is::<header::InvalidHeaderValue>()); 140 assert!(ie.is::<status::InvalidStatusCode>()); 141 ie.downcast_ref::<status::InvalidStatusCode>().unwrap(); 142 143 assert!(!err.is::<header::InvalidHeaderValue>()); 144 assert!(err.is::<status::InvalidStatusCode>()); 145 } else { 146 panic!("Bad status allowed!"); 147 } 148 } 149 } 150