1use core::fmt;
4
5use super::context::PendingSizes;
6use super::huffman::{HpackHuffmanDecodeError, HpackHuffmanDecoder};
7use super::representation::{HpackLiteralMode, HpackRepresentation, HpackRepresentationParseError};
8use super::string::HpackStringLiteral;
9use super::table::{
10 HPACK_STATIC_TABLE_LEN, HpackDynamicTable, HpackDynamicTableError, HpackHeaderFieldRef,
11 HpackStaticTable,
12};
13
14#[derive(Clone, Copy, Debug, Eq, PartialEq)]
16pub enum HpackDecodedFieldMode {
17 Indexed,
19 IncrementalIndexing,
21 WithoutIndexing,
23 NeverIndexed,
25}
26
27#[derive(Clone, Copy, Debug, Eq, PartialEq)]
29pub struct HpackDecodedField<'a> {
30 name: &'a [u8],
31 value: &'a [u8],
32 mode: HpackDecodedFieldMode,
33}
34
35impl<'a> HpackDecodedField<'a> {
36 pub const fn name(self) -> &'a [u8] {
38 self.name
39 }
40
41 pub const fn value(self) -> &'a [u8] {
43 self.value
44 }
45
46 pub const fn mode(self) -> HpackDecodedFieldMode {
48 self.mode
49 }
50}
51
52#[derive(Clone, Copy, Debug, Eq, PartialEq)]
54pub enum HpackDecodeStep<'a> {
55 Field(HpackDecodedField<'a>),
57 DynamicTableSizeUpdate {
59 maximum_size: usize,
61 },
62 Complete,
64}
65
66#[derive(Clone, Copy, Debug, Eq, PartialEq)]
68pub enum HpackDecodeError {
69 Representation(HpackRepresentationParseError),
71 IndexNotRepresentable {
73 index: u64,
75 },
76 UnavailableIndex {
78 index: u64,
80 },
81 MaximumSizeNotRepresentable {
83 maximum_size: u64,
85 },
86 AllowedMaximumExceedsCapacity {
88 allowed: usize,
90 capacity: usize,
92 },
93 DynamicTableSizeUpdateRequired,
95 DynamicTableSizeUpdateMismatch {
97 expected: usize,
99 requested: usize,
101 },
102 DynamicTableSizeUpdateAfterField,
104 DynamicTableSizeUpdateExceedsAllowed {
106 requested: usize,
108 allowed: usize,
110 },
111 DynamicTableSizeUpdate(HpackDynamicTableError),
113 HuffmanName(HpackHuffmanDecodeError),
115 HuffmanValue(HpackHuffmanDecodeError),
117 DecodedLengthOverflow,
119 EntrySizeOverflow,
121 OutputTooShort {
123 required: usize,
125 available: usize,
127 },
128}
129
130impl fmt::Display for HpackDecodeError {
131 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132 match self {
133 Self::Representation(error) => write!(f, "invalid HPACK representation: {error}"),
134 Self::IndexNotRepresentable { index } => {
135 write!(f, "HPACK index {index} cannot be represented as usize")
136 }
137 Self::UnavailableIndex { index } => write!(f, "HPACK index {index} is unavailable"),
138 Self::MaximumSizeNotRepresentable { maximum_size } => write!(
139 f,
140 "HPACK maximum size {maximum_size} cannot be represented as usize"
141 ),
142 Self::AllowedMaximumExceedsCapacity { allowed, capacity } => write!(
143 f,
144 "HPACK allowed maximum {allowed} exceeds table capacity {capacity}"
145 ),
146 Self::DynamicTableSizeUpdateRequired => {
147 f.write_str("HPACK dynamic-table size update is required before a header field")
148 }
149 Self::DynamicTableSizeUpdateMismatch {
150 expected,
151 requested,
152 } => write!(
153 f,
154 "HPACK dynamic-table update {requested} does not match required update {expected}"
155 ),
156 Self::DynamicTableSizeUpdateAfterField => {
157 f.write_str("HPACK dynamic-table update follows a header field")
158 }
159 Self::DynamicTableSizeUpdateExceedsAllowed { requested, allowed } => write!(
160 f,
161 "HPACK dynamic-table update {requested} exceeds allowed maximum {allowed}"
162 ),
163 Self::DynamicTableSizeUpdate(error) => {
164 write!(f, "HPACK dynamic-table update failed: {error:?}")
165 }
166 Self::HuffmanName(error) => write!(f, "invalid HPACK Huffman name: {error}"),
167 Self::HuffmanValue(error) => write!(f, "invalid HPACK Huffman value: {error}"),
168 Self::DecodedLengthOverflow => {
169 f.write_str("HPACK decoded field length overflows usize")
170 }
171 Self::EntrySizeOverflow => {
172 f.write_str("HPACK dynamic-table entry size overflows usize")
173 }
174 Self::OutputTooShort {
175 required,
176 available,
177 } => write!(
178 f,
179 "HPACK output is too short: need {required} bytes, have {available}"
180 ),
181 }
182 }
183}
184
185pub struct HpackBlockDecoder<'block, 'table, 'storage, 'entries> {
187 remaining: &'block [u8],
188 table: &'table mut HpackDynamicTable<'storage, 'entries>,
189 pending: &'table mut PendingSizes,
190 allowed_maximum_size: usize,
191 saw_field: bool,
192}
193
194impl<'block, 'table, 'storage, 'entries> HpackBlockDecoder<'block, 'table, 'storage, 'entries> {
195 pub(super) fn from_context(
196 block: &'block [u8],
197 table: &'table mut HpackDynamicTable<'storage, 'entries>,
198 pending: &'table mut PendingSizes,
199 allowed_maximum_size: usize,
200 ) -> Self {
201 Self {
202 remaining: block,
203 table,
204 pending,
205 allowed_maximum_size,
206 saw_field: false,
207 }
208 }
209
210 pub const fn remaining(&self) -> &'block [u8] {
212 self.remaining
213 }
214
215 pub const fn is_complete(&self) -> bool {
220 self.remaining.is_empty()
221 }
222
223 pub fn decode_next<'output>(
225 &mut self,
226 output: &'output mut [u8],
227 ) -> Result<HpackDecodeStep<'output>, HpackDecodeError> {
228 if self.remaining.is_empty() {
229 if self.pending.next().is_some() {
230 return Err(HpackDecodeError::DynamicTableSizeUpdateRequired);
231 }
232 return Ok(HpackDecodeStep::Complete);
233 }
234 let representation =
235 HpackRepresentation::parse(self.remaining).map_err(HpackDecodeError::Representation)?;
236 match representation {
237 HpackRepresentation::DynamicTableSizeUpdate(update) => {
238 if self.saw_field {
239 return Err(HpackDecodeError::DynamicTableSizeUpdateAfterField);
240 }
241 let maximum_size = usize::try_from(update.size_value()).map_err(|_| {
242 HpackDecodeError::MaximumSizeNotRepresentable {
243 maximum_size: update.size_value(),
244 }
245 })?;
246 if let Some(expected) = self.pending.next()
247 && maximum_size != expected
248 {
249 return Err(HpackDecodeError::DynamicTableSizeUpdateMismatch {
250 expected,
251 requested: maximum_size,
252 });
253 }
254 if maximum_size > self.allowed_maximum_size {
255 return Err(HpackDecodeError::DynamicTableSizeUpdateExceedsAllowed {
256 requested: maximum_size,
257 allowed: self.allowed_maximum_size,
258 });
259 }
260 self.table
261 .set_maximum_size(maximum_size)
262 .map_err(HpackDecodeError::DynamicTableSizeUpdate)?;
263 self.remaining = &self.remaining[update.as_bytes().len()..];
264 if self.pending.next().is_some() {
265 self.pending.advance();
266 }
267 Ok(HpackDecodeStep::DynamicTableSizeUpdate { maximum_size })
268 }
269 HpackRepresentation::Indexed(indexed) => {
270 if self.pending.next().is_some() {
271 return Err(HpackDecodeError::DynamicTableSizeUpdateRequired);
272 }
273 let consumed = indexed.as_bytes().len();
274 let (name_len, required) = {
275 let field = self.resolve(indexed.index_value())?;
276 let name_len = field.name().len();
277 let required = name_len
278 .checked_add(field.value().len())
279 .ok_or(HpackDecodeError::DecodedLengthOverflow)?;
280 if output.len() < required {
281 return Err(HpackDecodeError::OutputTooShort {
282 required,
283 available: output.len(),
284 });
285 }
286 output[..name_len].copy_from_slice(field.name());
287 output[name_len..required].copy_from_slice(field.value());
288 (name_len, required)
289 };
290 self.remaining = &self.remaining[consumed..];
291 self.saw_field = true;
292 Ok(HpackDecodeStep::Field(HpackDecodedField {
293 name: &output[..name_len],
294 value: &output[name_len..required],
295 mode: HpackDecodedFieldMode::Indexed,
296 }))
297 }
298 HpackRepresentation::Literal(literal) => {
299 if self.pending.next().is_some() {
300 return Err(HpackDecodeError::DynamicTableSizeUpdateRequired);
301 }
302 let mode = match literal.mode() {
303 HpackLiteralMode::IncrementalIndexing => {
304 HpackDecodedFieldMode::IncrementalIndexing
305 }
306 HpackLiteralMode::WithoutIndexing => HpackDecodedFieldMode::WithoutIndexing,
307 HpackLiteralMode::NeverIndexed => HpackDecodedFieldMode::NeverIndexed,
308 };
309 let name = match literal.name() {
310 Some(name) => NameSource::Literal(name),
311 None => NameSource::Borrowed(self.resolve(literal.name_index_value())?.name()),
312 };
313 let value = literal.value();
314 let name_len = name.required_len()?;
315 let value_len = literal_len(value, false)?;
316 let required = name_len
317 .checked_add(value_len)
318 .ok_or(HpackDecodeError::DecodedLengthOverflow)?;
319 if output.len() < required {
320 return Err(HpackDecodeError::OutputTooShort {
321 required,
322 available: output.len(),
323 });
324 }
325 let entry_size = (mode == HpackDecodedFieldMode::IncrementalIndexing)
326 .then(|| {
327 HpackDynamicTable::entry_size(
328 &output[..name_len],
329 &output[name_len..required],
330 )
331 })
332 .transpose()
333 .map_err(|_| HpackDecodeError::EntrySizeOverflow)?;
334 write_name(name, &mut output[..name_len])?;
335 write_literal(value, &mut output[name_len..required], false)?;
336 if let Some(entry_size) = entry_size {
337 self.table.insert_prevalidated(
338 &output[..name_len],
339 &output[name_len..required],
340 entry_size,
341 );
342 }
343 self.remaining = &self.remaining[literal.as_bytes().len()..];
344 self.saw_field = true;
345 Ok(HpackDecodeStep::Field(HpackDecodedField {
346 name: &output[..name_len],
347 value: &output[name_len..required],
348 mode,
349 }))
350 }
351 }
352 }
353
354 fn resolve(&self, index: u64) -> Result<HpackHeaderFieldRef<'_>, HpackDecodeError> {
355 let index = usize::try_from(index)
356 .map_err(|_| HpackDecodeError::IndexNotRepresentable { index })?;
357 if index == 0 {
358 return Err(HpackDecodeError::UnavailableIndex { index: 0 });
359 }
360 if index <= HPACK_STATIC_TABLE_LEN {
361 return HpackStaticTable::get(index).ok_or(HpackDecodeError::UnavailableIndex {
362 index: index as u64,
363 });
364 }
365 let dynamic = index - HPACK_STATIC_TABLE_LEN;
366 self.table
367 .get(dynamic)
368 .ok_or(HpackDecodeError::UnavailableIndex {
369 index: index as u64,
370 })
371 }
372}
373
374#[derive(Clone, Copy)]
375enum NameSource<'a> {
376 Borrowed(&'a [u8]),
377 Literal(HpackStringLiteral<'a>),
378}
379
380impl NameSource<'_> {
381 fn required_len(self) -> Result<usize, HpackDecodeError> {
382 match self {
383 Self::Borrowed(bytes) => Ok(bytes.len()),
384 Self::Literal(literal) => literal_len(literal, true),
385 }
386 }
387}
388
389fn literal_len(literal: HpackStringLiteral<'_>, name: bool) -> Result<usize, HpackDecodeError> {
390 if literal.is_huffman() {
391 HpackHuffmanDecoder::required_decoded_len(literal.encoded_bytes()).map_err(|error| {
392 if name {
393 HpackDecodeError::HuffmanName(error)
394 } else {
395 HpackDecodeError::HuffmanValue(error)
396 }
397 })
398 } else {
399 Ok(literal.encoded_bytes().len())
400 }
401}
402
403fn write_name(source: NameSource<'_>, output: &mut [u8]) -> Result<(), HpackDecodeError> {
404 match source {
405 NameSource::Borrowed(bytes) => output.copy_from_slice(bytes),
406 NameSource::Literal(literal) => write_literal(literal, output, true)?,
407 }
408 Ok(())
409}
410
411fn write_literal(
412 literal: HpackStringLiteral<'_>,
413 output: &mut [u8],
414 name: bool,
415) -> Result<(), HpackDecodeError> {
416 if literal.is_huffman() {
417 HpackHuffmanDecoder::new(literal.encoded_bytes(), output)
418 .decode()
419 .map_err(|error| {
420 if name {
421 HpackDecodeError::HuffmanName(error)
422 } else {
423 HpackDecodeError::HuffmanValue(error)
424 }
425 })?;
426 } else {
427 output.copy_from_slice(literal.encoded_bytes());
428 }
429 Ok(())
430}