Skip to main content

simoom_hpack/
decoder.rs

1//! The header block decoder (RFC 7541 §3, §6).
2
3use crate::table::{DynTable, Name, STATIC_TABLE};
4use crate::{decode_integer, field_size, read_string, Error};
5
6/// A stateful header block decoder.
7#[derive(Debug, Clone)]
8pub struct Decoder {
9    table: DynTable,
10    /// Upper bound for dynamic table size updates: our SETTINGS_HEADER_TABLE_SIZE.
11    max_allowed: usize,
12    /// Cap on the decoded list (name + value + 32 per field).
13    max_list: usize,
14    name_buf: Vec<u8>,
15    value_buf: Vec<u8>,
16}
17
18impl Decoder {
19    /// A decoder whose dynamic table may grow to `max_table_size` (the value advertised in
20    /// SETTINGS_HEADER_TABLE_SIZE) and whose decoded header lists are capped at `max_list_size`.
21    pub fn new(max_table_size: usize, max_list_size: usize) -> Self {
22        Decoder {
23            table: DynTable::new(max_table_size),
24            max_allowed: max_table_size,
25            max_list: max_list_size,
26            name_buf: Vec::new(),
27            value_buf: Vec::new(),
28        }
29    }
30
31    /// Changes the largest table size the peer may select (after our new SETTINGS were
32    /// acknowledged). A smaller value shrinks the table at once.
33    pub fn set_max_allowed(&mut self, max: usize) {
34        self.max_allowed = max;
35        if self.table.max() > max {
36            self.table.set_max(max);
37        }
38    }
39
40    /// Changes the header list cap.
41    pub fn set_max_list_size(&mut self, max: usize) {
42        self.max_list = max;
43    }
44
45    /// Current dynamic table size in octets (RFC 7541 §4.1).
46    pub fn table_size(&self) -> usize {
47        self.table.size()
48    }
49
50    /// Current dynamic table maximum (the last size update).
51    pub fn table_max_size(&self) -> usize {
52        self.table.max()
53    }
54
55    /// Number of dynamic table entries.
56    pub fn table_len(&self) -> usize {
57        self.table.len()
58    }
59
60    /// Dynamic table entry `i` (0 = newest).
61    pub fn table_entry(&self, i: usize) -> Option<(&[u8], &[u8])> {
62        self.table.get(i)
63    }
64
65    #[inline]
66    fn lookup(&self, idx: usize) -> Result<(&[u8], &[u8]), Error> {
67        if idx == 0 {
68            Err(Error::InvalidIndex)
69        } else if idx <= STATIC_TABLE.len() {
70            Ok(STATIC_TABLE[idx - 1])
71        } else {
72            self.table.get(idx - STATIC_TABLE.len() - 1).ok_or(Error::InvalidIndex)
73        }
74    }
75
76    /// Decodes one complete header block, passing each field (name, value) to `emit` in order.
77    ///
78    /// When the list grows past the cap the rest of the block is still decoded, to keep the
79    /// dynamic table in step, but not emitted, and [`Error::HeaderListTooLarge`] is returned.
80    pub fn decode(&mut self, block: &[u8], emit: &mut dyn FnMut(&[u8], &[u8])) -> Result<(), Error> {
81        let mut pos = 0;
82        let mut size = 0usize;
83        let mut over = false;
84        let mut seen_field = false;
85        while pos < block.len() {
86            let b = block[pos];
87            if b & 0x80 != 0 {
88                // indexed field (§6.1)
89                let idx = decode_integer(block, &mut pos, 7)?;
90                let (n, v) = self.lookup(idx)?;
91                seen_field = true;
92                size += field_size(n, v);
93                if size > self.max_list {
94                    over = true;
95                }
96                if !over {
97                    emit(n, v);
98                }
99                continue;
100            }
101            if b & 0xe0 == 0x20 {
102                // dynamic table size update (§6.3): only before the first field
103                if seen_field {
104                    return Err(Error::InvalidTableSizeUpdate);
105                }
106                let s = decode_integer(block, &mut pos, 5)?;
107                if s > self.max_allowed {
108                    return Err(Error::InvalidTableSizeUpdate);
109                }
110                self.table.set_max(s);
111                continue;
112            }
113            // literals: with incremental indexing (01), without (0000), never indexed (0001)
114            let indexing = b & 0x40 != 0;
115            let idx = decode_integer(block, &mut pos, if indexing { 6 } else { 4 })?;
116            seen_field = true;
117            let dyn_name = idx > STATIC_TABLE.len();
118            if dyn_name && idx - STATIC_TABLE.len() - 1 >= self.table.len() {
119                return Err(Error::InvalidIndex);
120            }
121            let lit_name: &[u8] = if idx == 0 { read_string(block, &mut pos, &mut self.name_buf)? } else { &[] };
122            let value = read_string(block, &mut pos, &mut self.value_buf)?;
123            let name: &[u8] = if idx == 0 {
124                lit_name
125            } else if dyn_name {
126                self.table.get(idx - STATIC_TABLE.len() - 1).map_or(&[][..], |e| e.0)
127            } else {
128                STATIC_TABLE[idx - 1].0
129            };
130            size += field_size(name, value);
131            if size > self.max_list {
132                over = true;
133            }
134            if !indexing || field_size(name, value) > self.table.max() {
135                // emit from the sources; an oversized entry then just empties the table
136                if !over {
137                    emit(name, value);
138                }
139                if indexing {
140                    self.table.clear(); // RFC 7541 §4.4
141                }
142                continue;
143            }
144            let src = if idx == 0 {
145                Name::Bytes(lit_name)
146            } else if dyn_name {
147                Name::Dyn(idx - STATIC_TABLE.len() - 1)
148            } else {
149                Name::Bytes(STATIC_TABLE[idx - 1].0)
150            };
151            self.table.insert(src, value);
152            if !over {
153                if let Some((n, v)) = self.table.get(0) {
154                    emit(n, v);
155                }
156            }
157        }
158        if over {
159            Err(Error::HeaderListTooLarge)
160        } else {
161            Ok(())
162        }
163    }
164}