Coverage Report

Created: 2026-09-19 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/hyper-1.9.0/src/error.rs
Line
Count
Source
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
///
12
/// # Formatting
13
///
14
/// The `Display` implementation of this type will only print the details of
15
/// this level of error, even though it may have been caused by another error
16
/// and contain that error in its source. To print all the relevant
17
/// information, including the source chain, using something like
18
/// `std::error::Report`, or equivalent 3rd party types.
19
///
20
/// The contents of the formatted error message of this specific `Error` type
21
/// is unspecified. **You must not depend on it.** The wording and details may
22
/// change in any version, with the goal of improving error messages.
23
///
24
/// # Source
25
///
26
/// A `hyper::Error` may be caused by another error. To aid in debugging,
27
/// those are exposed in `Error::source()` as erased types. While it is
28
/// possible to check the exact type of the sources, they **can not be depended
29
/// on**. They may come from private internal dependencies, and are subject to
30
/// change at any moment.
31
pub struct Error {
32
    inner: Box<ErrorImpl>,
33
}
34
35
struct ErrorImpl {
36
    kind: Kind,
37
    cause: Option<Cause>,
38
}
39
40
#[derive(Debug)]
41
pub(super) enum Kind {
42
    Parse(Parse),
43
    User(User),
44
    /// A message reached EOF, but is not complete.
45
    #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
46
    IncompleteMessage,
47
    /// A connection received a message (or bytes) when not waiting for one.
48
    #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
49
    UnexpectedMessage,
50
    /// A pending item was dropped before ever being processed.
51
    Canceled,
52
    /// Indicates a channel (client or body sender) is closed.
53
    #[cfg(any(
54
        all(feature = "http1", any(feature = "client", feature = "server")),
55
        all(feature = "http2", feature = "client")
56
    ))]
57
    ChannelClosed,
58
    /// An `io::Error` that occurred while trying to read or write to a network stream.
59
    #[cfg(all(
60
        any(feature = "client", feature = "server"),
61
        any(feature = "http1", feature = "http2")
62
    ))]
63
    Io,
64
    /// User took too long to send headers
65
    #[cfg(all(feature = "http1", feature = "server"))]
66
    HeaderTimeout,
67
    /// Error while reading a body from connection.
68
    #[cfg(all(
69
        any(feature = "client", feature = "server"),
70
        any(feature = "http1", feature = "http2")
71
    ))]
72
    Body,
73
    /// Error while writing a body to connection.
74
    #[cfg(all(
75
        any(feature = "client", feature = "server"),
76
        any(feature = "http1", feature = "http2")
77
    ))]
78
    BodyWrite,
79
    /// Error calling AsyncWrite::shutdown()
80
    #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
81
    Shutdown,
82
83
    /// A general error from h2.
84
    #[cfg(all(any(feature = "client", feature = "server"), feature = "http2"))]
85
    Http2,
86
}
87
88
#[derive(Debug)]
89
pub(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")]
110
pub(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)]
121
pub(super) enum User {
122
    /// Error calling user's Body::poll_data().
123
    #[cfg(all(
124
        any(feature = "client", feature = "server"),
125
        any(feature = "http1", feature = "http2")
126
    ))]
127
    Body,
128
    /// The user aborted writing of the outgoing body.
129
    #[cfg(any(
130
        all(feature = "http1", any(feature = "client", feature = "server")),
131
        feature = "ffi"
132
    ))]
133
    BodyWriteAborted,
134
    /// User tried to send a connect request with a nonzero body
135
    #[cfg(all(feature = "client", feature = "http2"))]
136
    InvalidConnectWithBody,
137
    /// Error from future of user's Service.
138
    #[cfg(any(
139
        all(any(feature = "client", feature = "server"), feature = "http1"),
140
        all(feature = "server", feature = "http2")
141
    ))]
142
    Service,
143
    /// User tried to send a certain header in an unexpected context.
144
    ///
145
    /// For example, sending both `content-length` and `transfer-encoding`.
146
    #[cfg(any(feature = "http1", feature = "http2"))]
