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