http/
error.rs

1use std::error;
2use std::fmt;
3use std::result;
4
5use crate::header;
6use crate::method;
7use crate::status;
8use 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.
16pub struct Error {
17    inner: ErrorKind,
18}
19
20/// A `Result` typedef to use with the `http::Error` type
21pub type Result<T> = result::Result<T, Error>;
22
23enum 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
32impl fmt::Debug for Error {
33    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
41impl fmt::Display for Error {
42    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43        fmt::Display::fmt(self.get_ref(), f)
44    }
45}
46
47impl Error {
48    /// Return true if the underlying error has the same type as T.
49    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.
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
68impl error::Error for Error {
69    // Return any available cause from the inner error. Note the inner error is
70    // not itself the cause.
71    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
72        self.get_ref().source()
73    }
74}
75
76impl From<status::InvalidStatusCode> for Error {
77    fn from(err: status::InvalidStatusCode) -> Error {
78        Error {
79            inner: ErrorKind::StatusCode(err),
80        }
81    }
82}
83
84impl From<method::InvalidMethod> for Error {
85    fn from(err: method::InvalidMethod) -> Error {
86        Error {
87            inner: ErrorKind::Method(err),
88        }
89    }
90}
91
92impl From<uri::InvalidUri> for Error {
93    fn from(err: uri::InvalidUri) -> Error {
94        Error {
95            inner: ErrorKind::Uri(err),
96        }
97    }
98}
99
100impl From<uri::InvalidUriParts> for Error {
101    fn from(err: uri::InvalidUriParts) -> Error {
102        Error {
103            inner: ErrorKind::UriParts(err),
104        }
105    }
106}
107
108impl From<header::InvalidHeaderName> for Error {
109    fn from(err: header::InvalidHeaderName) -> Error {
110        Error {
111            inner: ErrorKind::HeaderName(err),
112        }
113    }
114}
115
116impl From<header::InvalidHeaderValue> for Error {
117    fn from(err: header::InvalidHeaderValue) -> Error {
118        Error {
119            inner: ErrorKind::HeaderValue(err),
120        }
121    }
122}
123
124impl From<std::convert::Infallible> for Error {
125    fn from(err: std::convert::Infallible) -> Error {
126        match err {}
127    }
128}
129
130#[cfg(test)]
131mod tests {
132    use super::*;
133
134    #[test]
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}