minreq 3.0.0-rc.0

Simple, minimal-dependency HTTP client
Documentation
use std::{error, fmt, io, str};

/// Represents an error while sending, receiving, or parsing an HTTP response.
#[derive(Debug)]
#[non_exhaustive]
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),
    #[cfg(feature = "native-tls")]
    /// Ran into a native_tls error while creating the connection.
    NativeTlsCreateConnection(native_tls::HandshakeError<std::net::TcpStream>),
    #[cfg(feature = "openssl")]
    /// Ran into an openssl error while creating the connection.
    OpenSslCreateConnection(openssl::ssl::HandshakeError<std::net::TcpStream>),
    /// 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,
    /// 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,
}

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),
            #[cfg(feature = "native-tls")]
            NativeTlsCreateConnection(err) => {
                write!(f, "error creating openssl connection: {}", err)
            }
            #[cfg(feature = "openssl")]
            OpenSslCreateConnection(err) => write!(f, "error creating openssl 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"),
            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://"
            ),
        }
    }
}

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)
    }
}