httpbis/
error.rs

1use std::error::Error as std_Error;
2use std::fmt;
3use std::io;
4use std::ops::Deref;
5use std::sync::Arc;
6
7use crate::assert_types::*;
8
9use crate::hpack::decoder::DecoderError;
10
11use tls_api;
12
13use crate::common::sender::SendError;
14use crate::display_comma_separated::DisplayCommaSeparated;
15use crate::solicit::error_code::ErrorCode;
16use crate::solicit::frame::HttpFrameType;
17use crate::solicit::frame::ParseFrameError;
18use crate::solicit::frame::RawHttpFrameType;
19use crate::StreamDead;
20use crate::StreamId;
21use std::net::SocketAddr;
22use tokio::time::Timeout;
23use void::Void;
24
25/// An enum representing errors that can arise when performing operations involving an HTTP/2
26/// connection.
27#[derive(Debug)]
28pub enum Error {
29    /// The underlying IO layer raised an error
30    IoError(io::Error),
31    /// TLS error.
32    TlsError(tls_api::Error),
33    /// Error code error.
34    CodeError(ErrorCode),
35    /// `RST_STREAM` received.
36    RstStreamReceived(ErrorCode),
37    /// Address resolved to empty list.
38    AddrResolvedToEmptyList,
39    /// Address resolved to more than one address.
40    AddrResolvedToMoreThanOneAddr(Vec<SocketAddr>),
41    /// The HTTP/2 connection received an invalid HTTP/2 frame
42    InvalidFrame(String),
43    /// The HPACK decoder was unable to decode a header chunk and raised an error.
44    /// Any decoder error is fatal to the HTTP/2 connection as it means that the decoder contexts
45    /// will be out of sync.
46    CompressionError(DecoderError),
47    /// Indicates that the local peer has discovered an overflow in the size of one of the
48    /// connection flow control window, which is a connection error.
49    WindowSizeOverflow,
50    /// Unknown stream id.
51    UnknownStreamId,
52    /// Cannot connect.
53    UnableToConnect,
54    /// Malformed response.
55    MalformedResponse,
56    /// Connection timed out.
57    ConnectionTimeout,
58    /// Shutdown of local client or server
59    Shutdown,
60    /// Request handler panicked.
61    HandlerPanicked(String),
62    /// Failed to parse frame.
63    ParseFrameError(ParseFrameError),
64    /// Generic internal error.
65    // TODO: get rid of it
66    InternalError(String),
67    /// Something is not implemented
68    // TODO: implement it
69    NotImplemented(&'static str),
70    /// User error
71    User(String),
72    /// Std error
73    StdError(Box<dyn std_Error + Sync + Send + 'static>),
74    /// Client died
75    // TODO: explain
76    ClientDied(Option<Arc<Error>>),
77    /// Client died, reconnect failed
78    ClientDiedAndReconnectFailed,
79    /// Client controller died.
80    ClientControllerDied,
81    /// Channel died.
82    // TODO: meaningless
83    ChannelDied,
84    /// Connection died.
85    ConnDied,
86    /// Client panicked.
87    ClientPanicked(String),
88    /// Client completed without error.
89    ClientCompletedWithoutError,
90    /// Send failed.
91    SendError(SendError),
92    /// Stream dead.
93    StreamDead(StreamDead),
94    /// Called died.
95    CallerDied,
96    /// End of stream.
97    // TODO: meaningless
98    EofFromStream,
99    /// Expecting `CONTINUATION` frame.
100    // TODO: move to separate error type
101    ExpectingContinuationGot(RawHttpFrameType),
102    /// Expecting `CONTINUATION` frame with different stream id.
103    ExpectingContinuationGotDifferentStreamId(StreamId, StreamId),
104    /// `CONTINUATION` frame without headers.
105    ContinuationFrameWithoutHeaders,
106    /// Wrong stream id.
107    InitiatedStreamWithServerIdFromClient(StreamId),
108    /// Wrong stream id.
109    StreamIdLeExistingStream(StreamId, StreamId),
110    /// Failed to send request to dump state.
111    // TODO: reason
112    FailedToSendReqToDumpState,
113    /// Need something better.
114    // TODO: reason
115    OneshotCancelled,
116    /// Stream id windows overflow.
117    StreamInWindowOverflow(StreamId, i32, u32),
118    /// Connection in windows overflow.
119    ConnInWindowOverflow(i32, u32),
120    /// Ping response wrong payload.
121    PingAckOpaqueDataMismatch(u64, u64),
122    /// Goaway after goaway.
123    GoawayAfterGoaway,
124    /// Got `SETTINGS` ack without `SETTINGS` sent.
125    SettingsAckWithoutSettingsSent,
126    /// `GOAWAY`
127    // TODO: explain
128    Goaway,
129    /// Received `GOAWAY`
130    GoawayReceived,
131    /// Stream died.
132    // TODO: explain
133    PullStreamDied,
134    /// Payload too large.
135    PayloadTooLarge(u32, u32),
136    /// Request is made using HTTP/1
137    RequestIsMadeUsingHttp1,
138    /// Listen address is not specified.
139    ListenAddrNotSpecified,
140}
141
142fn _assert_error_sync_send() {
143    assert_send::<Error>();
144    assert_sync::<Error>();
145}
146
147/// Implement the trait that allows us to automatically convert `io::Error`s
148/// into an `HttpError` by wrapping the given `io::Error` into an `HttpError::IoError` variant.
149impl From<io::Error> for Error {
150    fn from(err: io::Error) -> Error {
151        Error::IoError(err)
152    }
153}
154
155impl From<tls_api::Error> for Error {
156    fn from(error: tls_api::Error) -> Error {
157        Error::TlsError(error)
158    }
159}
160
161impl<F> From<Timeout<F>> for Error {
162    fn from(_err: Timeout<F>) -> Error {
163        Error::ConnectionTimeout
164    }
165}
166
167impl From<ParseFrameError> for Error {
168    fn from(e: ParseFrameError) -> Self {
169        Error::ParseFrameError(e)
170    }
171}
172
173impl From<SendError> for Error {
174    fn from(e: SendError) -> Self {
175        Error::SendError(e)
176    }
177}
178
179impl From<StreamDead> for Error {
180    fn from(e: StreamDead) -> Self {
181        Error::StreamDead(e)
182    }
183}
184
185impl From<Void> for Error {
186    fn from(v: Void) -> Self {
187        match v {}
188    }
189}
190
191impl fmt::Display for Error {
192    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
193        match self {
194            Error::IoError(_) => write!(f, "Encountered an IO error"),
195            Error::TlsError(_) => write!(f, "Encountered TLS error"),
196            Error::CodeError(_) => write!(f, "Encountered HTTP named error"),
197            Error::RstStreamReceived(_) => write!(f, "Received RST_STREAM from peer"),
198            Error::InvalidFrame(..) => {
199                write!(f, "Encountered an invalid or unexpected HTTP/2 frame")
200            }
201            Error::CompressionError(_) => write!(f, "Encountered an error with HPACK compression"),
202            Error::WindowSizeOverflow => write!(f, "The connection flow control window overflowed"),
203            Error::UnknownStreamId => {
204                write!(f, "Attempted an operation with an unknown HTTP/2 stream ID")
205            }
206            Error::UnableToConnect => {
207                write!(f, "An error attempting to establish an HTTP/2 connection")
208            }
209            Error::MalformedResponse => write!(f, "The received response was malformed"),
210            Error::ConnectionTimeout => write!(f, "Connection time out"),
211            Error::Shutdown => write!(f, "Local shutdown"),
212            Error::HandlerPanicked(_) => write!(f, "Handler panicked"),
213            Error::ParseFrameError(_) => write!(f, "Failed to parse frame"),
214            Error::NotImplemented(_) => write!(f, "Not implemented"),
215            Error::InternalError(_) => write!(f, "Internal error"),
216            Error::ClientDied(_) => write!(f, "Client died"),
217            Error::ClientPanicked(_) => write!(f, "Client panicked"),
218            Error::ClientCompletedWithoutError => write!(f, "Client completed without error"),
219            Error::SendError(_) => write!(f, "Failed to write message to stream"),
220            Error::CallerDied => write!(f, "Request caller died"),
221            Error::StreamDead(_) => write!(f, "Stream dead"),
222            Error::StdError(e) => write!(f, "{}", e),
223            Error::User(e) => write!(f, "User error: {}", e),
224            Error::AddrResolvedToEmptyList => write!(f, "Address resolved to empty list"),
225            Error::AddrResolvedToMoreThanOneAddr(a) => write!(
226                f,
227                "Address resolved to more than one address: {}",
228                DisplayCommaSeparated(&a[..])
229            ),
230            Error::ClientDiedAndReconnectFailed => write!(f, "Client died and reconnect failed"),
231            Error::ClientControllerDied => write!(f, "Client controller died"),
232            Error::ChannelDied => write!(f, "Channel died"),
233            Error::ConnDied => write!(f, "Conn died"),
234            Error::EofFromStream => write!(f, "EOF from stream"),
235            Error::ExpectingContinuationGot(t) => {
236                write!(f, "Expecting {} got {}", HttpFrameType::Continuation, t)
237            }
238            Error::ExpectingContinuationGotDifferentStreamId(_, _) => write!(
239                f,
240                "Expecting {} got different stream id",
241                HttpFrameType::Continuation
242            ),
243            Error::ContinuationFrameWithoutHeaders => write!(
244                f,
245                "{} frame without {}",
246                HttpFrameType::Continuation,
247                HttpFrameType::Headers
248            ),
249            Error::InitiatedStreamWithServerIdFromClient(stream_id) => write!(
250                f,
251                "Initiated stream with server id from client: {}",
252                stream_id
253            ),
254            Error::StreamIdLeExistingStream(_, _) => write!(f, "Stream id <= existing stream"),
255            Error::FailedToSendReqToDumpState => write!(f, "Failed to send request to dump state"),
256            Error::OneshotCancelled => write!(f, "Oneshot cancelled"),
257            Error::StreamInWindowOverflow(stream_id, _, _) => {
258                write!(f, "Stream {} in windows overflow", stream_id)
259            }
260            Error::ConnInWindowOverflow(_, _) => write!(f, "Conn in windows overflow"),
261            Error::PingAckOpaqueDataMismatch(_, _) => {
262                write!(f, "{} ack opaque data mismatch", HttpFrameType::Ping)
263            }
264            Error::GoawayAfterGoaway => write!(
265                f,
266                "{} after {}",
267                HttpFrameType::Goaway,
268                HttpFrameType::Goaway
269            ),
270            Error::SettingsAckWithoutSettingsSent => write!(
271                f,
272                "{} ack without {} sent",
273                HttpFrameType::Settings,
274                HttpFrameType::Settings
275            ),
276            Error::Goaway => write!(f, "{}", HttpFrameType::Goaway),
277            Error::GoawayReceived => write!(f, "{} received", HttpFrameType::Goaway),
278            Error::PullStreamDied => write!(f, "Pull stream died"),
279            Error::PayloadTooLarge(_, _) => write!(f, "Payload too large"),
280            Error::RequestIsMadeUsingHttp1 => write!(f, "Request is made using HTTP/1"),
281            Error::ListenAddrNotSpecified => write!(f, "Listen addr not specified"),
282        }
283    }
284}
285
286impl std_Error for Error {
287    fn cause(&self) -> Option<&dyn std_Error> {
288        match *self {
289            Error::IoError(ref e) => Some(e),
290            Error::TlsError(ref e) => Some(e),
291            Error::StdError(ref e) => Some(Box::deref(e) as &dyn std_Error),
292            _ => None,
293        }
294    }
295}