1use crate::Error;
20use crate::hpack::dynamic::{DynamicTable, lookup};
21use crate::hpack::huffman;
22use crate::hpack::static_table;
23
24pub const MAX_STRING: usize = 512;
29
30pub struct Header {
32 pub name: heapless::String<MAX_STRING>,
33 pub value: heapless::String<MAX_STRING>,
34}
35
36#[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 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 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 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 let (prefix, indexing) = if first & 0xc0 == 0x40 {
102 (6, true)
103 } else {
104 (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
140pub 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 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
176fn 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
199pub 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 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 assert_eq!(decode_integer(&[0x0a], 5).unwrap().0, 10);
236 assert_eq!(decode_integer(&[0x1f, 0x9a, 0x0a], 5).unwrap().0, 1337);
238 assert_eq!(decode_integer(&[0x2a], 8).unwrap().0, 42);
240 assert_eq!(decode_integer(&[0x1f], 5), Err(Error::Incomplete));
242 }
243
244 #[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 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 #[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 #[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 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 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 let mut decoder = Decoder::new(4096);
350 assert_eq!(decoder.decode(&hex("be"), |_, _| {}), Err(Error::Hpack));
351 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 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 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}