1use alloc::vec::Vec;
7
8use crate::integer::{IntegerError, decode_integer};
9use crate::string::{StringError, decode_string};
10use crate::table::{HeaderField, Table};
11
12#[derive(Debug, Clone, PartialEq, Eq)]
14pub enum DecoderError {
15 InvalidIndex(u64),
17 Integer(IntegerError),
19 String(StringError),
21 Truncated,
23}
24
25impl core::fmt::Display for DecoderError {
26 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
27 match self {
28 Self::InvalidIndex(i) => write!(f, "invalid index {i}"),
29 Self::Integer(e) => write!(f, "integer: {e}"),
30 Self::String(e) => write!(f, "string: {e}"),
31 Self::Truncated => f.write_str("input truncated"),
32 }
33 }
34}
35
36#[cfg(feature = "std")]
37impl std::error::Error for DecoderError {}
38
39impl From<IntegerError> for DecoderError {
40 fn from(e: IntegerError) -> Self {
41 Self::Integer(e)
42 }
43}
44
45impl From<StringError> for DecoderError {
46 fn from(e: StringError) -> Self {
47 Self::String(e)
48 }
49}
50
51#[derive(Debug, Clone, PartialEq, Eq, Default)]
53pub struct Decoder {
54 table: Table,
55}
56
57impl Decoder {
58 #[must_use]
60 pub fn new() -> Self {
61 Self::default()
62 }
63
64 #[must_use]
66 pub fn with_max_size(max: usize) -> Self {
67 Self {
68 table: Table::new(max),
69 }
70 }
71
72 #[must_use]
74 pub fn table(&self) -> &Table {
75 &self.table
76 }
77
78 pub fn table_mut(&mut self) -> &mut Table {
80 &mut self.table
81 }
82
83 pub fn decode(&mut self, mut input: &[u8]) -> Result<Vec<HeaderField>, DecoderError> {
88 let mut out = Vec::new();
89 while !input.is_empty() {
90 let first = input[0];
91 if first & 0x80 != 0 {
92 let (index, consumed) = decode_integer(input, 7)?;
94 input = &input[consumed..];
95 if index == 0 {
96 return Err(DecoderError::InvalidIndex(0));
97 }
98 let h = self
99 .table
100 .get(index as usize)
101 .ok_or(DecoderError::InvalidIndex(index))?;
102 out.push(h);
103 } else if first & 0xc0 == 0x40 {
104 let (index, consumed) = decode_integer(input, 6)?;
106 input = &input[consumed..];
107 let name = if index == 0 {
108 let (s, c) = decode_string(input)?;
109 input = &input[c..];
110 s
111 } else {
112 self.table
113 .get(index as usize)
114 .ok_or(DecoderError::InvalidIndex(index))?
115 .name
116 };
117 let (value, c) = decode_string(input)?;
118 input = &input[c..];
119 let h = HeaderField { name, value };
120 self.table.add(h.clone());
121 out.push(h);
122 } else if first & 0xe0 == 0x20 {
123 let (new_size, consumed) = decode_integer(input, 5)?;
125 input = &input[consumed..];
126 self.table.set_max_size(new_size as usize);
127 } else if first & 0xf0 == 0x00 || first & 0xf0 == 0x10 {
128 let prefix_bits = 4u8;
130 let (index, consumed) = decode_integer(input, prefix_bits)?;
131 input = &input[consumed..];
132 let name = if index == 0 {
133 let (s, c) = decode_string(input)?;
134 input = &input[c..];
135 s
136 } else {
137 self.table
138 .get(index as usize)
139 .ok_or(DecoderError::InvalidIndex(index))?
140 .name
141 };
142 let (value, c) = decode_string(input)?;
143 input = &input[c..];
144 out.push(HeaderField { name, value });
145 } else {
146 return Err(DecoderError::Truncated);
147 }
148 }
149 Ok(out)
150 }
151}
152
153#[cfg(test)]
154#[allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
155mod tests {
156 use super::*;
157 use crate::encoder::Encoder;
158
159 fn hf(n: &str, v: &str) -> HeaderField {
160 HeaderField {
161 name: n.into(),
162 value: v.into(),
163 }
164 }
165
166 #[test]
167 fn round_trip_static_match() {
168 let mut e = Encoder::new();
169 let mut d = Decoder::new();
170 let headers = alloc::vec![hf(":method", "GET"), hf(":scheme", "https")];
171 let buf = e.encode(&headers);
172 let decoded = d.decode(&buf).unwrap();
173 assert_eq!(decoded, headers);
174 }
175
176 #[test]
177 fn round_trip_literal_with_indexing() {
178 let mut e = Encoder::new();
179 let mut d = Decoder::new();
180 let headers = alloc::vec![hf("custom-key", "custom-value")];
181 let buf = e.encode(&headers);
182 let decoded = d.decode(&buf).unwrap();
183 assert_eq!(decoded, headers);
184 assert_eq!(d.table().len(), 1);
186 }
187
188 #[test]
189 fn round_trip_indexed_match_after_first() {
190 let mut e = Encoder::new();
191 let mut d = Decoder::new();
192 let headers = alloc::vec![hf("foo", "bar")];
193 let _ = d.decode(&e.encode(&headers)).unwrap();
194 let buf = e.encode(&headers);
196 let decoded = d.decode(&buf).unwrap();
197 assert_eq!(decoded, headers);
198 }
199
200 #[test]
201 fn round_trip_huffman_strings() {
202 let mut e = Encoder::with_max_size(4096);
203 e.use_huffman = true;
204 let mut d = Decoder::with_max_size(4096);
205 let headers = alloc::vec![hf("custom-key", "custom-value")];
206 let buf = e.encode(&headers);
207 let decoded = d.decode(&buf).unwrap();
208 assert_eq!(decoded, headers);
209 }
210
211 #[test]
212 fn invalid_index_zero_rejected() {
213 let mut d = Decoder::new();
214 let buf = alloc::vec![0x80];
216 assert!(matches!(d.decode(&buf), Err(DecoderError::InvalidIndex(0))));
217 }
218
219 #[test]
220 fn dynamic_table_size_update_applied() {
221 let mut d = Decoder::new();
222 let buf = alloc::vec![0x20];
224 d.decode(&buf).unwrap();
225 assert_eq!(d.table().max_size(), 0);
226 }
227
228 #[test]
229 fn rfc7541_c2_1_literal_with_indexing() {
230 let mut d = Decoder::new();
234 let buf = alloc::vec![
235 0x40, 0x0a, b'c', b'u', b's', b't', b'o', b'm', b'-', b'k', b'e', b'y', 0x0d, b'c',
236 b'u', b's', b't', b'o', b'm', b'-', b'h', b'e', b'a', b'd', b'e', b'r',
237 ];
238 let decoded = d.decode(&buf).unwrap();
239 assert_eq!(decoded, alloc::vec![hf("custom-key", "custom-header")]);
240 }
241
242 #[test]
243 fn literal_without_indexing_does_not_grow_table() {
244 let mut d = Decoder::new();
245 let buf = alloc::vec![0x00, 0x03, b'a', b'b', b'c', 0x03, b'1', b'2', b'3',];
248 let decoded = d.decode(&buf).unwrap();
249 assert_eq!(decoded, alloc::vec![hf("abc", "123")]);
250 assert!(d.table().is_empty());
251 }
252}