147
    #[cfg(feature = "server")]
148
    UnexpectedHeader,
149
    /// User tried to respond with a 1xx (not 101) response code.
150
    #[cfg(feature = "http1")]
151
    #[cfg(feature = "server")]
152
    UnsupportedStatusCode,
153
154
    /// User tried polling for an upgrade that doesn't exist.
155
    NoUpgrade,
156
157
    /// User polled for an upgrade, but low-level API is not using upgrades.
158
    #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
159
    ManualUpgrade,
160
161
    /// The dispatch task is gone.
162
    #[cfg(all(feature = "client", any(feature = "http1", feature = "http2")))]
163
    DispatchGone,
164
165
    /// User aborted in an FFI callback.
166
    #[cfg(feature = "ffi")]
167
    AbortedByCallback,
168
}
169
170
// Sentinel type to indicate the error was caused by a timeout.
171
#[derive(Debug)]
172
pub(super) struct TimedOut;
173
174
impl Error {
175
    /// Returns true if this was an HTTP parse error.
176
0
    pub fn is_parse(&self) -> bool {
177
0
        matches!(self.inner.kind, Kind::Parse(_))
178
0
    }
179
180
    /// Returns true if this was an HTTP parse error caused by a message that was too large.
181
    #[cfg(all(feature = "http1", feature = "server"))]
182
0
    pub fn is_parse_too_large(&self) -> bool {
183
0
        matches!(
184
0
            self.inner.kind,
185
            Kind::Parse(Parse::TooLarge) | Kind::Parse(Parse::UriTooLong)
186
        )
187
0
    }
188
189
    /// Returns true if this was an HTTP parse error caused by an invalid response status code or
190
    /// reason phrase.
191
0
    pub fn is_parse_status(&self) -> bool {
192
0
        matches!(self.inner.kind, Kind::Parse(Parse::Status))
193
0
    }
194
195
    /// Returns true if this was an HTTP parse error caused by HTTP2 preface sent over an HTTP1
196
    /// connection.
197
    #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
198
0
    pub fn is_parse_version_h2(&self) -> bool {
199
0
        matches!(self.inner.kind, Kind::Parse(Parse::VersionH2))
200
0
    }
201
202
    /// Returns true if this error was caused by user code.
203
0
    pub fn is_user(&self) -> bool {
204
0
        matches!(self.inner.kind, Kind::User(_))
205
0
    }
206
207
    /// Returns true if this was about a `Request` that was canceled.
208
0
    pub fn is_canceled(&self) -> bool {
209
0
        matches!(self.inner.kind, Kind::Canceled)
210
0
    }
211
212
    /// Returns true if a sender's channel is closed.
213
0
    pub fn is_closed(&self) -> bool {
214
        #[cfg(not(any(
215
            all(feature = "http1", any(feature = "client", feature = "server")),
216
            all(feature = "http2", feature = "client")
217
        )))]
218
        return false;
219
220
        #[cfg(any(
221
            all(feature = "http1", any(feature = "client", feature = "server")),
222
            all(feature = "http2", feature = "client")
223
        ))]
224
0
        matches!(self.inner.kind, Kind::ChannelClosed)
225
0
    }
226
227
    /// Returns true if the connection closed before a message could complete.
228
    ///
229
    /// This means that the supplied IO connection reported EOF (closed) while
230
    /// hyper's HTTP state indicates more of the message (either request or
231
    /// response) needed to be transmitted.
232
    ///
233
    /// Some cases this could happen (not exhaustive):
234
    ///
235
    /// - A request is written on a connection, and the next `read` reports
236
    ///   EOF (perhaps a server just closed an "idle" connection).
237
    /// - A message body is only partially receive before the connection
238
    ///   reports EOF.
239
    /// - A client writes a request to your server, and then closes the write
240
    ///   half while waiting for your response. If you need to support this,
241
    ///   consider enabling [`half_close`].
242
    ///
243
    /// [`half_close`]: crate::server::conn::http1::Builder::half_close()
