1use std::convert::Infallible;
2use std::error::Error as StdError;
3use std::fmt::{self, Display};
4use std::io;
5use std::result;
6
7#[derive(Debug)]
9pub enum InvalidResponseKind {
10 LocationHeader,
12 RedirectionUrl,
14 StatusLine,
16 StatusCode,
18 Header,
20 ChunkSize,
22 Chunk,
24 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#[derive(Debug)]
47pub enum ErrorKind {
48 ConnectNotSupported,
50 ConnectError {
52 status_code: http::StatusCode,
54 body: Vec<u8>,
56 },
57 Http(http::Error),
59 Io(io::Error),
61 InvalidBaseUrl,
63 InvalidUrlHost,
65 InvalidUrlPort,
67 InvalidResponse(InvalidResponseKind),
69 TooManyRedirections,
71 StatusCode(http::StatusCode),
73 #[cfg(feature = "json")]
75 Json(serde_json::Error),
76 #[cfg(feature = "form")]
78 UrlEncoded(serde_urlencoded::ser::Error),
79 #[cfg(feature = "tls-native")]
81 Tls(native_tls::Error),
82 #[cfg(all(feature = "__rustls", not(feature = "tls-native")))]
84 Tls(rustls::Error),
85 #[cfg(feature = "__rustls")]
87 InvalidDNSName(String),
88 InvalidMimeType(String),
90 TlsDisabled,
92 #[cfg(all(feature = "__rustls", not(feature = "tls-native")))]
94 ServerCertVerifier(rustls::client::VerifierBuilderError),
95}
96
97#[derive(Debug)]
99pub struct Error(pub(crate) Box<ErrorKind>);
100
101impl Error {
102 pub fn kind(&self) -> &ErrorKind {
104 &self.0
105 }
106
107 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
243pub type Result<T = ()> = result::Result<T, Error>;