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 pub struct Error {
12     inner: Box<ErrorImpl>,
13 }
14 
15 struct ErrorImpl {
16     kind: Kind,
17     cause: Option<Cause>,
18 }
19 
20 #[derive(Debug)]
21 pub(super) enum Kind {
22     Parse(Parse),
23     User(User),
24     /// A message reached EOF, but is not complete.
25     #[allow(unused)]
26     IncompleteMessage,
27     /// A connection received a message (or bytes) when not waiting for one.
28     #[cfg(feature = "http1")]
29     UnexpectedMessage,
30     /// A pending item was dropped before ever being processed.
31     Canceled,
32     /// Indicates a channel (client or body sender) is closed.
33     ChannelClosed,
34     /// An `io::Error` that occurred while trying to read or write to a network stream.
35     #[cfg(any(feature = "http1", feature = "http2"))]
36     Io,
37     /// Error occurred while connecting.
38     #[allow(unused)]
39     Connect,
40     /// Error creating a TcpListener.
41     #[cfg(all(feature = "tcp", feature = "server"))]
42     Listen,
43     /// Error accepting on an Incoming stream.
44     #[cfg(any(feature = "http1", feature = "http2"))]
45     #[cfg(feature = "server")]
46     Accept,
47     /// User took too long to send headers
48     #[cfg(all(feature = "http1", feature = "server", feature = "runtime"))]
49     HeaderTimeout,
50     /// Error while reading a body from connection.
51     #[cfg(any(feature = "http1", feature = "http2", feature = "stream"))]
52     Body,
53     /// Error while writing a body to connection.
54     #[cfg(any(feature = "http1", feature = "http2"))]
55     BodyWrite,
56     /// The body write was aborted.
57     BodyWriteAborted,
58     /// Error calling AsyncWrite::shutdown()
59     #[cfg(feature = "http1")]
60     Shutdown,
61 
62     /// A general error from h2.
63     #[cfg(feature = "http2")]
64     Http2,
65 }
66 
67 #[derive(Debug)]
68 pub(super) enum Parse {
69     Method,
70     Version,
71     #[cfg(feature = "http1")]
72     VersionH2,
73     Uri,
74     #[cfg_attr(not(all(feature = "http1", feature = "server")), allow(unused))]
75     UriTooLong,
76     Header(Header),
77     TooLarge,
78     Status,
79     #[cfg_attr(debug_assertions, allow(unused))]
80     Internal,
81 }
82 
83 #[derive(Debug)]
84 pub(super) enum Header {
85     Token,
86     #[cfg(feature = "http1")]
87     ContentLengthInvalid,
88     #[cfg(all(feature = "http1", feature = "server"))]
89     TransferEncodingInvalid,
90     #[cfg(feature = "http1")]
91     TransferEncodingUnexpected,
92 }
93 
94 #[derive(Debug)]
95 pub(super) enum User {
96     /// Error calling user's HttpBody::poll_data().
97     #[cfg(any(feature = "http1", feature = "http2"))]
98     Body,
99     /// Error calling user's MakeService.
100     #[cfg(any(feature = "http1", feature = "http2"))]
101     #[cfg(feature = "server")]
102     MakeService,
103     /// Error from future of user's Service.
104     #[cfg(any(feature = "http1", feature = "http2"))]
105     Service,
106     /// User tried to send a certain header in an unexpected context.
107     ///
108     /// For example, sending both `content-length` and `transfer-encoding`.
109     #[cfg(any(feature = "http1", feature = "http2"))]
110     #[cfg(feature = "server")]
111     UnexpectedHeader,
112     /// User tried to create a Request with bad version.
113     #[cfg(any(feature = "http1", feature = "http2"))]
114     #[cfg(feature = "client")]
115     UnsupportedVersion,
116     /// User tried to create a CONNECT Request with the Client.
117     #[cfg(any(feature = "http1", feature = "http2"))]
118     #[cfg(feature = "client")]
119     UnsupportedRequestMethod,
120     /// User tried to respond with a 1xx (not 101) response code.
121     #[cfg(feature = "http1")]
122     #[cfg(feature = "server")]
123     UnsupportedStatusCode,
124     /// User tried to send a Request with Client with non-absolute URI.
125     #[cfg(any(feature = "http1", feature = "http2"))]
126     #[cfg(feature = "client")]
127     AbsoluteUriRequired,
128 
129     /// User tried polling for an upgrade that doesn't exist.
130     NoUpgrade,
131 
132     /// User polled for an upgrade, but low-level API is not using upgrades.
133     #[cfg(feature = "http1")]
134     ManualUpgrade,
135 
136     /// User called `server::Connection::without_shutdown()` on an HTTP/2 conn.
137     #[cfg(feature = "server")]
138     WithoutShutdownNonHttp1,
139 
140     /// User aborted in an FFI callback.
141     #[cfg(feature = "ffi")]
142     AbortedByCallback,
143 }
144 
145 // Sentinel type to indicate the error was caused by a timeout.
146 #[derive(Debug)]
147 pub(super) struct TimedOut;
148 
149 impl Error {
150     /// Returns true if this was an HTTP parse error.
is_parse(&self) -> bool151     pub fn is_parse(&self) -> bool {
152         matches!(self.inner.kind, Kind::Parse(_))
153     }
154 
155     /// Returns true if this was an HTTP parse error caused by a message that was too large.
is_parse_too_large(&self) -> bool156     pub fn is_parse_too_large(&self) -> bool {
157         matches!(
158             self.inner.kind,
159             Kind::Parse(Parse::TooLarge) | Kind::Parse(Parse::UriTooLong)
160         )
161     }
162 
163     /// Returns true if this was an HTTP parse error caused by an invalid response status code or
164     /// reason phrase.
is_parse_status(&self) -> bool165     pub fn is_parse_status(&self) -> bool {
166         matches!(self.inner.kind, Kind::Parse(Parse::Status))
167     }
168 
169     /// Returns true if this error was caused by user code.
is_user(&self) -> bool170     pub fn is_user(&self) -> bool {
171         matches!(self.inner.kind, Kind::User(_))
172     }
173 
174     /// Returns true if this was about a `Request` that was canceled.
is_canceled(&self) -> bool175     pub fn is_canceled(&self) -> bool {
176         matches!(self.inner.kind, Kind::Canceled)
177     }
178 
179     /// Returns true if a sender's channel is closed.
is_closed(&self) -> bool180     pub fn is_closed(&self) -> bool {
181         matches!(self.inner.kind, Kind::ChannelClosed)
182     }
183 
184     /// Returns true if this was an error from `Connect`.
is_connect(&self) -> bool185     pub fn is_connect(&self) -> bool {
186         matches!(self.inner.kind, Kind::Connect)
187     }
188 
189     /// Returns true if the connection closed before a message could complete.
is_incomplete_message(&self) -> bool190     pub fn is_incomplete_message(&self) -> bool {
191         matches!(self.inner.kind, Kind::IncompleteMessage)
192     }
193 
194     /// Returns true if the body write was aborted.
is_body_write_aborted(&self) -> bool195     pub fn is_body_write_aborted(&self) -> bool {
196         matches!(self.inner.kind, Kind::BodyWriteAborted)
197     }
198 
199     /// Returns true if the error was caused by a timeout.
is_timeout(&self) -> bool200     pub fn is_timeout(&self) -> bool {
201         self.find_source::<TimedOut>().is_some()
202     }
203 
204     /// Consumes the error, returning its cause.
into_cause(self) -> Option<Box<dyn StdError + Send + Sync>>205     pub fn into_cause(self) -> Option<Box<dyn StdError + Send + Sync>> {
206         self.inner.cause
207     }
208 
new(kind: Kind) -> Error209     pub(super) fn new(kind: Kind) -> Error {
210         Error {
211             inner: Box::new(ErrorImpl { kind, cause: None }),
212         }
213     }
214 
with<C: Into<Cause>>(mut self, cause: C) -> Error215     pub(super) fn with<C: Into<Cause>>(mut self, cause: C) -> Error {
216         self.inner.cause = Some(cause.into());
217         self
218     }
219 
220     #[cfg(any(all(feature = "http1", feature = "server"), feature = "ffi"))]
kind(&self) -> &Kind221     pub(super) fn kind(&self) -> &Kind {
222         &self.inner.kind
223     }
224 
find_source<E: StdError + 'static>(&self) -> Option<&E>225     pub(crate) fn find_source<E: StdError + 'static>(&self) -> Option<&E> {
226         let mut cause = self.source();
227         while let Some(err) = cause {
228             if let Some(ref typed) = err.downcast_ref() {
229                 return Some(typed);
230             }
231             cause = err.source();
232         }
233 
234         // else
235         None
236     }
237 
238     #[cfg(feature = "http2")]
h2_reason(&self) -> h2::Reason239     pub(super) fn h2_reason(&self) -> h2::Reason {
240         // Find an h2::Reason somewhere in the cause stack, if it exists,
241         // otherwise assume an INTERNAL_ERROR.
242         self.find_source::<h2::Error>()
243             .and_then(|h2_err| h2_err.reason())
244             .unwrap_or(h2::Reason::INTERNAL_ERROR)
245     }
246 
new_canceled() -> Error247     pub(super) fn new_canceled() -> Error {
248         Error::new(Kind::Canceled)
249     }
250 
251     #[cfg(feature = "http1")]
new_incomplete() -> Error252     pub(super) fn new_incomplete() -> Error {
253         Error::new(Kind::IncompleteMessage)
254     }
255 
256     #[cfg(feature = "http1")]
new_too_large() -> Error257     pub(super) fn new_too_large() -> Error {
258         Error::new(Kind::Parse(Parse::TooLarge))
259     }
260 
261     #[cfg(feature = "http1")]
new_version_h2() -> Error262     pub(super) fn new_version_h2() -> Error {
263         Error::new(Kind::Parse(Parse::VersionH2))
264     }
265 
266     #[cfg(feature = "http1")]
new_unexpected_message() -> Error267     pub(super) fn new_unexpected_message() -> Error {
268         Error::new(Kind::UnexpectedMessage)
269     }
270 
271     #[cfg(any(feature = "http1", feature = "http2"))]
new_io(cause: std::io::Error) -> Error272     pub(super) fn new_io(cause: std::io::Error) -> Error {
273         Error::new(Kind::Io).with(cause)
274     }
275 
276     #[cfg(all(feature = "server", feature = "tcp"))]
new_listen<E: Into<Cause>>(cause: E) -> Error277     pub(super) fn new_listen<E: Into<Cause>>(cause: E) -> Error {
278         Error::new(Kind::Listen).with(cause)
279     }
280 
281     #[cfg(any(feature = "http1", feature = "http2"))]
282     #[cfg(feature = "server")]
new_accept<E: Into<Cause>>(cause: E) -> Error283     pub(super) fn new_accept<E: Into<Cause>>(cause: E) -> Error {
284         Error::new(Kind::Accept).with(cause)
285     }
286 
287     #[cfg(any(feature = "http1", feature = "http2"))]
288     #[cfg(feature = "client")]
new_connect<E: Into<Cause>>(cause: E) -> Error289     pub(super) fn new_connect<E: Into<Cause>>(cause: E) -> Error {
290         Error::new(Kind::Connect).with(cause)
291     }
292 
new_closed() -> Error293     pub(super) fn new_closed() -> Error {
294         Error::new(Kind::ChannelClosed)
295     }
296 
297     #[cfg(any(feature = "http1", feature = "http2", feature = "stream"))]
new_body<E: Into<Cause>>(cause: E) -> Error298     pub(super) fn new_body<E: Into<Cause>>(cause: E) -> Error {
299         Error::new(Kind::Body).with(cause)
300     }
301 
302     #[cfg(any(feature = "http1", feature = "http2"))]
new_body_write<E: Into<Cause>>(cause: E) -> Error303     pub(super) fn new_body_write<E: Into<Cause>>(cause: E) -> Error {
304         Error::new(Kind::BodyWrite).with(cause)
305     }
306 
new_body_write_aborted() -> Error307     pub(super) fn new_body_write_aborted() -> Error {
308         Error::new(Kind::BodyWriteAborted)
309     }
310 
new_user(user: User) -> Error311     fn new_user(user: User) -> Error {
312         Error::new(Kind::User(user))
313     }
314 
315     #[cfg(any(feature = "http1", feature = "http2"))]
316     #[cfg(feature = "server")]
new_user_header() -> Error317     pub(super) fn new_user_header() -> Error {
318         Error::new_user(User::UnexpectedHeader)
319     }
320 
321     #[cfg(all(feature = "http1", feature = "server", feature = "runtime"))]
new_header_timeout() -> Error322     pub(super) fn new_header_timeout() -> Error {
323         Error::new(Kind::HeaderTimeout)
324     }
325 
326     #[cfg(any(feature = "http1", feature = "http2"))]
327     #[cfg(feature = "client")]
new_user_unsupported_version() -> Error328     pub(super) fn new_user_unsupported_version() -> Error {
329         Error::new_user(User::UnsupportedVersion)
330     }
331 
332     #[cfg(any(feature = "http1", feature = "http2"))]
333     #[cfg(feature = "client")]
new_user_unsupported_request_method() -> Error334     pub(super) fn new_user_unsupported_request_method() -> Error {
335         Error::new_user(User::UnsupportedRequestMethod)
336     }
337 
338     #[cfg(feature = "http1")]
339     #[cfg(feature = "server")]
new_user_unsupported_status_code() -> Error340     pub(super) fn new_user_unsupported_status_code() -> Error {
341         Error::new_user(User::UnsupportedStatusCode)
342     }
343 
344     #[cfg(any(feature = "http1", feature = "http2"))]
345     #[cfg(feature = "client")]
new_user_absolute_uri_required() -> Error346     pub(super) fn new_user_absolute_uri_required() -> Error {
347         Error::new_user(User::AbsoluteUriRequired)
348     }
349 
new_user_no_upgrade() -> Error350     pub(super) fn new_user_no_upgrade() -> Error {
351         Error::new_user(User::NoUpgrade)
352     }
353 
354     #[cfg(feature = "http1")]
new_user_manual_upgrade() -> Error355     pub(super) fn new_user_manual_upgrade() -> Error {
356         Error::new_user(User::ManualUpgrade)
357     }
358 
359     #[cfg(any(feature = "http1", feature = "http2"))]
360     #[cfg(feature = "server")]
new_user_make_service<E: Into<Cause>>(cause: E) -> Error361     pub(super) fn new_user_make_service<E: Into<Cause>>(cause: E) -> Error {
362         Error::new_user(User::MakeService).with(cause)
363     }
364 
365     #[cfg(any(feature = "http1", feature = "http2"))]
new_user_service<E: Into<Cause>>(cause: E) -> Error366     pub(super) fn new_user_service<E: Into<Cause>>(cause: E) -> Error {
367         Error::new_user(User::Service).with(cause)
368     }
369 
370     #[cfg(any(feature = "http1", feature = "http2"))]
new_user_body<E: Into<Cause>>(cause: E) -> Error371     pub(super) fn new_user_body<E: Into<Cause>>(cause: E) -> Error {
372         Error::new_user(User::Body).with(cause)
373     }
374 
375     #[cfg(feature = "server")]
new_without_shutdown_not_h1() -> Error376     pub(super) fn new_without_shutdown_not_h1() -> Error {
377         Error::new(Kind::User(User::WithoutShutdownNonHttp1))
378     }
379 
380     #[cfg(feature = "http1")]
new_shutdown(cause: std::io::Error) -> Error381     pub(super) fn new_shutdown(cause: std::io::Error) -> Error {
382         Error::new(Kind::Shutdown).with(cause)
383     }
384 
385     #[cfg(feature = "ffi")]
new_user_aborted_by_callback() -> Error386     pub(super) fn new_user_aborted_by_callback() -> Error {
387         Error::new_user(User::AbortedByCallback)
388     }
389 
390     #[cfg(feature = "http2")]
new_h2(cause: ::h2::Error) -> Error391     pub(super) fn new_h2(cause: ::h2::Error) -> Error {
392         if cause.is_io() {
393             Error::new_io(cause.into_io().expect("h2::Error::is_io"))
394         } else {
395             Error::new(Kind::Http2).with(cause)
396         }
397     }
398 
description(&self) -> &str399     fn description(&self) -> &str {
400         match self.inner.kind {
401             Kind::Parse(Parse::Method) => "invalid HTTP method parsed",
402             Kind::Parse(Parse::Version) => "invalid HTTP version parsed",
403             #[cfg(feature = "http1")]
404             Kind::Parse(Parse::VersionH2) => "invalid HTTP version parsed (found HTTP2 preface)",
405             Kind::Parse(Parse::Uri) => "invalid URI",
406             Kind::Parse(Parse::UriTooLong) => "URI too long",
407             Kind::Parse(Parse::Header(Header::Token)) => "invalid HTTP header parsed",
408             #[cfg(feature = "http1")]
409             Kind::Parse(Parse::Header(Header::ContentLengthInvalid)) => {
410                 "invalid content-length parsed"
411             }
412             #[cfg(all(feature = "http1", feature = "server"))]
413             Kind::Parse(Parse::Header(Header::TransferEncodingInvalid)) => {
414                 "invalid transfer-encoding parsed"
415             }
416             #[cfg(feature = "http1")]
417             Kind::Parse(Parse::Header(Header::TransferEncodingUnexpected)) => {
418                 "unexpected transfer-encoding parsed"
419             }
420             Kind::Parse(Parse::TooLarge) => "message head is too large",
421             Kind::Parse(Parse::Status) => "invalid HTTP status-code parsed",
422             Kind::Parse(Parse::Internal) => {
423                 "internal error inside Hyper and/or its dependencies, please report"
424             }
425             Kind::IncompleteMessage => "connection closed before message completed",
426             #[cfg(feature = "http1")]
427             Kind::UnexpectedMessage => "received unexpected message from connection",
428             Kind::ChannelClosed => "channel closed",
429             Kind::Connect => "error trying to connect",
430             Kind::Canceled => "operation was canceled",
431             #[cfg(all(feature = "server", feature = "tcp"))]
432             Kind::Listen => "error creating server listener",
433             #[cfg(any(feature = "http1", feature = "http2"))]
434             #[cfg(feature = "server")]
435             Kind::Accept => "error accepting connection",
436             #[cfg(all(feature = "http1", feature = "server", feature = "runtime"))]
437             Kind::HeaderTimeout => "read header from client timeout",
438             #[cfg(any(feature = "http1", feature = "http2", feature = "stream"))]
439             Kind::Body => "error reading a body from connection",
440             #[cfg(any(feature = "http1", feature = "http2"))]
441             Kind::BodyWrite => "error writing a body to connection",
442             Kind::BodyWriteAborted => "body write aborted",
443             #[cfg(feature = "http1")]
444             Kind::Shutdown => "error shutting down connection",
445             #[cfg(feature = "http2")]
446             Kind::Http2 => "http2 error",
447             #[cfg(any(feature = "http1", feature = "http2"))]
448             Kind::Io => "connection error",
449 
450             #[cfg(any(feature = "http1", feature = "http2"))]
451             Kind::User(User::Body) => "error from user's HttpBody stream",
452             #[cfg(any(feature = "http1", feature = "http2"))]
453             #[cfg(feature = "server")]
454             Kind::User(User::MakeService) => "error from user's MakeService",
455             #[cfg(any(feature = "http1", feature = "http2"))]
456             Kind::User(User::Service) => "error from user's Service",
457             #[cfg(any(feature = "http1", feature = "http2"))]
458             #[cfg(feature = "server")]
459             Kind::User(User::UnexpectedHeader) => "user sent unexpected header",
460             #[cfg(any(feature = "http1", feature = "http2"))]
461             #[cfg(feature = "client")]
462             Kind::User(User::UnsupportedVersion) => "request has unsupported HTTP version",
463             #[cfg(any(feature = "http1", feature = "http2"))]
464             #[cfg(feature = "client")]
465             Kind::User(User::UnsupportedRequestMethod) => "request has unsupported HTTP method",
466             #[cfg(feature = "http1")]
467             #[cfg(feature = "server")]
468             Kind::User(User::UnsupportedStatusCode) => {
469                 "response has 1xx status code, not supported by server"
470             }
471             #[cfg(any(feature = "http1", feature = "http2"))]
472             #[cfg(feature = "client")]
473             Kind::User(User::AbsoluteUriRequired) => "client requires absolute-form URIs",
474             Kind::User(User::NoUpgrade) => "no upgrade available",
475             #[cfg(feature = "http1")]
476             Kind::User(User::ManualUpgrade) => "upgrade expected but low level API in use",
477             #[cfg(feature = "server")]
478             Kind::User(User::WithoutShutdownNonHttp1) => {
479                 "without_shutdown() called on a non-HTTP/1 connection"
480             }
481             #[cfg(feature = "ffi")]
482             Kind::User(User::AbortedByCallback) => "operation aborted by an application callback",
483         }
484     }
485 }
486 
487 impl fmt::Debug for Error {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result488     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
489         let mut f = f.debug_tuple("hyper::Error");
490         f.field(&self.inner.kind);
491         if let Some(ref cause) = self.inner.cause {
492             f.field(cause);
493         }
494         f.finish()
495     }
496 }
497 
498 impl fmt::Display for Error {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result499     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
500         if let Some(ref cause) = self.inner.cause {
501             write!(f, "{}: {}", self.description(), cause)
502         } else {
503             f.write_str(self.description())
504         }
505     }
506 }
507 
508 impl StdError for Error {
source(&self) -> Option<&(dyn StdError + 'static)>509     fn source(&self) -> Option<&(dyn StdError + 'static)> {
510         self.inner
511             .cause
512             .as_ref()
513             .map(|cause| &**cause as &(dyn StdError + 'static))
514     }
515 }
516 
517 #[doc(hidden)]
518 impl From<Parse> for Error {
from(err: Parse) -> Error519     fn from(err: Parse) -> Error {
520         Error::new(Kind::Parse(err))
521     }
522 }
523 
524 #[cfg(feature = "http1")]
525 impl Parse {
content_length_invalid() -> Self526     pub(crate) fn content_length_invalid() -> Self {
527         Parse::Header(Header::ContentLengthInvalid)
528     }
529 
530     #[cfg(all(feature = "http1", feature = "server"))]
transfer_encoding_invalid() -> Self531     pub(crate) fn transfer_encoding_invalid() -> Self {
532         Parse::Header(Header::TransferEncodingInvalid)
533     }
534 
transfer_encoding_unexpected() -> Self535     pub(crate) fn transfer_encoding_unexpected() -> Self {
536         Parse::Header(Header::TransferEncodingUnexpected)
537     }
538 }
539 
540 impl From<httparse::Error> for Parse {
from(err: httparse::Error) -> Parse541     fn from(err: httparse::Error) -> Parse {
542         match err {
543             httparse::Error::HeaderName
544             | httparse::Error::HeaderValue
545             | httparse::Error::NewLine
546             | httparse::Error::Token => Parse::Header(Header::Token),
547             httparse::Error::Status => Parse::Status,
548             httparse::Error::TooManyHeaders => Parse::TooLarge,
549             httparse::Error::Version => Parse::Version,
550         }
551     }
552 }
553 
554 impl From<http::method::InvalidMethod> for Parse {
from(_: http::method::InvalidMethod) -> Parse555     fn from(_: http::method::InvalidMethod) -> Parse {
556         Parse::Method
557     }
558 }
559 
560 impl From<http::status::InvalidStatusCode> for Parse {
from(_: http::status::InvalidStatusCode) -> Parse561     fn from(_: http::status::InvalidStatusCode) -> Parse {
562         Parse::Status
563     }
564 }
565 
566 impl From<http::uri::InvalidUri> for Parse {
from(_: http::uri::InvalidUri) -> Parse567     fn from(_: http::uri::InvalidUri) -> Parse {
568         Parse::Uri
569     }
570 }
571 
572 impl From<http::uri::InvalidUriParts> for Parse {
from(_: http::uri::InvalidUriParts) -> Parse573     fn from(_: http::uri::InvalidUriParts) -> Parse {
574         Parse::Uri
575     }
576 }
577 
578 #[doc(hidden)]
579 trait AssertSendSync: Send + Sync + 'static {}
580 #[doc(hidden)]
581 impl AssertSendSync for Error {}
582 
583 // ===== impl TimedOut ====
584 
585 impl fmt::Display for TimedOut {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result586     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
587         f.write_str("operation timed out")
588     }
589 }
590 
591 impl StdError for TimedOut {}
592 
593 #[cfg(test)]
594 mod tests {
595     use super::*;
596     use std::mem;
597 
598     #[test]
error_size_of()599     fn error_size_of() {
600         assert_eq!(mem::size_of::<Error>(), mem::size_of::<usize>());
601     }
602 
603     #[cfg(feature = "http2")]
604     #[test]
h2_reason_unknown()605     fn h2_reason_unknown() {
606         let closed = Error::new_closed();
607         assert_eq!(closed.h2_reason(), h2::Reason::INTERNAL_ERROR);
608     }
609 
610     #[cfg(feature = "http2")]
611     #[test]
h2_reason_one_level()612     fn h2_reason_one_level() {
613         let body_err = Error::new_user_body(h2::Error::from(h2::Reason::ENHANCE_YOUR_CALM));
614         assert_eq!(body_err.h2_reason(), h2::Reason::ENHANCE_YOUR_CALM);
615     }
616 
617     #[cfg(feature = "http2")]
618     #[test]
h2_reason_nested()619     fn h2_reason_nested() {
620         let recvd = Error::new_h2(h2::Error::from(h2::Reason::HTTP_1_1_REQUIRED));
621         // Suppose a user were proxying the received error
622         let svc_err = Error::new_user_service(recvd);
623         assert_eq!(svc_err.h2_reason(), h2::Reason::HTTP_1_1_REQUIRED);
624     }
625 }
626