1use std::error::Error as StdError;
3use std::fmt;
4
5pub type Result<T> = std::result::Result<T, Error>;
7
8type Cause = Box<dyn StdError + Send + Sync>;
9
10pub struct Error {
32 inner: Box<ErrorImpl>,
33}
34
35struct ErrorImpl {
36 kind: Kind,
37 cause: Option<Cause>,
38}
39
40#[derive(Debug)]
41pub(super) enum Kind {
42 Parse(Parse),
43 User(User),
44 #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
46 IncompleteMessage,
47 #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
49 UnexpectedMessage,
50 Canceled,
52 #[cfg(any(
54 all(feature = "http1", any(feature = "client", feature = "server")),
55 all(feature = "http2", feature = "client")
56 ))]
57 ChannelClosed,
58 #[cfg(all(
60 any(feature = "client", feature = "server"),
61 any(feature = "http1", feature = "http2")
62 ))]
63 Io,
64 #[cfg(all(feature = "http1", feature = "server"))]
66 HeaderTimeout,
67 #[cfg(all(
69 any(feature = "client", feature = "server"),
70 any(feature = "http1", feature = "http2")
71 ))]
72 Body,
73 #[cfg(all(
75 any(feature = "client", feature = "server"),
76 any(feature = "http1", feature = "http2")
77 ))]
78 BodyWrite,
79 #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
81 Shutdown,
82
83 #[cfg(all(any(feature = "client", feature = "server"), feature = "http2"))]
85 Http2,
86}
87
88#[derive(Debug)]
89pub(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")]
110pub(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)]
121pub(super) enum User {
122 #[cfg(all(
124 any(feature = "client", feature = "server"),
125 any(feature = "http1", feature = "http2")
126 ))]
127 Body,
128 #[cfg(any(
130 all(feature = "http1", any(feature = "client", feature = "server")),
131 feature = "ffi"
132 ))]
133 BodyWriteAborted,
134 #[cfg(any(
136 all(any(feature = "client", feature = "server"), feature = "http1"),
137 all(feature = "server", feature = "http2")
138 ))]
139 Service,
140 #[cfg(any(feature = "http1", feature = "http2"))]
144 #[cfg(feature = "server")]
145 UnexpectedHeader,
146 #[cfg(feature = "http1")]
148 #[cfg(feature = "server")]
149 UnsupportedStatusCode,
150
151 NoUpgrade,
153
154 #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
156 ManualUpgrade,
157
158 #[cfg(all(feature = "client", any(feature = "http1", feature = "http2")))]
160 DispatchGone,
161
162 #[cfg(feature = "ffi")]
164 AbortedByCallback,
165}
166
167#[derive(Debug)]
169pub(super) struct TimedOut;
170
171impl Error {
172 pub fn is_parse(&self) -> bool {
174 matches!(self.inner.kind, Kind::Parse(_))
175 }
176
177 #[cfg(all(feature = "http1", feature = "server"))]
179 pub fn is_parse_too_large(&self) -> bool {
180 matches!(
181 self.inner.kind,
182 Kind::Parse(Parse::TooLarge) | Kind::Parse(Parse::UriTooLong)
183 )
184 }
185
186 pub fn is_parse_status(&self) -> bool {
189 matches!(self.inner.kind, Kind::Parse(Parse::Status))
190 }
191
192 pub fn is_user(&self) -> bool {
194 matches!(self.inner.kind, Kind::User(_))
195 }
196
197 pub fn is_canceled(&self) -> bool {
199 matches!(self.inner.kind, Kind::Canceled)
200 }
201
202 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 matches!(self.inner.kind, Kind::ChannelClosed)
215 }
216
217 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 matches!(self.inner.kind, Kind::IncompleteMessage)
224 }
225
226 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 matches!(self.inner.kind, Kind::User(User::BodyWriteAborted))
239 }
240
241 pub fn is_timeout(&self) -> bool {
243 #[cfg(all(feature = "http1", feature = "server"))]
244 if matches!(self.inner.kind, Kind::HeaderTimeout) {
245 return true;
246 }
247 self.find_source::<TimedOut>().is_some()
248 }
249
250 pub(super) fn new(kind: Kind) -> Error {
251 Error {
252 inner: Box::new(ErrorImpl { kind, cause: None }),
253 }
254 }
255
256 pub(super) fn with<C: Into<Cause>>(mut self, cause: C) -> Error {
257 self.inner.cause = Some(cause.into());
258 self
259 }
260
261 #[cfg(any(all(feature = "http1", feature = "server"), feature = "ffi"))]
262 pub(super) fn kind(&self) -> &Kind {
263 &self.inner.kind
264 }
265
266 pub(crate) fn find_source<E: StdError + 'static>(&self) -> Option<&E> {
267 let mut cause = self.source();
268 while let Some(err) = cause {
269 if let Some(typed) = err.downcast_ref() {
270 return Some(typed);
271 }
272 cause = err.source();
273 }
274
275 None
277 }
278
279 #[cfg(all(any(feature = "client", feature = "server"), feature = "http2"))]
280 pub(super) fn h2_reason(&self) -> h2::Reason {
281 self.find_source::<h2::Error>()
284 .and_then(|h2_err| h2_err.reason())
285 .unwrap_or(h2::Reason::INTERNAL_ERROR)
286 }
287
288 pub(super) fn new_canceled() -> Error {
289 Error::new(Kind::Canceled)
290 }
291
292 #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
293 pub(super) fn new_incomplete() -> Error {
294 Error::new(Kind::IncompleteMessage)
295 }
296
297 #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
298 pub(super) fn new_too_large() -> Error {
299 Error::new(Kind::Parse(Parse::TooLarge))
300 }
301
302 #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
303 pub(super) fn new_version_h2() -> Error {
304 Error::new(Kind::Parse(Parse::VersionH2))
305 }
306
307 #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
308 pub(super) fn new_unexpected_message() -> Error {
309 Error::new(Kind::UnexpectedMessage)
310 }
311
312 #[cfg(all(
313 any(feature = "client", feature = "server"),
314 any(feature = "http1", feature = "http2")
315 ))]
316 pub(super) fn new_io(cause: std::io::Error) -> Error {
317 Error::new(Kind::Io).with(cause)
318 }
319
320 #[cfg(any(
321 all(feature = "http1", any(feature = "client", feature = "server")),
322 all(feature = "http2", feature = "client")
323 ))]
324 pub(super) fn new_closed() -> Error {
325 Error::new(Kind::ChannelClosed)
326 }
327
328 #[cfg(all(
329 any(feature = "client", feature = "server"),
330 any(feature = "http1", feature = "http2")
331 ))]
332 pub(super) fn new_body<E: Into<Cause>>(cause: E) -> Error {
333 Error::new(Kind::Body).with(cause)
334 }
335
336 #[cfg(all(
337 any(feature = "client", feature = "server"),
338 any(feature = "http1", feature = "http2")
339 ))]
340 pub(super) fn new_body_write<E: Into<Cause>>(cause: E) -> Error {
341 Error::new(Kind::BodyWrite).with(cause)
342 }
343
344 #[cfg(any(
345 all(feature = "http1", any(feature = "client", feature = "server")),
346 feature = "ffi"
347 ))]
348 pub(super) fn new_body_write_aborted() -> Error {
349 Error::new(Kind::User(User::BodyWriteAborted))
350 }
351
352 fn new_user(user: User) -> Error {
353 Error::new(Kind::User(user))
354 }
355
356 #[cfg(any(feature = "http1", feature = "http2"))]
357 #[cfg(feature = "server")]
358 pub(super) fn new_user_header() -> Error {
359 Error::new_user(User::UnexpectedHeader)
360 }
361
362 #[cfg(all(feature = "http1", feature = "server"))]
363 pub(super) fn new_header_timeout() -> Error {
364 Error::new(Kind::HeaderTimeout)
365 }
366
367 #[cfg(feature = "http1")]
368 #[cfg(feature = "server")]
369 pub(super) fn new_user_unsupported_status_code() -> Error {
370 Error::new_user(User::UnsupportedStatusCode)
371 }
372
373 pub(super) fn new_user_no_upgrade() -> Error {
374 Error::new_user(User::NoUpgrade)
375 }
376
377 #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
378 pub(super) fn new_user_manual_upgrade() -> Error {
379 Error::new_user(User::ManualUpgrade)
380 }
381
382 #[cfg(any(
383 all(any(feature = "client", feature = "server"), feature = "http1"),
384 all(feature = "server", feature = "http2")
385 ))]
386 pub(super) fn new_user_service<E: Into<Cause>>(cause: E) -> Error {
387 Error::new_user(User::Service).with(cause)
388 }
389
390 #[cfg(all(
391 any(feature = "client", feature = "server"),
392 any(feature = "http1", feature = "http2")
393 ))]
394 pub(super) fn new_user_body<E: Into<Cause>>(cause: E) -> Error {
395 Error::new_user(User::Body).with(cause)
396 }
397
398 #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
399 pub(super) fn new_shutdown(cause: std::io::Error) -> Error {
400 Error::new(Kind::Shutdown).with(cause)
401 }
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 pub(super) fn new_user_dispatch_gone() -> Error {
410 Error::new(Kind::User(User::DispatchGone))
411 }
412
413 #[cfg(all(any(feature = "client", feature = "server"), feature = "http2"))]
414 pub(super) fn new_h2(cause: ::h2::Error) -> Error {
415 if cause.is_io() {
416 Error::new_io(cause.into_io().expect("h2::Error::is_io"))
417 } else {
418 Error::new(Kind::Http2).with(cause)
419 }
420 }
421
422 fn description(&self) -> &str {
423 match self.inner.kind {
424 Kind::Parse(Parse::Method) => "invalid HTTP method parsed",
425 #[cfg(feature = "http1")]
426 Kind::Parse(Parse::Version) => "invalid HTTP version parsed",
427 #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
428 Kind::Parse(Parse::VersionH2) => "invalid HTTP version parsed (found HTTP2 preface)",
429 Kind::Parse(Parse::Uri) => "invalid URI",
430 #[cfg(all(feature = "http1", feature = "server"))]
431 Kind::Parse(Parse::UriTooLong) => "URI too long",
432 #[cfg(feature = "http1")]
433 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 "invalid content-length parsed"
437 }
438 #[cfg(all(feature = "http1", feature = "server"))]
439 Kind::Parse(Parse::Header(Header::TransferEncodingInvalid)) => {
440 "invalid transfer-encoding parsed"
441 }
442 #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
443 Kind::Parse(Parse::Header(Header::TransferEncodingUnexpected)) => {
444 "unexpected transfer-encoding parsed"
445 }
446 #[cfg(any(feature = "http1", feature = "http2"))]
447 Kind::Parse(Parse::TooLarge) => "message head is too large",
448 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 "internal error inside Hyper and/or its dependencies, please report"
452 }
453 #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
454 Kind::IncompleteMessage => "connection closed before message completed",
455 #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
456 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 Kind::ChannelClosed => "channel closed",
462 Kind::Canceled => "operation was canceled",
463 #[cfg(all(feature = "http1", feature = "server"))]
464 Kind::HeaderTimeout => "read header from client timeout",
465 #[cfg(all(
466 any(feature = "client", feature = "server"),
467 any(feature = "http1", feature = "http2")
468 ))]
469 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 Kind::BodyWrite => "error writing a body to connection",
475 #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
476 Kind::Shutdown => "error shutting down connection",
477 #[cfg(all(any(feature = "client", feature = "server"), feature = "http2"))]
478 Kind::Http2 => "http2 error",
479 #[cfg(all(
480 any(feature = "client", feature = "server"),
481 any(feature = "http1", feature = "http2")
482 ))]
483 Kind::Io => "connection error",
484
485 #[cfg(all(
486 any(feature = "client", feature = "server"),
487 any(feature = "http1", feature = "http2")
488 ))]
489 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 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 Kind::User(User::Service) => "error from user's Service",
500 #[cfg(any(feature = "http1", feature = "http2"))]
501 #[cfg(feature = "server")]
502 Kind::User(User::UnexpectedHeader) => "user sent unexpected header",
503 #[cfg(feature = "http1")]
504 #[cfg(feature = "server")]
505 Kind::User(User::UnsupportedStatusCode) => {
506 "response has 1xx status code, not supported by server"
507 }
508 Kind::User(User::NoUpgrade) => "no upgrade available",
509 #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
510 Kind::User(User::ManualUpgrade) => "upgrade expected but low level API in use",
511 #[cfg(all(feature = "client", any(feature = "http1", feature = "http2")))]
512 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 }
517}
518
519impl fmt::Debug for Error {
520 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
521 let mut f = f.debug_tuple("hyper::Error");
522 f.field(&self.inner.kind);
523 if let Some(ref cause) = self.inner.cause {
524 f.field(cause);
525 }
526 f.finish()
527 }
528}
529
530impl fmt::Display for Error {
531 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
532 f.write_str(self.description())
533 }
534}
535
536impl StdError for Error {
537 fn source(&self) -> Option<&(dyn StdError + 'static)> {
538 self.inner
539 .cause
540 .as_ref()
541 .map(|cause| &**cause as &(dyn StdError + 'static))
542 }
543}
544
545#[doc(hidden)]
546impl From<Parse> for Error {
547 fn from(err: Parse) -> Error {
548 Error::new(Kind::Parse(err))
549 }
550}
551
552#[cfg(feature = "http1")]
553impl Parse {
554 #[cfg(any(feature = "client", feature = "server"))]
555 pub(crate) fn content_length_invalid() -> Self {
556 Parse::Header(Header::ContentLengthInvalid)
557 }
558
559 #[cfg(feature = "server")]
560 pub(crate) fn transfer_encoding_invalid() -> Self {
561 Parse::Header(Header::TransferEncodingInvalid)
562 }
563
564 #[cfg(any(feature = "client", feature = "server"))]
565 pub(crate) fn transfer_encoding_unexpected() -> Self {
566 Parse::Header(Header::TransferEncodingUnexpected)
567 }
568}
569
570#[cfg(feature = "http1")]
571impl From<httparse::Error> for Parse {
572 fn from(err: httparse::Error) -> Parse {
573 match err {
574 httparse::Error::HeaderName
575 | httparse::Error::HeaderValue
576 | httparse::Error::NewLine
577 | httparse::Error::Token => Parse::Header(Header::Token),
578 httparse::Error::Status => Parse::Status,
579 httparse::Error::TooManyHeaders => Parse::TooLarge,
580 httparse::Error::Version => Parse::Version,
581 }
582 }
583}
584
585impl From<http::method::InvalidMethod> for Parse {
586 fn from(_: http::method::InvalidMethod) -> Parse {
587 Parse::Method
588 }
589}
590
591impl From<http::status::InvalidStatusCode> for Parse {
592 fn from(_: http::status::InvalidStatusCode) -> Parse {
593 Parse::Status
594 }
595}
596
597impl From<http::uri::InvalidUri> for Parse {
598 fn from(_: http::uri::InvalidUri) -> Parse {
599 Parse::Uri
600 }
601}
602
603impl From<http::uri::InvalidUriParts> for Parse {
604 fn from(_: http::uri::InvalidUriParts) -> Parse {
605 Parse::Uri
606 }
607}
608
609impl fmt::Display for TimedOut {
612 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
613 f.write_str("operation timed out")
614 }
615}
616
617impl StdError for TimedOut {}
618
619#[cfg(test)]
620mod 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 let svc_err = Error::new_user_service(recvd);
656 assert_eq!(svc_err.h2_reason(), h2::Reason::HTTP_1_1_REQUIRED);
657 }
658}