Skip to main content

micro_h2/hpack/
decode.rs

1//! Decoding a header block.
2//!
3//! The five representations of RFC 7541 section 6, distinguished by the top
4//! bits of the first byte:
5//!
6//! ```text
7//! 1xxxxxxx   indexed header field                    (7-bit prefix)
8//! 01xxxxxx   literal, incremental indexing           (6-bit prefix)
9//! 001xxxxx   dynamic table size update               (5-bit prefix)
10//! 0001xxxx   literal, never indexed                  (4-bit prefix)
11//! 0000xxxx   literal, without indexing               (4-bit prefix)
12//! ```
13//!
14//! The order matters: `0001xxxx` must be tested before `0000xxxx`, and the size
15//! update before both. Getting the prefix lengths wrong misreads the integer
16//! that follows, which then consumes the wrong number of bytes and desynchronises
17//! the rest of the block.
18
19use crate::Error;
20use crate::hpack::dynamic::{DynamicTable, lookup};
21use crate::hpack::huffman;
22use crate::hpack::static_table;
23
24/// The longest header name or value this decoder will materialise.
25///
26/// Bounded because there is no allocator. Exceeding it is an error rather than a
27/// truncation: a silently shortened header value is worse than a failed request.
28pub const MAX_STRING: usize = 512;
29
30/// One decoded header.
31pub struct Header {
32    pub name: heapless::String<MAX_STRING>,
33    pub value: heapless::String<MAX_STRING>,
34}
35
36/// Decodes header blocks, carrying the dynamic table between them.
37///
38/// One decoder per connection, never one per message: the table is connection
39/// state, and a fresh decoder for each response would resolve every index the
40/// server sent against an empty table.
41#[derive(Clone)]
42pub struct Decoder {
43    table: DynamicTable,
44    max_capacity: usize,
45}
46
47impl Decoder {
48    pub fn new(table_size: usize) -> Self {
49        Self {
50            table: DynamicTable::new(table_size),
51            max_capacity: table_size,
52        }
53    }
54
55    pub fn table(&self) -> &DynamicTable {
56        &self.table
57    }
58
59    /// Decode a complete header block, calling `on_header` for each field.
60    ///
61    /// A callback rather than a returned collection: a response's headers do not
62    /// all need to be held at once, and the caller usually wants two of them.
63    pub fn decode(
64        &mut self,
65        mut input: &[u8],
66        mut on_header: impl FnMut(&str, &str),
67    ) -> Result<(), Error> {
68        let mut saw_header = false;
69        while !input.is_empty() {
70            let first = input[0];
71
72            if first & 0x80 != 0 {
73                // Indexed: name and value both come from a table.
74                let (index, rest) = decode_integer(input, 7)?;
75                input = rest;
76                let (name, value) = lookup(
77                    &self.table,
78                    usize::try_from(index).map_err(|_| Error::Hpack)?,
79                )?;
80                on_header(name, value);
81                saw_header = true;
82                continue;
83            }
84
85            if first & 0xe0 == 0x20 {
86                // Size updates may only precede all header fields.
87                if saw_header {
88                    return Err(Error::Hpack);
89                }
90                let (size, rest) = decode_integer(input, 5)?;
91                input = rest;
92                let size = usize::try_from(size).map_err(|_| Error::Hpack)?;
93                if size > self.max_capacity {
94                    return Err(Error::Protocol);
95                }
96                self.table.set_capacity(size);
97                continue;
98            }
99
100            // The three literal forms differ only in what they do to the table.
101            let (prefix, indexing) = if first & 0xc0 == 0x40 {
102                (6, true)
103            } else {
104                // Both `0000xxxx` and `0001xxxx` have a 4-bit prefix and neither
105                // indexes. "Never indexed" additionally means intermediaries must
106                // not index it, which as an endpoint we honour by doing nothing.
107                (4, false)
108            };
109
110            let (index, rest) = decode_integer(input, prefix)?;
111            input = rest;
112
113            let mut name = heapless::String::<MAX_STRING>::new();
114            if index == 0 {
115                input = decode_string(input, &mut name)?;
116            } else {
117                let (existing, _) = lookup(
118                    &self.table,
119                    usize::try_from(index).map_err(|_| Error::Hpack)?,
120                )?;
121                name.push_str(existing).map_err(|_| Error::BufferTooSmall)?;
122            }
123
124            let mut value = heapless::String::<MAX_STRING>::new();
125            input = decode_string(input, &mut value)?;
126
127            if indexing {
128                self.table.insert(&name, &value);
129                if !self.table.synchronized() {
130                    return Err(Error::BufferTooSmall);
131                }
132            }
133            on_header(&name, &value);
134            saw_header = true;
135        }
136        Ok(())
137    }
138}
139
140/// RFC 7541 section 5.1: an integer with an `n`-bit prefix, continued in
141/// seven-bit groups when the prefix is all ones.
142///
143/// Returns the value and the remaining input.
144pub fn decode_integer(input: &[u8], prefix_bits: u32) -> Result<(u64, &[u8]), Error> {
145    if !(1..=8).contains(&prefix_bits) {
146        return Err(Error::Hpack);
147    }
148    let mask = (1u64 << prefix_bits) - 1;
149    let first = *input.first().ok_or(Error::Incomplete)? as u64;
150    let value = first & mask;
151    if value < mask {
152        return Ok((value, &input[1..]));
153    }
154
155    let mut value = mask;
156    let mut shift = 0;
157    let mut rest = &input[1..];
158    loop {
159        let byte = *rest.first().ok_or(Error::Incomplete)?;
160        rest = &rest[1..];
161        // Bounded so a hostile encoder cannot spin here, and so the shift cannot
162        // overflow — 64 bits is ten seven-bit groups.
163        if shift > 63 || (shift == 63 && byte & 0x7f > 1) {
164            return Err(Error::Hpack);
165        }
166        value = value
167            .checked_add(((byte & 0x7f) as u64) << shift)
168            .ok_or(Error::Hpack)?;
169        if byte & 0x80 == 0 {
170            return Ok((value, rest));
171        }
172        shift += 7;
173    }
174}
175
176/// RFC 7541 section 5.2: a length-prefixed string, optionally Huffman-coded.
177fn decode_string<'a>(
178    input: &'a [u8],
179    out: &mut heapless::String<MAX_STRING>,
180) -> Result<&'a [u8], Error> {
181    let huffman_coded = input.first().ok_or(Error::Incomplete)? & 0x80 != 0;
182    let (len, rest) = decode_integer(input, 7)?;
183    let len = usize::try_from(len).map_err(|_| Error::Hpack)?;
184    let bytes = rest.get(..len).ok_or(Error::Incomplete)?;
185
186    let mut buffer = [0u8; MAX_STRING];
187    let decoded: &[u8] = if huffman_coded {
188        let n = huffman::decode(bytes, &mut buffer)?;
189        &buffer[..n]
190    } else {
191        bytes
192    };
193
194    let text = core::str::from_utf8(decoded).map_err(|_| Error::Hpack)?;
195    out.push_str(text).map_err(|_| Error::BufferTooSmall)?;
196    Ok(&rest[len..])
197}
198
199/// The static table, re-exported so callers can name indices without reaching
200/// into a sibling module.
201pub use static_table::{DYNAMIC_BASE, ENTRIES as STATIC_ENTRIES};
202
203#[cfg(test)]
204mod tests {
205    use super::*;
206
207    fn hex(text: &str) -> heapless::Vec<u8, 256> {
208        let mut bytes = heapless::Vec::new();
209        for pair in text.as_bytes().chunks(2) {
210            bytes
211                .push(u8::from_str_radix(core::str::from_utf8(pair).unwrap(), 16).unwrap())
212                .unwrap();
213        }
214        bytes
215    }
216
217    /// Collect a block's headers as `name: value` strings.
218    fn decode_all(decoder: &mut Decoder, block: &str) -> heapless::Vec<heapless::String<256>, 16> {
219        let mut headers = heapless::Vec::new();
220        decoder
221            .decode(&hex(block), |name, value| {
222                let mut entry = heapless::String::<256>::new();
223                entry.push_str(name).unwrap();
224                entry.push_str(": ").unwrap();
225                entry.push_str(value).unwrap();
226                headers.push(entry).unwrap();
227            })
228            .unwrap();
229        headers
230    }
231
232    #[test]
233    fn decodes_integers_as_the_rfc_section_5_1_examples_do() {
234        // 10 in a 5-bit prefix fits inline.
235        assert_eq!(decode_integer(&[0x0a], 5).unwrap().0, 10);
236        // 1337 in a 5-bit prefix needs continuation bytes.
237        assert_eq!(decode_integer(&[0x1f, 0x9a, 0x0a], 5).unwrap().0, 1337);
238        // 42 in an 8-bit prefix.
239        assert_eq!(decode_integer(&[0x2a], 8).unwrap().0, 42);
240        // A prefix that is all ones with nothing following is incomplete, not 31.
241        assert_eq!(decode_integer(&[0x1f], 5), Err(Error::Incomplete));
242    }
243
244    /// RFC 7541 Appendix C.3 — three requests on one connection, with the
245    /// dynamic table carried between them. This is the case a per-message
246    /// decoder gets wrong.
247    #[test]
248    fn decodes_the_rfc_appendix_c_3_request_sequence() {
249        let mut decoder = Decoder::new(4096);
250
251        let first = decode_all(&mut decoder, "828684410f7777772e6578616d706c652e636f6d");
252        assert_eq!(first[0].as_str(), ":method: GET");
253        assert_eq!(first[1].as_str(), ":scheme: http");
254        assert_eq!(first[2].as_str(), ":path: /");
255        assert_eq!(first[3].as_str(), ":authority: www.example.com");
256        assert_eq!(decoder.table().len(), 1);
257
258        // The second request references the entry the first one created.
259        let second = decode_all(&mut decoder, "828684be58086e6f2d6361636865");
260        assert_eq!(second[3].as_str(), ":authority: www.example.com");
261        assert_eq!(second[4].as_str(), "cache-control: no-cache");
262        assert_eq!(decoder.table().len(), 2);
263
264        let third = decode_all(
265            &mut decoder,
266            "828785bf400a637573746f6d2d6b65790c637573746f6d2d76616c7565",
267        );
268        assert_eq!(third[3].as_str(), ":authority: www.example.com");
269        assert_eq!(third[4].as_str(), "custom-key: custom-value");
270        assert_eq!(decoder.table().len(), 3);
271    }
272
273    /// RFC 7541 Appendix C.4 — the same three requests, Huffman-coded.
274    #[test]
275    fn decodes_the_rfc_appendix_c_4_huffman_request_sequence() {
276        let mut decoder = Decoder::new(4096);
277
278        let first = decode_all(&mut decoder, "828684418cf1e3c2e5f23a6ba0ab90f4ff");
279        assert_eq!(first[3].as_str(), ":authority: www.example.com");
280
281        let second = decode_all(&mut decoder, "828684be5886a8eb10649cbf");
282        assert_eq!(second[4].as_str(), "cache-control: no-cache");
283
284        let third = decode_all(
285            &mut decoder,
286            "828785bf408825a849e95ba97d7f8925a849e95bb8e8b4bf",
287        );
288        assert_eq!(third[4].as_str(), "custom-key: custom-value");
289    }
290
291    /// RFC 7541 Appendix C.5 — responses with a table small enough to evict,
292    /// which is where an eviction bug turns into wrong headers rather than
293    /// missing ones.
294    #[test]
295    fn decodes_the_rfc_appendix_c_5_response_sequence_with_eviction() {
296        let mut decoder = Decoder::new(256);
297
298        let first = decode_all(
299            &mut decoder,
300            "4803333032580770726976617465611d4d6f6e2c203231204f637420323031332032303a31333a323120474d546e1768747470733a2f2f7777772e6578616d706c652e636f6d",
301        );
302        assert_eq!(first[0].as_str(), ":status: 302");
303        assert_eq!(first[3].as_str(), "location: https://www.example.com");
304
305        let second = decode_all(&mut decoder, "4803333037c1c0bf");
306        assert_eq!(second[0].as_str(), ":status: 307");
307        assert_eq!(second[1].as_str(), "cache-control: private");
308        assert_eq!(second[3].as_str(), "location: https://www.example.com");
309
310        let third = decode_all(
311            &mut decoder,
312            "88c1611d4d6f6e2c203231204f637420323031332032303a31333a323220474d54c05a04677a69707738666f6f3d4153444a4b48514b425a584f5157454f50495541585157454f49553b206d61782d6167653d333630303b2076657273696f6e3d31",
313        );
314        assert_eq!(third[0].as_str(), ":status: 200");
315        assert_eq!(third[4].as_str(), "content-encoding: gzip");
316        assert!(
317            third[5]
318                .as_str()
319                .starts_with("set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU")
320        );
321    }
322
323    #[test]
324    fn a_dynamic_table_size_update_is_applied_and_is_not_a_header() {
325        let mut decoder = Decoder::new(4096);
326        // 0x20 | 0 => set capacity to 0, then an indexed :method GET.
327        let headers = decode_all(&mut decoder, "2082");
328        assert_eq!(headers.len(), 1);
329        assert_eq!(headers[0].as_str(), ":method: GET");
330        assert_eq!(decoder.table().capacity(), 0);
331    }
332
333    #[test]
334    fn a_dynamic_table_update_cannot_exceed_the_advertised_bound() {
335        let mut decoder = Decoder::new(256);
336        // HPACK integer with a 5-bit prefix encodes a requested capacity of 512.
337        assert_eq!(
338            decoder.decode(&[0x3f, 0xe1, 0x03], |_, _| {}),
339            Err(Error::Protocol)
340        );
341        assert_eq!(decoder.table().capacity(), 256);
342    }
343
344    #[test]
345    fn an_index_the_peer_never_defined_is_an_error() {
346        // The failure this prevents is subtle: carrying on would shift every
347        // later index, so headers would decode as *other headers* for the rest
348        // of the connection.
349        let mut decoder = Decoder::new(4096);
350        assert_eq!(decoder.decode(&hex("be"), |_, _| {}), Err(Error::Hpack));
351        // ...and a static index past the end of the table, likewise.
352        assert_eq!(decoder.decode(&hex("ff00"), |_, _| {}), Err(Error::Hpack));
353    }
354
355    #[test]
356    fn a_truncated_block_is_incomplete_rather_than_a_short_header() {
357        let mut decoder = Decoder::new(4096);
358        // A literal whose declared length runs past the end of the block.
359        assert_eq!(
360            decoder.decode(&hex("400a637573746f6d"), |_, _| {}),
361            Err(Error::Incomplete)
362        );
363    }
364
365    #[test]
366    fn never_indexed_headers_do_not_enter_the_table() {
367        let mut decoder = Decoder::new(4096);
368        // 0x10 => literal never indexed, new name.
369        let headers = decode_all(&mut decoder, "10012d0131");
370        assert_eq!(headers[0].as_str(), "-: 1");
371        assert!(
372            decoder.table().is_empty(),
373            "a never-indexed header must not be remembered"
374        );
375    }
376    #[test]
377    fn indexed_long_values_do_not_shift_the_dynamic_table() {
378        let mut decoder = Decoder::new(256);
379        decoder
380            .decode(&[0x40, 1, b'x', 1, b'y'], |_, _| {})
381            .unwrap();
382        let mut block = heapless::Vec::<u8, 256>::new();
383        block.extend_from_slice(&[0x40, 1, b'a', 0x7f, 2]).unwrap();
384        block.extend_from_slice(&[b'z'; 129]).unwrap();
385        decoder.decode(&block, |_, _| {}).unwrap();
386        let mut seen = false;
387        decoder
388            .decode(&[0xbe], |name, value| {
389                assert_eq!(name, "a");
390                assert_eq!(value.len(), 129);
391                seen = true;
392            })
393            .unwrap();
394        assert!(seen);
395    }
396
397    #[test]
398    fn overflowing_integer_is_rejected_instead_of_wrapping() {
399        let bytes = [
400            0xff, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x02,
401        ];
402        assert_eq!(decode_integer(&bytes, 7), Err(Error::Hpack));
403    }
404    #[test]
405    fn table_storage_exhaustion_fails_before_an_index_can_be_misread() {
406        let mut decoder = Decoder::new(4096);
407        for _ in 0..8 {
408            decoder
409                .decode(&[0x40, 1, b'x', 1, b'y'], |_, _| {})
410                .unwrap();
411        }
412        assert_eq!(
413            decoder.decode(&[0x40, 1, b'a', 1, b'b'], |_, _| {}),
414            Err(Error::BufferTooSmall)
415        );
416        assert_eq!(decoder.decode(&[0xbe], |_, _| {}), Err(Error::Hpack));
417    }
418
419    #[test]
420    fn table_updates_after_headers_are_rejected() {
421        assert_eq!(
422            Decoder::new(256).decode(&[0x88, 0x20], |_, _| {}),
423            Err(Error::Hpack)
424        );
425    }
426}