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