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
use std::io;
use std::convert::From;
use futures::sync::mpsc::SendError;
use httparse::Error as HttpError;
use httparse::InvalidChunkSize;
quick_error! {
#[derive(Debug)]
/// HTTP client error
pub enum Error wraps pub 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 being on keep-alive")
}
Custom(err: Box<::std::error::Error + Send + Sync>) {
description("custom error")
display("custom error: {}", err)
cause(&**err)
}
}
}
impl<T> From<SendError<T>> for ErrorEnum {
fn from(_: SendError<T>) -> ErrorEnum {
ErrorEnum::PoolError
}
}
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()))
}
/// Tries to catch all the conditions where this isn't error
///
/// Currently catches these conditions:
///
/// 1. Connection timed out while being on keep-alive (no inprogress
/// requests)
/// 2. Connection is closed after `Connection: close` header
///
/// More conditions may be added in future. This should be commonly used
/// to skip logging of useless errors.
pub fn is_graceful(&self) -> bool {
match self.0 {
ErrorEnum::Closed => true,
ErrorEnum::KeepAliveTimeout => true,
_ => false,
}
}
}
#[test]
fn send_sync() {
fn send_sync<T: Send+Sync>(_: T) {}
send_sync(Error::from(ErrorEnum::Canceled));
}