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