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