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