ntex_h2/
error.rs

1pub use crate::codec::EncoderError;
2
3use crate::frame::{self, GoAway, Reason, StreamId};
4use crate::stream::StreamRef;
5
6#[derive(Debug, Copy, Clone, PartialEq, Eq, thiserror::Error)]
7pub enum ConnectionError {
8    #[error("Go away: {0}")]
9    GoAway(Reason),
10    #[error("Unknown stream id in {0} frame")]
11    UnknownStream(&'static str),
12    #[error("Encoder error: {0}")]
13    Encoder(#[from] EncoderError),
14    #[error("Decoder error: {0}")]
15    Decoder(#[from] frame::FrameError),
16    #[error("{0:?} is closed, {1}")]
17    StreamClosed(StreamId, &'static str),
18    /// An invalid stream identifier was provided
19    #[error("An invalid stream identifier was provided: {0}")]
20    InvalidStreamId(&'static str),
21    #[error("Unexpected setting ack received")]
22    UnexpectedSettingsAck,
23    /// Missing pseudo header
24    #[error("Missing pseudo header {0:?}")]
25    MissingPseudo(&'static str),
26    /// Missing pseudo header
27    #[error("Unexpected pseudo header {0:?}")]
28    UnexpectedPseudo(&'static str),
29    /// Window update value is zero
30    #[error("Window update value is zero")]
31    ZeroWindowUpdateValue,
32    #[error("Window value is overflowed")]
33    WindowValueOverflow,
34    #[error("Max concurrent streams count achieved")]
35    ConcurrencyOverflow,
36    #[error("Stream rapid reset count achieved")]
37    StreamResetsLimit,
38    /// Keep-alive timeout
39    #[error("Keep-alive timeout")]
40    KeepaliveTimeout,
41    /// Read timeout
42    #[error("Read timeout")]
43    ReadTimeout,
44}
45
46impl ConnectionError {
47    pub fn to_goaway(&self) -> GoAway {
48        match self {
49            ConnectionError::GoAway(reason) => GoAway::new(*reason),
50            ConnectionError::Encoder(_) => {
51                GoAway::new(Reason::PROTOCOL_ERROR).set_data("Error during frame encoding")
52            }
53            ConnectionError::Decoder(_) => {
54                GoAway::new(Reason::PROTOCOL_ERROR).set_data("Error during frame decoding")
55            }
56            ConnectionError::MissingPseudo(s) => GoAway::new(Reason::PROTOCOL_ERROR)
57                .set_data(format!("Missing pseudo header {:?}", s)),
58            ConnectionError::UnexpectedPseudo(s) => GoAway::new(Reason::PROTOCOL_ERROR)
59                .set_data(format!("Unexpected pseudo header {:?}", s)),
60            ConnectionError::UnknownStream(_) => {
61                GoAway::new(Reason::PROTOCOL_ERROR).set_data("Unknown stream")
62            }
63            ConnectionError::InvalidStreamId(_) => GoAway::new(Reason::PROTOCOL_ERROR)
64                .set_data("An invalid stream identifier was provided"),
65            ConnectionError::StreamClosed(s, _) => {
66                GoAway::new(Reason::STREAM_CLOSED).set_data(format!("{:?} is closed", s))
67            }
68            ConnectionError::UnexpectedSettingsAck => {
69                GoAway::new(Reason::PROTOCOL_ERROR).set_data("Received unexpected settings ack")
70            }
71            ConnectionError::ZeroWindowUpdateValue => GoAway::new(Reason::PROTOCOL_ERROR)
72                .set_data("Zero value for window update frame is not allowed"),
73            ConnectionError::WindowValueOverflow => GoAway::new(Reason::FLOW_CONTROL_ERROR)
74                .set_data("Updated value for window is overflowed"),
75            ConnectionError::ConcurrencyOverflow => GoAway::new(Reason::FLOW_CONTROL_ERROR)
76                .set_data("Max concurrent streams count achieved"),
77            ConnectionError::StreamResetsLimit => GoAway::new(Reason::FLOW_CONTROL_ERROR)
78                .set_data("Stream rapid reset count achieved"),
79            ConnectionError::KeepaliveTimeout => {
80                GoAway::new(Reason::NO_ERROR).set_data("Keep-alive timeout")
81            }
82            ConnectionError::ReadTimeout => {
83                GoAway::new(Reason::NO_ERROR).set_data("Frame read timeout")
84            }
85        }
86    }
87}
88
89#[derive(Debug, Clone, thiserror::Error)]
90#[error("Stream error: {kind:?}")]
91pub(crate) struct StreamErrorInner {
92    kind: StreamError,
93    stream: StreamRef,
94}
95
96impl StreamErrorInner {
97    pub(crate) fn new(stream: StreamRef, kind: StreamError) -> Self {
98        Self { kind, stream }
99    }
100
101    pub(crate) fn into_inner(self) -> (StreamRef, StreamError) {
102        (self.stream, self.kind)
103    }
104}
105
106#[derive(Debug, Copy, Clone, PartialEq, Eq, thiserror::Error)]
107pub enum StreamError {
108    #[error("Stream in idle state: {0}")]
109    Idle(&'static str),
110    #[error("Stream is closed")]
111    Closed,
112    #[error("Window value is overflowed")]
113    WindowOverflowed,
114    #[error("Zero value for window")]
115    WindowZeroUpdateValue,
116    #[error("Trailers headers without end of stream flags")]
117    TrailersWithoutEos,
118    #[error("Invalid content length")]
119    InvalidContentLength,
120    #[error("Payload length does not match content-length header")]
121    WrongPayloadLength,
122    #[error("Non-empty payload for HEAD response")]
123    NonEmptyPayload,
124    #[error("Stream has been reset with {0}")]
125    Reset(Reason),
126}
127
128impl StreamError {
129    #[inline]
130    pub(crate) fn reason(&self) -> Reason {
131        match self {
132            StreamError::Idle(_) => Reason::PROTOCOL_ERROR,
133            StreamError::Closed => Reason::STREAM_CLOSED,
134            StreamError::WindowOverflowed => Reason::FLOW_CONTROL_ERROR,
135            StreamError::WindowZeroUpdateValue => Reason::PROTOCOL_ERROR,
136            StreamError::TrailersWithoutEos => Reason::PROTOCOL_ERROR,
137            StreamError::InvalidContentLength => Reason::PROTOCOL_ERROR,
138            StreamError::WrongPayloadLength => Reason::PROTOCOL_ERROR,
139            StreamError::NonEmptyPayload => Reason::PROTOCOL_ERROR,
140            StreamError::Reset(r) => *r,
141        }
142    }
143}
144
145/// Operation errors
146#[derive(Debug, Clone, thiserror::Error)]
147pub enum OperationError {
148    #[error("{0:?}")]
149    Stream(#[from] StreamError),
150
151    #[error("{0}")]
152    Connection(#[from] ConnectionError),
153
154    /// Cannot process operation for idle stream
155    #[error("Cannot process operation for idle stream")]
156    Idle,
157
158    /// Cannot process operation for stream in payload state
159    #[error("Cannot process operation for stream in payload state")]
160    Payload,
161
162    /// Stream is closed
163    #[error("Stream is closed {0:?}")]
164    Closed(Option<Reason>),
165
166    /// Stream has been reset from the peer
167    #[error("Stream has been reset from the peer with {0}")]
168    RemoteReset(Reason),
169
170    /// Stream has been reset from local side
171    #[error("Stream has been reset from local side with {0}")]
172    LocalReset(Reason),
173
174    /// The stream ID space is overflowed
175    ///
176    /// A new connection is needed.
177    #[error("The stream ID space is overflowed")]
178    OverflowedStreamId,
179
180    /// Disconnecting
181    #[error("Connection is disconnecting")]
182    Disconnecting,
183
184    /// Disconnected
185    #[error("Connection is closed")]
186    Disconnected,
187}