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}