244
0
    pub fn is_incomplete_message(&self) -> bool {
245
        #[cfg(not(all(any(feature = "client", feature = "server"), feature = "http1")))]
246
        return false;
247
248
        #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
249
0
        matches!(self.inner.kind, Kind::IncompleteMessage)
250
0
    }
251
252
    /// Returns true if the body write was aborted.
253
0
    pub fn is_body_write_aborted(&self) -> bool {
254
        #[cfg(not(any(
255
            all(feature = "http1", any(feature = "client", feature = "server")),
256
            feature = "ffi"
257
        )))]
258
        return false;
259
260
        #[cfg(any(
261
            all(feature = "http1", any(feature = "client", feature = "server")),
262
            feature = "ffi"
263
        ))]
264
0
        matches!(self.inner.kind, Kind::User(User::BodyWriteAborted))
265
0
    }
266
267
    /// Returns true if the error was caused while calling `AsyncWrite::shutdown()`.
268
0
    pub fn is_shutdown(&self) -> bool {
269
        #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
270
0
        if matches!(self.inner.kind, Kind::Shutdown) {
271
0
            return true;
272
0
        }
273
0
        false
274
0
    }
275
276
    /// Returns true if the error was caused by a timeout.
277
0
    pub fn is_timeout(&self) -> bool {
278
        #[cfg(all(feature = "http1", feature = "server"))]
279
0
        if matches!(self.inner.kind, Kind::HeaderTimeout) {
280
0
            return true;
281
0
        }
282
0
        self.find_source::<TimedOut>().is_some()
283
0
    }
284
285
0
    pub(super) fn new(kind: Kind) -> Error {
286
0
        Error {
287
0
            inner: Box::new(ErrorImpl { kind, cause: None }),
288
0
        }
289
0
    }
290
291
0
    pub(super) fn with<C: Into<Cause>>(mut self, cause: C) -> Error {
292
0
        self.inner.cause = Some(cause.into());
293
0
        self
294
0
    }
Unexecuted instantiation: <hyper::error::Error>::with::<tonic::status::Status>
Unexecuted instantiation: <hyper::error::Error>::with::<hyper::upgrade::UpgradeExpected>
Unexecuted instantiation: <hyper::error::Error>::with::<h2::error::Error>
Unexecuted instantiation: <hyper::error::Error>::with::<std::io::error::Error>
Unexecuted instantiation: <hyper::error::Error>::with::<hyper::proto::h2::ping::KeepAliveTimedOut>
Unexecuted instantiation: <hyper::error::Error>::with::<&str>
295
296
    #[cfg(any(all(feature = "http1", feature = "server"), feature = "ffi"))]
297
0
    pub(super) fn kind(&self) -> &Kind {
298
0
        &self.inner.kind
299
0
    }
300
301
0
    pub(crate) fn find_source<E: StdError + 'static>(&self) -> Option<&E> {
302
0
        let mut cause = self.source();
303
0
        while let Some(err) = cause {
304
0
            if let Some(typed) = err.downcast_ref() {
305
0
                return Some(typed);
306
0
            }
307
0
            cause = err.source();
308
        }
309
310
        // else
311
0
        None
312
0
    }
Unexecuted instantiation: <hyper::error::Error>::find_source::<hyper::error::TimedOut>
Unexecuted instantiation: <hyper::error::Error>::find_source::<h2::error::Error>
313
314
    #[cfg(all(any(feature = "client", feature = "server"), feature = "http2"))]
315
0
    pub(super) fn h2_reason(&self) -> h2::Reason {
316
        // Find an h2::Reason somewhere in the cause stack, if it exists,
317
        // otherwise assume an INTERNAL_ERROR.
318
0
        self.find_source::<h2::Error>()
319
0
            .and_then(|h2_err| h2_err.reason())
320
0
            .unwrap_or(h2::Reason::INTERNAL_ERROR)
321
0
    }
322
323
0
    pub(super) fn new_canceled() -> Error {
324
0
        Error::new(Kind::Canceled)
325
0
    }
