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