1#![forbid(unsafe_code)]
24
25mod decoder;
26mod encoder;
27pub mod huffman;
28mod table;
29
30pub use decoder::Decoder;
31pub use encoder::{is_sensitive, Encoder};
32pub use table::STATIC_TABLE;
33
34use std::fmt;
35
36pub const DEFAULT_TABLE_SIZE: usize = 4096;
38
39#[inline]
41pub fn field_size(name: &[u8], value: &[u8]) -> usize {
42 name.len() + value.len() + 32
43}
44
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
49pub enum Error {
50 Truncated,
52 IntegerOverflow,
54 InvalidIndex,
56 Huffman,
58 InvalidTableSizeUpdate,
60 HeaderListTooLarge,
64}
65
66impl fmt::Display for Error {
67 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68 f.write_str(match self {
69 Error::Truncated => "truncated header block",
70 Error::IntegerOverflow => "integer overflow",
71 Error::InvalidIndex => "invalid table index",
72 Error::Huffman => "invalid huffman string",
73 Error::InvalidTableSizeUpdate => "invalid dynamic table size update",
74 Error::HeaderListTooLarge => "header list too large",
75 })
76 }
77}
78
79impl std::error::Error for Error {}
80
81#[inline]
84pub fn bytes_eq(a: &[u8], b: &[u8]) -> bool {
85 let n = a.len();
86 if n != b.len() {
87 return false;
88 }
89 if n >= 8 {
90 #[inline(always)]
91 fn w(s: &[u8], i: usize) -> u64 {
92 u64::from_ne_bytes(s[i..i + 8].try_into().unwrap_or([0; 8]))
93 }
94 let mut i = 0;
95 while i + 8 <= n {
96 if w(a, i) != w(b, i) {
97 return false;
98 }
99 i += 8;
100 }
101 i == n || w(a, n - 8) == w(b, n - 8)
102 } else if n >= 4 {
103 #[inline(always)]
104 fn w(s: &[u8], i: usize) -> u32 {
105 u32::from_ne_bytes(s[i..i + 4].try_into().unwrap_or([0; 4]))
106 }
107 w(a, 0) == w(b, 0) && w(a, n - 4) == w(b, n - 4)
108 } else {
109 a.iter().zip(b).all(|(x, y)| x == y)
110 }
111}
112
113pub fn encode_integer(value: usize, prefix_bits: u8, first: u8, out: &mut Vec<u8>) {
116 let max = (1usize << prefix_bits) - 1;
117 if value < max {
118 out.push(first | value as u8);
119 return;
120 }
121 out.push(first | max as u8);
122 let mut v = value - max;
123 while v >= 128 {
124 out.push((v as u8 & 0x7f) | 0x80);
125 v >>= 7;
126 }
127 out.push(v as u8);
128}
129
130pub fn decode_integer(buf: &[u8], pos: &mut usize, prefix_bits: u8) -> Result<usize, Error> {
133 let max = (1usize << prefix_bits) - 1;
134 let first = *buf.get(*pos).ok_or(Error::Truncated)? as usize & max;
135 *pos += 1;
136 if first < max {
137 return Ok(first);
138 }
139 let mut value = max;
140 let mut shift = 0u32;
141 loop {
142 let b = *buf.get(*pos).ok_or(Error::Truncated)? as usize;
143 *pos += 1;
144 if shift > 21 {
145 return Err(Error::IntegerOverflow);
146 }
147 value += (b & 0x7f) << shift;
148 shift += 7;
149 if b & 0x80 == 0 {
150 return Ok(value);
151 }
152 }
153}
154
155pub fn encode_string(s: &[u8], huffman: bool, out: &mut Vec<u8>) {
157 if huffman {
158 let hlen = huffman::encoded_len(s);
159 if hlen < s.len() {
160 encode_integer(hlen, 7, 0x80, out);
161 huffman::encode(s, out);
162 return;
163 }
164 }
165 encode_integer(s.len(), 7, 0, out);
166 out.extend_from_slice(s);
167}
168
169pub(crate) fn read_string<'a>(block: &'a [u8], pos: &mut usize, scratch: &'a mut Vec<u8>) -> Result<&'a [u8], Error> {
172 let huff = *block.get(*pos).ok_or(Error::Truncated)? & 0x80 != 0;
173 let len = decode_integer(block, pos, 7)?;
174 if len > block.len() - *pos {
175 return Err(Error::Truncated);
176 }
177 let raw = &block[*pos..*pos + len];
178 *pos += len;
179 if huff {
180 scratch.clear();
181 huffman::decode(raw, scratch)?;
182 Ok(scratch)
183 } else {
184 Ok(raw)
185 }
186}
187
188#[cfg(test)]
189mod tests {
190 use super::*;
191
192 #[test]
193 fn integers_c1() {
194 let mut out = Vec::new();
195 encode_integer(10, 5, 0, &mut out);
196 assert_eq!(out, [0b01010]);
197 out.clear();
198 encode_integer(1337, 5, 0, &mut out);
199 assert_eq!(out, [31, 154, 10]);
200 let mut pos = 0;
201 assert_eq!(decode_integer(&out, &mut pos, 5), Ok(1337));
202 assert_eq!(pos, 3);
203 out.clear();
204 encode_integer(42, 8, 0, &mut out);
205 assert_eq!(out, [42]);
206 for v in [0usize, 30, 31, 127, 128, 255, 16_383, 1 << 20, (1 << 28) - 1] {
207 for p in 1..=8u8 {
208 let mut o = Vec::new();
209 encode_integer(v, p, 0, &mut o);
210 let mut pos = 0;
211 assert_eq!(decode_integer(&o, &mut pos, p), Ok(v), "{v} prefix {p}");
212 assert_eq!(pos, o.len());
213 }
214 }
215 let mut pos = 0;
216 assert_eq!(decode_integer(&[0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f], &mut pos, 5), Err(Error::IntegerOverflow));
217 let mut pos = 0;
218 assert_eq!(decode_integer(&[0x1f, 0xff], &mut pos, 5), Err(Error::Truncated));
219 let mut pos = 0;
220 assert_eq!(decode_integer(&[], &mut pos, 5), Err(Error::Truncated));
221 }
222
223 #[test]
224 fn short_equality() {
225 let s = b"abcdefghijklmnopqrstuvwxyz0123456789";
226 for i in 0..s.len() {
227 for j in i..s.len() {
228 let a = &s[i..j];
229 assert!(bytes_eq(a, &a.to_vec()));
230 let mut b = a.to_vec();
231 for k in 0..b.len() {
232 b[k] ^= 1;
233 assert!(!bytes_eq(a, &b));
234 b[k] ^= 1;
235 }
236 if j < s.len() {
237 assert!(!bytes_eq(a, &s[i..j + 1]), "different lengths");
238 }
239 }
240 }
241 }
242
243 #[test]
244 fn strings() {
245 let mut out = Vec::new();
246 encode_string(b"www.example.com", true, &mut out);
247 assert_eq!(out[0], 0x8c);
248 let mut scratch = Vec::new();
249 let mut pos = 0;
250 assert_eq!(read_string(&out, &mut pos, &mut scratch).unwrap(), b"www.example.com");
251 out.clear();
252 encode_string(b"\xff\xfe", true, &mut out); assert_eq!(out, [2, 0xff, 0xfe]);
254 let mut pos = 0;
255 assert_eq!(read_string(&[5, b'a'], &mut pos, &mut scratch), Err(Error::Truncated));
256 }
257}