1 | use std::error; |
2 | use std::fmt; |
3 | use std::result; |
4 | |
5 | use crate::header; |
6 | use crate::header::MaxSizeReached; |
7 | use crate::method; |
8 | use crate::status; |
9 | use 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. |
17 | pub struct Error { |
18 | inner: ErrorKind, |
19 | } |
20 | |
21 | /// A `Result` typedef to use with the `http::Error` type |
22 | pub type Result<T> = result::Result<T, Error>; |
23 | |
24 | enum 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 | |
34 | impl fmt::Debug for Error { |
35 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
36 | f&mut DebugTuple<'_, '_>.debug_tuple(name:"http::Error" ) |
37 | // Skip the noise of the ErrorKind enum |
38 | .field(&self.get_ref()) |
39 | .finish() |
40 | } |
41 | } |
42 | |
43 | impl 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 | |
49 | impl 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: &InvalidStatusCode) => e, |
61 | Method(ref e: &InvalidMethod) => e, |
62 | Uri(ref e: &InvalidUri) => e, |
63 | UriParts(ref e: &InvalidUriParts) => e, |
64 | HeaderName(ref e: &InvalidHeaderName) => e, |
65 | HeaderValue(ref e: &InvalidHeaderValue) => e, |
66 | MaxSizeReached(ref e: &MaxSizeReached) => e, |
67 | } |
68 | } |
69 | } |
70 | |
71 | impl 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 | |
79 | impl From<MaxSizeReached> for Error { |
80 | fn from(err: MaxSizeReached) -> Error { |
81 | Error { |
82 | inner: ErrorKind::MaxSizeReached(err), |
83 | } |
84 | } |
85 | } |
86 | |
87 | impl From<status::InvalidStatusCode> for Error { |
88 | fn from(err: status::InvalidStatusCode) -> Error { |
89 | Error { |
90 | inner: ErrorKind::StatusCode(err), |
91 | } |
92 | } |
93 | } |
94 | |
95 | impl From<method::InvalidMethod> for Error { |
96 | fn from(err: method::InvalidMethod) -> Error { |
97 | Error { |
98 | inner: ErrorKind::Method(err), |
99 | } |
100 | } |
101 | } |
102 | |
103 | impl From<uri::InvalidUri> for Error { |
104 | fn from(err: uri::InvalidUri) -> Error { |
105 | Error { |
106 | inner: ErrorKind::Uri(err), |
107 | } |
108 | } |
109 | } |
110 | |
111 | impl From<uri::InvalidUriParts> for Error { |
112 | fn from(err: uri::InvalidUriParts) -> Error { |
113 | Error { |
114 | inner: ErrorKind::UriParts(err), |
115 | } |
116 | } |
117 | } |
118 | |
119 | impl From<header::InvalidHeaderName> for Error { |
120 | fn from(err: header::InvalidHeaderName) -> Error { |
121 | Error { |
122 | inner: ErrorKind::HeaderName(err), |
123 | } |
124 | } |
125 | } |
126 | |
127 | impl From<header::InvalidHeaderValue> for Error { |
128 | fn from(err: header::InvalidHeaderValue) -> Error { |
129 | Error { |
130 | inner: ErrorKind::HeaderValue(err), |
131 | } |
132 | } |
133 | } |
134 | |
135 | impl From<std::convert::Infallible> for Error { |
136 | fn from(err: std::convert::Infallible) -> Error { |
137 | match err {} |
138 | } |
139 | } |
140 | |
141 | #[cfg (test)] |
142 | mod 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 | } |
161 | |