minreq/error.rs
1use std::{error, fmt, io, str};
2
3/// Represents an error while sending, receiving, or parsing an HTTP response.
4#[derive(Debug)]
5// TODO: Make non-exhaustive for 3.0?
6// TODO: Maybe make a few inner error types containing groups of these, based on
7// what the user might want to handle? This error doesn't really invite graceful
8// handling.
9pub enum Error {
10 #[cfg(feature = "json-using-serde")]
11 /// Ran into a Serde error.
12 SerdeJsonError(serde_json::Error),
13 /// The response body contains invalid UTF-8, so the `as_str()`
14 /// conversion failed.
15 InvalidUtf8InBody(str::Utf8Error),
16
17 #[cfg(feature = "rustls")]
18 /// Ran into a rustls error while creating the connection.
19 RustlsCreateConnection(rustls::Error),
20 // TODO: Add separate errors for openssl and native_tls errors as well
21 /// Ran into an IO problem while loading the response.
22 IoError(io::Error),
23 /// Couldn't parse the incoming chunk's length while receiving a
24 /// response with the header `Transfer-Encoding: chunked`.
25 MalformedChunkLength,
26 /// The chunk did not end after reading the previously read amount
27 /// of bytes.
28 MalformedChunkEnd,
29 /// Couldn't parse the `Content-Length` header's value as an
30 /// `usize`.
31 MalformedContentLength,
32 /// The response contains headers whose total size surpasses
33 /// [Request::with_max_headers_size](crate::request::Request::with_max_headers_size).
34 HeadersOverflow,
35 /// The response's status line length surpasses
36 /// [Request::with_max_status_line_size](crate::request::Request::with_max_status_line_length).
37 StatusLineOverflow,
38 /// [ToSocketAddrs](std::net::ToSocketAddrs) did not resolve to an
39 /// address.
40 AddressNotFound,
41 /// The response was a redirection, but the `Location` header is
42 /// missing.
43 RedirectLocationMissing,
44 /// The response redirections caused an infinite redirection loop.
45 InfiniteRedirectionLoop,
46 /// Followed
47 /// [`max_redirections`](struct.Request.html#method.with_max_redirections)
48 /// redirections, won't follow any more.
49 TooManyRedirections,
50 /// The response contained invalid UTF-8 where it should be valid
51 /// (eg. headers), so the response cannot interpreted correctly.
52 InvalidUtf8InResponse,
53 /// The provided url contained a domain that has non-ASCII
54 /// characters, and could not be converted into punycode. It is
55 /// probably not an actual domain.
56 PunycodeConversionFailed,
57 /// Tried to send a secure request (ie. the url started with
58 /// `https://`), but the crate's `https` feature was not enabled,
59 /// and as such, a connection cannot be made.
60 HttpsFeatureNotEnabled,
61 /// The provided url contained a domain that has non-ASCII
62 /// characters, but it could not be converted into punycode
63 /// because the `punycode` feature was not enabled.
64 PunycodeFeatureNotEnabled,
65 /// The provided proxy information was not properly formatted. See
66 /// [Proxy::new](crate::Proxy::new) for the valid format.
67 BadProxy,
68 /// The provided credentials were rejected by the proxy server.
69 BadProxyCreds,
70 /// The provided proxy credentials were malformed.
71 ProxyConnect,
72 /// The provided credentials were rejected by the proxy server.
73 InvalidProxyCreds,
74 // TODO: Uncomment these two for 3.0
75 // /// The URL does not start with http:// or https://.
76 // InvalidProtocol,
77 // /// The URL ended up redirecting to an URL that does not start
78 // /// with http:// or https://.
79 // InvalidProtocolInRedirect,
80 /// This is a special error case, one that should never be
81 /// returned! Think of this as a cleaner alternative to calling
82 /// `unreachable!()` inside the library. If you come across this,
83 /// please open an issue, and include the string inside this
84 /// error, as it can be used to locate the problem.
85 Other(&'static str),
86}
87
88impl fmt::Display for Error {
89 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
90 use Error::*;
91 match self {
92 #[cfg(feature = "json-using-serde")]
93 SerdeJsonError(err) => write!(f, "{}", err),
94 IoError(err) => write!(f, "{}", err),
95 InvalidUtf8InBody(err) => write!(f, "{}", err),
96
97 #[cfg(feature = "rustls")]
98 RustlsCreateConnection(err) => write!(f, "error creating rustls connection: {}", err),
99 MalformedChunkLength => write!(f, "non-usize chunk length with transfer-encoding: chunked"),
100 MalformedChunkEnd => write!(f, "chunk did not end after reading the expected amount of bytes"),
101 MalformedContentLength => write!(f, "non-usize content length"),
102 HeadersOverflow => write!(f, "the headers' total size surpassed max_headers_size"),
103 StatusLineOverflow => write!(f, "the status line length surpassed max_status_line_length"),
104 AddressNotFound => write!(f, "could not resolve host to a socket address"),
105 RedirectLocationMissing => write!(f, "redirection location header missing"),
106 InfiniteRedirectionLoop => write!(f, "infinite redirection loop detected"),
107 TooManyRedirections => write!(f, "too many redirections (over the max)"),
108 InvalidUtf8InResponse => write!(f, "response contained invalid utf-8 where valid utf-8 was expected"),
109 HttpsFeatureNotEnabled => write!(f, "request url contains https:// but the https feature is not enabled"),
110 PunycodeFeatureNotEnabled => write!(f, "non-ascii urls needs to be converted into punycode, and the feature is missing"),
111 PunycodeConversionFailed => write!(f, "non-ascii url conversion to punycode failed"),
112 BadProxy => write!(f, "the provided proxy information is malformed"),
113 BadProxyCreds => write!(f, "the provided proxy credentials are malformed"),
114 ProxyConnect => write!(f, "could not connect to the proxy server"),
115 InvalidProxyCreds => write!(f, "the provided proxy credentials are invalid"),
116 // TODO: Uncomment these two for 3.0
117 // InvalidProtocol => write!(f, "the url does not start with http:// or https://"),
118 // InvalidProtocolInRedirect => write!(f, "got redirected to an absolute url which does not start with http:// or https://"),
119 Other(msg) => write!(f, "error in minreq: please open an issue in the minreq repo, include the following: '{}'", msg),
120 }
121 }
122}
123
124impl error::Error for Error {
125 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
126 use Error::*;
127 match self {
128 #[cfg(feature = "json-using-serde")]
129 SerdeJsonError(err) => Some(err),
130 IoError(err) => Some(err),
131 InvalidUtf8InBody(err) => Some(err),
132 #[cfg(feature = "rustls")]
133 RustlsCreateConnection(err) => Some(err),
134 _ => None,
135 }
136 }
137}
138
139impl From<io::Error> for Error {
140 fn from(other: io::Error) -> Error {
141 Error::IoError(other)
142 }
143}