326
327
    #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
328
0
    pub(super) fn new_incomplete() -> Error {
329
0
        Error::new(Kind::IncompleteMessage)
330
0
    }
331
332
    #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
333
0
    pub(super) fn new_too_large() -> Error {
334
0
        Error::new(Kind::Parse(Parse::TooLarge))
335
0
    }
336
337
    #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
338
0
    pub(super) fn new_version_h2() -> Error {
339
0
        Error::new(Kind::Parse(Parse::VersionH2))
340
0
    }
341
342
    #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
343
0
    pub(super) fn new_unexpected_message() -> Error {
344
0
        Error::new(Kind::UnexpectedMessage)
345
0
    }
346
347
    #[cfg(all(
348
        any(feature = "client", feature = "server"),
349
        any(feature = "http1", feature = "http2")
350
    ))]
351
0
    pub(super) fn new_io(cause: std::io::Error) -> Error {
352
0
        Error::new(Kind::Io).with(cause)
353
0
    }
354
355
    #[cfg(any(
356
        all(feature = "http1", any(feature = "client", feature = "server")),
357
        all(feature = "http2", feature = "client")
358
    ))]
359
0
    pub(super) fn new_closed() -> Error {
360
0
        Error::new(Kind::ChannelClosed)
361
0
    }
362
363
    #[cfg(all(
364
        any(feature = "client", feature = "server"),
365
        any(feature = "http1", feature = "http2")
366
    ))]
367
0
    pub(super) fn new_body<E: Into<Cause>>(cause: E) -> Error {
368
0
        Error::new(Kind::Body).with(cause)
369
0
    }
370
371
    #[cfg(all(
372
        any(feature = "client", feature = "server"),
373
        any(feature = "http1", feature = "http2")
374
    ))]
375
0
    pub(super) fn new_body_write<E: Into<Cause>>(cause: E) -> Error {
376
0
        Error::new(Kind::BodyWrite).with(cause)
377
0
    }
Unexecuted instantiation: <hyper::error::Error>::new_body_write::<h2::error::Error>
Unexecuted instantiation: <hyper::error::Error>::new_body_write::<&str>
Unexecuted instantiation: <hyper::error::Error>::new_body_write::<_>
378
379
    #[cfg(any(
380
        all(feature = "http1", any(feature = "client", feature = "server")),
381
        feature = "ffi"
382
    ))]
383
0
    pub(super) fn new_body_write_aborted() -> Error {
384
0
        Error::new(Kind::User(User::BodyWriteAborted))
385
0
    }
386
387
0
    fn new_user(user: User) -> Error {
388
0
        Error::new(Kind::User(user))
389
0
    }
390
391
    #[cfg(any(feature = "http1", feature = "http2"))]
392
    #[cfg(feature = "server")]
393
0
    pub(super) fn new_user_header() -> Error {
394
0
        Error::new_user(User::UnexpectedHeader)
395
0
    }
396
397
    #[cfg(all(feature = "http1", feature = "server"))]
398
0
    pub(super) fn new_header_timeout() -> Error {
399
0
        Error::new(Kind::HeaderTimeout)
400
0
    }
401
402
    #[cfg(feature = "http1")]
403
    #[cfg(feature = "server")]
404
0
    pub(super) fn new_user_unsupported_status_code() -> Error {
405
0
        Error::new_user(User::UnsupportedStatusCode)
406
0
    }
407
408
0
    pub(super) fn new_user_no_upgrade() -> Error {
409
0
        Error::new_user(User::NoUpgrade)
410
0
    }
411
412
    #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
413
0
    pub(super) fn new_user_manual_upgrade() -> Error {
414
0
        Error::new_user(User::ManualUpgrade)
415
0
    }
416
417
    #[cfg(any(
418
        all(any(feature = "client", feature = "server"), feature = "http1"),
419
        all(feature = "server", feature = "http2")
420
    ))]
421
0
    pub(super) fn new_user_service<E: Into<Cause>>(cause: E) -> Error {
422
0
        Error::new_user(User::Service).with(cause)
423
0
    }
