1 | use std::error; |
2 | use std::fmt; |
3 | use std::result; |
4 | |
5 | use crate::header; |
6 | use crate::method; |
7 | use crate::status; |
8 | use 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. |
16 | pub struct Error { |
17 | inner: ErrorKind, |
18 | } |
19 | |
20 | /// A `Result` typedef to use with the `http::Error` type |
21 | pub type Result<T> = result::Result<T, Error>; |
22 | |
23 | enum 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 | |
32 | impl 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 | |
41 | impl 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 | |
47 | impl 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 | |
68 | impl 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 | |
76 | impl From<status::InvalidStatusCode> for Error { |
77 | fn from(err: status::InvalidStatusCode) -> Error { |
78 | Error { |
79 | inner: ErrorKind::StatusCode(err), |
80 | } |
81 | } |
82 | } |
83 | |
84 | impl From<method::InvalidMethod> for Error { |
85 | fn from(err: method::InvalidMethod) -> Error { |
86 | Error { |
87 | inner: ErrorKind::Method(err), |
88 | } |
89 | } |
90 | } |
91 | |
92 | impl From<uri::InvalidUri> for Error { |
93 | fn from(err: uri::InvalidUri) -> Error { |
94 | Error { |
95 | inner: ErrorKind::Uri(err), |
96 | } |
97 | } |
98 | } |
99 | |
100 | impl From<uri::InvalidUriParts> for Error { |
101 | fn from(err: uri::InvalidUriParts) -> Error { |
102 | Error { |
103 | inner: ErrorKind::UriParts(err), |
104 | } |
105 | } |
106 | } |
107 | |
108 | impl From<header::InvalidHeaderName> for Error { |
109 | fn from(err: header::InvalidHeaderName) -> Error { |
110 | Error { |
111 | inner: ErrorKind::HeaderName(err), |
112 | } |
113 | } |
114 | } |
115 | |
116 | impl From<header::InvalidHeaderValue> for Error { |
117 | fn from(err: header::InvalidHeaderValue) -> Error { |
118 | Error { |
119 | inner: ErrorKind::HeaderValue(err), |
120 | } |
121 | } |
122 | } |
123 | |
124 | impl From<std::convert::Infallible> for Error { |
125 | fn from(err: std::convert::Infallible) -> Error { |
126 | match err {} |
127 | } |
128 | } |
129 | |
130 | #[cfg (test)] |
131 | mod 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 | } |
150 | |