1use std::{error, fmt, result};
2
3pub use crate::value::{InvalidHeaderValue, ToStrError};
4
5#[derive(Clone)]
6pub struct Error {
13 inner: ErrorKind,
14}
15
16#[derive(thiserror::Error, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
17#[error("Invalid URI")]
18pub struct InvalidUri {
20 _priv: (),
21}
22
23#[derive(thiserror::Error, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
24#[error("Invalid HTTP header name")]
25pub struct InvalidHeaderName {
27 _priv: (),
28}
29
30#[derive(thiserror::Error, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
31#[error("Invalid status code")]
32pub struct InvalidStatusCode {
37 _priv: (),
38}
39
40#[derive(thiserror::Error, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
41#[error("Invalid HTTP method")]
42pub struct InvalidMethod {
44 _priv: (),
45}
46
47pub type Result<T> = result::Result<T, Error>;
49
50#[derive(Clone)]
51enum ErrorKind {
52 StatusCode(InvalidStatusCode),
53 Method(InvalidMethod),
54 Uri(InvalidUri),
55 UriParts(InvalidUri),
56 HeaderName(InvalidHeaderName),
57 HeaderValue(InvalidHeaderValue),
58 Http,
59}
60
61impl fmt::Debug for Error {
62 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63 f.debug_tuple("ntex_http::Error")
64 .field(&self.get_ref())
66 .finish()
67 }
68}
69
70impl fmt::Display for Error {
71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72 fmt::Display::fmt(self.get_ref(), f)
73 }
74}
75
76impl Error {
77 pub fn is<T: error::Error + 'static>(&self) -> bool {
79 self.get_ref().is::<T>()
80 }
81
82 pub fn get_ref(&self) -> &(dyn error::Error + 'static) {
84 use self::ErrorKind::*;
85
86 match self.inner {
87 StatusCode(ref e) => e,
88 Method(ref e) => e,
89 Uri(ref e) => e,
90 UriParts(ref e) => e,
91 HeaderName(ref e) => e,
92 HeaderValue(ref e) => e,
93 Http => &DEFAULT_ERR,
94 }
95 }
96}
97
98#[derive(thiserror::Error, Copy, Clone, Debug)]
99#[error("{_0}")]
100struct ErrorMessage(&'static str);
101
102const DEFAULT_ERR: ErrorMessage = ErrorMessage("http error");
103
104impl error::Error for Error {
105 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
108 self.get_ref().source()
109 }
110}
111
112impl From<http::status::InvalidStatusCode> for Error {
113 fn from(_: http::status::InvalidStatusCode) -> Error {
114 Error {
115 inner: ErrorKind::StatusCode(InvalidStatusCode { _priv: () }),
116 }
117 }
118}
119
120impl From<http::method::InvalidMethod> for Error {
121 fn from(_: http::method::InvalidMethod) -> Error {
122 Error {
123 inner: ErrorKind::Method(InvalidMethod { _priv: () }),
124 }
125 }
126}
127
128impl From<http::uri::InvalidUri> for Error {
129 fn from(_: http::uri::InvalidUri) -> Error {
130 Error {
131 inner: ErrorKind::Uri(InvalidUri { _priv: () }),
132 }
133 }
134}
135
136impl From<http::uri::InvalidUriParts> for Error {
137 fn from(_: http::uri::InvalidUriParts) -> Error {
138 Error {
139 inner: ErrorKind::UriParts(InvalidUri { _priv: () }),
140 }
141 }
142}
143
144impl From<http::header::InvalidHeaderName> for Error {
145 fn from(_: http::header::InvalidHeaderName) -> Error {
146 Error {
147 inner: ErrorKind::HeaderName(InvalidHeaderName { _priv: () }),
148 }
149 }
150}
151
152impl From<InvalidHeaderValue> for Error {
153 fn from(err: InvalidHeaderValue) -> Error {
154 Error {
155 inner: ErrorKind::HeaderValue(err),
156 }
157 }
158}
159
160impl From<http::Error> for Error {
161 fn from(err: http::Error) -> Error {
162 let inner = if err.is::<http::status::InvalidStatusCode>() {
163 ErrorKind::StatusCode(InvalidStatusCode { _priv: () })
164 } else if err.is::<http::method::InvalidMethod>() {
165 ErrorKind::Method(InvalidMethod { _priv: () })
166 } else if err.is::<http::uri::InvalidUri>() {
167 ErrorKind::Uri(InvalidUri { _priv: () })
168 } else if err.is::<http::header::InvalidHeaderName>() {
169 ErrorKind::HeaderName(InvalidHeaderName { _priv: () })
170 } else if err.is::<http::header::InvalidHeaderValue>() {
171 ErrorKind::HeaderValue(InvalidHeaderValue::default())
172 } else {
173 ErrorKind::Http
174 };
175 Error { inner }
176 }
177}
178
179impl From<std::convert::Infallible> for Error {
180 fn from(err: std::convert::Infallible) -> Error {
181 match err {}
182 }
183}
184
185impl From<http::status::InvalidStatusCode> for InvalidStatusCode {
186 fn from(_: http::status::InvalidStatusCode) -> InvalidStatusCode {
187 InvalidStatusCode { _priv: () }
188 }
189}
190
191impl From<http::method::InvalidMethod> for InvalidMethod {
192 fn from(_: http::method::InvalidMethod) -> InvalidMethod {
193 InvalidMethod { _priv: () }
194 }
195}
196
197impl From<http::uri::InvalidUri> for InvalidUri {
198 fn from(_: http::uri::InvalidUri) -> InvalidUri {
199 InvalidUri { _priv: () }
200 }
201}
202
203impl From<http::header::InvalidHeaderName> for InvalidHeaderName {
204 fn from(_: http::header::InvalidHeaderName) -> InvalidHeaderName {
205 InvalidHeaderName { _priv: () }
206 }
207}
208
209impl From<http::header::InvalidHeaderValue> for InvalidHeaderValue {
210 fn from(_: http::header::InvalidHeaderValue) -> InvalidHeaderValue {
211 InvalidHeaderValue::default()
212 }
213}
214
215#[cfg(test)]
216mod tests {
217 use super::*;
218 use std::error::Error as StdError;
219
220 #[test]
221 fn inner_http_error() {
222 let e = http::method::Method::from_bytes(b"").unwrap_err();
223 let err: Error = http::Error::from(e).into();
224 let ie = err.get_ref();
225 assert!(!ie.is::<http::Error>());
226 }
227
228 #[test]
229 fn inner_error_is_invalid_status_code() {
230 let e = http::status::StatusCode::from_u16(6666).unwrap_err();
231 let err: Error = e.into();
232 let ie = err.get_ref();
233 assert!(!ie.is::<InvalidHeaderValue>());
234 assert!(ie.is::<InvalidStatusCode>());
235 ie.downcast_ref::<InvalidStatusCode>().unwrap();
236
237 assert!(err.source().is_none());
238 assert!(!err.is::<InvalidHeaderValue>());
239 assert!(err.is::<InvalidStatusCode>());
240
241 let s = format!("{err:?}");
242 assert!(s.starts_with("ntex_http::Error"));
243 }
244
245 #[test]
246 fn inner_error_is_invalid_method() {
247 let e = http::method::Method::from_bytes(b"").unwrap_err();
248 let err: Error = e.into();
249 let ie = err.get_ref();
250 assert!(ie.is::<InvalidMethod>());
251 ie.downcast_ref::<InvalidMethod>().unwrap();
252
253 assert!(err.source().is_none());
254 assert!(err.is::<InvalidMethod>());
255
256 let s = format!("{err:?}");
257 assert!(s.starts_with("ntex_http::Error"));
258 }
259}