Skip to main content

ts_http_util/
error.rs

1use std::error::Error as StdError;
2
3/// General categories of error that can occur during any phase of an HTTP connection.
4#[derive(Debug, Copy, Clone, PartialEq, Eq, thiserror::Error)]
5pub enum Error {
6    /// A function argument or field value wasn't populated, or contained an invalid value, or user-
7    /// supplied code caused an error.
8    #[error("invalid parameter or other input")]
9    InvalidInput,
10
11    /// An underlying I/O error occurred that prevented a connection from being established, a
12    /// request from being sent, or a response from being read.
13    #[error("i/o error encountered")]
14    Io,
15
16    /// A timeout expired while waiting for the server to respond, or the client (us) didn't send
17    /// request headers within the timeframe the server expected.
18    #[error("timed out")]
19    Timeout,
20
21    /// The connection is no longer usable for some (probably unexpected) reason.
22    #[error("an error occurred and the connection must be re-established before retrying")]
23    ConnectionClosed,
24
25    /// An invalid status code or HTTP 2 message where HTTP 1 was expected.
26    #[error("received a response which was invalid in some way")]
27    InvalidResponse,
28}
29
30impl From<hyper::Error> for Error {
31    fn from(e: hyper::Error) -> Self {
32        if io_error(&e) {
33            Error::Io
34        } else if e.is_timeout() {
35            Error::Timeout
36        } else if e.is_parse() || e.is_user() {
37            Error::InvalidInput
38        } else if e.is_parse_status() || e.is_parse_version_h2() {
39            Error::InvalidResponse
40        } else {
41            // A problem with the connection, or something occurred where we should do some kind of
42            // reset before retrying.
43            // e.is_canceled() || e.is_shutdown() || e.is_body_write_aborted() || e.is_closed() || e.is_incomplete_message
44            Error::ConnectionClosed
45        }
46    }
47}
48
49fn io_error(e: &hyper::Error) -> bool {
50    let mut e = e as &dyn StdError;
51    loop {
52        match e.source() {
53            None => return false,
54            Some(source) => {
55                let io = source.downcast_ref::<std::io::Error>();
56                if io.is_some() {
57                    return true;
58                }
59                e = source;
60            }
61        }
62    }
63}