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