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