Skip to main content

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    pub(crate) fn is_empty_uri(&self) -> bool {
51        match self.inner {
52            ErrorKind::Uri(ref err) => err.is_empty(),
53            _ => false,
54        }
55    }
56
57    /// Return true if the underlying error has the same type as T.
58    pub fn is<T: error::Error + 'static>(&self) -> bool {
59        self.get_ref().is::<T>()
60    }
61
62    /// Return a reference to the lower level, inner error.
63    pub fn get_ref(&self) -> &(dyn error::Error + 'static) {
64        use self::ErrorKind::*;
65
66        match self.inner {
67            StatusCode(ref e) => e,
68            Method(ref e) => e,
69            Uri(ref e) => e,
70            UriParts(ref e) => e,
71            HeaderName(ref e) => e,
72            HeaderValue(ref e) => e,
73            MaxSizeReached(ref e) => e,
74        }
75    }
76}
77
78impl error::Error for Error {
79    // Return any available cause from the inner error. Note the inner error is
80    // not itself the cause.
81    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
82        self.get_ref().source()
83    }
84}
85
86impl From<MaxSizeReached> for Error {
87    fn from(err: MaxSizeReached) -> Error {
88        Error {
89            inner: ErrorKind::MaxSizeReached(err),
90        }
91    }
92}
93
94impl From<status::InvalidStatusCode> for Error {
95    fn from(err: status::InvalidStatusCode) -> Error {
96        Error {
97            inner: ErrorKind::StatusCode(err),
98        }
99    }
100}
101
102impl From<method::InvalidMethod> for Error {
103    fn from(err: method::InvalidMethod) -> Error {
104        Error {
105            inner: ErrorKind::Method(err),
106        }
107    }
108}
109
110impl From<uri::InvalidUri> for Error {
111    fn from(err: uri::InvalidUri) -> Error {
112        Error {
113            inner: ErrorKind::Uri(err),
114        }
115    }
116}
117
118impl From<uri::InvalidUriParts> for Error {
119    fn from(err: uri::InvalidUriParts) -> Error {
120        Error {
121            inner: ErrorKind::UriParts(err),
122        }
123    }
124}
125
126impl From<header::InvalidHeaderName> for Error {
127    fn from(err: header::InvalidHeaderName) -> Error {
128        Error {
129            inner: ErrorKind::HeaderName(err),
130        }
131    }
132}
133
134impl From<header::InvalidHeaderValue> for Error {
135    fn from(err: header::InvalidHeaderValue) -> Error {
136        Error {
137            inner: ErrorKind::HeaderValue(err),
138        }
139    }
140}
141
142impl From<std::convert::Infallible> for Error {
143    fn from(err: std::convert::Infallible) -> Error {
144        match err {}
145    }
146}
147
148#[cfg(test)]
149mod tests {
150    use super::*;
151
152    #[test]
153    fn inner_error_is_invalid_status_code() {
154        if let Err(e) = status::StatusCode::from_u16(6666) {
155            let err: Error = e.into();
156            let ie = err.get_ref();
157            assert!(!ie.is::<header::InvalidHeaderValue>());
158            assert!(ie.is::<status::InvalidStatusCode>());
159            ie.downcast_ref::<status::InvalidStatusCode>().unwrap();
160
161            assert!(!err.is::<header::InvalidHeaderValue>());
162            assert!(err.is::<status::InvalidStatusCode>());
163        } else {
164            panic!("Bad status allowed!");
165        }
166    }
167}