1use std::error::Error as StdError;
3use std::fmt;
4use std::io::Error as IoError;
5use std::str::Utf8Error;
6use std::string::FromUtf8Error;
7
8use httparse;
9
10pub use uri::UriError;
11
12use self::Error::{
13 Method,
14 Uri,
15 Version,
16 Header,
17 Status,
18 Timeout,
19 Upgrade,
20 Closed,
21 Cancel,
22 Io,
23 TooLarge,
24 Incomplete,
25 Utf8
26};
27
28pub type Result<T> = ::std::result::Result<T, Error>;
30
31#[derive(Debug)]
33pub enum Error {
34 Method,
36 Uri(UriError),
38 Version,
40 Header,
42 TooLarge,
44 Incomplete,
46 Status,
48 Timeout,
50 Upgrade,
52 Cancel(Canceled),
54 Closed,
56 Io(IoError),
58 Utf8(Utf8Error),
60
61 #[doc(hidden)]
62 __Nonexhaustive(Void)
63}
64
65impl Error {
66 #[doc(hidden)]
67 pub fn __internal_new_canceled<E: Into<Box<StdError + Send + Sync>>>(cause: Option<E>) -> Error {
68 Error::Cancel(Canceled {
69 cause: cause.map(Into::into),
70 })
71 }
72}
73
74#[derive(Debug)]
81pub struct Canceled {
82 cause: Option<Box<StdError + Send + Sync>>,
83}
84
85impl Canceled {
86 fn description(&self) -> &str {
87 "an operation was canceled internally before starting"
88 }
89}
90
91impl fmt::Display for Canceled {
92 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
93 f.pad(self.description())
94 }
95}
96
97#[doc(hidden)]
98pub struct Void(());
99
100impl fmt::Debug for Void {
101 fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
102 unreachable!()
103 }
104}
105
106impl fmt::Display for Error {
107 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
108 match *self {
109 Uri(ref e) => fmt::Display::fmt(e, f),
110 Io(ref e) => fmt::Display::fmt(e, f),
111 Utf8(ref e) => fmt::Display::fmt(e, f),
112 ref e => f.write_str(e.description()),
113 }
114 }
115}
116
117impl StdError for Error {
118 fn description(&self) -> &str {
119 match *self {
120 Method => "invalid Method specified",
121 Version => "invalid HTTP version specified",
122 Header => "invalid Header provided",
123 TooLarge => "message head is too large",
124 Status => "invalid Status provided",
125 Incomplete => "message is incomplete",
126 Timeout => "timeout",
127 Upgrade => "unsupported protocol upgrade",
128 Closed => "connection is closed",
129 Cancel(ref e) => e.description(),
130 Uri(ref e) => e.description(),
131 Io(ref e) => e.description(),
132 Utf8(ref e) => e.description(),
133 Error::__Nonexhaustive(..) => unreachable!(),
134 }
135 }
136
137 fn cause(&self) -> Option<&StdError> {
138 match *self {
139 Io(ref error) => Some(error),
140 Uri(ref error) => Some(error),
141 Utf8(ref error) => Some(error),
142 Cancel(ref e) => e.cause.as_ref().map(|e| &**e as &StdError),
143 Error::__Nonexhaustive(..) => unreachable!(),
144 _ => None,
145 }
146 }
147}
148
149impl From<UriError> for Error {
150 fn from(err: UriError) -> Error {
151 Uri(err)
152 }
153}
154
155impl From<IoError> for Error {
156 fn from(err: IoError) -> Error {
157 Io(err)
158 }
159}
160
161impl From<Utf8Error> for Error {
162 fn from(err: Utf8Error) -> Error {
163 Utf8(err)
164 }
165}
166
167impl From<FromUtf8Error> for Error {
168 fn from(err: FromUtf8Error) -> Error {
169 Utf8(err.utf8_error())
170 }
171}
172
173impl From<httparse::Error> for Error {
174 fn from(err: httparse::Error) -> Error {
175 match err {
176 httparse::Error::HeaderName |
177 httparse::Error::HeaderValue |
178 httparse::Error::NewLine |
179 httparse::Error::Token => Header,
180 httparse::Error::Status => Status,
181 httparse::Error::TooManyHeaders => TooLarge,
182 httparse::Error::Version => Version,
183 }
184 }
185}
186
187#[doc(hidden)]
188trait AssertSendSync: Send + Sync + 'static {}
189#[doc(hidden)]
190impl AssertSendSync for Error {}
191
192#[cfg(test)]
193mod tests {
194 use std::error::Error as StdError;
195 use std::io;
196 use httparse;
197 use super::Error;
198 use super::Error::*;
199
200 #[test]
201 fn test_cause() {
202 let orig = io::Error::new(io::ErrorKind::Other, "other");
203 let desc = orig.description().to_owned();
204 let e = Io(orig);
205 assert_eq!(e.cause().unwrap().description(), desc);
206 }
207
208 macro_rules! from {
209 ($from:expr => $error:pat) => {
210 match Error::from($from) {
211 e @ $error => {
212 assert!(e.description().len() >= 5);
213 } ,
214 e => panic!("{:?}", e)
215 }
216 }
217 }
218
219 macro_rules! from_and_cause {
220 ($from:expr => $error:pat) => {
221 match Error::from($from) {
222 e @ $error => {
223 let desc = e.cause().unwrap().description();
224 assert_eq!(desc, $from.description().to_owned());
225 assert_eq!(desc, e.description());
226 },
227 _ => panic!("{:?}", $from)
228 }
229 }
230 }
231
232 #[test]
233 fn test_from() {
234
235 from_and_cause!(io::Error::new(io::ErrorKind::Other, "other") => Io(..));
236
237 from!(httparse::Error::HeaderName => Header);
238 from!(httparse::Error::HeaderName => Header);
239 from!(httparse::Error::HeaderValue => Header);
240 from!(httparse::Error::NewLine => Header);
241 from!(httparse::Error::Status => Status);
242 from!(httparse::Error::Token => Header);
243 from!(httparse::Error::TooManyHeaders => TooLarge);
244 from!(httparse::Error::Version => Version);
245 }
246}