fluke_hpack/
decoder.rs

1//! Exposes the struct `Decoder` that allows for HPACK-encoded header blocks to
2//! be decoded into a header list.
3//!
4//! The decoder only follows HPACK rules, without performing any additional
5//! (semantic) checks on the header name/value pairs, i.e. it considers the
6//! headers as opaque octets.
7//!
8//! # Example
9//!
10//! A simple example of using the decoder that demonstrates its API:
11//!
12//! ```rust
13//! use fluke_hpack::Decoder;
14//! let mut decoder = Decoder::new();
15//!
16//! let header_list = decoder.decode(&[0x82, 0x84]).unwrap();
17//!
18//! assert_eq!(header_list, [
19//!     (b":method".to_vec(), b"GET".to_vec()),
20//!     (b":path".to_vec(), b"/".to_vec()),
21//! ]);
22//! ```
23//!
24//! A more complex example where the callback API is used, providing the client a
25//! borrowed representation of each header, rather than an owned representation.
26//!
27//! ```rust
28//! use fluke_hpack::Decoder;
29//! let mut decoder = Decoder::new();
30//!
31//! let mut count = 0;
32//! let header_list = decoder.decode_with_cb(&[0x82, 0x84], |name, value| {
33//!     count += 1;
34//!     match count {
35//!         1 => {
36//!             assert_eq!(&name[..], &b":method"[..]);
37//!             assert_eq!(&value[..], &b"GET"[..]);
38//!         },
39//!         2 => {
40//!             assert_eq!(&name[..], &b":path"[..]);
41//!             assert_eq!(&value[..], &b"/"[..]);
42//!         },
43//!         _ => panic!("Did not expect more than two headers!"),
44//!     };
45//! });
46//! ```
47
48use std::borrow::Cow;
49use std::num::Wrapping;
50
51use tracing::{debug, trace};
52
53use super::huffman::HuffmanDecoder;
54use super::huffman::HuffmanDecoderError;
55
56use super::STATIC_TABLE;
57use super::{HeaderTable, StaticTable};
58
59/// Decodes an integer encoded with a given prefix size (in bits).
60/// Assumes that the buffer `buf` contains the integer to be decoded,
61/// with the first byte representing the octet that contains the
62/// prefix.
63///
64/// Returns a tuple representing the decoded integer and the number
65/// of bytes from the buffer that were used.
66fn decode_integer(buf: &[u8], prefix_size: u8) -> Result<(usize, usize), DecoderError> {
67    if !(1..=8).contains(&prefix_size) {
68        return Err(DecoderError::IntegerDecodingError(
69            IntegerDecodingError::InvalidPrefix,
70        ));
71    }
72    if buf.is_empty() {
73        return Err(DecoderError::IntegerDecodingError(
74            IntegerDecodingError::NotEnoughOctets,
75        ));
76    }
77
78    // Make sure there's no overflow in the shift operation
79    let Wrapping(mask) = if prefix_size == 8 {
80        Wrapping(0xFF)
81    } else {
82        Wrapping(1u8 << prefix_size) - Wrapping(1)
83    };
84    let mut value = (buf[0] & mask) as usize;
85    if value < (mask as usize) {
86        // Value fits in the prefix bits.
87        return Ok((value, 1));
88    }
89
90    // The value does not fit into the prefix bits, so we read as many following
91    // bytes as necessary to decode the integer.
92    // Already one byte used (the prefix)
93    let mut total = 1;
94    let mut m = 0;
95    // The octet limit is chosen such that the maximum allowed *value* can
96    // never overflow an unsigned 32-bit integer. The maximum value of any
97    // integer that can be encoded with 5 octets is ~2^28
98    let octet_limit = 5;
99
100    for &b in buf[1..].iter() {
101        total += 1;
102        value += ((b & 127) as usize) * (1 << m);
103        m += 7;
104
105        if b & 128 != 128 {
106            // Most significant bit is not set => no more continuation bytes
107            return Ok((value, total));
108        }
109
110        if total == octet_limit {
111            // The spec tells us that we MUST treat situations where the
112            // encoded representation is too long (in octets) as an error.
113            return Err(DecoderError::IntegerDecodingError(
114                IntegerDecodingError::TooManyOctets,
115            ));
116        }
117    }
118
119    // If we have reached here, it means the buffer has been exhausted without
120    // hitting the termination condition.
121    Err(DecoderError::IntegerDecodingError(
122        IntegerDecodingError::NotEnoughOctets,
123    ))
124}
125
126/// Decodes an octet string under HPACK rules of encoding found in the given
127/// buffer `buf`.
128///
129/// It is assumed that the first byte in the buffer represents the start of the
130/// encoded octet string.
131///
132/// Returns the decoded string in a newly allocated `Vec` and the number of
133/// bytes consumed from the given buffer.
134fn decode_string(buf: &[u8]) -> Result<(Cow<'_, [u8]>, usize), DecoderError> {
135    let (len, consumed) = decode_integer(buf, 7)?;
136    debug!("decode_string: Consumed = {}, len = {}", consumed, len);
137    if consumed + len > buf.len() {
138        return Err(DecoderError::StringDecodingError(
139            StringDecodingError::NotEnoughOctets,
140        ));
141    }
142    let raw_string = &buf[consumed..consumed + len];
143    if buf[0] & 128 == 128 {
144        debug!("decode_string: Using the Huffman code");
145        // Huffman coding used: pass the raw octets to the Huffman decoder
146        // and return its result.
147        let mut decoder = HuffmanDecoder::new();
148        let decoded = match decoder.decode(raw_string) {
149            Err(e) => {
150                return Err(DecoderError::StringDecodingError(
151                    StringDecodingError::HuffmanDecoderError(e),
152                ));
153            }
154            Ok(res) => res,
155        };
156        Ok((Cow::Owned(decoded), consumed + len))
157    } else {
158        // The octets were transmitted raw
159        debug!("decode_string: Raw octet string received");
160        Ok((Cow::Borrowed(raw_string), consumed + len))
161    }
162}
163
164/// Different variants of how a particular header field can be represented in
165/// an HPACK encoding.
166enum FieldRepresentation {
167    Indexed,
168    LiteralWithIncrementalIndexing,
169    SizeUpdate,
170    LiteralNeverIndexed,
171    LiteralWithoutIndexing,
172}
173
174impl FieldRepresentation {
175    /// Based on the given octet, returns the type of the field representation.
176    ///
177    /// The given octet should be the top-order byte of the header field that
178    /// is about to be decoded.
179    fn new(octet: u8) -> FieldRepresentation {
180        if octet & 128 == 128 {
181            // High-order bit set
182            FieldRepresentation::Indexed
183        } else if octet & 64 == 64 {
184            // Bit pattern `01`
185            FieldRepresentation::LiteralWithIncrementalIndexing
186        } else if octet & 32 == 32 {
187            // Bit pattern `001`
188            FieldRepresentation::SizeUpdate
189        } else if octet & 16 == 16 {
190            // Bit pattern `0001`
191            FieldRepresentation::LiteralNeverIndexed
192        } else {
193            // None of the top 4 bits is set => bit pattern `0000xxxx`
194            FieldRepresentation::LiteralWithoutIndexing
195        }
196    }
197}
198
199/// Represents all errors that can be encountered while decoding an
200/// integer.
201#[derive(PartialEq, Copy, Clone, Debug)]
202pub enum IntegerDecodingError {
203    /// 5.1. specifies that "excessively large integer decodings" MUST be
204    /// considered an error (whether the size is the number of octets or
205    /// value). This variant corresponds to the encoding containing too many
206    /// octets.
207    TooManyOctets,
208    /// The variant corresponds to the case where the value of the integer
209    /// being decoded exceeds a certain threshold.
210    ValueTooLarge,
211    /// When a buffer from which an integer was supposed to be encoded does
212    /// not contain enough octets to complete the decoding.
213    NotEnoughOctets,
214    /// Only valid prefixes are [1, 8]
215    InvalidPrefix,
216}
217
218/// Represents all errors that can be encountered while decoding an octet
219/// string.
220#[derive(PartialEq, Copy, Clone, Debug)]
221pub enum StringDecodingError {
222    NotEnoughOctets,
223    HuffmanDecoderError(HuffmanDecoderError),
224}
225
226/// Represents all errors that can be encountered while performing the decoding
227/// of an HPACK header set.
228#[derive(PartialEq, Copy, Clone, Debug)]
229pub enum DecoderError {
230    HeaderIndexOutOfBounds,
231    IntegerDecodingError(IntegerDecodingError),
232    StringDecodingError(StringDecodingError),
233    /// The size of the dynamic table can never be allowed to exceed the max
234    /// size mandated to the decoder by the protocol. (by performing changes
235    /// made by SizeUpdate blocks).
236    InvalidMaxDynamicSize,
237    /// A header block cannot end with a dynamic table size update, it
238    /// must be treating as a decoding error.
239    SizeUpdateAtEnd,
240}
241
242/// The result returned by the `decode` method of the `Decoder`.
243pub type DecoderResult = Result<Vec<(Vec<u8>, Vec<u8>)>, DecoderError>;
244
245/// Decodes headers encoded using HPACK.
246///
247/// For now, incremental decoding is not supported, i.e. it is necessary
248/// to pass in the entire encoded representation of all headers to the
249/// decoder, rather than processing it piece-by-piece.
250pub struct Decoder<'a> {
251    // The dynamic table will own its own copy of headers
252    header_table: HeaderTable<'a>,
253
254    max_allowed_table_size: Option<usize>,
255
256    // Allow trailing size updates (used by tests)
257    #[cfg(test)]
258    pub(crate) allow_trailing_size_updates: bool,
259}
260
261impl Default for Decoder<'_> {
262    fn default() -> Decoder<'static> {
263        Decoder::with_static_table(STATIC_TABLE)
264    }
265}
266
267type DecodedLiteralCow<'a> = ((Cow<'a, [u8]>, Cow<'a, [u8]>), usize);
268type DecodedLiteralSlice<'a> = ((&'a [u8], &'a [u8]), usize);
269
270/// Represents a decoder of HPACK encoded headers. Maintains the state
271/// necessary to correctly decode subsequent HPACK blocks.
272impl<'a> Decoder<'a> {
273    /// Creates a new `Decoder` with all settings set to default values.
274    pub fn new() -> Decoder<'a> {
275        Default::default()
276    }
277
278    /// Creates a new `Decoder` with the given slice serving as its static
279    /// table.
280    ///
281    /// The slice should contain tuples where the tuple coordinates represent
282    /// the header name and value, respectively.
283    ///
284    /// Note: in order for the final decoded content to match the encoding
285    ///       (according to the standard, at least), this static table must be
286    ///       the one defined in the HPACK spec.
287    fn with_static_table(static_table: StaticTable<'a>) -> Decoder<'a> {
288        Decoder {
289            header_table: HeaderTable::with_static_table(static_table),
290            max_allowed_table_size: None,
291            #[cfg(test)]
292            allow_trailing_size_updates: false,
293        }
294    }
295
296    /// Sets a new maximum dynamic table size for the decoder.
297    ///
298    /// If `max_allowed_table_size` is set, `new_max_size` must be <= to it.
299    pub fn set_max_table_size(&mut self, new_max_size: usize) {
300        if let Some(max_allowed_size) = self.max_allowed_table_size {
301            // this lives as an assert for now, since if you're calling this
302            // explicitly so you can check preconditions first.
303            assert!(
304                new_max_size <= max_allowed_size,
305                "new_max_size ({}) > max_allowed_size ({})",
306                new_max_size,
307                max_allowed_size
308            );
309        }
310
311        self.header_table
312            .dynamic_table
313            .set_max_table_size(new_max_size);
314    }
315
316    /// Sets max allowed table size: any "dynamic table size updates" that try
317    /// to bring the table size over that value will error out with
318    /// [DecoderError::InvalidMaxDynamicSize]
319    pub fn set_max_allowed_table_size(&mut self, max_allowed_size: usize) {
320        self.max_allowed_table_size = Some(max_allowed_size);
321    }
322
323    /// Decodes the headers found in the given buffer `buf`. Invokes the callback `cb` for each
324    /// decoded header in turn, by providing it the header name and value as `Cow` byte array
325    /// slices.
326    ///
327    /// The callback is free to decide how to handle the emitted header, however the `Cow` cannot
328    /// outlive the closure body without assuming ownership or otherwise copying the contents.
329    ///
330    /// This is due to the fact that the header might be found (fully or partially) in the header
331    /// table of the decoder, in which case the callback will have received a borrow of its
332    /// contents. However, when one of the following headers is decoded, it is possible that the
333    /// header table might have to be modified; so the borrow is only valid until the next header
334    /// decoding begins, meaning until the end of the callback's body.
335    ///
336    /// If an error is encountered during the decoding of any header, decoding halts and the
337    /// appropriate error is returned as the `Err` variant of the `Result`.
338    pub fn decode_with_cb<F>(&mut self, buf: &[u8], mut cb: F) -> Result<(), DecoderError>
339    where
340        F: FnMut(Cow<[u8]>, Cow<[u8]>),
341    {
342        let mut current_octet_index = 0;
343
344        let mut last_was_size_update = false;
345        while current_octet_index < buf.len() {
346            // At this point we are always at the beginning of the next block
347            // within the HPACK data.
348            // The type of the block can always be determined from the first
349            // byte.
350            let initial_octet = buf[current_octet_index];
351            let buffer_leftover = &buf[current_octet_index..];
352            let field_representation = FieldRepresentation::new(initial_octet);
353            last_was_size_update = matches!(field_representation, FieldRepresentation::SizeUpdate);
354
355            let consumed = match field_representation {
356                FieldRepresentation::Indexed => {
357                    let ((name, value), consumed) = self.decode_indexed(buffer_leftover)?;
358                    cb(Cow::Borrowed(name), Cow::Borrowed(value));
359
360                    consumed
361                }
362                FieldRepresentation::LiteralWithIncrementalIndexing => {
363                    let ((name, value), consumed) = {
364                        let ((name, value), consumed) =
365                            self.decode_literal(buffer_leftover, true)?;
366                        cb(Cow::Borrowed(&name), Cow::Borrowed(&value));
367
368                        // Since we are to add the decoded header to the header table, we need to
369                        // convert them into owned buffers that the decoder can keep internally.
370                        let name = name.into_owned();
371                        let value = value.into_owned();
372
373                        ((name, value), consumed)
374                    };
375                    // This cannot be done in the same scope as the `decode_literal` call, since
376                    // Rust cannot figure out that the `into_owned` calls effectively drop the
377                    // borrow on `self` that the `decode_literal` return value had. Since adding
378                    // a header to the table requires a `&mut self`, it fails to compile.
379                    // Manually separating it out here works around it...
380                    self.header_table.add_header(name, value);
381
382                    consumed
383                }
384                FieldRepresentation::LiteralWithoutIndexing => {
385                    let ((name, value), consumed) = self.decode_literal(buffer_leftover, false)?;
386                    cb(name, value);
387
388                    consumed
389                }
390                FieldRepresentation::LiteralNeverIndexed => {
391                    // Same as the previous one, except if we were also a proxy
392                    // we would need to make sure not to change the
393                    // representation received here. We don't care about this
394                    // for now.
395                    let ((name, value), consumed) = self.decode_literal(buffer_leftover, false)?;
396                    cb(name, value);
397
398                    consumed
399                }
400                FieldRepresentation::SizeUpdate => {
401                    // Handle the dynamic table size update...
402                    self.update_max_dynamic_size(buffer_leftover)?
403                }
404            };
405
406            current_octet_index += consumed;
407        }
408
409        if last_was_size_update {
410            #[cfg(test)]
411            if self.allow_trailing_size_updates {
412                return Ok(());
413            }
414
415            return Err(DecoderError::SizeUpdateAtEnd);
416        }
417
418        Ok(())
419    }
420
421    /// Decode the header block found in the given buffer.
422    ///
423    /// The decoded representation is returned as a sequence of headers, where both the name and
424    /// value of each header is represented by an owned byte sequence (i.e. `Vec<u8>`).
425    ///
426    /// The buffer should represent the entire block that should be decoded.
427    /// For example, in HTTP/2, all continuation frames need to be concatenated
428    /// to a single buffer before passing them to the decoder.
429    pub fn decode(&mut self, buf: &[u8]) -> DecoderResult {
430        let mut header_list = Vec::new();
431
432        self.decode_with_cb(buf, |n, v| {
433            header_list.push((n.into_owned(), v.into_owned()))
434        })?;
435
436        Ok(header_list)
437    }
438
439    /// Decodes an indexed header representation.
440    fn decode_indexed(&self, buf: &[u8]) -> Result<DecodedLiteralSlice<'_>, DecoderError> {
441        let (index, consumed) = decode_integer(buf, 7)?;
442        debug!(
443            "Decoding indexed: index = {}, consumed = {}",
444            index, consumed
445        );
446
447        let (name, value) = self.get_from_table(index)?;
448
449        Ok(((name, value), consumed))
450    }
451
452    /// Gets the header (name, value) pair with the given index from the table.
453    ///
454    /// In this context, the "table" references the definition of the table
455    /// where the static table is concatenated with the dynamic table and is
456    /// 1-indexed.
457    fn get_from_table(&self, index: usize) -> Result<(&[u8], &[u8]), DecoderError> {
458        self.header_table
459            .get_from_table(index)
460            .ok_or(DecoderError::HeaderIndexOutOfBounds)
461    }
462
463    /// Decodes a literal header representation from the given buffer.
464    ///
465    /// # Parameters
466    ///
467    /// - index: whether or not the decoded value should be indexed (i.e.
468    ///   included in the dynamic table).
469    fn decode_literal<'b>(
470        &'b self,
471        buf: &'b [u8],
472        index: bool,
473    ) -> Result<DecodedLiteralCow<'b>, DecoderError> {
474        let prefix = if index { 6 } else { 4 };
475        let (table_index, mut consumed) = decode_integer(buf, prefix)?;
476
477        // First read the name appropriately
478        let name = if table_index == 0 {
479            // Read name string as literal
480            let (name, name_len) = decode_string(&buf[consumed..])?;
481            consumed += name_len;
482            name
483        } else {
484            // Read name indexed from the table
485            let (name, _) = self.get_from_table(table_index)?;
486            Cow::Borrowed(name)
487        };
488
489        // Now read the value as a literal...
490        let (value, value_len) = decode_string(&buf[consumed..])?;
491        consumed += value_len;
492
493        Ok(((name, value), consumed))
494    }
495
496    /// Handles processing the `SizeUpdate` HPACK block: updates the maximum
497    /// size of the underlying dynamic table, possibly causing a number of
498    /// headers to be evicted from it.
499    ///
500    /// Assumes that the first byte in the given buffer `buf` is the first
501    /// octet in the `SizeUpdate` block.
502    ///
503    /// Returns the number of octets consumed from the given buffer.
504    fn update_max_dynamic_size(&mut self, buf: &[u8]) -> Result<usize, DecoderError> {
505        let (new_size, consumed) = decode_integer(buf, 5).ok().unwrap();
506        if let Some(max_size) = self.max_allowed_table_size {
507            if new_size > max_size {
508                return Err(DecoderError::InvalidMaxDynamicSize);
509            }
510        }
511        self.header_table.dynamic_table.set_max_table_size(new_size);
512
513        trace!(
514            "Decoder changed max table size from {} to {}",
515            self.header_table.dynamic_table.get_size(),
516            new_size
517        );
518
519        Ok(consumed)
520    }
521}
522
523#[cfg(test)]
524mod tests {
525    use super::decode_integer;
526
527    use std::borrow::Cow;
528
529    use super::super::encoder::encode_integer;
530    use super::super::huffman::HuffmanDecoderError;
531    use super::decode_string;
532    use super::Decoder;
533    use super::FieldRepresentation;
534    use super::{DecoderError, DecoderResult};
535    use super::{IntegerDecodingError, StringDecodingError};
536
537    /// Tests that valid integer encodings are properly decoded.
538    #[test]
539    fn test_decode_integer() {
540        assert_eq!((10, 1), decode_integer(&[10], 5).ok().unwrap());
541        assert_eq!((1337, 3), decode_integer(&[31, 154, 10], 5).ok().unwrap());
542        assert_eq!(
543            (1337, 3),
544            decode_integer(&[31 + 32, 154, 10], 5).ok().unwrap()
545        );
546        assert_eq!(
547            (1337, 3),
548            decode_integer(&[31 + 64, 154, 10], 5).ok().unwrap()
549        );
550        assert_eq!(
551            (1337, 3),
552            decode_integer(&[31, 154, 10, 111, 22], 5).ok().unwrap()
553        );
554
555        assert_eq!((127, 2), decode_integer(&[255, 0], 7).ok().unwrap());
556        assert_eq!((127, 2), decode_integer(&[127, 0], 7).ok().unwrap());
557        assert_eq!((255, 3), decode_integer(&[127, 128, 1], 7).ok().unwrap());
558        assert_eq!((255, 2), decode_integer(&[255, 0], 8).unwrap());
559        assert_eq!((254, 1), decode_integer(&[254], 8).unwrap());
560        assert_eq!((1, 1), decode_integer(&[1], 8).unwrap());
561        assert_eq!((0, 1), decode_integer(&[0], 8).unwrap());
562        // The largest allowed integer correctly gets decoded...
563        assert_eq!(
564            (268435710, 5),
565            decode_integer(&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF - 128], 8)
566                .ok()
567                .unwrap()
568        );
569    }
570
571    /// A helper macro that asserts that a given `DecoderResult` represents
572    /// the given `IntegerDecodingError`.
573    macro_rules! assert_integer_err (
574        ($err_type:expr, $decoder_result:expr) => (
575            assert_eq!($err_type, match $decoder_result {
576                Err(DecoderError::IntegerDecodingError(e)) => e,
577                _ => panic!("Expected a decoding error"),
578            });
579        );
580    );
581
582    /// Tests that some invalid integer encodings are detected and signalled as
583    /// errors.
584    #[test]
585    fn test_decode_integer_errors() {
586        assert_integer_err!(
587            IntegerDecodingError::NotEnoughOctets,
588            decode_integer(&[], 5)
589        );
590        assert_integer_err!(
591            IntegerDecodingError::NotEnoughOctets,
592            decode_integer(&[0xFF, 0xFF], 5)
593        );
594        assert_integer_err!(
595            IntegerDecodingError::TooManyOctets,
596            decode_integer(
597                &[0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80],
598                1
599            )
600        );
601        assert_integer_err!(
602            IntegerDecodingError::TooManyOctets,
603            decode_integer(&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0], 8)
604        );
605        assert_integer_err!(
606            IntegerDecodingError::InvalidPrefix,
607            decode_integer(&[10], 0)
608        );
609        assert_integer_err!(
610            IntegerDecodingError::InvalidPrefix,
611            decode_integer(&[10], 9)
612        );
613    }
614
615    #[test]
616    fn test_detect_literal_without_indexing() {
617        assert!(matches!(
618            FieldRepresentation::new(0),
619            FieldRepresentation::LiteralWithoutIndexing
620        ));
621        assert!(matches!(
622            FieldRepresentation::new((1 << 4) - 1),
623            FieldRepresentation::LiteralWithoutIndexing
624        ));
625        assert!(matches!(
626            FieldRepresentation::new(2),
627            FieldRepresentation::LiteralWithoutIndexing
628        ));
629    }
630
631    #[test]
632    fn test_detect_literal_never_indexed() {
633        assert!(matches!(
634            FieldRepresentation::new(1 << 4),
635            FieldRepresentation::LiteralNeverIndexed
636        ));
637        assert!(matches!(
638            FieldRepresentation::new((1 << 4) + 15),
639            FieldRepresentation::LiteralNeverIndexed
640        ));
641    }
642
643    #[test]
644    fn test_detect_literal_incremental_indexing() {
645        assert!(matches!(
646            FieldRepresentation::new(1 << 6),
647            FieldRepresentation::LiteralWithIncrementalIndexing
648        ));
649        assert!(matches!(
650            FieldRepresentation::new((1 << 6) + (1 << 4)),
651            FieldRepresentation::LiteralWithIncrementalIndexing
652        ));
653        assert!(matches!(
654            FieldRepresentation::new((1 << 7) - 1),
655            FieldRepresentation::LiteralWithIncrementalIndexing
656        ));
657    }
658
659    #[test]
660    fn test_detect_indexed() {
661        assert!(matches!(
662            FieldRepresentation::new(1 << 7),
663            FieldRepresentation::Indexed
664        ));
665        assert!(matches!(
666            FieldRepresentation::new((1 << 7) + (1 << 4)),
667            FieldRepresentation::Indexed
668        ));
669        assert!(matches!(
670            FieldRepresentation::new((1 << 7) + (1 << 5)),
671            FieldRepresentation::Indexed
672        ));
673        assert!(matches!(
674            FieldRepresentation::new((1 << 7) + (1 << 6)),
675            FieldRepresentation::Indexed
676        ));
677        assert!(matches!(
678            FieldRepresentation::new(255),
679            FieldRepresentation::Indexed
680        ));
681    }
682
683    #[test]
684    fn test_detect_dynamic_table_size_update() {
685        assert!(matches!(
686            FieldRepresentation::new(1 << 5),
687            FieldRepresentation::SizeUpdate
688        ));
689        assert!(matches!(
690            FieldRepresentation::new((1 << 5) + (1 << 4)),
691            FieldRepresentation::SizeUpdate
692        ));
693        assert!(matches!(
694            FieldRepresentation::new((1 << 6) - 1),
695            FieldRepresentation::SizeUpdate
696        ));
697    }
698
699    #[test]
700    fn test_decode_string_no_huffman() {
701        /// Checks that the result matches the expectation, but also that the `Cow` is borrowed!
702        fn assert_borrowed_eq(expected: (&[u8], usize), result: (Cow<'_, [u8]>, usize)) {
703            let (expected_str, expected_len) = expected;
704            let (actual_str, actual_len) = result;
705            assert_eq!(expected_len, actual_len);
706            match actual_str {
707                Cow::Borrowed(actual) => assert_eq!(actual, expected_str),
708                _ => panic!("Expected the result to be borrowed!"),
709            };
710        }
711
712        assert_eq!(
713            (Cow::Borrowed(&b"abc"[..]), 4),
714            decode_string(&[3, b'a', b'b', b'c']).ok().unwrap()
715        );
716        assert_eq!(
717            (Cow::Borrowed(&b"a"[..]), 2),
718            decode_string(&[1, b'a']).ok().unwrap()
719        );
720        assert_eq!(
721            (Cow::Borrowed(&b""[..]), 1),
722            decode_string(&[0, b'a']).ok().unwrap()
723        );
724
725        assert_borrowed_eq(
726            (&b"abc"[..], 4),
727            decode_string(&[3, b'a', b'b', b'c']).ok().unwrap(),
728        );
729        assert_borrowed_eq((&b"a"[..], 2), decode_string(&[1, b'a']).ok().unwrap());
730        assert_borrowed_eq((&b""[..], 1), decode_string(&[0, b'a']).ok().unwrap());
731
732        // Buffer smaller than advertised string length
733        assert_eq!(
734            StringDecodingError::NotEnoughOctets,
735            match decode_string(&[3, b'a', b'b']) {
736                Err(DecoderError::StringDecodingError(e)) => e,
737                _ => panic!("Expected NotEnoughOctets error!"),
738            }
739        );
740    }
741
742    /// Tests that an octet string is correctly decoded when it's length
743    /// is longer than what can fit into the 7-bit prefix.
744    #[test]
745    fn test_decode_string_no_huffman_long() {
746        {
747            let full_string: Vec<u8> = (0u8..200).collect();
748            let mut encoded = encode_integer(full_string.len(), 7);
749            encoded.extend(full_string.clone());
750
751            assert_eq!(
752                (Cow::Owned(full_string), encoded.len()),
753                decode_string(&encoded).ok().unwrap()
754            );
755        }
756        {
757            let full_string: Vec<u8> = (0u8..127).collect();
758            let mut encoded = encode_integer(full_string.len(), 7);
759            encoded.extend(full_string.clone());
760
761            assert_eq!(
762                (Cow::Owned(full_string), encoded.len()),
763                decode_string(&encoded).ok().unwrap()
764            );
765        }
766    }
767
768    /// Tests that a header list with only a single header found fully in the
769    /// static header table is correctly decoded.
770    /// (example from: HPACK-draft-10, C.2.4.)
771    #[test]
772    fn test_decode_fully_in_static_table() {
773        let mut decoder = Decoder::new();
774
775        let header_list = decoder.decode(&[0x82]).ok().unwrap();
776
777        assert_eq!(vec![(b":method".to_vec(), b"GET".to_vec())], header_list);
778    }
779
780    #[test]
781    fn test_decode_multiple_fully_in_static_table() {
782        let mut decoder = Decoder::new();
783
784        let header_list = decoder.decode(&[0x82, 0x86, 0x84]).ok().unwrap();
785
786        assert_eq!(
787            header_list,
788            [
789                (b":method".to_vec(), b"GET".to_vec()),
790                (b":scheme".to_vec(), b"http".to_vec()),
791                (b":path".to_vec(), b"/".to_vec()),
792            ]
793        );
794    }
795
796    /// Tests that a literal with an indexed name and literal value is correctly
797    /// decoded.
798    /// (example from: HPACK-draft-10, C.2.2.)
799    #[test]
800    fn test_decode_literal_indexed_name() {
801        let mut decoder = Decoder::new();
802        let hex_dump = [
803            0x04, 0x0c, 0x2f, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x70, 0x61, 0x74, 0x68,
804        ];
805
806        let header_list = decoder.decode(&hex_dump).ok().unwrap();
807
808        assert_eq!(
809            header_list,
810            [(b":path".to_vec(), b"/sample/path".to_vec()),]
811        );
812        // Nothing was added to the dynamic table
813        assert_eq!(decoder.header_table.dynamic_table.len(), 0);
814    }
815
816    /// Tests that a header with both a literal name and value is correctly
817    /// decoded.
818    /// (example from: HPACK-draft-10, C.2.1.)
819    #[test]
820    fn test_decode_literal_both() {
821        let mut decoder = Decoder::new();
822        let hex_dump = [
823            0x40, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79, 0x0d, 0x63,
824            0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72,
825        ];
826
827        let header_list = decoder.decode(&hex_dump).ok().unwrap();
828
829        assert_eq!(
830            header_list,
831            [(b"custom-key".to_vec(), b"custom-header".to_vec()),]
832        );
833        // The entry got added to the dynamic table?
834        assert_eq!(decoder.header_table.dynamic_table.len(), 1);
835        let expected_table = vec![(b"custom-key".to_vec(), b"custom-header".to_vec())];
836        let actual = decoder.header_table.dynamic_table.to_vec();
837        assert_eq!(actual, expected_table);
838    }
839
840    /// Tests that a header with a name indexed from the dynamic table and a
841    /// literal value is correctly decoded.
842    #[test]
843    fn test_decode_literal_name_in_dynamic() {
844        let mut decoder = Decoder::new();
845        {
846            // Prepares the context: the dynamic table contains a custom-key.
847            let hex_dump = [
848                0x40, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79, 0x0d, 0x63,
849                0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72,
850            ];
851
852            let header_list = decoder.decode(&hex_dump).ok().unwrap();
853
854            assert_eq!(
855                header_list,
856                [(b"custom-key".to_vec(), b"custom-header".to_vec()),]
857            );
858            // The entry got added to the dynamic table?
859            assert_eq!(decoder.header_table.dynamic_table.len(), 1);
860            let expected_table = vec![(b"custom-key".to_vec(), b"custom-header".to_vec())];
861            let actual = decoder.header_table.dynamic_table.to_vec();
862            assert_eq!(actual, expected_table);
863        }
864        {
865            let hex_dump = [
866                0x40 + 62, // Index 62 in the table => 1st in dynamic table
867                0x0e,
868                0x63,
869                0x75,
870                0x73,
871                0x74,
872                0x6f,
873                0x6d,
874                0x2d,
875                0x68,
876                0x65,
877                0x61,
878                0x64,
879                0x65,
880                0x72,
881                0x2d,
882            ];
883
884            let header_list = decoder.decode(&hex_dump).ok().unwrap();
885
886            assert_eq!(
887                header_list,
888                [(b"custom-key".to_vec(), b"custom-header-".to_vec()),]
889            );
890            // The entry got added to the dynamic table, so now we have two?
891            assert_eq!(decoder.header_table.dynamic_table.len(), 2);
892            let expected_table = vec![
893                (b"custom-key".to_vec(), b"custom-header-".to_vec()),
894                (b"custom-key".to_vec(), b"custom-header".to_vec()),
895            ];
896            let actual = decoder.header_table.dynamic_table.to_vec();
897            assert_eq!(actual, expected_table);
898        }
899    }
900
901    /// Tests that a header with a "never indexed" type is correctly
902    /// decoded.
903    /// (example from: HPACK-draft-10, C.2.3.)
904    #[test]
905    fn test_decode_literal_field_never_indexed() {
906        let mut decoder = Decoder::new();
907        let hex_dump = [
908            0x10, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x06, 0x73, 0x65, 0x63,
909            0x72, 0x65, 0x74,
910        ];
911
912        let header_list = decoder.decode(&hex_dump).ok().unwrap();
913
914        assert_eq!(header_list, [(b"password".to_vec(), b"secret".to_vec()),]);
915        // Nothing was added to the dynamic table
916        assert_eq!(decoder.header_table.dynamic_table.len(), 0);
917    }
918
919    /// Tests that a each header list from a sequence of requests is correctly
920    /// decoded.
921    /// (example from: HPACK-draft-10, C.3.*)
922    #[test]
923    fn test_request_sequence_no_huffman() {
924        let mut decoder = Decoder::new();
925        {
926            // First Request (C.3.1.)
927            let hex_dump = [
928                0x82, 0x86, 0x84, 0x41, 0x0f, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70,
929                0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
930            ];
931
932            let header_list = decoder.decode(&hex_dump).ok().unwrap();
933
934            assert_eq!(
935                header_list,
936                [
937                    (b":method".to_vec(), b"GET".to_vec()),
938                    (b":scheme".to_vec(), b"http".to_vec()),
939                    (b":path".to_vec(), b"/".to_vec()),
940                    (b":authority".to_vec(), b"www.example.com".to_vec()),
941                ]
942            );
943            // Only one entry got added to the dynamic table?
944            assert_eq!(decoder.header_table.dynamic_table.len(), 1);
945            let expected_table = vec![(b":authority".to_vec(), b"www.example.com".to_vec())];
946            let actual = decoder.header_table.dynamic_table.to_vec();
947            assert_eq!(actual, expected_table);
948        }
949        {
950            // Second Request (C.3.2.)
951            let hex_dump = [
952                0x82, 0x86, 0x84, 0xbe, 0x58, 0x08, 0x6e, 0x6f, 0x2d, 0x63, 0x61, 0x63, 0x68, 0x65,
953            ];
954
955            let header_list = decoder.decode(&hex_dump).ok().unwrap();
956
957            assert_eq!(
958                header_list,
959                [
960                    (b":method".to_vec(), b"GET".to_vec()),
961                    (b":scheme".to_vec(), b"http".to_vec()),
962                    (b":path".to_vec(), b"/".to_vec()),
963                    (b":authority".to_vec(), b"www.example.com".to_vec()),
964                    (b"cache-control".to_vec(), b"no-cache".to_vec()),
965                ]
966            );
967            // One entry got added to the dynamic table, so we have two?
968            let expected_table = vec![
969                (b"cache-control".to_vec(), b"no-cache".to_vec()),
970                (b":authority".to_vec(), b"www.example.com".to_vec()),
971            ];
972            let actual = decoder.header_table.dynamic_table.to_vec();
973            assert_eq!(actual, expected_table);
974        }
975        {
976            // Third Request (C.3.3.)
977            let hex_dump = [
978                0x82, 0x87, 0x85, 0xbf, 0x40, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b,
979                0x65, 0x79, 0x0c, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x76, 0x61, 0x6c, 0x75,
980                0x65,
981            ];
982
983            let header_list = decoder.decode(&hex_dump).ok().unwrap();
984
985            assert_eq!(
986                header_list,
987                [
988                    (b":method".to_vec(), b"GET".to_vec()),
989                    (b":scheme".to_vec(), b"https".to_vec()),
990                    (b":path".to_vec(), b"/index.html".to_vec()),
991                    (b":authority".to_vec(), b"www.example.com".to_vec()),
992                    (b"custom-key".to_vec(), b"custom-value".to_vec()),
993                ]
994            );
995            // One entry got added to the dynamic table, so we have three at
996            // this point...?
997            let expected_table = vec![
998                (b"custom-key".to_vec(), b"custom-value".to_vec()),
999                (b"cache-control".to_vec(), b"no-cache".to_vec()),
1000                (b":authority".to_vec(), b"www.example.com".to_vec()),
1001            ];
1002            let actual = decoder.header_table.dynamic_table.to_vec();
1003            assert_eq!(actual, expected_table);
1004        }
1005    }
1006
1007    /// Tests that a each header list from a sequence of responses is correctly
1008    /// decoded.
1009    /// (example from: HPACK-draft-10, C.5.*)
1010    #[test]
1011    fn response_sequence_no_huffman() {
1012        let mut decoder = Decoder::new();
1013        // The example sets the max table size to 256 octets.
1014        decoder.set_max_table_size(256);
1015        {
1016            // First Response (C.5.1.)
1017            let hex_dump = [
1018                0x48, 0x03, 0x33, 0x30, 0x32, 0x58, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65,
1019                0x61, 0x1d, 0x4d, 0x6f, 0x6e, 0x2c, 0x20, 0x32, 0x31, 0x20, 0x4f, 0x63, 0x74, 0x20,
1020                0x32, 0x30, 0x31, 0x33, 0x20, 0x32, 0x30, 0x3a, 0x31, 0x33, 0x3a, 0x32, 0x31, 0x20,
1021                0x47, 0x4d, 0x54, 0x6e, 0x17, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77,
1022                0x77, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
1023            ];
1024
1025            let header_list = decoder.decode(&hex_dump).ok().unwrap();
1026
1027            assert_eq!(
1028                header_list,
1029                [
1030                    (b":status".to_vec(), b"302".to_vec()),
1031                    (b"cache-control".to_vec(), b"private".to_vec()),
1032                    (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1033                    (b"location".to_vec(), b"https://www.example.com".to_vec()),
1034                ]
1035            );
1036            // All entries in the dynamic table too?
1037            let expected_table = vec![
1038                (b"location".to_vec(), b"https://www.example.com".to_vec()),
1039                (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1040                (b"cache-control".to_vec(), b"private".to_vec()),
1041                (b":status".to_vec(), b"302".to_vec()),
1042            ];
1043            let actual = decoder.header_table.dynamic_table.to_vec();
1044            assert_eq!(actual, expected_table);
1045        }
1046        {
1047            // Second Response (C.5.2.)
1048            let hex_dump = [0x48, 0x03, 0x33, 0x30, 0x37, 0xc1, 0xc0, 0xbf];
1049
1050            let header_list = decoder.decode(&hex_dump).ok().unwrap();
1051
1052            assert_eq!(
1053                header_list,
1054                [
1055                    (b":status".to_vec(), b"307".to_vec()),
1056                    (b"cache-control".to_vec(), b"private".to_vec()),
1057                    (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1058                    (b"location".to_vec(), b"https://www.example.com".to_vec()),
1059                ]
1060            );
1061            // The new status replaces the old status in the table, since it
1062            // cannot fit without evicting something from the table.
1063            let expected_table = vec![
1064                (b":status".to_vec(), b"307".to_vec()),
1065                (b"location".to_vec(), b"https://www.example.com".to_vec()),
1066                (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1067                (b"cache-control".to_vec(), b"private".to_vec()),
1068            ];
1069            let actual = decoder.header_table.dynamic_table.to_vec();
1070            assert_eq!(actual, expected_table);
1071        }
1072        {
1073            // Third Response (C.5.3.)
1074            let hex_dump = [
1075                0x88, 0xc1, 0x61, 0x1d, 0x4d, 0x6f, 0x6e, 0x2c, 0x20, 0x32, 0x31, 0x20, 0x4f, 0x63,
1076                0x74, 0x20, 0x32, 0x30, 0x31, 0x33, 0x20, 0x32, 0x30, 0x3a, 0x31, 0x33, 0x3a, 0x32,
1077                0x32, 0x20, 0x47, 0x4d, 0x54, 0xc0, 0x5a, 0x04, 0x67, 0x7a, 0x69, 0x70, 0x77, 0x38,
1078                0x66, 0x6f, 0x6f, 0x3d, 0x41, 0x53, 0x44, 0x4a, 0x4b, 0x48, 0x51, 0x4b, 0x42, 0x5a,
1079                0x58, 0x4f, 0x51, 0x57, 0x45, 0x4f, 0x50, 0x49, 0x55, 0x41, 0x58, 0x51, 0x57, 0x45,
1080                0x4f, 0x49, 0x55, 0x3b, 0x20, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65, 0x3d, 0x33,
1081                0x36, 0x30, 0x30, 0x3b, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3d, 0x31,
1082            ];
1083
1084            let header_list = decoder.decode(&hex_dump).ok().unwrap();
1085
1086            let expected_header_list = [
1087                (b":status".to_vec(), b"200".to_vec()),
1088                (b"cache-control".to_vec(), b"private".to_vec()),
1089                (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:22 GMT".to_vec()),
1090                (b"location".to_vec(), b"https://www.example.com".to_vec()),
1091                (b"content-encoding".to_vec(), b"gzip".to_vec()),
1092                (
1093                    b"set-cookie".to_vec(),
1094                    b"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1".to_vec(),
1095                ),
1096            ];
1097            assert_eq!(header_list, expected_header_list);
1098            // The new status replaces the old status in the table, since it
1099            // cannot fit without evicting something from the table.
1100            let expected_table = vec![
1101                (
1102                    b"set-cookie".to_vec(),
1103                    b"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1".to_vec(),
1104                ),
1105                (b"content-encoding".to_vec(), b"gzip".to_vec()),
1106                (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:22 GMT".to_vec()),
1107            ];
1108            let actual = decoder.header_table.dynamic_table.to_vec();
1109            assert_eq!(actual, expected_table);
1110        }
1111    }
1112
1113    /// Tests that when the decoder receives an update of the max dynamic table
1114    /// size as 0, all entries are cleared from the dynamic table.
1115    #[test]
1116    fn test_decoder_clear_dynamic_table() {
1117        let mut decoder = Decoder::new();
1118        decoder.allow_trailing_size_updates = true;
1119
1120        {
1121            let hex_dump = [
1122                0x48, 0x03, 0x33, 0x30, 0x32, 0x58, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65,
1123                0x61, 0x1d, 0x4d, 0x6f, 0x6e, 0x2c, 0x20, 0x32, 0x31, 0x20, 0x4f, 0x63, 0x74, 0x20,
1124                0x32, 0x30, 0x31, 0x33, 0x20, 0x32, 0x30, 0x3a, 0x31, 0x33, 0x3a, 0x32, 0x31, 0x20,
1125                0x47, 0x4d, 0x54, 0x6e, 0x17, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77,
1126                0x77, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
1127            ];
1128
1129            let header_list = decoder.decode(&hex_dump).ok().unwrap();
1130
1131            assert_eq!(
1132                header_list,
1133                [
1134                    (b":status".to_vec(), b"302".to_vec()),
1135                    (b"cache-control".to_vec(), b"private".to_vec()),
1136                    (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1137                    (b"location".to_vec(), b"https://www.example.com".to_vec()),
1138                ]
1139            );
1140            // All entries in the dynamic table too?
1141            let expected_table = vec![
1142                (b"location".to_vec(), b"https://www.example.com".to_vec()),
1143                (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1144                (b"cache-control".to_vec(), b"private".to_vec()),
1145                (b":status".to_vec(), b"302".to_vec()),
1146            ];
1147            let actual = decoder.header_table.dynamic_table.to_vec();
1148            assert_eq!(actual, expected_table);
1149        }
1150        {
1151            let hex_dump = [
1152                0x48, 0x03, 0x33, 0x30, 0x37, 0xc1, 0xc0, 0xbf,
1153                // This instructs the decoder to clear the list
1154                // (it's doubtful that it would ever be found there in a real
1155                // response, though...)
1156                0x20,
1157            ];
1158
1159            let header_list = decoder.decode(&hex_dump).ok().unwrap();
1160
1161            // Headers have been correctly decoded...
1162            assert_eq!(
1163                header_list,
1164                [
1165                    (b":status".to_vec(), b"307".to_vec()),
1166                    (b"cache-control".to_vec(), b"private".to_vec()),
1167                    (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1168                    (b"location".to_vec(), b"https://www.example.com".to_vec()),
1169                ]
1170            );
1171            // Expect an empty table!
1172            let expected_table = vec![];
1173            let actual = decoder.header_table.dynamic_table.to_vec();
1174            assert_eq!(actual, expected_table);
1175            assert_eq!(0, decoder.header_table.dynamic_table.get_max_table_size());
1176        }
1177    }
1178
1179    /// Tests that a each header list from a sequence of requests is correctly
1180    /// decoded, when Huffman coding is used
1181    /// (example from: HPACK-draft-10, C.4.*)
1182    #[test]
1183    fn request_sequence_huffman() {
1184        let mut decoder = Decoder::new();
1185        {
1186            // First Request (B.4.1.)
1187            let hex_dump = [
1188                0x82, 0x86, 0x84, 0x41, 0x8c, 0xf1, 0xe3, 0xc2, 0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab,
1189                0x90, 0xf4, 0xff,
1190            ];
1191
1192            let header_list = decoder.decode(&hex_dump).ok().unwrap();
1193
1194            assert_eq!(
1195                header_list,
1196                [
1197                    (b":method".to_vec(), b"GET".to_vec()),
1198                    (b":scheme".to_vec(), b"http".to_vec()),
1199                    (b":path".to_vec(), b"/".to_vec()),
1200                    (b":authority".to_vec(), b"www.example.com".to_vec()),
1201                ]
1202            );
1203            // Only one entry got added to the dynamic table?
1204            assert_eq!(decoder.header_table.dynamic_table.len(), 1);
1205            let expected_table = vec![(b":authority".to_vec(), b"www.example.com".to_vec())];
1206            let actual = decoder.header_table.dynamic_table.to_vec();
1207            assert_eq!(actual, expected_table);
1208        }
1209        {
1210            // Second Request (C.4.2.)
1211            let hex_dump = [
1212                0x82, 0x86, 0x84, 0xbe, 0x58, 0x86, 0xa8, 0xeb, 0x10, 0x64, 0x9c, 0xbf,
1213            ];
1214
1215            let header_list = decoder.decode(&hex_dump).ok().unwrap();
1216
1217            assert_eq!(
1218                header_list,
1219                [
1220                    (b":method".to_vec(), b"GET".to_vec()),
1221                    (b":scheme".to_vec(), b"http".to_vec()),
1222                    (b":path".to_vec(), b"/".to_vec()),
1223                    (b":authority".to_vec(), b"www.example.com".to_vec()),
1224                    (b"cache-control".to_vec(), b"no-cache".to_vec()),
1225                ]
1226            );
1227            // One entry got added to the dynamic table, so we have two?
1228            let expected_table = vec![
1229                (b"cache-control".to_vec(), b"no-cache".to_vec()),
1230                (b":authority".to_vec(), b"www.example.com".to_vec()),
1231            ];
1232            let actual = decoder.header_table.dynamic_table.to_vec();
1233            assert_eq!(actual, expected_table);
1234        }
1235        {
1236            // Third Request (C.4.3.)
1237            let hex_dump = [
1238                0x82, 0x87, 0x85, 0xbf, 0x40, 0x88, 0x25, 0xa8, 0x49, 0xe9, 0x5b, 0xa9, 0x7d, 0x7f,
1239                0x89, 0x25, 0xa8, 0x49, 0xe9, 0x5b, 0xb8, 0xe8, 0xb4, 0xbf,
1240            ];
1241
1242            let header_list = decoder.decode(&hex_dump).ok().unwrap();
1243
1244            assert_eq!(
1245                header_list,
1246                [
1247                    (b":method".to_vec(), b"GET".to_vec()),
1248                    (b":scheme".to_vec(), b"https".to_vec()),
1249                    (b":path".to_vec(), b"/index.html".to_vec()),
1250                    (b":authority".to_vec(), b"www.example.com".to_vec()),
1251                    (b"custom-key".to_vec(), b"custom-value".to_vec()),
1252                ]
1253            );
1254            // One entry got added to the dynamic table, so we have three at
1255            // this point...?
1256            let expected_table = vec![
1257                (b"custom-key".to_vec(), b"custom-value".to_vec()),
1258                (b"cache-control".to_vec(), b"no-cache".to_vec()),
1259                (b":authority".to_vec(), b"www.example.com".to_vec()),
1260            ];
1261            let actual = decoder.header_table.dynamic_table.to_vec();
1262            assert_eq!(actual, expected_table);
1263        }
1264    }
1265
1266    /// Tests that a each header list from a sequence of responses is correctly
1267    /// decoded, when Huffman encoding is used
1268    /// (example from: HPACK-draft-10, C.6.*)
1269    #[test]
1270    fn response_sequence_huffman() {
1271        let mut decoder = Decoder::new();
1272        // The example sets the max table size to 256 octets.
1273        decoder.set_max_table_size(256);
1274        {
1275            // First Response (C.6.1.)
1276            let hex_dump = [
1277                0x48, 0x82, 0x64, 0x02, 0x58, 0x85, 0xae, 0xc3, 0x77, 0x1a, 0x4b, 0x61, 0x96, 0xd0,
1278                0x7a, 0xbe, 0x94, 0x10, 0x54, 0xd4, 0x44, 0xa8, 0x20, 0x05, 0x95, 0x04, 0x0b, 0x81,
1279                0x66, 0xe0, 0x82, 0xa6, 0x2d, 0x1b, 0xff, 0x6e, 0x91, 0x9d, 0x29, 0xad, 0x17, 0x18,
1280                0x63, 0xc7, 0x8f, 0x0b, 0x97, 0xc8, 0xe9, 0xae, 0x82, 0xae, 0x43, 0xd3,
1281            ];
1282
1283            let header_list = decoder.decode(&hex_dump).ok().unwrap();
1284
1285            assert_eq!(
1286                header_list,
1287                [
1288                    (b":status".to_vec(), b"302".to_vec()),
1289                    (b"cache-control".to_vec(), b"private".to_vec()),
1290                    (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1291                    (b"location".to_vec(), b"https://www.example.com".to_vec()),
1292                ]
1293            );
1294            // All entries in the dynamic table too?
1295            let expected_table = vec![
1296                (b"location".to_vec(), b"https://www.example.com".to_vec()),
1297                (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1298                (b"cache-control".to_vec(), b"private".to_vec()),
1299                (b":status".to_vec(), b"302".to_vec()),
1300            ];
1301            let actual = decoder.header_table.dynamic_table.to_vec();
1302            assert_eq!(actual, expected_table);
1303        }
1304        {
1305            // Second Response (C.6.2.)
1306            let hex_dump = [0x48, 0x83, 0x64, 0x0e, 0xff, 0xc1, 0xc0, 0xbf];
1307
1308            let header_list = decoder.decode(&hex_dump).ok().unwrap();
1309
1310            assert_eq!(
1311                header_list,
1312                [
1313                    (b":status".to_vec(), b"307".to_vec()),
1314                    (b"cache-control".to_vec(), b"private".to_vec()),
1315                    (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1316                    (b"location".to_vec(), b"https://www.example.com".to_vec()),
1317                ]
1318            );
1319            // The new status replaces the old status in the table, since it
1320            // cannot fit without evicting something from the table.
1321            let expected_table = vec![
1322                (b":status".to_vec(), b"307".to_vec()),
1323                (b"location".to_vec(), b"https://www.example.com".to_vec()),
1324                (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1325                (b"cache-control".to_vec(), b"private".to_vec()),
1326            ];
1327            let actual = decoder.header_table.dynamic_table.to_vec();
1328            assert_eq!(actual, expected_table);
1329        }
1330        {
1331            // Third Response (C.6.3.)
1332            let hex_dump = [
1333                0x88, 0xc1, 0x61, 0x96, 0xd0, 0x7a, 0xbe, 0x94, 0x10, 0x54, 0xd4, 0x44, 0xa8, 0x20,
1334                0x05, 0x95, 0x04, 0x0b, 0x81, 0x66, 0xe0, 0x84, 0xa6, 0x2d, 0x1b, 0xff, 0xc0, 0x5a,
1335                0x83, 0x9b, 0xd9, 0xab, 0x77, 0xad, 0x94, 0xe7, 0x82, 0x1d, 0xd7, 0xf2, 0xe6, 0xc7,
1336                0xb3, 0x35, 0xdf, 0xdf, 0xcd, 0x5b, 0x39, 0x60, 0xd5, 0xaf, 0x27, 0x08, 0x7f, 0x36,
1337                0x72, 0xc1, 0xab, 0x27, 0x0f, 0xb5, 0x29, 0x1f, 0x95, 0x87, 0x31, 0x60, 0x65, 0xc0,
1338                0x03, 0xed, 0x4e, 0xe5, 0xb1, 0x06, 0x3d, 0x50, 0x07,
1339            ];
1340
1341            let header_list = decoder.decode(&hex_dump).ok().unwrap();
1342
1343            let expected_header_list = [
1344                (b":status".to_vec(), b"200".to_vec()),
1345                (b"cache-control".to_vec(), b"private".to_vec()),
1346                (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:22 GMT".to_vec()),
1347                (b"location".to_vec(), b"https://www.example.com".to_vec()),
1348                (b"content-encoding".to_vec(), b"gzip".to_vec()),
1349                (
1350                    b"set-cookie".to_vec(),
1351                    b"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1".to_vec(),
1352                ),
1353            ];
1354            assert_eq!(header_list, expected_header_list);
1355            // The new status replaces the old status in the table, since it
1356            // cannot fit without evicting something from the table.
1357            let expected_table = vec![
1358                (
1359                    b"set-cookie".to_vec(),
1360                    b"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1".to_vec(),
1361                ),
1362                (b"content-encoding".to_vec(), b"gzip".to_vec()),
1363                (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:22 GMT".to_vec()),
1364            ];
1365            let actual = decoder.header_table.dynamic_table.to_vec();
1366            assert_eq!(actual, expected_table);
1367        }
1368    }
1369
1370    /// Helper function that verifies whether the given `DecoderResult`
1371    /// indicates the given `DecoderError`
1372    fn is_decoder_error(err: &DecoderError, result: &DecoderResult) -> bool {
1373        match *result {
1374            Err(ref e) => e == err,
1375            _ => false,
1376        }
1377    }
1378
1379    /// Tests that when a header representation indicates an indexed header
1380    /// encoding, but the index is out of valid bounds, the appropriate error
1381    /// is returned by the decoder.
1382    #[test]
1383    fn test_index_out_of_bounds() {
1384        let mut decoder = Decoder::new();
1385        // Some fixtures of raw messages which definitely need to cause an
1386        // index out of bounds error.
1387        let raw_messages = [
1388            // This indicates that the index of the header is 0, which is
1389            // invalid...
1390            vec![0x80],
1391            // This indicates that the index of the header is 62, which is out
1392            // of the bounds of the header table, given that there are no
1393            // entries in the dynamic table and the static table contains 61
1394            // elements.
1395            vec![0xbe],
1396            // Literal encoded with an indexed name where the index is out of
1397            // bounds.
1398            vec![126, 1, 65],
1399        ];
1400
1401        // Check them all...
1402        for raw_message in raw_messages.iter() {
1403            assert!(
1404                is_decoder_error(
1405                    &DecoderError::HeaderIndexOutOfBounds,
1406                    &decoder.decode(raw_message)
1407                ),
1408                "Expected index out of bounds"
1409            );
1410        }
1411    }
1412
1413    /// Tests that if a header encoded using a literal string representation
1414    /// (using Huffman encoding) contains an invalid string encoding, an error
1415    /// is returned.
1416    #[test]
1417    fn test_invalid_literal_huffman_string() {
1418        let mut decoder = Decoder::new();
1419        // Invalid padding introduced into the message
1420        let hex_dump = [
1421            0x82, 0x86, 0x84, 0x41, 0x8c, 0xf1, 0xe3, 0xc2, 0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab,
1422            0x90, 0xf4, 0xfe,
1423        ];
1424
1425        assert!(matches!(
1426            decoder.decode(&hex_dump),
1427            Err(DecoderError::StringDecodingError(
1428                StringDecodingError::HuffmanDecoderError(HuffmanDecoderError::InvalidPadding,)
1429            ))
1430        ));
1431    }
1432
1433    /// Tests that if the message cuts short before the header key is decoded,
1434    /// we get an appropriate error.
1435    #[test]
1436    fn test_literal_header_key_incomplete() {
1437        let mut decoder = Decoder::new();
1438        // The message does not have the length specifier of the header value
1439        // (cuts short after the header key is complete)
1440        let hex_dump = [
1441            0x40, 0x0a, b'c', b'u', b's', b't', b'o', b'm', b'-', b'k', b'e',
1442        ];
1443
1444        let result = decoder.decode(&hex_dump);
1445
1446        assert!(matches!(
1447            result,
1448            Err(DecoderError::StringDecodingError(
1449                StringDecodingError::NotEnoughOctets
1450            ))
1451        ));
1452    }
1453
1454    /// Tests that when a header is encoded as a literal with both a name and
1455    /// a value, if the value is missing, we get an error.
1456    #[test]
1457    fn test_literal_header_missing_value() {
1458        let mut decoder = Decoder::new();
1459        // The message does not have the length specifier of the header value
1460        // (cuts short after the header key is complete)
1461        let hex_dump = [
1462            0x40, 0x0a, b'c', b'u', b's', b't', b'o', b'm', b'-', b'k', b'e', b'y',
1463        ];
1464
1465        let result = decoder.decode(&hex_dump);
1466
1467        assert!(matches!(
1468            result,
1469            Err(DecoderError::IntegerDecodingError(
1470                IntegerDecodingError::NotEnoughOctets
1471            ))
1472        ));
1473    }
1474}
1475
1476/// The module defines interop tests between this HPACK decoder
1477/// and some other encoder implementations, based on their results
1478/// published at
1479/// [http2jp/hpack-test-case](https://github.com/http2jp/hpack-test-case)
1480#[cfg(test)]
1481#[cfg(feature = "interop-tests")]
1482mod interop_tests {
1483    use std::fs;
1484    use std::path::{Path, PathBuf};
1485    use std::{borrow::Cow, collections::HashMap};
1486
1487    use serde::Deserialize;
1488    use tracing::debug;
1489
1490    use super::Decoder;
1491
1492    #[derive(Deserialize)]
1493    struct RawTestStory<'a> {
1494        cases: Vec<RawTestFixture<'a>>,
1495    }
1496
1497    #[derive(Deserialize)]
1498    struct RawTestFixture<'a> {
1499        // The raw bytes of the message, as a hex-encoded string.
1500        wire: Cow<'a, str>,
1501
1502        // The headers of the message: each HashMap has a single key-value pair
1503        headers: Vec<HashMap<Cow<'a, str>, Cow<'a, str>>>,
1504    }
1505
1506    /// Defines the structure of a single part of a story file. We only care
1507    /// about the bytes and corresponding headers and ignore the rest.
1508    struct TestFixture {
1509        wire_bytes: Vec<u8>,
1510        headers: Vec<(Vec<u8>, Vec<u8>)>,
1511    }
1512
1513    /// Defines the structure corresponding to a full story file. We only
1514    /// care about the cases for now.
1515    struct TestStory {
1516        cases: Vec<TestFixture>,
1517    }
1518
1519    #[derive(Debug, thiserror::Error)]
1520    enum DecodeError {
1521        #[error("Failed to parse hex-encoded bytes: {0}")]
1522        FromHex(#[from] hex::FromHexError),
1523    }
1524
1525    impl TryFrom<RawTestStory<'_>> for TestStory {
1526        type Error = DecodeError;
1527
1528        fn try_from(raw_story: RawTestStory) -> Result<Self, Self::Error> {
1529            let mut cases = Vec::with_capacity(raw_story.cases.len());
1530            for raw_case in raw_story.cases {
1531                let wire_bytes = hex::decode(raw_case.wire.as_bytes())?;
1532
1533                let headers: Vec<_> = raw_case
1534                    .headers
1535                    .into_iter()
1536                    .flat_map(|h| {
1537                        h.into_iter().map(|(k, v)| {
1538                            (k.into_owned().into_bytes(), v.into_owned().into_bytes())
1539                        })
1540                    })
1541                    .collect();
1542
1543                cases.push(TestFixture {
1544                    wire_bytes,
1545                    headers,
1546                });
1547            }
1548
1549            Ok(TestStory { cases })
1550        }
1551    }
1552
1553    /// Tests that the `TestStory` can be properly read out of a JSON encoded
1554    /// string. Sanity check for the `Decodable` implementation.
1555    #[test]
1556    fn test_story_parser_sanity_check() {
1557        let raw_json = r#"
1558            {
1559              "cases": [
1560                {
1561                  "seqno": 0,
1562                  "wire": "82864188f439ce75c875fa5784",
1563                  "headers": [
1564                    {
1565                      ":method": "GET"
1566                    },
1567                    {
1568                      ":scheme": "http"
1569                    },
1570                    {
1571                      ":authority": "yahoo.co.jp"
1572                    },
1573                    {
1574                      ":path": "/"
1575                    }
1576                  ]
1577                },
1578                {
1579                  "seqno": 1,
1580                  "wire": "8286418cf1e3c2fe8739ceb90ebf4aff84",
1581                  "headers": [
1582                    {
1583                      ":method": "GET"
1584                    },
1585                    {
1586                      ":scheme": "http"
1587                    },
1588                    {
1589                      ":authority": "www.yahoo.co.jp"
1590                    },
1591                    {
1592                      ":path": "/"
1593                    }
1594                  ]
1595                }
1596              ],
1597              "draft": 9
1598            }
1599        "#;
1600
1601        let decoded: RawTestStory = serde_json::from_str(raw_json).unwrap();
1602        let decoded = TestStory::try_from(decoded).unwrap();
1603
1604        assert_eq!(decoded.cases.len(), 2);
1605        assert_eq!(
1606            decoded.cases[0].wire_bytes,
1607            vec![0x82, 0x86, 0x41, 0x88, 0xf4, 0x39, 0xce, 0x75, 0xc8, 0x75, 0xfa, 0x57, 0x84]
1608        );
1609        assert_eq!(
1610            decoded.cases[0].headers,
1611            vec![
1612                (b":method".to_vec(), b"GET".to_vec()),
1613                (b":scheme".to_vec(), b"http".to_vec()),
1614                (b":authority".to_vec(), b"yahoo.co.jp".to_vec()),
1615                (b":path".to_vec(), b"/".to_vec()),
1616            ]
1617        );
1618    }
1619
1620    /// A helper function that performs an interop test for a given story file.
1621    ///
1622    /// It does so by first decoding the JSON representation of the story into
1623    /// a `TestStory` struct. After this, each subsequent block of headers is
1624    /// passed to the same decoder instance (since each story represents one
1625    /// coder context). The result returned by the decoder is compared to the
1626    /// headers stored for that particular block within the story file.
1627    fn test_story(story_file_name: PathBuf) {
1628        // Set up the story by parsing the given file
1629        let story: TestStory = {
1630            let buf = std::fs::read_to_string(story_file_name);
1631            let raw_story: RawTestStory = serde_json::from_str(&buf.unwrap()).unwrap();
1632            raw_story.try_into().unwrap()
1633        };
1634        // Set up the decoder
1635        let mut decoder = Decoder::new();
1636        // decoder.allow_trailing_size_updates = true;
1637
1638        // Now check whether we correctly decode each case
1639        for case in story.cases.iter() {
1640            let decoded = decoder.decode(&case.wire_bytes).unwrap();
1641            assert_eq!(decoded, case.headers);
1642        }
1643    }
1644
1645    /// Tests a full fixture set, provided a path to a directory containing a
1646    /// number of story files (and no other file types).
1647    ///
1648    /// It calls the `test_story` function for each file found in the given
1649    /// directory.
1650    fn test_fixture_set(fixture_dir: &str) {
1651        let files = fs::read_dir(Path::new(fixture_dir)).unwrap();
1652
1653        for fixture in files {
1654            let file_name = fixture.unwrap().path();
1655            debug!("Testing fixture: {:?}", file_name);
1656            test_story(file_name);
1657        }
1658    }
1659
1660    #[test]
1661    fn test_nghttp2_interop() {
1662        test_fixture_set("fixtures/hpack/interop/nghttp2");
1663    }
1664
1665    #[test]
1666    fn test_nghttp2_change_table_size_interop() {
1667        test_fixture_set("fixtures/hpack/interop/nghttp2-change-table-size");
1668    }
1669
1670    #[test]
1671    fn test_go_hpack_interop() {
1672        test_fixture_set("fixtures/hpack/interop/go-hpack");
1673    }
1674
1675    #[test]
1676    fn test_node_http2_hpack_interop() {
1677        test_fixture_set("fixtures/hpack/interop/node-http2-hpack");
1678    }
1679
1680    #[test]
1681    fn test_haskell_http2_linear_huffman() {
1682        test_fixture_set("fixtures/hpack/interop/haskell-http2-linear-huffman");
1683    }
1684}