cogo_http/
error.rs

1//! Error and Result module.
2use 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
29/// Result type often returned from methods that can have hyper `Error`s.
30pub type Result<T> = ::std::result::Result<T, Error>;
31
32/// A set of errors that can occur parsing HTTP streams.
33#[derive(Debug)]
34pub enum Error {
35    /// An invalid `Method`, such as `GE,T`.
36    Method,
37    /// An invalid `RequestUri`, such as `exam ple.domain`.
38    Uri(url::ParseError),
39    /// An invalid `HttpVersion`, such as `HTP/1.1`
40    Version,
41    /// An invalid `Header`.
42    Header,
43    /// A message head is too large to be reasonable.
44    TooLarge,
45    /// An invalid `Status`, such as `1337 ELITE`.
46    Status,
47    /// An `io::Error` that occurred while trying to read or write to a network stream.
48    Io(IoError),
49    /// An error from a SSL library.
50    Ssl(Box<dyn StdError + Send + Sync>),
51    /// Parsing a field as string failed
52    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}