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? // TODO: Maybe make a few inner error types containing groups of these, based on // what the user might want to handle? This error doesn't really invite graceful // handling. 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), // TODO: Add separate errors for openssl and native_tls errors as well /// 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 for Error { fn from(other: io::Error) -> Error { Error::IoError(other) } }