424
425
    #[cfg(all(
426
        any(feature = "client", feature = "server"),
427
        any(feature = "http1", feature = "http2")
428
    ))]
429
0
    pub(super) fn new_user_body<E: Into<Cause>>(cause: E) -> Error {
430
0
        Error::new_user(User::Body).with(cause)
431
0
    }
Unexecuted instantiation: <hyper::error::Error>::new_user_body::<tonic::status::Status>
Unexecuted instantiation: <hyper::error::Error>::new_user_body::<_>
432
433
    #[cfg(all(feature = "client", feature = "http2"))]
434
0
    pub(super) fn new_user_invalid_connect() -> Error {
435
0
        Error::new_user(User::InvalidConnectWithBody)
436
0
    }
437
438
    #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
439
0
    pub(super) fn new_shutdown(cause: std::io::Error) -> Error {
440
0
        Error::new(Kind::Shutdown).with(cause)
441
0
    }
442
443
    #[cfg(feature = "ffi")]
444
    pub(super) fn new_user_aborted_by_callback() -> Error {
445
        Error::new_user(User::AbortedByCallback)
446
    }
447
448
    #[cfg(all(feature = "client", any(feature = "http1", feature = "http2")))]
449
0
    pub(super) fn new_user_dispatch_gone() -> Error {
450
0
        Error::new(Kind::User(User::DispatchGone))
451
0
    }
452
453
    #[cfg(all(any(feature = "client", feature = "server"), feature = "http2"))]
454
0
    pub(super) fn new_h2(cause: ::h2::Error) -> Error {
455
0
        if cause.is_io() {
456
0
            Error::new_io(cause.into_io().expect("h2::Error::is_io"))
457
        } else {
458
0
            Error::new(Kind::Http2).with(cause)
459
        }
460
0
    }
461
462
0
    fn description(&self) -> &str {
463
0
        match self.inner.kind {
464
0
            Kind::Parse(Parse::Method) => "invalid HTTP method parsed",
465
            #[cfg(feature = "http1")]
466
0
            Kind::Parse(Parse::Version) => "invalid HTTP version parsed",
467
            #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
468
0
            Kind::Parse(Parse::VersionH2) => "invalid HTTP version parsed (found HTTP2 preface)",
469
0
            Kind::Parse(Parse::Uri) => "invalid URI",
470
            #[cfg(all(feature = "http1", feature = "server"))]
471
0
            Kind::Parse(Parse::UriTooLong) => "URI too long",
472
            #[cfg(feature = "http1")]
473
0
            Kind::Parse(Parse::Header(Header::Token)) => "invalid HTTP header parsed",
474
            #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
475
            Kind::Parse(Parse::Header(Header::ContentLengthInvalid)) => {
476
0
                "invalid content-length parsed"
477
            }
478
            #[cfg(all(feature = "http1", feature = "server"))]
479
            Kind::Parse(Parse::Header(Header::TransferEncodingInvalid)) => {
480
0
                "invalid transfer-encoding parsed"
481
            }
482
            #[cfg(all(feature = "http1", any(feature = "client", feature = "server")))]
483
            Kind::Parse(Parse::Header(Header::TransferEncodingUnexpected)) => {
484
0
                "unexpected transfer-encoding parsed"
485
            }
486
            #[cfg(any(feature = "http1", feature = "http2"))]
487
0
            Kind::Parse(Parse::TooLarge) => "message head is too large",
488
0
            Kind::Parse(Parse::Status) => "invalid HTTP status-code parsed",
489
            #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
490
            Kind::Parse(Parse::Internal) => {
491
0
                "internal error inside Hyper and/or its dependencies, please report"
492
            }
493
            #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
494
0
            Kind::IncompleteMessage => "connection closed before message completed",
495
            #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
496
0
            Kind::UnexpectedMessage => "received unexpected message from connection",
497
            #[cfg(any(
498
                all(feature = "http1", any(feature = "client", feature = "server")),
499
                all(feature = "http2", feature = "client")
500
            ))]
