1 //! Error and Result module.
2 
3 #[cfg(all(feature = "client", any(feature = "http1", feature = "http2")))]
4 use crate::client::connect::Connected;
5 use std::error::Error as StdError;
6 use std::fmt;
7 
8 /// Result type often returned from methods that can have hyper `Error`s.
9 pub type Result<T> = std::result::Result<T, Error>;
10 
11 type Cause = Box<dyn StdError + Send + Sync>;
12 
13 /// Represents errors that can occur handling HTTP streams.
14 pub struct Error {
15     inner: Box<ErrorImpl>,
16 }
17 
18 struct ErrorImpl {
19     kind: Kind,
20     cause: Option<Cause>,
21     #[cfg(all(feature = "client", any(feature = "http1", feature = "http2")))]
22     connect_info: Option<Connected>,
23 }
24 
25 #[derive(Debug)]
26 pub(super) enum Kind {
27     Parse(Parse),
28     User(User),
29     /// A message reached EOF, but is not complete.
30     #[allow(unused)]
31     IncompleteMessage,
32     /// A connection received a message (or bytes) when not waiting for one.
33     #[cfg(feature = "http1")]
34     UnexpectedMessage,
35     /// A pending item was dropped before ever being processed.
36     Canceled,
37     /// Indicates a channel (client or body sender) is closed.
38     ChannelClosed,
39     /// An `io::Error` that occurred while trying to read or write to a network stream.
40     #[cfg(any(feature = "http1", feature = "http2"))]
41     Io,
42     /// Error occurred while connecting.
43     #[allow(unused)]
44     Connect,
45     /// Error creating a TcpListener.
46     #[cfg(all(feature = "tcp", feature = "server"))]
47     Listen,
48     /// Error accepting on an Incoming stream.
49     #[cfg(any(feature = "http1", feature = "http2"))]
50     #[cfg(feature = "server")]
51     Accept,
52     /// User took too long to send headers
53     #[cfg(all(feature = "http1", feature = "server", feature = "runtime"))]
54     HeaderTimeout,
55     /// Error while reading a body from connection.
56     #[cfg(any(feature = "http1", feature = "http2", feature = "stream"))]
57     Body,
58     /// Error while writing a body to connection.
59     #[cfg(any(feature = "http1", feature = "http2"))]
60     BodyWrite,
61     /// Error calling AsyncWrite::shutdown()
62     #[cfg(feature = "http1")]
63     Shutdown,
64 
65     /// A general error from h2.
66     #[cfg(feature = "http2")]
67     Http2,
68 }
69 
70 #[derive(Debug)]
71 pub(super) enum Parse {
72     Method,
73     Version,
74     #[cfg(feature = "http1")]
75     VersionH2,
76     Uri,
77     #[cfg_attr(not(all(feature = "http1", feature = "server")), allow(unused))]
78     UriTooLong,
79     Header(Header),
80     TooLarge,
81     Status,
82     #[cfg_attr(debug_assertions, allow(unused))]
83     Internal,
84 }
85 
86 #[derive(Debug)]
87 pub(super) enum Header {
88     Token,
89     #[cfg(feature = "http1")]
90     ContentLengthInvalid,
91     #[cfg(all(feature = "http1", feature = "server"))]
92     TransferEncodingInvalid,
93     #[cfg(feature = "http1")]
94     TransferEncodingUnexpected,
95 }
96 
97 #[derive(Debug)]
98 pub(super) enum User {
99     /// Error calling user's HttpBody::poll_data().
100     #[cfg(any(feature = "http1", feature = "http2"))]
101     Body,
102     /// The user aborted writing of the outgoing body.
103     BodyWriteAborted,
104     /// Error calling user's MakeService.
105     #[cfg(any(feature = "http1", feature = "http2"))]
106     #[cfg(feature = "server")]
107     MakeService,
108     /// Error from future of user's Service.
109     #[cfg(any(feature = "http1", feature = "http2"))]
110     Service,
111     /// User tried to send a certain header in an unexpected context.
112     ///
113     /// For example, sending both `content-length` and `transfer-encoding`.
114     #[cfg(any(feature = "http1", feature = "http2"))]
115     #[cfg(feature = "server")]
116     UnexpectedHeader,
117     /// User tried to create a Request with bad version.
118     #[cfg(any(feature = "http1", feature = "http2"))]
119     #[cfg(feature = "client")]
120     UnsupportedVersion,
121     /// User tried to create a CONNECT Request with the Client.
122     #[cfg(any(feature = "http1", feature = "http2"))]
123     #[cfg(feature = "client")]
124     UnsupportedRequestMethod,
125     /// User tried to respond with a 1xx (not 101) response code.
126     #[cfg(feature = "http1")]
127     #[cfg(feature = "server")]
128     UnsupportedStatusCode,
129     /// User tried to send a Request with Client with non-absolute URI.
130     #[cfg(any(feature = "http1", feature = "http2"))]
131     #[cfg(feature = "client")]
132     AbsoluteUriRequired,
133 
134     /// User tried polling for an upgrade that doesn't exist.
135     NoUpgrade,
136 
137     /// User polled for an upgrade, but low-level API is not using upgrades.
138     #[cfg(feature = "http1")]
139     ManualUpgrade,
140 
141     /// User called `server::Connection::without_shutdown()` on an HTTP/2 conn.
142     #[cfg(feature = "server")]
143     WithoutShutdownNonHttp1,
144 
145     /// The dispatch task is gone.
146     #[cfg(feature = "client")]
147     DispatchGone,
148 
149     /// User aborted in an FFI callback.
150     #[cfg(feature = "ffi")]
151     AbortedByCallback,
152 }
153 
154 // Sentinel type to indicate the error was caused by a timeout.
155 #[derive(Debug)]
156 pub(super) struct TimedOut;
157 
158 impl Error {
159     /// Returns true if this was an HTTP parse error.
is_parse(&self) -> bool160     pub fn is_parse(&self) -> bool {
161         matches!(self.inner.kind, Kind::Parse(_))
162     }
163 
164     /// Returns true if this was an HTTP parse error caused by a message that was too large.
is_parse_too_large(&self) -> bool165     pub fn is_parse_too_large(&self) -> bool {
166         matches!(
167             self.inner.kind,
168             Kind::Parse(Parse::TooLarge) | Kind::Parse(Parse::UriTooLong)
169         )
170     }
171 
172     /// Returns true if this was an HTTP parse error caused by an invalid response status code or
173     /// reason phrase.
is_parse_status(&self) -> bool174     pub fn is_parse_status(&self) -> bool {
175         matches!(self.inner.kind, Kind::Parse(Parse::Status))
176     }
177 
178     /// Returns true if this error was caused by user code.
is_user(&self) -> bool179     pub fn is_user(&self) -> bool {
180         matches!(self.inner.kind, Kind::User(_))
181     }
182 
183     /// Returns true if this was about a `Request` that was canceled.
is_canceled(&self) -> bool184     pub fn is_canceled(&self) -> bool {
185         matches!(self.inner.kind, Kind::Canceled)
186     }
187 
188     /// Returns true if a sender's channel is closed.
is_closed(&self) -> bool189     pub fn is_closed(&self) -> bool {
190         matches!(self.inner.kind, Kind::ChannelClosed)
191     }
192 
193     /// Returns true if this was an error from `Connect`.
is_connect(&self) -> bool194     pub fn is_connect(&self) -> bool {
195         matches!(self.inner.kind, Kind::Connect)
196     }
197 
198     /// Returns true if the connection closed before a message could complete.
is_incomplete_message(&self) -> bool199     pub fn is_incomplete_message(&self) -> bool {
200         matches!(self.inner.kind, Kind::IncompleteMessage)
201     }
202 
203     /// Returns true if the body write was aborted.
is_body_write_aborted(&self) -> bool204     pub fn is_body_write_aborted(&self) -> bool {
205         matches!(self.inner.kind, Kind::User(User::BodyWriteAborted))
206     }
207 
208     /// Returns true if the error was caused by a timeout.
is_timeout(&self) -> bool209     pub fn is_timeout(&self) -> bool {
210         self.find_source::<TimedOut>().is_some()
211     }
212 
213     /// Consumes the error, returning its cause.
into_cause(self) -> Option<Box<dyn StdError + Send + Sync>>214     pub fn into_cause(self) -> Option<Box<dyn StdError + Send + Sync>> {
215         self.inner.cause
216     }
217 
218     /// Returns the info of the client connection on which this error occurred.
219     #[cfg(all(feature = "client", any(feature = "http1", feature = "http2")))]
client_connect_info(&self) -> Option<&Connected>220     pub fn client_connect_info(&self) -> Option<&Connected> {
221         self.inner.connect_info.as_ref()
222     }
223 
new(kind: Kind) -> Error224     pub(super) fn new(kind: Kind) -> Error {
225         Error {
226             inner: Box::new(ErrorImpl {
227                 kind,
228                 cause: None,
229                 #[cfg(all(feature = "client", any(feature = "http1", feature = "http2")))]
230                 connect_info: None,
231             }),
232         }
233     }
234 
with<C: Into<Cause>>(mut self, cause: C) -> Error235     pub(super) fn with<C: Into<Cause>>(mut self, cause: C) -> Error {
236         self.inner.cause = Some(cause.into());
237         self
238     }
239 
240     #[cfg(all(feature = "client", any(feature = "http1", feature = "http2")))]
with_client_connect_info(mut self, connect_info: Connected) -> Error241     pub(super) fn with_client_connect_info(mut self, connect_info: Connected) -> Error {
242         self.inner.connect_info = Some(connect_info);
243         self
244     }
245 
246     #[cfg(any(all(feature = "http1", feature = "server"), feature = "ffi"))]
kind(&self) -> &Kind247     pub(super) fn kind(&self) -> &Kind {
248         &self.inner.kind
249     }
250 
find_source<E: StdError + 'static>(&self) -> Option<&E>251     pub(crate) fn find_source<E: StdError + 'static>(&self) -> Option<&E> {
252         let mut cause = self.source();
253         while let Some(err) = cause {
254             if let Some(ref typed) = err.downcast_ref() {
255                 return Some(typed);
256             }
257             cause = err.source();
258         }
259 
260         // else
261         None
262     }
263 
264     #[cfg(feature = "http2")]
h2_reason(&self) -> h2::Reason265     pub(super) fn h2_reason(&self) -> h2::Reason {
266         // Find an h2::Reason somewhere in the cause stack, if it exists,
267         // otherwise assume an INTERNAL_ERROR.
268         self.find_source::<h2::Error>()
269             .and_then(|h2_err| h2_err.reason())
270             .unwrap_or(h2::Reason::INTERNAL_ERROR)
271     }
272 
new_canceled() -> Error273     pub(super) fn new_canceled() -> Error {
274         Error::new(Kind::Canceled)
275     }
276 
277     #[cfg(feature = "http1")]
new_incomplete() -> Error278     pub(super) fn new_incomplete() -> Error {
279         Error::new(Kind::IncompleteMessage)
280     }
281 
282     #[cfg(feature = "http1")]
new_too_large() -> Error283     pub(super) fn new_too_large() -> Error {
284         Error::new(Kind::Parse(Parse::TooLarge))
285     }
286 
287     #[cfg(feature = "http1")]
new_version_h2() -> Error288     pub(super) fn new_version_h2() -> Error {
289         Error::new(Kind::Parse(Parse::VersionH2))
290     }
291 
292     #[cfg(feature = "http1")]
new_unexpected_message() -> Error293     pub(super) fn new_unexpected_message() -> Error {
294         Error::new(Kind::UnexpectedMessage)
295     }
296 
297     #[cfg(any(feature = "http1", feature = "http2"))]
new_io(cause: std::io::Error) -> Error298     pub(super) fn new_io(cause: std::io::Error) -> Error {
299         Error::new(Kind::Io).with(cause)
300     }
301 
302     #[cfg(all(feature = "server", feature = "tcp"))]
new_listen<E: Into<Cause>>(cause: E) -> Error303     pub(super) fn new_listen<E: Into<Cause>>(cause: E) -> Error {
304         Error::new(Kind::Listen).with(cause)
305     }
306 
307     #[cfg(any(feature = "http1", feature = "http2"))]
308     #[cfg(feature = "server")]
new_accept<E: Into<Cause>>(cause: E) -> Error309     pub(super) fn new_accept<E: Into<Cause>>(cause: E) -> Error {
310         Error::new(Kind::Accept).with(cause)
311     }
312 
313     #[cfg(any(feature = "http1", feature = "http2"))]
314     #[cfg(feature = "client")]
new_connect<E: Into<Cause>>(cause: E) -> Error315     pub(super) fn new_connect<E: Into<Cause>>(cause: E) -> Error {
316         Error::new(Kind::Connect).with(cause)
317     }
318 
new_closed() -> Error319     pub(super) fn new_closed() -> Error {
320         Error::new(Kind::ChannelClosed)
321     }
322 
323     #[cfg(any(feature = "http1", feature = "http2", feature = "stream"))]
new_body<E: Into<Cause>>(cause: E) -> Error324     pub(super) fn new_body<E: Into<Cause>>(cause: E) -> Error {
325         Error::new(Kind::Body).with(cause)
326     }
327 
328     #[cfg(any(feature = "http1", feature = "http2"))]
new_body_write<E: Into<Cause>>(cause: E) -> Error329     pub(super) fn new_body_write<E: Into<Cause>>(cause: E) -> Error {
330         Error::new(Kind::BodyWrite).with(cause)
331     }
332 
new_body_write_aborted() -> Error333     pub(super) fn new_body_write_aborted() -> Error {
334         Error::new(Kind::User(User::BodyWriteAborted))
335     }
336 
new_user(user: User) -> Error337     fn new_user(user: User) -> Error {
338         Error::new(Kind::User(user))
339     }
340 
341     #[cfg(any(feature = "http1", feature = "http2"))]
342     #[cfg(feature = "server")]
new_user_header() -> Error343     pub(super) fn new_user_header() -> Error {
344         Error::new_user(User::UnexpectedHeader)
345     }
346 
347     #[cfg(all(feature = "http1", feature = "server", feature = "runtime"))]
new_header_timeout() -> Error348     pub(super) fn new_header_timeout() -> Error {
349         Error::new(Kind::HeaderTimeout)
350     }
351 
352     #[cfg(any(feature = "http1", feature = "http2"))]
353     #[cfg(feature = "client")]
new_user_unsupported_version() -> Error354     pub(super) fn new_user_unsupported_version() -> Error {
355         Error::new_user(User::UnsupportedVersion)
356     }
357 
358     #[cfg(any(feature = "http1", feature = "http2"))]
359     #[cfg(feature = "client")]
new_user_unsupported_request_method() -> Error360     pub(super) fn new_user_unsupported_request_method() -> Error {
361         Error::new_user(User::UnsupportedRequestMethod)
362     }
363 
364     #[cfg(feature = "http1")]
365     #[cfg(feature = "server")]
new_user_unsupported_status_code() -> Error366     pub(super) fn new_user_unsupported_status_code() -> Error {
367         Error::new_user(User::UnsupportedStatusCode)
368     }
369 
370     #[cfg(any(feature = "http1", feature = "http2"))]
371     #[cfg(feature = "client")]
new_user_absolute_uri_required() -> Error372     pub(super) fn new_user_absolute_uri_required() -> Error {
373         Error::new_user(User::AbsoluteUriRequired)
374     }
375 
new_user_no_upgrade() -> Error376     pub(super) fn new_user_no_upgrade() -> Error {
377         Error::new_user(User::NoUpgrade)
378     }
379 
380     #[cfg(feature = "http1")]
new_user_manual_upgrade() -> Error381     pub(super) fn new_user_manual_upgrade() -> Error {
382         Error::new_user(User::ManualUpgrade)
383     }
384 
385     #[cfg(any(feature = "http1", feature = "http2"))]
386     #[cfg(feature = "server")]
new_user_make_service<E: Into<Cause>>(cause: E) -> Error387     pub(super) fn new_user_make_service<E: Into<Cause>>(cause: E) -> Error {
388         Error::new_user(User::MakeService).with(cause)
389     }
390 
391     #[cfg(any(feature = "http1", feature = "http2"))]
new_user_service<E: Into<Cause>>(cause: E) -> Error392     pub(super) fn new_user_service<E: Into<Cause>>(cause: E) -> Error {
393         Error::new_user(User::Service).with(cause)
394     }
395 
396     #[cfg(any(feature = "http1", feature = "http2"))]
new_user_body<E: Into<Cause>>(cause: E) -> Error397     pub(super) fn new_user_body<E: Into<Cause>>(cause: E) -> Error {
398         Error::new_user(User::Body).with(cause)
399     }
400 
401     #[cfg(feature = "server")]
new_without_shutdown_not_h1() -> Error402     pub(super) fn new_without_shutdown_not_h1() -> Error {
403         Error::new(Kind::User(User::WithoutShutdownNonHttp1))
404     }
405 
406     #[cfg(feature = "http1")]
new_shutdown(cause: std::io::Error) -> Error407     pub(super) fn new_shutdown(cause: std::io::Error) -> Error {
408         Error::new(Kind::Shutdown).with(cause)
409     }
410 
411     #[cfg(feature = "ffi")]
new_user_aborted_by_callback() -> Error412     pub(super) fn new_user_aborted_by_callback() -> Error {
413         Error::new_user(User::AbortedByCallback)
414     }
415 
416     #[cfg(feature = "client")]
new_user_dispatch_gone() -> Error417     pub(super) fn new_user_dispatch_gone() -> Error {
418         Error::new(Kind::User(User::DispatchGone))
419     }
420 
421     #[cfg(feature = "http2")]
new_h2(cause: ::h2::Error) -> Error422     pub(super) fn new_h2(cause: ::h2::Error) -> Error {
423         if cause.is_io() {
424             Error::new_io(cause.into_io().expect("h2::Error::is_io"))
425         } else {
426             Error::new(Kind::Http2).with(cause)
427         }
428     }
429 
430     /// The error's standalone message, without the message from the source.
message(&self) -> impl fmt::Display + '_431     pub fn message(&self) -> impl fmt::Display + '_ {
432         self.description()
433     }
434 
description(&self) -> &str435     fn description(&self) -> &str {
436         match self.inner.kind {
437             Kind::Parse(Parse::Method) => "invalid HTTP method parsed",
438             Kind::Parse(Parse::Version) => "invalid HTTP version parsed",
439             #[cfg(feature = "http1")]
440             Kind::Parse(Parse::VersionH2) => "invalid HTTP version parsed (found HTTP2 preface)",
441             Kind::Parse(Parse::Uri) => "invalid URI",
442             Kind::Parse(Parse::UriTooLong) => "URI too long",
443             Kind::Parse(Parse::Header(Header::Token)) => "invalid HTTP header parsed",
444             #[cfg(feature = "http1")]
445             Kind::Parse(Parse::Header(Header::ContentLengthInvalid)) => {
446                 "invalid content-length parsed"
447             }
448             #[cfg(all(feature = "http1", feature = "server"))]
449             Kind::Parse(Parse::Header(Header::TransferEncodingInvalid)) => {
450                 "invalid transfer-encoding parsed"
451             }
452             #[cfg(feature = "http1")]
453             Kind::Parse(Parse::Header(Header::TransferEncodingUnexpected)) => {
454                 "unexpected transfer-encoding parsed"
455             }
456             Kind::Parse(Parse::TooLarge) => "message head is too large",
457             Kind::Parse(Parse::Status) => "invalid HTTP status-code parsed",
458             Kind::Parse(Parse::Internal) => {
459                 "internal error inside Hyper and/or its dependencies, please report"
460             }
461             Kind::IncompleteMessage => "connection closed before message completed",
462             #[cfg(feature = "http1")]
463             Kind::UnexpectedMessage => "received unexpected message from connection",
464             Kind::ChannelClosed => "channel closed",
465             Kind::Connect => "error trying to connect",
466             Kind::Canceled => "operation was canceled",
467             #[cfg(all(feature = "server", feature = "tcp"))]
468             Kind::Listen => "error creating server listener",
469             #[cfg(any(feature = "http1", feature = "http2"))]
470             #[cfg(feature = "server")]
471             Kind::Accept => "error accepting connection",
472             #[cfg(all(feature = "http1", feature = "server", feature = "runtime"))]
473             Kind::HeaderTimeout => "read header from client timeout",
474             #[cfg(any(feature = "http1", feature = "http2", feature = "stream"))]
475             Kind::Body => "error reading a body from connection",
476             #[cfg(any(feature = "http1", feature = "http2"))]
477             Kind::BodyWrite => "error writing a body to connection",
478             #[cfg(feature = "http1")]
479             Kind::Shutdown => "error shutting down connection",
480             #[cfg(feature = "http2")]
481             Kind::Http2 => "http2 error",
482             #[cfg(any(feature = "http1", feature = "http2"))]
483             Kind::Io => "connection error",
484 
485             #[cfg(any(feature = "http1", feature = "http2"))]
486             Kind::User(User::Body) => "error from user's HttpBody stream",
487             Kind::User(User::BodyWriteAborted) => "user body write aborted",
488             #[cfg(any(feature = "http1", feature = "http2"))]
489             #[cfg(feature = "server")]
490             Kind::User(User::MakeService) => "error from user's MakeService",
491             #[cfg(any(feature = "http1", feature = "http2"))]
492             Kind::User(User::Service) => "error from user's Service",
493             #[cfg(any(feature = "http1", feature = "http2"))]
494             #[cfg(feature = "server")]
495             Kind::User(User::UnexpectedHeader) => "user sent unexpected header",
496             #[cfg(any(feature = "http1", feature = "http2"))]
497             #[cfg(feature = "client")]
498             Kind::User(User::UnsupportedVersion) => "request has unsupported HTTP version",
499             #[cfg(any(feature = "http1", feature = "http2"))]
500             #[cfg(feature = "client")]
501             Kind::User(User::UnsupportedRequestMethod) => "request has unsupported HTTP method",
502             #[cfg(feature = "http1")]
503             #[cfg(feature = "server")]
504             Kind::User(User::UnsupportedStatusCode) => {
505                 "response has 1xx status code, not supported by server"
506             }
507             #[cfg(any(feature = "http1", feature = "http2"))]
508             #[cfg(feature = "client")]
509             Kind::User(User::AbsoluteUriRequired) => "client requires absolute-form URIs",
510             Kind::User(User::NoUpgrade) => "no upgrade available",
511             #[cfg(feature = "http1")]
512             Kind::User(User::ManualUpgrade) => "upgrade expected but low level API in use",
513             #[cfg(feature = "server")]
514             Kind::User(User::WithoutShutdownNonHttp1) => {
515                 "without_shutdown() called on a non-HTTP/1 connection"
516             }
517             #[cfg(feature = "client")]
518             Kind::User(User::DispatchGone) => "dispatch task is gone",
519             #[cfg(feature = "ffi")]
520             Kind::User(User::AbortedByCallback) => "operation aborted by an application callback",
521         }
522     }
523 }
524 
525 impl fmt::Debug for Error {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result526     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
527         let mut f = f.debug_tuple("hyper::Error");
528         f.field(&self.inner.kind);
529         if let Some(ref cause) = self.inner.cause {
530             f.field(cause);
531         }
532         f.finish()
533     }
534 }
535 
536 impl fmt::Display for Error {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result537     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
538         if let Some(ref cause) = self.inner.cause {
539             write!(f, "{}: {}", self.description(), cause)
540         } else {
541             f.write_str(self.description())
542         }
543     }
544 }
545 
546 impl StdError for Error {
source(&self) -> Option<&(dyn StdError + 'static)>547     fn source(&self) -> Option<&(dyn StdError + 'static)> {
548         self.inner
549             .cause
550             .as_ref()
551             .map(|cause| &**cause as &(dyn StdError + 'static))
552     }
553 }
554 
555 #[doc(hidden)]
556 impl From<Parse> for Error {
from(err: Parse) -> Error557     fn from(err: Parse) -> Error {
558         Error::new(Kind::Parse(err))
559     }
560 }
561 
562 #[cfg(feature = "http1")]
563 impl Parse {
content_length_invalid() -> Self564     pub(crate) fn content_length_invalid() -> Self {
565         Parse::Header(Header::ContentLengthInvalid)
566     }
567 
568     #[cfg(all(feature = "http1", feature = "server"))]
transfer_encoding_invalid() -> Self569     pub(crate) fn transfer_encoding_invalid() -> Self {
570         Parse::Header(Header::TransferEncodingInvalid)
571     }
572 
transfer_encoding_unexpected() -> Self573     pub(crate) fn transfer_encoding_unexpected() -> Self {
574         Parse::Header(Header::TransferEncodingUnexpected)
575     }
576 }
577 
578 impl From<httparse::Error> for Parse {
from(err: httparse::Error) -> Parse579     fn from(err: httparse::Error) -> Parse {
580         match err {
581             httparse::Error::HeaderName
582             | httparse::Error::HeaderValue
583             | httparse::Error::NewLine
584             | httparse::Error::Token => Parse::Header(Header::Token),
585             httparse::Error::Status => Parse::Status,
586             httparse::Error::TooManyHeaders => Parse::TooLarge,
587             httparse::Error::Version => Parse::Version,
588         }
589     }
590 }
591 
592 impl From<http::method::InvalidMethod> for Parse {
from(_: http::method::InvalidMethod) -> Parse593     fn from(_: http::method::InvalidMethod) -> Parse {
594         Parse::Method
595     }
596 }
597 
598 impl From<http::status::InvalidStatusCode> for Parse {
from(_: http::status::InvalidStatusCode) -> Parse599     fn from(_: http::status::InvalidStatusCode) -> Parse {
600         Parse::Status
601     }
602 }
603 
604 impl From<http::uri::InvalidUri> for Parse {
from(_: http::uri::InvalidUri) -> Parse605     fn from(_: http::uri::InvalidUri) -> Parse {
606         Parse::Uri
607     }
608 }
609 
610 impl From<http::uri::InvalidUriParts> for Parse {
from(_: http::uri::InvalidUriParts) -> Parse611     fn from(_: http::uri::InvalidUriParts) -> Parse {
612         Parse::Uri
613     }
614 }
615 
616 #[doc(hidden)]
617 trait AssertSendSync: Send + Sync + 'static {}
618 #[doc(hidden)]
619 impl AssertSendSync for Error {}
620 
621 // ===== impl TimedOut ====
622 
623 impl fmt::Display for TimedOut {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result624     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
625         f.write_str("operation timed out")
626     }
627 }
628 
629 impl StdError for TimedOut {}
630 
631 #[cfg(test)]
632 mod tests {
633     use super::*;
634     use std::mem;
635 
636     #[test]
error_size_of()637     fn error_size_of() {
638         assert_eq!(mem::size_of::<Error>(), mem::size_of::<usize>());
639     }
640 
641     #[cfg(feature = "http2")]
642     #[test]
h2_reason_unknown()643     fn h2_reason_unknown() {
644         let closed = Error::new_closed();
645         assert_eq!(closed.h2_reason(), h2::Reason::INTERNAL_ERROR);
646     }
647 
648     #[cfg(feature = "http2")]
649     #[test]
h2_reason_one_level()650     fn h2_reason_one_level() {
651         let body_err = Error::new_user_body(h2::Error::from(h2::Reason::ENHANCE_YOUR_CALM));
652         assert_eq!(body_err.h2_reason(), h2::Reason::ENHANCE_YOUR_CALM);
653     }
654 
655     #[cfg(feature = "http2")]
656     #[test]
h2_reason_nested()657     fn h2_reason_nested() {
658         let recvd = Error::new_h2(h2::Error::from(h2::Reason::HTTP_1_1_REQUIRED));
659         // Suppose a user were proxying the received error
660         let svc_err = Error::new_user_service(recvd);
661         assert_eq!(svc_err.h2_reason(), h2::Reason::HTTP_1_1_REQUIRED);
662     }
663 }
664