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