501
0
            Kind::ChannelClosed => "channel closed",
502
0
            Kind::Canceled => "operation was canceled",
503
            #[cfg(all(feature = "http1", feature = "server"))]
504
0
            Kind::HeaderTimeout => "read header from client timeout",
505
            #[cfg(all(
506
                any(feature = "client", feature = "server"),
507
                any(feature = "http1", feature = "http2")
508
            ))]
509
0
            Kind::Body => "error reading a body from connection",
510
            #[cfg(all(
511
                any(feature = "client", feature = "server"),
512
                any(feature = "http1", feature = "http2")
513
            ))]
514
0
            Kind::BodyWrite => "error writing a body to connection",
515
            #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
516
0
            Kind::Shutdown => "error shutting down connection",
517
            #[cfg(all(any(feature = "client", feature = "server"), feature = "http2"))]
518
0
            Kind::Http2 => "http2 error",
519
            #[cfg(all(
520
                any(feature = "client", feature = "server"),
521
                any(feature = "http1", feature = "http2")
522
            ))]
523
0
            Kind::Io => "connection error",
524
525
            #[cfg(all(
526
                any(feature = "client", feature = "server"),
527
                any(feature = "http1", feature = "http2")
528
            ))]
529
0
            Kind::User(User::Body) => "error from user's Body stream",
530
            #[cfg(any(
531
                all(feature = "http1", any(feature = "client", feature = "server")),
532
                feature = "ffi"
533
            ))]
534
0
            Kind::User(User::BodyWriteAborted) => "user body write aborted",
535
            #[cfg(all(feature = "client", feature = "http2"))]
536
            Kind::User(User::InvalidConnectWithBody) => {
537
0
                "user sent CONNECT request with non-zero body"
538
            }
539
            #[cfg(any(
540
                all(any(feature = "client", feature = "server"), feature = "http1"),
541
                all(feature = "server", feature = "http2")
542
            ))]
543
0
            Kind::User(User::Service) => "error from user's Service",
544
            #[cfg(any(feature = "http1", feature = "http2"))]
545
            #[cfg(feature = "server")]
546
0
            Kind::User(User::UnexpectedHeader) => "user sent unexpected header",
547
            #[cfg(feature = "http1")]
548
            #[cfg(feature = "server")]
549
            Kind::User(User::UnsupportedStatusCode) => {
550
0
                "response has 1xx status code, not supported by server"
551
            }
552
0
            Kind::User(User::NoUpgrade) => "no upgrade available",
553
            #[cfg(all(any(feature = "client", feature = "server"), feature = "http1"))]
554
0
            Kind::User(User::ManualUpgrade) => "upgrade expected but low level API in use",
555
            #[cfg(all(feature = "client", any(feature = "http1", feature = "http2")))]
556
0
            Kind::User(User::DispatchGone) => "dispatch task is gone",
557
            #[cfg(feature = "ffi")]
558
            Kind::User(User::AbortedByCallback) => "operation aborted by an application callback",
559
        }
560
0
    }
561
}
562
563
impl fmt::Debug for Error {
564
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
565
0
        let mut f = f.debug_tuple("hyper::Error");
566
0
        f.field(&self.inner.kind);
567
0
        if let Some(ref cause) = self.inner.cause {
568
0
            f.field(cause);
569
0
        }
570
0
        f.finish()
571
0
    }
572
}
573
574
impl fmt::Display for Error {
575
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
576
0
        f.write_str(self.description())
577
0
    }
