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