a2httpc/
error.rs

1use std::convert::Infallible;
2use std::error::Error as StdError;
3use std::fmt::{self, Display};
4use std::io;
5use std::result;
6
7/// Errors than can occur while parsing the response from the server.
8#[derive(Debug)]
9pub enum InvalidResponseKind {
10    /// Invalid or missing Location header in redirection
11    LocationHeader,
12    /// Invalid redirection URL
13    RedirectionUrl,
14    /// Status line
15    StatusLine,
16    /// Status code
17    StatusCode,
18    /// Error parsing header
19    Header,
20    /// Error decoding chunk size
21    ChunkSize,
22    /// Error decoding chunk
23    Chunk,
24    /// Invalid Content-Length header
25    ContentLength,
26}
27
28impl Display for InvalidResponseKind {
29    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
30        use InvalidResponseKind::*;
31
32        match self {
33            LocationHeader => write!(f, "missing or invalid location header"),
34            RedirectionUrl => write!(f, "invalid redirection url"),
35            StatusLine => write!(f, "invalid status line"),
36            StatusCode => write!(f, "invalid status code"),
37            Header => write!(f, "invalid header"),
38            ChunkSize => write!(f, "invalid chunk size"),
39            Chunk => write!(f, "invalid chunk"),
40            ContentLength => write!(f, "invalid content length"),
41        }
42    }
43}
44
45/// Common errors that can occur during HTTP requests.
46#[derive(Debug)]
47pub enum ErrorKind {
48    /// CONNECT is not supported.
49    ConnectNotSupported,
50    /// Could not connect to proxy with CONNECT method.
51    ConnectError {
52        /// Status code from the proxy.
53        status_code: http::StatusCode,
54        /// Up to 10 KiB of body data from the proxy which might help diagnose the error.
55        body: Vec<u8>,
56    },
57    /// Error generated by the `http` crate.
58    Http(http::Error),
59    /// IO Error
60    Io(io::Error),
61    /// Invalid base URL given to the Request.
62    InvalidBaseUrl,
63    /// An URL with an invalid host was found while processing the request.
64    InvalidUrlHost,
65    /// The URL scheme is unknown and the port is missing.
66    InvalidUrlPort,
67    /// Server sent an invalid response.
68    InvalidResponse(InvalidResponseKind),
69    /// Too many redirections
70    TooManyRedirections,
71    /// Status code indicates failure
72    StatusCode(http::StatusCode),
73    /// JSON decoding/encoding error.
74    #[cfg(feature = "json")]
75    Json(serde_json::Error),
76    /// Form-URL encoding error.
77    #[cfg(feature = "form")]
78    UrlEncoded(serde_urlencoded::ser::Error),
79    /// TLS error encountered while connecting to an https server.
80    #[cfg(feature = "tls-native")]
81    Tls(native_tls::Error),
82    /// TLS error encountered while connecting to an https server.
83    #[cfg(all(feature = "__rustls", not(feature = "tls-native")))]
84    Tls(rustls::Error),
85    /// Invalid DNS name used for TLS certificate verification
86    #[cfg(feature = "__rustls")]
87    InvalidDNSName(String),
88    /// Invalid mime type in a Multipart form
89    InvalidMimeType(String),
90    /// TLS was not enabled by features.
91    TlsDisabled,
92    /// Empty cert store
93    #[cfg(all(feature = "__rustls", not(feature = "tls-native")))]
94    ServerCertVerifier(rustls::client::VerifierBuilderError),
95}
96
97/// A type that contains all the errors that can possibly occur while accessing an HTTP server.
98#[derive(Debug)]
99pub struct Error(pub(crate) Box<ErrorKind>);
100
101impl Error {
102    /// Get a reference to the `ErrorKind` inside.
103    pub fn kind(&self) -> &ErrorKind {
104        &self.0
105    }
106
107    /// Comsume this `Error` and get the `ErrorKind` inside.
108    pub fn into_kind(self) -> ErrorKind {
109        *self.0
110    }
111}
112
113impl Display for Error {
114    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
115        use ErrorKind::*;
116
117        match *self.0 {
118            ConnectNotSupported => write!(w, "CONNECT is not supported"),
119            ConnectError { status_code, .. } => write!(w, "Proxy CONNECT error: {status_code}"),
120            Http(ref e) => write!(w, "Http Error: {e}"),
121            Io(ref e) => write!(w, "Io Error: {e}"),
122            InvalidBaseUrl => write!(w, "Invalid base URL"),
123            InvalidUrlHost => write!(w, "URL is missing a host"),
124            InvalidUrlPort => write!(w, "URL is missing a port"),
125            InvalidResponse(ref k) => write!(w, "InvalidResponse: {k}"),
126            TooManyRedirections => write!(w, "Too many redirections"),
127            StatusCode(ref sc) => write!(w, "Status code {sc} indicates failure"),
128            #[cfg(feature = "json")]
129            Json(ref e) => write!(w, "Json Error: {e}"),
130            #[cfg(feature = "form")]
131            UrlEncoded(ref e) => write!(w, "URL Encoding Error: {e}"),
132            #[cfg(any(feature = "tls-native", feature = "__rustls"))]
133            Tls(ref e) => write!(w, "Tls Error: {e}"),
134            #[cfg(feature = "__rustls")]
135            InvalidDNSName(ref e) => write!(w, "Invalid DNS name: {e}"),
136            InvalidMimeType(ref e) => write!(w, "Invalid mime type: {e}"),
137            TlsDisabled => write!(w, "TLS is disabled, activate one of the tls- features"),
138            #[cfg(all(feature = "__rustls", not(feature = "tls-native")))]
139            ServerCertVerifier(ref e) => write!(w, "Invalid certificate: {e}"),
140        }
141    }
142}
143
144impl StdError for Error {
145    fn cause(&self) -> Option<&dyn StdError> {
146        use ErrorKind::*;
147
148        match *self.0 {
149            Io(ref e) => Some(e),
150            Http(ref e) => Some(e),
151            #[cfg(feature = "json")]
152            Json(ref e) => Some(e),
153            #[cfg(any(feature = "tls-native", feature = "__rustls"))]
154            Tls(ref e) => Some(e),
155            _ => None,
156        }
157    }
158}
159
160impl From<Infallible> for Error {
161    fn from(_err: Infallible) -> Error {
162        unreachable!()
163    }
164}
165
166impl From<io::Error> for Error {
167    fn from(err: io::Error) -> Error {
168        Error(Box::new(ErrorKind::Io(err)))
169    }
170}
171
172impl From<http::Error> for Error {
173    fn from(err: http::Error) -> Error {
174        Error(Box::new(ErrorKind::Http(err)))
175    }
176}
177
178impl From<http::header::InvalidHeaderValue> for Error {
179    fn from(err: http::header::InvalidHeaderValue) -> Error {
180        Error(Box::new(ErrorKind::Http(http::Error::from(err))))
181    }
182}
183
184#[cfg(feature = "tls-native")]
185impl From<native_tls::Error> for Error {
186    fn from(err: native_tls::Error) -> Error {
187        Error(Box::new(ErrorKind::Tls(err)))
188    }
189}
190
191#[cfg(all(feature = "__rustls", not(feature = "tls-native")))]
192impl From<rustls::Error> for Error {
193    fn from(err: rustls::Error) -> Error {
194        Error(Box::new(ErrorKind::Tls(err)))
195    }
196}
197
198#[cfg(feature = "json")]
199impl From<serde_json::Error> for Error {
200    fn from(err: serde_json::Error) -> Error {
201        Error(Box::new(ErrorKind::Json(err)))
202    }
203}
204
205#[cfg(feature = "form")]
206impl From<serde_urlencoded::ser::Error> for Error {
207    fn from(err: serde_urlencoded::ser::Error) -> Error {
208        Error(Box::new(ErrorKind::UrlEncoded(err)))
209    }
210}
211
212impl From<ErrorKind> for Error {
213    fn from(err: ErrorKind) -> Error {
214        Error(Box::new(err))
215    }
216}
217
218impl From<InvalidResponseKind> for Error {
219    fn from(kind: InvalidResponseKind) -> Error {
220        ErrorKind::InvalidResponse(kind).into()
221    }
222}
223
224#[cfg(all(feature = "__rustls", not(feature = "tls-native")))]
225impl From<rustls::client::VerifierBuilderError> for Error {
226    fn from(err: rustls::client::VerifierBuilderError) -> Error {
227        Error(Box::new(ErrorKind::ServerCertVerifier(err)))
228    }
229}
230
231impl From<Error> for io::Error {
232    fn from(err: Error) -> io::Error {
233        io::Error::other(err)
234    }
235}
236
237impl From<InvalidResponseKind> for io::Error {
238    fn from(kind: InvalidResponseKind) -> io::Error {
239        io::Error::other(Error(Box::new(ErrorKind::InvalidResponse(kind))))
240    }
241}
242
243/// Wrapper for the `Result` type with an `Error`.
244pub type Result<T = ()> = result::Result<T, Error>;