578
}
579
580
impl StdError for Error {
581
0
    fn source(&self) -> Option<&(dyn StdError + 'static)> {
582
0
        self.inner
583
0
            .cause
584
0
            .as_ref()
585
0
            .map(|cause| &**cause as &(dyn StdError + 'static))
586
0
    }
587
}
588
589
#[doc(hidden)]
590
impl From<Parse> for Error {
591
0
    fn from(err: Parse) -> Error {
592
0
        Error::new(Kind::Parse(err))
593
0
    }
594
}
595
596
#[cfg(feature = "http1")]
597
impl Parse {
598
    #[cfg(any(feature = "client", feature = "server"))]
599
0
    pub(crate) fn content_length_invalid() -> Self {
600
0
        Parse::Header(Header::ContentLengthInvalid)
601
0
    }
602
603
    #[cfg(feature = "server")]
604
0
    pub(crate) fn transfer_encoding_invalid() -> Self {
605
0
        Parse::Header(Header::TransferEncodingInvalid)
606
0
    }
607
608
    #[cfg(any(feature = "client", feature = "server"))]
609
0
    pub(crate) fn transfer_encoding_unexpected() -> Self {
610
0
        Parse::Header(Header::TransferEncodingUnexpected)
611
0
    }
612
}
613
614
#[cfg(feature = "http1")]
615
impl From<httparse::Error> for Parse {
616
0
    fn from(err: httparse::Error) -> Parse {
617
0
        match err {
618
            httparse::Error::HeaderName
619
            | httparse::Error::HeaderValue
620
            | httparse::Error::NewLine
621
0
            | httparse::Error::Token => Parse::Header(Header::Token),
622
0
            httparse::Error::Status => Parse::Status,
623
0
            httparse::Error::TooManyHeaders => Parse::TooLarge,
624
0
            httparse::Error::Version => Parse::Version,
625
        }
626
0
    }
627
}
628
629
impl From<http::method::InvalidMethod> for Parse {
630
0
    fn from(_: http::method::InvalidMethod) -> Parse {
631
0
        Parse::Method
632
0
    }
633
}
634
635
impl From<http::status::InvalidStatusCode> for Parse {
636
0
    fn from(_: http::status::InvalidStatusCode) -> Parse {
637
0
        Parse::Status
638
0
    }
639
}
640
641
impl From<http::uri::InvalidUri> for Parse {
642
0
    fn from(_: http::uri::InvalidUri) -> Parse {
643
0
        Parse::Uri
644
0
    }
645
}
646
647
impl From<http::uri::InvalidUriParts> for Parse {
648
0
    fn from(_: http::uri::InvalidUriParts) -> Parse {
649
0
        Parse::Uri
650
0
    }
651
}
652
653
// ===== impl TimedOut ====
654
655
impl fmt::Display for TimedOut {
656
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
657
0
        f.write_str("operation timed out")
658
0
    }
659
}
660
661
impl StdError for TimedOut {}
662
663
#[cfg(test)]
664
mod tests {
665
    use super::*;
666
    use std::mem;
667
668
    fn assert_send_sync<T: Send + Sync + 'static>() {}
669
670
    #[test]
671
    fn error_satisfies_send_sync() {
672
        assert_send_sync::<Error>()
673
    }
674
675
    #[test]
676
    fn error_size_of() {
677
        assert_eq!(mem::size_of::<Error>(), mem::size_of::<usize>());
678
    }
679
680
    #[cfg(feature = "http2")]
681
    #[test]
682
    fn h2_reason_unknown() {
683
        let closed = Error::new_closed();
684
        assert_eq!(closed.h2_reason(), h2::Reason::INTERNAL_ERROR);
685
    }
686
687
    #[cfg(feature = "http2")]
688
    #[test]
689
    fn h2_reason_one_level() {
690
        let body_err = Error::new_user_body(h2::Error::from(h2::Reason::ENHANCE_YOUR_CALM));
691
        assert_eq!(body_err.h2_reason(), h2::Reason::ENHANCE_YOUR_CALM);
692
    }
693
694
    #[cfg(feature = "http2")]
695
    #[test]
696
    fn h2_reason_nested() {
697
        let recvd = Error::new_h2(h2::Error::from(h2::Reason::HTTP_1_1_REQUIRED));
698
        // Suppose a user were proxying the received error
699
        let svc_err = Error::new_user_service(recvd);
700
        assert_eq!(svc_err.h2_reason(), h2::Reason::HTTP_1_1_REQUIRED);
701
    }
702
}