Skip to main content

net_wire/http2/
error.rs

1//! HTTP/2 parsing and construction errors.
2
3use core::fmt;
4
5/// Failure to validate a raw HTTP/2 wire layout.
6#[derive(Clone, Copy, Debug, Eq, PartialEq)]
7pub enum Http2ParseError {
8    /// Fewer bytes than a fixed prefix or declared frame payload were supplied.
9    Incomplete {
10        /// Required bytes.
11        required: usize,
12        /// Available bytes.
13        available: usize,
14    },
15    /// A byte differs from the required client-preface byte.
16    ClientPrefaceMismatch {
17        /// Offset of the mismatched byte.
18        offset: usize,
19        /// Required byte.
20        expected: u8,
21        /// Supplied byte.
22        actual: u8,
23    },
24    /// A declared frame payload exceeds the caller-provided maximum.
25    PayloadTooLarge {
26        /// Caller-provided maximum payload length.
27        maximum: usize,
28        /// Declared payload length.
29        actual: usize,
30    },
31    /// A typed frame view was requested for a different raw frame type.
32    WrongFrameType {
33        /// Required frame type.
34        expected: super::types::Http2FrameType,
35        /// Actual frame type.
36        actual: super::types::Http2FrameType,
37    },
38    /// A frame that requires a stream has a zero 31-bit stream identifier.
39    ZeroStreamId,
40    /// A frame that requires the connection stream has a nonzero 31-bit stream identifier.
41    ExpectedZeroStreamId,
42    /// A fixed-layout frame has an unexpected payload length.
43    FrameSizeMismatch {
44        /// Required payload length.
45        expected: usize,
46        /// Actual payload length.
47        actual: usize,
48    },
49    /// A WINDOW_UPDATE frame has a zero 31-bit increment.
50    ZeroWindowIncrement,
51    /// A SETTINGS payload does not contain a whole number of six-byte parameters.
52    SettingsPayloadLength {
53        /// Actual payload length.
54        actual: usize,
55    },
56    /// A SETTINGS frame with ACK set has a nonempty payload.
57    SettingsAckPayload {
58        /// Actual payload length.
59        actual: usize,
60    },
61    /// A SETTINGS parameter has an intrinsically invalid value.
62    InvalidSettingValue {
63        /// Encoded setting identifier.
64        id: super::types::Http2SettingId,
65        /// Encoded setting value.
66        value: u32,
67    },
68    /// A PUSH_PROMISE frame has a zero 31-bit promised stream identifier.
69    ZeroPromisedStreamId,
70    /// A PADDED frame has no pad-length byte or declares too much padding.
71    InvalidPadding {
72        /// Encoded padding length, or zero when the pad-length byte is absent.
73        padding_length: u8,
74        /// Total payload length.
75        payload_length: usize,
76    },
77    /// A required intrinsic payload section is truncated.
78    MalformedPayload {
79        /// Required bytes in the section.
80        required: usize,
81        /// Available bytes in the section.
82        available: usize,
83    },
84}
85
86impl fmt::Display for Http2ParseError {
87    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88        match self {
89            Self::Incomplete {
90                required,
91                available,
92            } => write!(
93                f,
94                "HTTP/2 input is incomplete: need {required} bytes, have {available}"
95            ),
96            Self::ClientPrefaceMismatch {
97                offset,
98                expected,
99                actual,
100            } => write!(
101                f,
102                "HTTP/2 client preface mismatch at byte {offset}: expected {expected}, got {actual}"
103            ),
104            Self::PayloadTooLarge { maximum, actual } => write!(
105                f,
106                "HTTP/2 frame payload is too large: maximum {maximum}, got {actual}"
107            ),
108            Self::WrongFrameType { expected, actual } => write!(
109                f,
110                "HTTP/2 frame type mismatch: expected {}, got {}",
111                expected.raw(),
112                actual.raw()
113            ),
114            Self::ZeroStreamId => f.write_str("HTTP/2 frame requires a nonzero stream identifier"),
115            Self::ExpectedZeroStreamId => {
116                f.write_str("HTTP/2 frame requires a zero stream identifier")
117            }
118            Self::FrameSizeMismatch { expected, actual } => write!(
119                f,
120                "HTTP/2 fixed-layout frame payload length mismatch: expected {expected}, got {actual}"
121            ),
122            Self::ZeroWindowIncrement => {
123                f.write_str("HTTP/2 WINDOW_UPDATE frame requires a nonzero increment")
124            }
125            Self::SettingsPayloadLength { actual } => write!(
126                f,
127                "HTTP/2 SETTINGS payload length must be a multiple of 6, got {actual}"
128            ),
129            Self::SettingsAckPayload { actual } => write!(
130                f,
131                "HTTP/2 SETTINGS ACK frame must have an empty payload, got {actual} bytes"
132            ),
133            Self::InvalidSettingValue { id, value } => write!(
134                f,
135                "HTTP/2 SETTINGS parameter {} has invalid value {value}",
136                id.raw()
137            ),
138            Self::ZeroPromisedStreamId => {
139                f.write_str("HTTP/2 PUSH_PROMISE requires a nonzero promised stream identifier")
140            }
141            Self::InvalidPadding {
142                padding_length,
143                payload_length,
144            } => write!(
145                f,
146                "HTTP/2 padding length {padding_length} is invalid for payload length {payload_length}"
147            ),
148            Self::MalformedPayload {
149                required,
150                available,
151            } => write!(
152                f,
153                "HTTP/2 payload section is truncated: need {required} bytes, have {available}"
154            ),
155        }
156    }
157}
158
159/// Failure to create an outgoing HTTP/2 stream identifier.
160#[derive(Clone, Copy, Debug, Eq, PartialEq)]
161pub enum Http2StreamIdError {
162    /// The reserved high bit is set.
163    ReservedBitSet,
164}
165
166impl fmt::Display for Http2StreamIdError {
167    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168        match self {
169            Self::ReservedBitSet => {
170                f.write_str("HTTP/2 stream identifier has its reserved bit set")
171            }
172        }
173    }
174}
175
176/// Failure to construct an HTTP/2 frame in caller-provided storage.
177#[derive(Clone, Copy, Debug, Eq, PartialEq)]
178pub enum Http2BuildError {
179    /// A frame that requires a stream was given the zero stream identifier.
180    ZeroStreamId,
181    /// The outgoing stream identifier has its reserved high bit set.
182    ReservedStreamId,
183    /// A WINDOW_UPDATE frame was given a zero 31-bit increment.
184    ZeroWindowIncrement,
185    /// The outgoing WINDOW_UPDATE increment has its reserved high bit set.
186    ReservedWindowIncrement,
187    /// A SETTINGS ACK frame was given one or more settings.
188    SettingsAckPayload {
189        /// Encoded payload length in bytes.
190        actual: usize,
191    },
192    /// A SETTINGS parameter has an intrinsically invalid value.
193    InvalidSettingValue {
194        /// Encoded setting identifier.
195        id: super::types::Http2SettingId,
196        /// Encoded setting value.
197        value: u32,
198    },
199    /// The outgoing GOAWAY last-stream identifier has its reserved high bit set.
200    ReservedLastStreamId,
201    /// Caller-supplied DATA flags include PADDED, which is controlled by the padding argument.
202    DataPaddedFlagSet,
203    /// Caller-supplied HEADERS flags include PADDED, which is controlled by the padding argument.
204    HeadersPaddedFlagSet,
205    /// Caller-supplied HEADERS flags include PRIORITY, which is controlled by the priority argument.
206    HeadersPriorityFlagSet,
207    /// Caller-supplied PUSH_PROMISE flags include PADDED, which is controlled by the padding argument.
208    PushPromisePaddedFlagSet,
209    /// A PUSH_PROMISE frame was given a zero promised stream identifier.
210    ZeroPromisedStreamId,
211    /// A PUSH_PROMISE frame was given a promised stream identifier with its reserved bit set.
212    ReservedPromisedStreamId,
213    /// The payload exceeds the caller-provided maximum or HTTP/2's 24-bit length field.
214    PayloadTooLarge {
215        /// Maximum permitted payload length.
216        maximum: usize,
217        /// Supplied payload length.
218        actual: usize,
219    },
220    /// The caller buffer cannot contain the complete frame.
221    BufferTooShort {
222        /// Required bytes.
223        required: usize,
224        /// Available bytes.
225        available: usize,
226    },
227}
228
229impl fmt::Display for Http2BuildError {
230    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
231        match self {
232            Self::ZeroStreamId => {
233                f.write_str("outgoing HTTP/2 frame requires a nonzero stream identifier")
234            }
235            Self::ReservedStreamId => {
236                f.write_str("outgoing HTTP/2 stream identifier has its reserved bit set")
237            }
238            Self::ZeroWindowIncrement => {
239                f.write_str("outgoing HTTP/2 WINDOW_UPDATE requires a nonzero increment")
240            }
241            Self::ReservedWindowIncrement => f.write_str(
242                "outgoing HTTP/2 WINDOW_UPDATE increment has its reserved bit set",
243            ),
244            Self::SettingsAckPayload { actual } => write!(
245                f,
246                "outgoing HTTP/2 SETTINGS ACK frame must have an empty payload, got {actual} bytes"
247            ),
248            Self::InvalidSettingValue { id, value } => write!(
249                f,
250                "outgoing HTTP/2 SETTINGS parameter {} has invalid value {value}",
251                id.raw()
252            ),
253            Self::ReservedLastStreamId => {
254                f.write_str("outgoing HTTP/2 GOAWAY last-stream identifier has its reserved bit set")
255            }
256            Self::DataPaddedFlagSet => f.write_str(
257                "outgoing HTTP/2 DATA flags must not include PADDED; use the padding length argument",
258            ),
259            Self::HeadersPaddedFlagSet => f.write_str(
260                "outgoing HTTP/2 HEADERS flags must not include PADDED; use the padding length argument",
261            ),
262            Self::HeadersPriorityFlagSet => f.write_str(
263                "outgoing HTTP/2 HEADERS flags must not include PRIORITY; use the priority argument",
264            ),
265            Self::PushPromisePaddedFlagSet => f.write_str(
266                "outgoing HTTP/2 PUSH_PROMISE flags must not include PADDED; use the padding length argument",
267            ),
268            Self::ZeroPromisedStreamId => {
269                f.write_str("outgoing HTTP/2 PUSH_PROMISE requires a nonzero promised stream identifier")
270            }
271            Self::ReservedPromisedStreamId => f.write_str(
272                "outgoing HTTP/2 PUSH_PROMISE promised stream identifier has its reserved bit set",
273            ),
274            Self::PayloadTooLarge { maximum, actual } => write!(
275                f,
276                "HTTP/2 payload is too large: maximum {maximum}, got {actual}"
277            ),
278            Self::BufferTooShort {
279                required,
280                available,
281            } => write!(
282                f,
283                "HTTP/2 buffer is too short: need {required} bytes, have {available}"
284            ),
285        }
286    }
287}