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