/rust/registry/src/index.crates.io-1949cf8c6b5b557f/hyper-1.6.0/src/error.rs
Line | Count | Source |
1 | | //! Error and Result module. |
2 | | use std::error::Error as StdError; |
3 | | use std::fmt; |
4 | | |
5 | | /// Result type often returned from methods that can have hyper `Error`s. |
6 | | pub type Result<T> = std::result::Result<T, Error>; |
7 | | |
8 | | type Cause = Box<dyn StdError + Send + Sync>; |
9 | | |
10 | | /// Represents errors that can occur handling HTTP streams. |
11 | | /// |
12 | | /// # Formatting |
13 | | /// |
14 | | /// The `Display` implementation of this type will only print the details of |
15 | | /// this level of error, even though it may have been caused by another error |
16 | | /// and contain that error in its source. To print all the relevant |
17 | | /// information, including the source chain, using something like |
18 | | /// `std::error::Report`, or equivalent 3rd party types. |
19 | | /// |
20 | | /// The contents of the formatted error message of this specific `Error` type |
21 | | /// is unspecified. **You must not depend on it.** The wording and details may |
22 | | /// change in any version, with the goal of improving error messages. |
23 | | /// |
24 | | /// # Source |
25 | | /// |
26 | | /// A `hyper::Error` may be caused by another error. To aid in debugging, |
27 | | /// those are exposed in `Error::source()` as erased types. While it is |
28 | | /// possible to check the exact type of the sources, they **can not be depended |
29 | | /// on**. They may come from private internal dependencies, and are subject to |
30 | | /// change at any moment. |
31 | | pub struct Error { |
32 | | inner: Box<ErrorImpl>, |
33 | | } |
34 | | |
35 | | struct ErrorImpl { |
36 | | kind: Kind, |
37 | | cause: Option<Cause>, |
38 | | } |
39 | | |
40 | | #[derive(Debug)] |
41 | | pub(super) enum Kind { |
42 | | Parse(Parse), |
43 | | User(User), |
44 | | /// A message reached EOF, but is not complete. |
45 | | #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))] |
46 | | IncompleteMessage, |
47 | | /// A connection received a message (or bytes) when not waiting for one. |
48 | | #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))] |
49 | | UnexpectedMessage, |
50 | | /// A pending item was dropped before ever being processed. |
51 | | Canceled, |
52 | | /// Indicates a channel (client or body sender) is closed. |
53 | | #[cfg(any( |
54 | | all(feature = "http1", any(feature = "client", feature = "server")), |
55 | | all(feature = "http2", feature = "client") |
56 | | ))] |
57 | | ChannelClosed, |
58 | | /// An `io::Error` that occurred while trying to read or write to a network stream. |
59 | | #[cfg(all( |
60 | | any(feature = "client", feature = "server"), |
61 | | any(feature = "http1", feature = "http2") |
62 | | ))] |
63 | | Io, |
64 | | /// User took too long to send headers |
65 | | #[cfg(all(feature = "http1", feature = "server"))] |
66 | | HeaderTimeout, |
67 | | /// Error while reading a body from connection. |
68 | | #[cfg(all( |
69 | | any(feature = "client", feature = "server"), |
70 | | any(feature = "http1", feature = "http2") |
71 | | ))] |
72 | | Body, |
73 | | /// Error while writing a body to connection. |
74 | | #[cfg(all( |
75 | | any(feature = "client", feature = "server"), |
76 | | any(feature = "http1", feature = "http2") |
77 | | ))] |
78 | | BodyWrite, |
79 | | /// Error calling AsyncWrite::shutdown() |
80 | | #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))] |
81 | | Shutdown, |
82 | | |
83 | | /// A general error from h2. |
84 | | #[cfg(all(any(feature = "client", feature = "server"), feature = "http2"))] |
85 | | Http2, |
86 | | } |
87 | | |
88 | | #[derive(Debug)] |
89 | | pub(super) enum Parse { |
90 | | Method, |
91 | | #[cfg(feature = "http1")] |
92 | | Version, |
93 | | #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))] |
94 | | VersionH2, |
95 | | Uri, |
96 | | #[cfg(all(feature = "http1", feature = "server"))] |
97 | | UriTooLong, |
98 | | #[cfg(feature = "http1")] |
99 | | Header(Header), |
100 | | #[cfg(any(feature = "http1", feature = "http2"))] |
101 | | #[cfg_attr(feature = "http2", allow(unused))] |
102 | | TooLarge, |
103 | | Status, |
104 | | #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))] |
105 | | Internal, |
106 | | } |
107 | | |
108 | | #[derive(Debug)] |
109 | | #[cfg(feature = "http1")] |
110 | | pub(super) enum Header { |
111 | | Token, |
112 | | #[cfg(any(feature = "client", feature = "server"))] |
113 | | ContentLengthInvalid, |
114 | | #[cfg(feature = "server")] |
115 | | TransferEncodingInvalid, |
116 | | #[cfg(any(feature = "client", feature = "server"))] |
117 | | TransferEncodingUnexpected, |
118 | | } |
119 | | |
120 | | #[derive(Debug)] |
121 | | pub(super) enum User { |
122 | | /// Error calling user's Body::poll_data(). |
123 | | #[cfg(all( |
124 | | any(feature = "client", feature = "server"), |
125 | | any(feature = "http1", feature = "http2") |
126 | | ))] |
127 | | Body, |
128 | | /// The user aborted writing of the outgoing body. |
129 | | #[cfg(any( |
130 | | all(feature = "http1", any(feature = "client", feature = "server")), |
131 | | feature = "ffi" |
132 | | ))] |
133 | | BodyWriteAborted, |
134 | | /// Error from future of user's Service. |
135 | | #[cfg(any( |
136 | | all(any(feature = "client", feature = "server"), feature = "http1"), |
137 | | all(feature = "server", feature = "http2") |
138 | | ))] |
139 | | Service, |
140 | | /// User tried to send a certain header in an unexpected context. |
141 | | /// |
142 | | /// For example, sending both `content-length` and `transfer-encoding`. |
143 | | #[cfg(any(feature = "http1", feature = "http2"))] |
144 | | #[cfg(feature = "server")] |
145 | | UnexpectedHeader, |
146 | | /// User tried to respond with a 1xx (not 101) response code. |
147 | | #[cfg(feature = "http1")] |
148 | | #[cfg(feature = "server")] |
149 | | UnsupportedStatusCode, |
150 | | |
151 | | /// User tried polling for an upgrade that doesn't exist. |
152 | | NoUpgrade, |
153 | | |
154 | | /// User polled for an upgrade, but low-level API is not using upgrades. |
155 | | #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))] |
156 | | ManualUpgrade, |
157 | | |
158 | | /// The dispatch task is gone. |
159 | | #[cfg(all(feature = "client", any(feature = "http1", feature = "http2")))] |
160 | | DispatchGone, |
161 | | |
162 | | /// User aborted in an FFI callback. |
163 | | #[cfg(feature = "ffi")] |
164 | | AbortedByCallback, |
165 | | } |
166 | | |
167 | | // Sentinel type to indicate the error was caused by a timeout. |
168 | | #[derive(Debug)] |
169 | | pub(super) struct TimedOut; |
170 | | |
171 | | impl Error { |
172 | | /// Returns true if this was an HTTP parse error. |
173 | 0 | pub fn is_parse(&self) -> bool { |
174 | 0 | matches!(self.inner.kind, Kind::Parse(_)) |
175 | 0 | } |
176 | | |
177 | | /// Returns true if this was an HTTP parse error caused by a message that was too large. |
178 | | #[cfg(all(feature = "http1", feature = "server"))] |
179 | 0 | pub fn is_parse_too_large(&self) -> bool { |
180 | 0 | matches!( |
181 | 0 | self.inner.kind, |
182 | | Kind::Parse(Parse::TooLarge) | Kind::Parse(Parse::UriTooLong) |
183 | | ) |
184 | 0 | } |
185 | | |
186 | | /// Returns true if this was an HTTP parse error caused by an invalid response status code or |
187 | | /// reason phrase. |
188 | 0 | pub fn is_parse_status(&self) -> bool { |
189 | 0 | matches!(self.inner.kind, Kind::Parse(Parse::Status)) |
190 | 0 | } |
191 | | |
192 | | /// Returns true if this error was caused by user code. |
193 | 0 | pub fn is_user(&self) -> bool { |
194 | 0 | matches!(self.inner.kind, Kind::User(_)) |
195 | 0 | } |
196 | | |
197 | | /// Returns true if this was about a `Request` that was canceled. |
198 | 0 | pub fn is_canceled(&self) -> bool { |
199 | 0 | matches!(self.inner.kind, Kind::Canceled) |
200 | 0 | } |
201 | | |
202 | | /// Returns true if a sender's channel is closed. |
203 | 0 | pub fn is_closed(&self) -> bool { |
204 | | #[cfg(not(any( |
205 | | all(feature = "http1", any(feature = "client", feature = "server")), |
206 | | all(feature = "http2", feature = "client") |
207 | | )))] |
208 | | return false; |
209 | | |
210 | | #[cfg(any( |
211 | | all(feature = "http1", any(feature = "client", feature = "server")), |
212 | | all(feature = "http2", feature = "client") |
213 | | ))] |
214 | 0 | matches!(self.inner.kind, Kind::ChannelClosed) |
215 | 0 | } |
216 | | |
217 | | /// Returns true if the connection closed before a message could complete. |
218 | 0 | pub fn is_incomplete_message(&self) -> bool { |
219 | | #[cfg(not(all(any(feature = "client", feature = "server"), feature = "http1")))] |
220 | | return false; |
221 | | |
222 | | #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))] |
223 | 0 | matches!(self.inner.kind, Kind::IncompleteMessage) |
224 | 0 | } |
225 | | |
226 | | /// Returns true if the body write was aborted. |
227 | 0 | pub fn is_body_write_aborted(&self) -> bool { |
228 | | #[cfg(not(any( |
229 | | all(feature = "http1", any(feature = "client", feature = "server")), |
230 | | feature = "ffi" |
231 | | )))] |
232 | | return false; |
233 | | |
234 | | #[cfg(any( |
235 | | all(feature = "http1", any(feature = "client", feature = "server")), |
236 | | feature = "ffi" |
237 | | ))] |
238 | 0 | matches!(self.inner.kind, Kind::User(User::BodyWriteAborted)) |
239 | 0 | } |
240 | | |
241 | | /// Returns true if the error was caused by a timeout. |
242 | 0 | pub fn is_timeout(&self) -> bool { |
243 | | #[cfg(all(feature = "http1", feature = "server"))] |
244 | 0 | if matches!(self.inner.kind, Kind::HeaderTimeout) { |
245 | 0 | return true; |
246 | 0 | } |
247 | 0 | self.find_source::<TimedOut>().is_some() |
248 | 0 | } |
249 | | |
250 | 0 | pub(super) fn new(kind: Kind) -> Error { |
251 | 0 | Error { |
252 | 0 | inner: Box::new(ErrorImpl { kind, cause: None }), |
253 | 0 | } |
254 | 0 | } |
255 | | |
256 | 0 | pub(super) fn with<C: Into<Cause>>(mut self, cause: C) -> Error { |
257 | 0 | self.inner.cause = Some(cause.into()); |
258 | 0 | self |
259 | 0 | } Unexecuted instantiation: <hyper::error::Error>::with::<tonic::status::Status> Unexecuted instantiation: <hyper::error::Error>::with::<hyper::upgrade::UpgradeExpected> Unexecuted instantiation: <hyper::error::Error>::with::<h2::error::Error> Unexecuted instantiation: <hyper::error::Error>::with::<std::io::error::Error> Unexecuted instantiation: <hyper::error::Error>::with::<hyper::proto::h2::ping::KeepAliveTimedOut> Unexecuted instantiation: <hyper::error::Error>::with::<&str> |
260 | | |
261 | | #[cfg(any(all(feature = "http1", feature = "server"), feature = "ffi"))] |
262 | 0 | pub(super) fn kind(&self) -> &Kind { |
263 | 0 | &self.inner.kind |
264 | 0 | } |
265 | | |
266 | 0 | pub(crate) fn find_source<E: StdError + 'static>(&self) -> Option<&E> { |
267 | 0 | let mut cause = self.source(); |
268 | 0 | while let Some(err) = cause { |
269 | 0 | if let Some(typed) = err.downcast_ref() { |
270 | 0 | return Some(typed); |
271 | 0 | } |
272 | 0 | cause = err.source(); |
273 | | } |
274 | | |
275 | | // else |
276 | 0 | None |
277 | 0 | } Unexecuted instantiation: <hyper::error::Error>::find_source::<hyper::error::TimedOut> Unexecuted instantiation: <hyper::error::Error>::find_source::<h2::error::Error> |
278 | | |
279 | | #[cfg(all(any(feature = "client", feature = "server"), feature = "http2"))] |
280 | 0 | pub(super) fn h2_reason(&self) -> h2::Reason { |
281 | | // Find an h2::Reason somewhere in the cause stack, if it exists, |
282 | | // otherwise assume an INTERNAL_ERROR. |
283 | 0 | self.find_source::<h2::Error>() |
284 | 0 | .and_then(|h2_err| h2_err.reason()) |
285 | 0 | .unwrap_or(h2::Reason::INTERNAL_ERROR) |
286 | 0 | } |
287 | | |
288 | 0 | pub(super) fn new_canceled() -> Error { |
289 | 0 | Error::new(Kind::Canceled) |
290 | 0 | } |
291 | | |
292 | | #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))] |
293 | 0 | pub(super) fn new_incomplete() -> Error { |
294 | 0 | Error::new(Kind::IncompleteMessage) |
295 | 0 | } |
296 | | |
297 | | #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))] |
298 | 0 | pub(super) fn new_too_large() -> Error { |
299 | 0 | Error::new(Kind::Parse(Parse::TooLarge)) |
300 | 0 | } |
301 | | |
302 | | #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))] |
303 | 0 | pub(super) fn new_version_h2() -> Error { |
304 | 0 | Error::new(Kind::Parse(Parse::VersionH2)) |
305 | 0 | } |
306 | | |
307 | | #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))] |
308 | 0 | pub(super) fn new_unexpected_message() -> Error { |
309 | 0 | Error::new(Kind::UnexpectedMessage) |
310 | 0 | } |
311 | | |
312 | | #[cfg(all( |
313 | | any(feature = "client", feature = "server"), |
314 | | any(feature = "http1", feature = "http2") |
315 | | ))] |
316 | 0 | pub(super) fn new_io(cause: std::io::Error) -> Error { |
317 | 0 | Error::new(Kind::Io).with(cause) |
318 | 0 | } |
319 | | |
320 | | #[cfg(any( |
321 | | all(feature = "http1", any(feature = "client", feature = "server")), |
322 | | all(feature = "http2", feature = "client") |
323 | | ))] |
324 | 0 | pub(super) fn new_closed() -> Error { |
325 | 0 | Error::new(Kind::ChannelClosed) |
326 | 0 | } |
327 | | |
328 | | #[cfg(all( |
329 | | any(feature = "client", feature = "server"), |
330 | | any(feature = "http1", feature = "http2") |
331 | | ))] |
332 | 0 | pub(super) fn new_body<E: Into<Cause>>(cause: E) -> Error { |
333 | 0 | Error::new(Kind::Body).with(cause) |
334 | 0 | } |
335 | | |
336 | | #[cfg(all( |
337 | | any(feature = "client", feature = "server"), |
338 | | any(feature = "http1", feature = "http2") |
339 | | ))] |
340 | 0 | pub(super) fn new_body_write<E: Into<Cause>>(cause: E) -> Error { |
341 | 0 | Error::new(Kind::BodyWrite).with(cause) |
342 | 0 | } Unexecuted instantiation: <hyper::error::Error>::new_body_write::<h2::error::Error> Unexecuted instantiation: <hyper::error::Error>::new_body_write::<&str> Unexecuted instantiation: <hyper::error::Error>::new_body_write::<_> |
343 | | |
344 | | #[cfg(any( |
345 | | all(feature = "http1", any(feature = "client", feature = "server")), |
346 | | feature = "ffi" |
347 | | ))] |
348 | 0 | pub(super) fn new_body_write_aborted() -> Error { |
349 | 0 | Error::new(Kind::User(User::BodyWriteAborted)) |
350 | 0 | } |
351 | | |
352 | 0 | fn new_user(user: User) -> Error { |
353 | 0 | Error::new(Kind::User(user)) |
354 | 0 | } |
355 | | |
356 | | #[cfg(any(feature = "http1", feature = "http2"))] |
357 | | #[cfg(feature = "server")] |
358 | 0 | pub(super) fn new_user_header() -> Error { |
359 | 0 | Error::new_user(User::UnexpectedHeader) |
360 | 0 | } |
361 | | |
362 | | #[cfg(all(feature = "http1", feature = "server"))] |
363 | 0 | pub(super) fn new_header_timeout() -> Error { |
364 | 0 | Error::new(Kind::HeaderTimeout) |
365 | 0 | } |
366 | | |
367 | | #[cfg(feature = "http1")] |
368 | | #[cfg(feature = "server")] |
369 | 0 | pub(super) fn new_user_unsupported_status_code() -> Error { |
370 | 0 | Error::new_user(User::UnsupportedStatusCode) |
371 | 0 | } |
372 | | |
373 | 0 | pub(super) fn new_user_no_upgrade() -> Error { |
374 | 0 | Error::new_user(User::NoUpgrade) |
375 | 0 | } |
376 | | |
377 | | #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))] |
378 | 0 | pub(super) fn new_user_manual_upgrade() -> Error { |
379 | 0 | Error::new_user(User::ManualUpgrade) |
380 | 0 | } |
381 | | |
382 | | #[cfg(any( |
383 | | all(any(feature = "client", feature = "server"), feature = "http1"), |
384 | | all(feature = "server", feature = "http2") |
385 | | ))] |
386 | 0 | pub(super) fn new_user_service<E: Into<Cause>>(cause: E) -> Error { |
387 | 0 | Error::new_user(User::Service).with(cause) |
388 | 0 | } |
389 | | |
390 | | #[cfg(all( |
391 | | any(feature = "client", feature = "server"), |
392 | | any(feature = "http1", feature = "http2") |
393 | | ))] |
394 | 0 | pub(super) fn new_user_body<E: Into<Cause>>(cause: E) -> Error { |
395 | 0 | Error::new_user(User::Body).with(cause) |
396 | 0 | } Unexecuted instantiation: <hyper::error::Error>::new_user_body::<tonic::status::Status> Unexecuted instantiation: <hyper::error::Error>::new_user_body::<_> |
397 | | |
398 | | #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))] |
399 | 0 | pub(super) fn new_shutdown(cause: std::io::Error) -> Error { |
400 | 0 | Error::new(Kind::Shutdown).with(cause) |
401 | 0 | } |
402 | | |
403 | | #[cfg(feature = "ffi")] |
404 | | pub(super) fn new_user_aborted_by_callback() -> Error { |
405 | | Error::new_user(User::AbortedByCallback) |
406 | | } |
407 | | |
408 | | #[cfg(all(feature = "client", any(feature = "http1", feature = "http2")))] |
409 | 0 | pub(super) fn new_user_dispatch_gone() -> Error { |
410 | 0 | Error::new(Kind::User(User::DispatchGone)) |
411 | 0 | } |
412 | | |
413 | | #[cfg(all(any(feature = "client", feature = "server"), feature = "http2"))] |
414 | 0 | pub(super) fn new_h2(cause: ::h2::Error) -> Error { |
415 | 0 | if cause.is_io() { |
416 | 0 | Error::new_io(cause.into_io().expect("h2::Error::is_io")) |
417 | | } else { |
418 | 0 | Error::new(Kind::Http2).with(cause) |
419 | | } |
420 | 0 | } |
421 | | |
422 | 0 | fn description(&self) -> &str { |
423 | 0 | match self.inner.kind { |
424 | 0 | Kind::Parse(Parse::Method) => "invalid HTTP method parsed", |
425 | | #[cfg(feature = "http1")] |
426 | 0 | Kind::Parse(Parse::Version) => "invalid HTTP version parsed", |
427 | | #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))] |
428 | 0 | Kind::Parse(Parse::VersionH2) => "invalid HTTP version parsed (found HTTP2 preface)", |
429 | 0 | Kind::Parse(Parse::Uri) => "invalid URI", |
430 | | #[cfg(all(feature = "http1", feature = "server"))] |
431 | 0 | Kind::Parse(Parse::UriTooLong) => "URI too long", |
432 | | #[cfg(feature = "http1")] |
433 | 0 | Kind::Parse(Parse::Header(Header::Token)) => "invalid HTTP header parsed", |
434 | | #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))] |
435 | | Kind::Parse(Parse::Header(Header::ContentLengthInvalid)) => { |
436 | 0 | "invalid content-length parsed" |
437 | | } |
438 | | #[cfg(all(feature = "http1", feature = "server"))] |
439 | | Kind::Parse(Parse::Header(Header::TransferEncodingInvalid)) => { |
440 | 0 | "invalid transfer-encoding parsed" |
441 | | } |
442 | | #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))] |
443 | | Kind::Parse(Parse::Header(Header::TransferEncodingUnexpected)) => { |
444 | 0 | "unexpected transfer-encoding parsed" |
445 | | } |
446 | | #[cfg(any(feature = "http1", feature = "http2"))] |
447 | 0 | Kind::Parse(Parse::TooLarge) => "message head is too large", |
448 | 0 | Kind::Parse(Parse::Status) => "invalid HTTP status-code parsed", |
449 | | #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))] |
450 | | Kind::Parse(Parse::Internal) => { |
451 | 0 | "internal error inside Hyper and/or its dependencies, please report" |
452 | | } |
453 | | #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))] |
454 | 0 | Kind::IncompleteMessage => "connection closed before message completed", |
455 | | #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))] |
456 | 0 | Kind::UnexpectedMessage => "received unexpected message from connection", |
457 | | #[cfg(any( |
458 | | all(feature = "http1", any(feature = "client", feature = "server")), |
459 | | all(feature = "http2", feature = "client") |
460 | | ))] |
461 | 0 | Kind::ChannelClosed => "channel closed", |
462 | 0 | Kind::Canceled => "operation was canceled", |
463 | | #[cfg(all(feature = "http1", feature = "server"))] |
464 | 0 | Kind::HeaderTimeout => "read header from client timeout", |
465 | | #[cfg(all( |
466 | | any(feature = "client", feature = "server"), |
467 | | any(feature = "http1", feature = "http2") |
468 | | ))] |
469 | 0 | Kind::Body => "error reading a body from connection", |
470 | | #[cfg(all( |
471 | | any(feature = "client", feature = "server"), |
472 | | any(feature = "http1", feature = "http2") |
473 | | ))] |
474 | 0 | Kind::BodyWrite => "error writing a body to connection", |
475 | | #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))] |
476 | 0 | Kind::Shutdown => "error shutting down connection", |
477 | | #[cfg(all(any(feature = "client", feature = "server"), feature = "http2"))] |
478 | 0 | Kind::Http2 => "http2 error", |
479 | | #[cfg(all( |
480 | | any(feature = "client", feature = "server"), |
481 | | any(feature = "http1", feature = "http2") |
482 | | ))] |
483 | 0 | Kind::Io => "connection error", |
484 | | |
485 | | #[cfg(all( |
486 | | any(feature = "client", feature = "server"), |
487 | | any(feature = "http1", feature = "http2") |
488 | | ))] |
489 | 0 | Kind::User(User::Body) => "error from user's Body stream", |
490 | | #[cfg(any( |
491 | | all(feature = "http1", any(feature = "client", feature = "server")), |
492 | | feature = "ffi" |
493 | | ))] |
494 | 0 | Kind::User(User::BodyWriteAborted) => "user body write aborted", |
495 | | #[cfg(any( |
496 | | all(any(feature = "client", feature = "server"), feature = "http1"), |
497 | | all(feature = "server", feature = "http2") |
498 | | ))] |
499 | 0 | Kind::User(User::Service) => "error from user's Service", |
500 | | #[cfg(any(feature = "http1", feature = "http2"))] |
501 | | #[cfg(feature = "server")] |
502 | 0 | Kind::User(User::UnexpectedHeader) => "user sent unexpected header", |
503 | | #[cfg(feature = "http1")] |
504 | | #[cfg(feature = "server")] |
505 | | Kind::User(User::UnsupportedStatusCode) => { |
506 | 0 | "response has 1xx status code, not supported by server" |
507 | | } |
508 | 0 | Kind::User(User::NoUpgrade) => "no upgrade available", |
509 | | #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))] |
510 | 0 | Kind::User(User::ManualUpgrade) => "upgrade expected but low level API in use", |
511 | | #[cfg(all(feature = "client", any(feature = "http1", feature = "http2")))] |
512 | 0 | Kind::User(User::DispatchGone) => "dispatch task is gone", |
513 | | #[cfg(feature = "ffi")] |
514 | | Kind::User(User::AbortedByCallback) => "operation aborted by an application callback", |
515 | | } |
516 | 0 | } |
517 | | } |
518 | | |
519 | | impl fmt::Debug for Error { |
520 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
521 | 0 | let mut f = f.debug_tuple("hyper::Error"); |
522 | 0 | f.field(&self.inner.kind); |
523 | 0 | if let Some(ref cause) = self.inner.cause { |
524 | 0 | f.field(cause); |
525 | 0 | } |
526 | 0 | f.finish() |
527 | 0 | } |
528 | | } |
529 | | |
530 | | impl fmt::Display for Error { |
531 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
532 | 0 | f.write_str(self.description()) |
533 | 0 | } |
534 | | } |
535 | | |
536 | | impl StdError for Error { |
537 | 0 | fn source(&self) -> Option<&(dyn StdError + 'static)> { |
538 | 0 | self.inner |
539 | 0 | .cause |
540 | 0 | .as_ref() |
541 | 0 | .map(|cause| &**cause as &(dyn StdError + 'static)) |
542 | 0 | } |
543 | | } |
544 | | |
545 | | #[doc(hidden)] |
546 | | impl From<Parse> for Error { |
547 | 0 | fn from(err: Parse) -> Error { |
548 | 0 | Error::new(Kind::Parse(err)) |
549 | 0 | } |
550 | | } |
551 | | |
552 | | #[cfg(feature = "http1")] |
553 | | impl Parse { |
554 | | #[cfg(any(feature = "client", feature = "server"))] |
555 | 0 | pub(crate) fn content_length_invalid() -> Self { |
556 | 0 | Parse::Header(Header::ContentLengthInvalid) |
557 | 0 | } |
558 | | |
559 | | #[cfg(feature = "server")] |
560 | 0 | pub(crate) fn transfer_encoding_invalid() -> Self { |
561 | 0 | Parse::Header(Header::TransferEncodingInvalid) |
562 | 0 | } |
563 | | |
564 | | #[cfg(any(feature = "client", feature = "server"))] |
565 | 0 | pub(crate) fn transfer_encoding_unexpected() -> Self { |
566 | 0 | Parse::Header(Header::TransferEncodingUnexpected) |
567 | 0 | } |
568 | | } |
569 | | |
570 | | #[cfg(feature = "http1")] |
571 | | impl From<httparse::Error> for Parse { |
572 | 0 | fn from(err: httparse::Error) -> Parse { |
573 | 0 | match err { |
574 | | httparse::Error::HeaderName |
575 | | | httparse::Error::HeaderValue |
576 | | | httparse::Error::NewLine |
577 | 0 | | httparse::Error::Token => Parse::Header(Header::Token), |
578 | 0 | httparse::Error::Status => Parse::Status, |
579 | 0 | httparse::Error::TooManyHeaders => Parse::TooLarge, |
580 | 0 | httparse::Error::Version => Parse::Version, |
581 | | } |
582 | 0 | } |
583 | | } |
584 | | |
585 | | impl From<http::method::InvalidMethod> for Parse { |
586 | 0 | fn from(_: http::method::InvalidMethod) -> Parse { |
587 | 0 | Parse::Method |
588 | 0 | } |
589 | | } |
590 | | |
591 | | impl From<http::status::InvalidStatusCode> for Parse { |
592 | 0 | fn from(_: http::status::InvalidStatusCode) -> Parse { |
593 | 0 | Parse::Status |
594 | 0 | } |
595 | | } |
596 | | |
597 | | impl From<http::uri::InvalidUri> for Parse { |
598 | 0 | fn from(_: http::uri::InvalidUri) -> Parse { |
599 | 0 | Parse::Uri |
600 | 0 | } |
601 | | } |
602 | | |
603 | | impl From<http::uri::InvalidUriParts> for Parse { |
604 | 0 | fn from(_: http::uri::InvalidUriParts) -> Parse { |
605 | 0 | Parse::Uri |
606 | 0 | } |
607 | | } |
608 | | |
609 | | // ===== impl TimedOut ==== |
610 | | |
611 | | impl fmt::Display for TimedOut { |
612 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
613 | 0 | f.write_str("operation timed out") |
614 | 0 | } |
615 | | } |
616 | | |
617 | | impl StdError for TimedOut {} |
618 | | |
619 | | #[cfg(test)] |
620 | | mod tests { |
621 | | use super::*; |
622 | | use std::mem; |
623 | | |
624 | | fn assert_send_sync<T: Send + Sync + 'static>() {} |
625 | | |
626 | | #[test] |
627 | | fn error_satisfies_send_sync() { |
628 | | assert_send_sync::<Error>() |
629 | | } |
630 | | |
631 | | #[test] |
632 | | fn error_size_of() { |
633 | | assert_eq!(mem::size_of::<Error>(), mem::size_of::<usize>()); |
634 | | } |
635 | | |
636 | | #[cfg(feature = "http2")] |
637 | | #[test] |
638 | | fn h2_reason_unknown() { |
639 | | let closed = Error::new_closed(); |
640 | | assert_eq!(closed.h2_reason(), h2::Reason::INTERNAL_ERROR); |
641 | | } |
642 | | |
643 | | #[cfg(feature = "http2")] |
644 | | #[test] |
645 | | fn h2_reason_one_level() { |
646 | | let body_err = Error::new_user_body(h2::Error::from(h2::Reason::ENHANCE_YOUR_CALM)); |
647 | | assert_eq!(body_err.h2_reason(), h2::Reason::ENHANCE_YOUR_CALM); |
648 | | } |
649 | | |
650 | | #[cfg(feature = "http2")] |
651 | | #[test] |
652 | | fn h2_reason_nested() { |
653 | | let recvd = Error::new_h2(h2::Error::from(h2::Reason::HTTP_1_1_REQUIRED)); |
654 | | // Suppose a user were proxying the received error |
655 | | let svc_err = Error::new_user_service(recvd); |
656 | | assert_eq!(svc_err.h2_reason(), h2::Reason::HTTP_1_1_REQUIRED); |
657 | | } |
658 | | } |