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