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;
9use url;
10
11#[cfg(feature = "openssl")]
12use openssl::ssl::error::SslError;
13
14use self::Error::{
15 Method,
16 Uri,
17 Version,
18 Header,
19 Status,
20 Io,
21 Ssl,
22 TooLarge,
23 Utf8
24};
25
26pub use url::ParseError;
27
28pub type Result<T> = ::std::result::Result<T, Error>;
30
31#[derive(Debug)]
33pub enum Error {
34 Method,
36 Uri(url::ParseError),
38 Version,
40 Header,
42 TooLarge,
44 Status,
46 Io(IoError),
48 Ssl(Box<StdError + Send + Sync>),
50 Utf8(Utf8Error),
52
53 #[doc(hidden)]
54 __Nonexhaustive(Void)
55}
56
57#[doc(hidden)]
58pub struct Void(());
59
60impl fmt::Debug for Void {
61 fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
62 unreachable!()
63 }
64}
65
66impl fmt::Display for Error {
67 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
68 match *self {
69 Uri(ref e) => fmt::Display::fmt(e, f),
70 Io(ref e) => fmt::Display::fmt(e, f),
71 Ssl(ref e) => fmt::Display::fmt(e, f),
72 Utf8(ref e) => fmt::Display::fmt(e, f),
73 ref e => f.write_str(e.description()),
74 }
75 }
76}
77
78impl StdError for Error {
79 fn description(&self) -> &str {
80 match *self {
81 Method => "Invalid Method specified",
82 Version => "Invalid HTTP version specified",
83 Header => "Invalid Header provided",
84 TooLarge => "Message head is too large",
85 Status => "Invalid Status provided",
86 Uri(ref e) => e.description(),
87 Io(ref e) => e.description(),
88 Ssl(ref e) => e.description(),
89 Utf8(ref e) => e.description(),
90 Error::__Nonexhaustive(..) => unreachable!(),
91 }
92 }
93
94 fn cause(&self) -> Option<&StdError> {
95 match *self {
96 Io(ref error) => Some(error),
97 Ssl(ref error) => Some(&**error),
98 Uri(ref error) => Some(error),
99 Utf8(ref error) => Some(error),
100 _ => None,
101 }
102 }
103}
104
105impl From<IoError> for Error {
106 fn from(err: IoError) -> Error {
107 Io(err)
108 }
109}
110
111impl From<url::ParseError> for Error {
112 fn from(err: url::ParseError) -> Error {
113 Uri(err)
114 }
115}
116
117#[cfg(feature = "openssl")]
118impl From<SslError> for Error {
119 fn from(err: SslError) -> Error {
120 match err {
121 SslError::StreamError(err) => Io(err),
122 err => Ssl(Box::new(err)),
123 }
124 }
125}
126
127impl From<Utf8Error> for Error {
128 fn from(err: Utf8Error) -> Error {
129 Utf8(err)
130 }
131}
132
133impl From<FromUtf8Error> for Error {
134 fn from(err: FromUtf8Error) -> Error {
135 Utf8(err.utf8_error())
136 }
137}
138
139impl From<httparse::Error> for Error {
140 fn from(err: httparse::Error) -> Error {
141 match err {
142 httparse::Error::HeaderName => Header,
143 httparse::Error::HeaderValue => Header,
144 httparse::Error::NewLine => Header,
145 httparse::Error::Status => Status,
146 httparse::Error::Token => Header,
147 httparse::Error::TooManyHeaders => TooLarge,
148 httparse::Error::Version => Version,
149 }
150 }
151}
152
153#[cfg(test)]
154mod tests {
155 use std::error::Error as StdError;
156 use std::io;
157 use httparse;
158 use url;
159 use super::Error;
160 use super::Error::*;
161
162 #[test]
163 fn test_cause() {
164 let orig = io::Error::new(io::ErrorKind::Other, "other");
165 let desc = orig.description().to_owned();
166 let e = Io(orig);
167 assert_eq!(e.cause().unwrap().description(), desc);
168 }
169
170 macro_rules! from {
171 ($from:expr => $error:pat) => {
172 match Error::from($from) {
173 e @ $error => {
174 assert!(e.description().len() > 5);
175 } ,
176 _ => panic!("{:?}", $from)
177 }
178 }
179 }
180
181 macro_rules! from_and_cause {
182 ($from:expr => $error:pat) => {
183 match Error::from($from) {
184 e @ $error => {
185 let desc = e.cause().unwrap().description();
186 assert_eq!(desc, $from.description().to_owned());
187 assert_eq!(desc, e.description());
188 },
189 _ => panic!("{:?}", $from)
190 }
191 }
192 }
193
194 #[test]
195 fn test_from() {
196
197 from_and_cause!(io::Error::new(io::ErrorKind::Other, "other") => Io(..));
198 from_and_cause!(url::ParseError::EmptyHost => Uri(..));
199
200 from!(httparse::Error::HeaderName => Header);
201 from!(httparse::Error::HeaderName => Header);
202 from!(httparse::Error::HeaderValue => Header);
203 from!(httparse::Error::NewLine => Header);
204 from!(httparse::Error::Status => Status);
205 from!(httparse::Error::Token => Header);
206 from!(httparse::Error::TooManyHeaders => TooLarge);
207 from!(httparse::Error::Version => Version);
208 }
209
210 #[cfg(feature = "openssl")]
211 #[test]
212 fn test_from_ssl() {
213 use openssl::ssl::error::SslError;
214
215 from!(SslError::StreamError(
216 io::Error::new(io::ErrorKind::Other, "ssl negotiation")) => Io(..));
217 from_and_cause!(SslError::SslSessionClosed => Ssl(..));
218 }
219}