1use std::{error, fmt, result};
2
3pub use http::header::InvalidHeaderName;
4pub use http::method::InvalidMethod;
5pub use http::status::InvalidStatusCode;
6pub use http::uri::InvalidUri;
7
8pub use crate::value::{InvalidHeaderValue, ToStrError};
9
10use http::header;
11use http::method;
12use http::status;
13use http::uri;
14
15pub struct Error {
22    inner: ErrorKind,
23}
24
25pub type Result<T> = result::Result<T, Error>;
27
28enum ErrorKind {
29    StatusCode(status::InvalidStatusCode),
30    Method(method::InvalidMethod),
31    Uri(uri::InvalidUri),
32    UriParts(uri::InvalidUriParts),
33    HeaderName(header::InvalidHeaderName),
34    HeaderValue(InvalidHeaderValue),
35    Http(http::Error),
36}
37
38impl fmt::Debug for Error {
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        f.debug_tuple("ntex_http::Error")
41            .field(&self.get_ref())
43            .finish()
44    }
45}
46
47impl fmt::Display for Error {
48    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49        fmt::Display::fmt(self.get_ref(), f)
50    }
51}
52
53impl Error {
54    pub fn is<T: error::Error + 'static>(&self) -> bool {
56        self.get_ref().is::<T>()
57    }
58
59    pub fn get_ref(&self) -> &(dyn error::Error + 'static) {
61        use self::ErrorKind::*;
62
63        match self.inner {
64            StatusCode(ref e) => e,
65            Method(ref e) => e,
66            Uri(ref e) => e,
67            UriParts(ref e) => e,
68            HeaderName(ref e) => e,
69            HeaderValue(ref e) => e,
70            Http(ref e) => e,
71        }
72    }
73}
74
75impl error::Error for Error {
76    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
79        self.get_ref().source()
80    }
81}
82
83impl From<status::InvalidStatusCode> for Error {
84    fn from(err: status::InvalidStatusCode) -> Error {
85        Error {
86            inner: ErrorKind::StatusCode(err),
87        }
88    }
89}
90
91impl From<method::InvalidMethod> for Error {
92    fn from(err: method::InvalidMethod) -> Error {
93        Error {
94            inner: ErrorKind::Method(err),
95        }
96    }
97}
98
99impl From<uri::InvalidUri> for Error {
100    fn from(err: uri::InvalidUri) -> Error {
101        Error {
102            inner: ErrorKind::Uri(err),
103        }
104    }
105}
106
107impl From<uri::InvalidUriParts> for Error {
108    fn from(err: uri::InvalidUriParts) -> Error {
109        Error {
110            inner: ErrorKind::UriParts(err),
111        }
112    }
113}
114
115impl From<header::InvalidHeaderName> for Error {
116    fn from(err: header::InvalidHeaderName) -> Error {
117        Error {
118            inner: ErrorKind::HeaderName(err),
119        }
120    }
121}
122
123impl From<InvalidHeaderValue> for Error {
124    fn from(err: InvalidHeaderValue) -> Error {
125        Error {
126            inner: ErrorKind::HeaderValue(err),
127        }
128    }
129}
130
131impl From<http::Error> for Error {
132    fn from(err: http::Error) -> Error {
133        Error {
134            inner: ErrorKind::Http(err),
135        }
136    }
137}
138
139impl From<std::convert::Infallible> for Error {
140    fn from(err: std::convert::Infallible) -> Error {
141        match err {}
142    }
143}
144
145#[cfg(test)]
146mod tests {
147    use super::*;
148    use std::error::Error as StdError;
149
150    #[test]
151    fn inner_http_error() {
152        let e = method::Method::from_bytes(b"").unwrap_err();
153        let err: Error = http::Error::from(e).into();
154        let ie = err.get_ref();
155        assert!(ie.is::<http::Error>());
156    }
157
158    #[test]
159    fn inner_error_is_invalid_status_code() {
160        let e = status::StatusCode::from_u16(6666).unwrap_err();
161        let err: Error = e.into();
162        let ie = err.get_ref();
163        assert!(!ie.is::<header::InvalidHeaderValue>());
164        assert!(ie.is::<status::InvalidStatusCode>());
165        ie.downcast_ref::<status::InvalidStatusCode>().unwrap();
166
167        assert!(err.source().is_none());
168        assert!(!err.is::<InvalidHeaderValue>());
169        assert!(err.is::<status::InvalidStatusCode>());
170
171        let s = format!("{:?}", err);
172        assert!(s.starts_with("ntex_http::Error"));
173    }
174
175    #[test]
176    fn inner_error_is_invalid_method() {
177        let e = method::Method::from_bytes(b"").unwrap_err();
178        let err: Error = e.into();
179        let ie = err.get_ref();
180        assert!(ie.is::<method::InvalidMethod>());
181        ie.downcast_ref::<method::InvalidMethod>().unwrap();
182
183        assert!(err.source().is_none());
184        assert!(err.is::<method::InvalidMethod>());
185
186        let s = format!("{:?}", err);
187        assert!(s.starts_with("ntex_http::Error"));
188    }
189}