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
36pub 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 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 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 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 let (prefix, indexing) = if first & 0xc0 == 0x40 {
101 (6, true)
102 } else {
103 (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
139pub 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 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
175fn 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
198pub 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 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 assert_eq!(decode_integer(&[0x0a], 5).unwrap().0, 10);
235 assert_eq!(decode_integer(&[0x1f, 0x9a, 0x0a], 5).unwrap().0, 1337);
237 assert_eq!(decode_integer(&[0x2a], 8).unwrap().0, 42);
239 assert_eq!(decode_integer(&[0x1f], 5), Err(Error::Incomplete));
241 }
242
243 #[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 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 #[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 #[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 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 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 let mut decoder = Decoder::new(4096);
349 assert_eq!(decoder.decode(&hex("be"), |_, _| {}), Err(Error::Hpack));
350 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 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 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}