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