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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
use std::io;
use std::fmt;
use std::convert::From;

use futures::sync::mpsc::SendError;
use httparse::Error as HttpError;
use httparse::InvalidChunkSize;


/// HTTP client error
pub struct Error(ErrorEnum);


quick_error! {
    #[derive(Debug)]
    /// Client request error
    pub enum ErrorEnum {
        /// I/O (basically networking) error occured during request
        Io(err: io::Error) {
            description("IO error")
            display("IO error: {}", err)
            from()
        }
        /// Bad response headers received
        Header(err: HttpError) {
            description("bad headers")
            display("bad headers: {}", err)
            from()
        }
        /// Bad chunk size received
        ChunkSize(err: InvalidChunkSize) {
            description("invalid chunk size")
            display("invalid chunk size: {}", err)
            from()
        }
        /// Bad `Content-Length` header
        BadContentLength {
            description("bad content length")
        }
        /// Duplicate `Content-Length` header
        DuplicateContentLength {
            description("duplicate content length")
        }
        /// Connection reset by peer when reading response headers
        ResetOnResponseHeaders {
            description("connection closed prematurely while reading headers")
        }
        /// Connection reset by peer when response body
        ResetOnResponseBody {
            description("connection closed prematurely while reading body")
        }
        /// Response headers are received while we had no request sent yet
        PrematureResponseHeaders {
            description("response headers received \
                         before request has been written")
        }
        /// This means connection is busy (over the limit or not yet
        /// established when trying to send request
        Busy {
            description("request can't be sent because connection is busy")
        }
        /// The channel for receiving response is canceled. This probably means
        /// that connection to server was closed before being able to fulfil
        /// the request. But it's unlikely that this error is related to this
        /// request itself.
        Canceled {
            description("request canceled")
        }
        /// Connection closed normally
        ///
        /// This error should be catched by connection poolm and not shown
        /// to the end users
        Closed {
            description("connection closed normally")
        }
        /// Invalid URL specified
        InvalidUrl {
            description("requesting an invalid url")
        }
        /// Error sending a request to a connection pool
        PoolError {
            description("error sending a request to a connection pool")
        }
        /// Request body is too big (happens only in buffered mode)
        ResponseBodyTooLong {
            description("response body too long")
        }
        /// Connection header is invalid
        ConnectionInvalid {
            description("invalid connection header in response")
        }
        /// Unsupported status returned by server
        ///
        /// You have to write your own Codec to handle unsupported status codes
        InvalidStatus {
            description("unsupported status")
        }
        /// Request timed out
        RequestTimeout {
            description("request timed out")
        }
        /// Connection timed out on keep alive
        KeepAliveTimeout {
            description("connection timed out beeing on keep-alive")
        }
        Custom(err: Box<::std::error::Error + Send + Sync>) {
            description("custom error")
            cause(&**err)
        }
    }
}

impl<T> From<SendError<T>> for ErrorEnum {
    fn from(_: SendError<T>) -> ErrorEnum {
        ErrorEnum::PoolError
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, f)
    }
}

impl From<ErrorEnum> for Error {
    fn from(err: ErrorEnum) -> Self {
        Error(err)
    }
}

impl ::std::error::Error for Error {
    fn description(&self) -> &str {
        self.0.description()
    }
    fn cause(&self) -> Option<&::std::error::Error> {
        self.0.cause()
    }
}

impl Error {
    /// Create an error instance wrapping custom error
    pub fn custom<E: Into<Box<::std::error::Error + Send + Sync>>>(err: E)
        -> Error
    {
        Error(ErrorEnum::Custom(err.into()))
    }
}

#[test]
fn send_sync() {
    fn send_sync<T: Send+Sync>(_: T) {}
    send_sync(Error::from(ErrorEnum::Canceled));
}