httlib_hpack/decoder/
mod.rs

1//! Provides an implementation of the [HPACK] decoder.
2//! 
3//! The decoder takes over the task of the decompressor, i.e. it executes the
4//! commands inversely to the encoder. It converts the data back into its
5//! readable form, ensuring that the indexing table is identical to that on the
6//! encoder side. 
7//! 
8//! The decoder is usually the one that determines how many resources can be
9//! used for the purposes of HPACK compression, among others. The decoder
10//! signals this to the encoder in the [HTTP/2] protocol with the parameter
11//! [SETTINGS_HEADER_TABLE_SIZE] using the 'SETTINGS' frame. This change is
12//! made when the settings are confirmed by both sides in a way that the HTTP/2
13//! protocol requires. In fact, the encoder is the one that actually requires a
14//! change in the size of the dynamic table to meet the requirements of the
15//! values agreed upon via the HTTP/2 protocol.
16//! 
17//! [HPACK]: https://tools.ietf.org/html/rfc7541
18//! [HTTP/2]: https://tools.ietf.org/html/rfc7540
19//! [SETTINGS_HEADER_TABLE_SIZE]: https://tools.ietf.org/html/rfc7540#section-6.5.2
20
21mod error;
22mod primitives;
23
24pub use error::*;
25use primitives::*;
26pub use httlib_huffman::DecoderSpeed;
27use super::Table;
28
29/// Provides the decoding engine for HTTP/2 headers.
30#[derive(Debug)]
31pub struct Decoder<'a> {
32    /// The number of bits to read at a time while decoding Huffman sequence.
33    /// More bits at a time mean faster decoding but at the same time a higher
34    /// memory footprint.
35    speed: DecoderSpeed,
36
37    /// The external protocol maximum allowed size of the dynamic table.
38    max_dynamic_size: u32,
39
40    /// A store for the static and the dynamic headers.
41    table: Table<'a>,
42}
43
44impl<'a> Decoder<'a> {
45    /// A flag indicating that a new header entry has been inserted into the
46    /// indexing table ([6.2.1.]).
47    pub const WITH_INDEXING: u8 = 0x4;
48
49    /// A flag indicating a sensitive header field ([6.2.3.]).
50    pub const NEVER_INDEXED: u8 = 0x8;
51
52    /// Returns a new decoder instance with a desired maximum allowed size of
53    /// the dynamic table.
54    pub fn with_dynamic_size(max_dynamic_size: u32) -> Self {
55        Self {
56            speed: DecoderSpeed::FiveBits,
57            max_dynamic_size,
58            table: Table::with_dynamic_size(max_dynamic_size),
59        }
60    }
61
62    /// Returns the maximum allowed size of the dynamic table.
63    /// 
64    /// Note that the dynamic table could actually be of different size. This
65    /// size is just a hard limit set by the external protocol.
66    pub fn max_dynamic_size(&self) -> u32 {
67        self.table.max_dynamic_size()
68    }
69
70    /// Sets the maximum allowed size of the dynamic table.
71    /// 
72    /// This size is just a hard limit that should be set by the external
73    /// protocol. Changing the size will not change the size of the actual
74    /// underlaying table. The table will be updated through the size update
75    /// signal when decoding.
76    pub fn set_max_dynamic_size(&mut self, size: u32) {
77        self.max_dynamic_size = size;
78    }
79
80    /// Decodes headers provided in HPACK's header field representation format.
81    /// 
82    /// The functions consumes the `buf` of bytes and writes header results to 
83    /// `dst`. Each item contains header name, value and flags. The decoder will
84    /// not index fields unless `0x4` flag is returned. When the `0x8` flag is
85    /// present, the header field should be treated with caution.
86    /// 
87    /// **Example:**
88    /// 
89    /// ```rust
90    /// use httlib_hpack::Decoder;
91    /// 
92    /// let mut decoder = Decoder::default();
93    /// let mut dst = Vec::new();
94    /// let mut buf = vec![0x80 | 2];
95    /// decoder.decode(&mut buf, &mut dst).unwrap();
96    /// ```
97    /// 
98    /// This function consumes the buffer only if the decoding succeeds. The
99    /// provided vector will stay untouched in case of an error.
100    pub fn decode(
101        &mut self,
102        buf: &mut Vec<u8>,
103        dst: &mut Vec<(Vec<u8>, Vec<u8>, u8)>,
104    ) -> Result<usize, DecoderError> {
105        let mut total = 0;
106        loop {
107            if buf.is_empty() {
108                return Ok(total);
109            }
110
111            let mut data = Vec::with_capacity(1);
112            total += self.decode_exact(buf, &mut data)?;
113            dst.append(&mut data);
114        }
115    }
116
117    /// Decodes the exact number of headers from the provided HPACK's sequence,
118    /// based on the available vector capacity.
119    /// 
120    /// The functions consumes the `buf` of bytes and writes header results to 
121    /// `dst`. Each item contains header name, value and flags. The decoder will
122    /// not index fields unless `0x4` flag is returned. When the `0x8` flag is
123    /// present, the header field should be treated with caution.
124    /// 
125    /// **Example:**
126    /// 
127    /// ```rust
128    /// use httlib_hpack::Decoder;
129    /// 
130    /// let mut decoder = Decoder::default();
131    /// let mut dst = Vec::with_capacity(2);
132    /// let mut buf = vec![0x80 | 2, 0x80 | 3];
133    /// decoder.decode_exact(&mut buf, &mut dst).unwrap();
134    /// ```
135    /// 
136    /// This function consumes the buffer only if the decoding succeeds. The
137    /// provided vector will stay untouched in case of an error.
138    pub fn decode_exact(
139        &mut self,
140        buf: &mut Vec<u8>,
141        dst: &mut Vec<(Vec<u8>, Vec<u8>, u8)>,
142    ) -> Result<usize, DecoderError> {
143        let mut total = 0;
144        let mut limit = dst.capacity();
145        loop {
146            if buf.is_empty() || limit == 0 {
147                return Ok(total);
148            } else {
149                limit -= 1;
150            }
151
152            let octet = buf[0];
153            if octet & 128 == 128 { // indexed
154                total += self.decode_indexed(buf, dst)?;
155            } else if octet & 64 == 64 { // with indexing
156                total += self.decode_literal(buf, dst)?;
157            } else if octet & 32 == 32 {
158                self.update_max_dynamic_size(buf)?;
159            } else if octet & 16 == 16 { // never indexed
160                total += self.decode_literal(buf, dst)?;
161            } else { // without indexing
162                total += self.decode_literal(buf, dst)?;
163            }
164        }
165    }
166
167    /// Decodes a header that exists in the indexing table.
168    /// 
169    /// The function reads the indexed header field representation and decodes
170    /// it into the provided `dst` buffer.
171    /// 
172    /// **Indexed header field representation ([6.1.], figure 5):**
173    /// 
174    /// ```txt
175    ///   0   1   2   3   4   5   6   7
176    /// +---+---+---+---+---+---+---+---+
177    /// | 1 |        Index (7+)         |
178    /// +---+---------------------------+
179    /// ```
180    /// 
181    /// This function consumes the buffer only if the decoding succeeds. The
182    /// provided vector will stay untouched in case of an error.
183    /// 
184    /// [6.1.]: https://tools.ietf.org/html/rfc7541#section-6.1
185    fn decode_indexed(
186        &self,
187        buf: &mut Vec<u8>,
188        dst: &mut Vec<(Vec<u8>, Vec<u8>, u8)>,
189    ) -> Result<usize, DecoderError> {
190        let mut index = 0;
191        let total = decode_integer(buf, &mut index, 7)?;
192
193        let (name, value) = match self.table.get(index) {
194            Some(field) => field,
195            None => return Err(DecoderError::InvalidIndex),
196        };
197        dst.push((name.to_vec(), value.to_vec(), 0x0));
198
199        buf.drain(0..total);
200        Ok(total)
201    }
202
203    /// Decodes a header represented as a literal.
204    /// 
205    /// The function reads the literal header field representation and decodes
206    /// it into the provided `dst` buffer.
207    /// 
208    /// **Literal header field with incremental indexing - indexed name
209    /// ([6.2.1.], figure 6):**
210    /// 
211    /// ```txt
212    ///   0   1   2   3   4   5   6   7
213    /// +---+---+---+---+---+---+---+---+
214    /// | 0 | 1 |      Index (6+)       | 
215    /// +---+---+-----------------------+
216    /// | H |     Value Length (7+)     |
217    /// +---+---------------------------+
218    /// | Value String (Length octets)  |
219    /// +-------------------------------+
220    /// ```
221    /// 
222    /// **Literal header field with incremental indexing - new name ([6.2.1.],
223    /// Figure 7):**
224    /// 
225    /// ```txt
226    ///   0   1   2   3   4   5   6   7
227    /// +---+---+---+---+---+---+---+---+
228    /// | 0 | 1 |           0           |
229    /// +---+---+-----------------------+
230    /// | H |     Name Length (7+)      |
231    /// +---+---------------------------+
232    /// |  Name String (Length octets)  |
233    /// +---+---------------------------+
234    /// | H |     Value Length (7+)     |
235    /// +---+---------------------------+
236    /// | Value String (Length octets)  |
237    /// +-------------------------------+
238    /// ```
239    /// 
240    /// **Literal header field without indexing - indexed name ([6.2.2.],
241    /// Figure 8):**
242    /// 
243    /// ```txt
244    ///   0   1   2   3   4   5   6   7
245    /// +---+---+---+---+---+---+---+---+
246    /// | 0 | 0 | 0 | 0 |  Index (4+)   |
247    /// +---+---+-----------------------+
248    /// | H |     Value Length (7+)     |
249    /// +---+---------------------------+
250    /// | Value String (Length octets)  |
251    /// +-------------------------------+
252    /// ```
253    /// 
254    /// **Literal header field without indexing - new name ([6.2.2.], figure 9):**
255    /// 
256    /// ```txt
257    ///   0   1   2   3   4   5   6   7
258    /// +---+---+---+---+---+---+---+---+
259    /// | 0 | 0 | 0 | 0 |       0       |
260    /// +---+---+-----------------------+
261    /// | H |     Name Length (7+)      |
262    /// +---+---------------------------+
263    /// |  Name String (Length octets)  |
264    /// +---+---------------------------+
265    /// | H |     Value Length (7+)     |
266    /// +---+---------------------------+
267    /// | Value String (Length octets)  |
268    /// +-------------------------------+
269    /// ```
270    /// 
271    /// **Literal header field never indexed - indexed name ([6.2.3.],
272    /// Figure 10):**
273    /// 
274    /// ```txt
275    ///   0   1   2   3   4   5   6   7
276    /// +---+---+---+---+---+---+---+---+
277    /// | 0 | 0 | 0 | 1 |  Index (4+)   |
278    /// +---+---+-----------------------+
279    /// | H |     Value Length (7+)     |
280    /// +---+---------------------------+
281    /// | Value String (Length octets)  |
282    /// +-------------------------------+
283    /// ```
284    /// 
285    /// **Literal header field never indexed - new name ([6.2.3.], figure 11):**
286    /// 
287    /// ```txt
288    ///   0   1   2   3   4   5   6   7
289    /// +---+---+---+---+---+---+---+---+
290    /// | 0 | 0 | 0 | 1 |       0       |
291    /// +---+---+-----------------------+
292    /// | H |     Name Length (7+)      |
293    /// +---+---------------------------+
294    /// |  Name String (Length octets)  |
295    /// +---+---------------------------+
296    /// | H |     Value Length (7+)     |
297    /// +---+---------------------------+
298    /// | Value String (Length octets)  |
299    /// +-------------------------------+
300    /// ```
301    /// 
302    /// This function consumes the buffer only if the decoding succeeds. The
303    /// provided vector will stay untouched in case of an error.
304    /// 
305    /// [6.2.1.]: https://tools.ietf.org/html/rfc7541#section-6.2.1
306    /// [6.2.2.]: https://tools.ietf.org/html/rfc7541#section-6.2.2
307    /// [6.2.3.]: https://tools.ietf.org/html/rfc7541#section-6.2.3
308    fn decode_literal(
309        &mut self,
310        buf: &mut Vec<u8>,
311        dst: &mut Vec<(Vec<u8>, Vec<u8>, u8)>,
312    ) -> Result<usize, DecoderError> {
313        let mut total = 0;
314        let octet = buf[0];
315
316        let prefix = if octet & 64 == 64 { // with indexing
317            6
318        } else { // without and never indexed
319            4
320        };
321
322        let mut index = 0;
323        total += decode_integer(&buf[total..], &mut index, prefix)?;
324
325        let name = if index == 0 {
326            let mut name = Vec::new();
327            total += decode_string(&buf[total..], self.speed, &mut name)?;
328            name
329        } else if let Some(h) = self.table.get(index) {
330            h.0.to_vec()
331        } else {
332            return Err(DecoderError::InvalidIndex);
333        };
334
335        let mut value = Vec::new();
336        total += decode_string(&buf[total..], self.speed, &mut value)?;
337
338        if octet & 64 == 64 {
339            self.table.insert(name.clone(), value.clone());        
340            dst.push((name, value, 0x4));
341        } else  if octet & 16 == 16 {
342            dst.push((name, value, 0x8));
343        } else {
344            dst.push((name, value, 0x0));
345        }
346
347        buf.drain(0..total);
348        Ok(total)
349    }
350
351    /// Decodes the dynamic table size update signal and sets the new size to
352    /// the dynamic table.
353    /// 
354    /// The new maximum size MUST be lower than or equal to the limit determined
355    /// by the protocol using HPACK. In HTTP/2, this limit is the last value of
356    /// the `SETTINGS_HEADER_TABLE_SIZE` received from the decoder and
357    /// acknowledged by the encoder.
358    /// 
359    /// **Maximum Dynamic table size change ([6.3.], figure 12):**
360    /// 
361    /// ```txt
362    ///   0   1   2   3   4   5   6   7
363    /// +---+---+---+---+---+---+---+---+
364    /// | 0 | 0 | 1 |   Max size (5+)   |
365    /// +---+---------------------------+
366    /// ```
367    /// 
368    /// This function consumes the buffer only if the decoding succeeds. The
369    /// provided vector will stay untouched in case of an error.
370    /// 
371    /// [6.3]: https://tools.ietf.org/html/rfc7541#section-6.3
372    fn update_max_dynamic_size(
373        &mut self,
374        buf: &mut Vec<u8>,
375    ) -> Result<usize, DecoderError> {
376        let mut new_size = 0;
377        let total = decode_integer(buf, &mut new_size, 5)?;
378
379        if new_size > self.max_dynamic_size {
380            return Err(DecoderError::InvalidMaxDynamicSize)
381        } else {
382            self.table.update_max_dynamic_size(new_size);
383        }
384
385        buf.drain(0..total);
386        Ok(total)
387    }
388}
389
390impl<'a> Default for Decoder<'a> {
391    fn default() -> Self {
392        let table = Table::default();
393        Self {
394            speed: DecoderSpeed::FiveBits, // fast decoding
395            max_dynamic_size: table.max_dynamic_size(),
396            table,
397        }
398    }
399}
400
401#[cfg(test)]
402mod test {
403    use super::*;
404
405    /// Should decode the HPACK's indexed header field representation into a
406    /// header that exists in the indexing table ([6.1.], figure 5).
407    /// 
408    /// [6.1.]: https://tools.ietf.org/html/rfc7541#section-6.1
409    #[test]
410    fn decodes_indexed() {
411        let mut decoder = Decoder::default();
412        let mut dst = Vec::new();
413        let mut buf = vec![
414            0x80 | 2, // index 2
415            0x80 | 14, // index 14
416        ];
417        decoder.decode(&mut buf, &mut dst).unwrap();
418        assert_eq!(dst, vec![
419            (b":method".to_vec(), b"GET".to_vec(), 0x0),
420            (b":status".to_vec(), b"500".to_vec(), 0x0),
421        ]);
422    }
423
424    /// Should decode the HPACK's literal header field representation with
425    /// incremental indexing where header name is represented with an index
426    /// ([6.2.1.], figure 6). A a new header entry should be added to the
427    /// indexing table .
428    /// 
429    /// [6.2.1.]: https://tools.ietf.org/html/rfc7541#section-6.2.1
430    #[test]
431    fn decodes_indexed_name_with_indexing() {
432        let mut decoder = Decoder::default();
433        let mut dst = Vec::new();
434        let mut buf = vec![
435            66, 133, 215, 14, 251, 216, 255,    // (index(2), huffman(PATCH))
436            78, 130, 108, 1                     // (index(14), huffman(501))
437        ];
438        decoder.decode(&mut buf, &mut dst).unwrap();
439        assert_eq!(dst, vec![
440            (b":method".to_vec(), b"PATCH".to_vec(), 0x4), // with indexing flag
441            (b":status".to_vec(), b"501".to_vec(), 0x4), // with indexing flag
442        ]);
443        assert_eq!(decoder.table.len(), 63); // 2 headers inserted into indexing table
444    }
445
446    /// Should decode the HPACK's literal header field representation with
447    /// incremental indexing where name and value are provided in bytes
448    /// ([6.2.1.], figure 7). A new header entry should be added to the indexing
449    /// table.
450    /// 
451    /// [6.2.1.]: https://tools.ietf.org/html/rfc7541#section-6.2.1
452    #[test]
453    fn decodes_literal_with_indexing() {
454        let mut decoder = Decoder::default();
455        let mut dst = Vec::new();
456        let mut buf = vec![
457            64, 131, 148, 231, 7, 131, 148, 231, 15,    // (2, huffman(PATCH))
458            64, 131, 140, 118, 3, 131, 140, 118, 7      // (14, huffman(501))
459        ];
460        decoder.decode(&mut buf, &mut dst).unwrap();
461        assert_eq!(dst, vec![
462            (b"foo0".to_vec(), b"foo1".to_vec(), 0x4), // with indexing flag
463            (b"bar0".to_vec(), b"bar1".to_vec(), 0x4), // with indexing flag
464        ]);
465        assert_eq!(decoder.table.len(), 63); // 2 headers inserted into indexing table
466    }
467
468    /// Should decode the HPACK's literal header field representation without
469    /// indexing where header name is represented with an index ([6.2.2.],
470    /// figure 8). The indexing table should not be altered.
471    /// 
472    /// [6.2.2.]: https://tools.ietf.org/html/rfc7541#section-6.2.2
473    #[test]
474    fn decodes_indexed_name_without_indexing() {
475        let mut decoder = Decoder::default();
476        let mut dst = Vec::new();
477        let mut buf = vec![
478            2, 5, 80, 65, 84, 67, 72,   // (2, PATCH)
479            14, 130, 108, 1             // (14, huffman(501))
480        ];
481        decoder.decode(&mut buf, &mut dst).unwrap();
482        assert_eq!(dst, vec![
483            (b":method".to_vec(), b"PATCH".to_vec(), 0x0), // without flags
484            (b":status".to_vec(), b"501".to_vec(), 0x0), // without flags
485        ]);
486        assert_eq!(decoder.table.len(), 61); // table not altered
487    }
488
489    /// Should decode the HPACK's literal header field representation without
490    /// indexing where name and value are provided in bytes ([6.2.2.],
491    /// figure 9). The indexing table should not be altered.
492    /// 
493    /// [6.2.2.]: https://tools.ietf.org/html/rfc7541#section-6.2.2
494    #[test]
495    fn decodes_literal_without_indexing() {
496        let mut decoder = Decoder::default();
497        let mut dst = Vec::new();
498        let mut buf = vec![
499            0, 4, 102, 111, 111, 48, 4, 98, 97, 114, 48,   // (foo0, bar0)
500            0, 131, 148, 231, 15, 131, 140, 118, 7         // (huffman(foo1), huffman(bar1))
501        ];
502        decoder.decode(&mut buf, &mut dst).unwrap();
503        assert_eq!(dst, vec![
504            (b"foo0".to_vec(), b"bar0".to_vec(), 0x0), // without flags
505            (b"foo1".to_vec(), b"bar1".to_vec(), 0x0), // without flags
506        ]);
507        assert_eq!(decoder.table.len(), 61); // table not altered
508    }
509
510    /// Should decode the HPACK's never indexed literal header field
511    /// representation where header name is represented with an index ([6.2.3.],
512    /// figure 10). The indexing table should not be altered.
513    /// 
514    /// [6.2.3.]: https://tools.ietf.org/html/rfc7541#section-6.2.3
515    #[test]
516    fn decodes_indexed_name_never_indexed() {
517        let mut decoder = Decoder::default();
518        let mut dst = Vec::new();
519        let mut buf = vec![
520            18, 5, 80, 65, 84, 67, 72,  // (2, PATCH)
521            30, 130, 108, 1             // (14, huffman(501))
522        ];
523        decoder.decode(&mut buf, &mut dst).unwrap();
524        assert_eq!(dst, vec![
525            (b":method".to_vec(), b"PATCH".to_vec(), 0x8), // never indexed flag
526            (b":status".to_vec(), b"501".to_vec(), 0x8), // never indexed flag
527        ]);
528        assert_eq!(decoder.table.len(), 61); // table not altered
529    }
530
531    /// Should decode the HPACK's never indexed literal header field
532    /// representation where name and value are provided in bytes ([6.2.3.],
533    /// figure 11). The indexing table should not be altered.
534    /// 
535    /// [6.2.3.]: https://tools.ietf.org/html/rfc7541#section-6.2.3
536    #[test]
537    fn decodes_literal_never_indexed() {
538        let mut decoder = Decoder::default();
539        let mut dst = Vec::new();
540        let mut buf = vec![
541            16, 4, 102, 111, 111, 48, 4, 98, 97, 114, 48,  // (foo0, bar0)
542            16, 4, 102, 111, 111, 49, 4, 98, 97, 114, 49   // (foo1, bar1)
543        ];
544        decoder.decode(&mut buf, &mut dst).unwrap();
545        assert_eq!(dst, vec![
546            (b"foo0".to_vec(), b"bar0".to_vec(), 0x8), // never indexed flag
547            (b"foo1".to_vec(), b"bar1".to_vec(), 0x8), // never indexed flag
548        ]);
549        assert_eq!(decoder.table.len(), 61); // table not altered
550    }
551
552    /// Should decode the exact number of headers based on vector capacity.
553    #[test]
554    fn decodes_exact() {
555        let mut decoder = Decoder::default();
556        let mut dst = Vec::with_capacity(1);
557        let mut buf = vec![
558            0x80 | 2, // index 2
559            0x80 | 14, // index 14
560        ];
561        decoder.decode_exact(&mut buf, &mut dst).unwrap();
562        assert_eq!(dst.len(), 1);
563    }
564
565    /// Should decode a dynamic table size update signal and set the new size
566    /// to the underlaying table.
567    #[test]
568    fn decodes_max_dynamic_size() {
569        let mut decoder = Decoder::with_dynamic_size(70);
570        decoder.table.insert(b"a".to_vec(), b"a".to_vec()); // size: +34
571        decoder.table.insert(b"b".to_vec(), b"b".to_vec()); // size: +34
572        let mut dst = Vec::new();
573        decoder.decode(&mut vec![63, 19], &mut dst).unwrap(); // set to size 50
574        assert_eq!(dst, vec![]); // no items
575        assert_eq!(decoder.table.max_dynamic_size(), 50); // new dynamic size is 50
576        assert_eq!(decoder.table.dynamic_len(), 1); // 1 header evicted
577    }
578}