http/
error.rs

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