/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 | | } |