1#[derive(Clone, Copy, Debug, Eq, PartialEq)]
5pub struct HpackHeaderFieldRef<'a> {
6 name: &'a [u8],
7 value: &'a [u8],
8}
9
10impl<'a> HpackHeaderFieldRef<'a> {
11 pub const fn new(name: &'a [u8], value: &'a [u8]) -> Self {
13 Self { name, value }
14 }
15
16 pub const fn name(self) -> &'a [u8] {
18 self.name
19 }
20
21 pub const fn value(self) -> &'a [u8] {
23 self.value
24 }
25}
26
27pub const HPACK_STATIC_TABLE_LEN: usize = 61;
29
30pub struct HpackStaticTable;
32
33impl HpackStaticTable {
34 pub const fn len() -> usize {
36 HPACK_STATIC_TABLE_LEN
37 }
38
39 pub const fn is_empty() -> bool {
41 false
42 }
43
44 pub fn get(index: usize) -> Option<HpackHeaderFieldRef<'static>> {
46 STATIC_TABLE.get(index.checked_sub(1)?).copied()
47 }
48}
49
50const STATIC_TABLE: [HpackHeaderFieldRef<'static>; HPACK_STATIC_TABLE_LEN] = [
51 HpackHeaderFieldRef::new(b":authority", b""),
52 HpackHeaderFieldRef::new(b":method", b"GET"),
53 HpackHeaderFieldRef::new(b":method", b"POST"),
54 HpackHeaderFieldRef::new(b":path", b"/"),
55 HpackHeaderFieldRef::new(b":path", b"/index.html"),
56 HpackHeaderFieldRef::new(b":scheme", b"http"),
57 HpackHeaderFieldRef::new(b":scheme", b"https"),
58 HpackHeaderFieldRef::new(b":status", b"200"),
59 HpackHeaderFieldRef::new(b":status", b"204"),
60 HpackHeaderFieldRef::new(b":status", b"206"),
61 HpackHeaderFieldRef::new(b":status", b"304"),
62 HpackHeaderFieldRef::new(b":status", b"400"),
63 HpackHeaderFieldRef::new(b":status", b"404"),
64 HpackHeaderFieldRef::new(b":status", b"500"),
65 HpackHeaderFieldRef::new(b"accept-charset", b""),
66 HpackHeaderFieldRef::new(b"accept-encoding", b"gzip, deflate"),
67 HpackHeaderFieldRef::new(b"accept-language", b""),
68 HpackHeaderFieldRef::new(b"accept-ranges", b""),
69 HpackHeaderFieldRef::new(b"accept", b""),
70 HpackHeaderFieldRef::new(b"access-control-allow-origin", b""),
71 HpackHeaderFieldRef::new(b"age", b""),
72 HpackHeaderFieldRef::new(b"allow", b""),
73 HpackHeaderFieldRef::new(b"authorization", b""),
74 HpackHeaderFieldRef::new(b"cache-control", b""),
75 HpackHeaderFieldRef::new(b"content-disposition", b""),
76 HpackHeaderFieldRef::new(b"content-encoding", b""),
77 HpackHeaderFieldRef::new(b"content-language", b""),
78 HpackHeaderFieldRef::new(b"content-length", b""),
79 HpackHeaderFieldRef::new(b"content-location", b""),
80 HpackHeaderFieldRef::new(b"content-range", b""),
81 HpackHeaderFieldRef::new(b"content-type", b""),
82 HpackHeaderFieldRef::new(b"cookie", b""),
83 HpackHeaderFieldRef::new(b"date", b""),
84 HpackHeaderFieldRef::new(b"etag", b""),
85 HpackHeaderFieldRef::new(b"expect", b""),
86 HpackHeaderFieldRef::new(b"expires", b""),
87 HpackHeaderFieldRef::new(b"from", b""),
88 HpackHeaderFieldRef::new(b"host", b""),
89 HpackHeaderFieldRef::new(b"if-match", b""),
90 HpackHeaderFieldRef::new(b"if-modified-since", b""),
91 HpackHeaderFieldRef::new(b"if-none-match", b""),
92 HpackHeaderFieldRef::new(b"if-range", b""),
93 HpackHeaderFieldRef::new(b"if-unmodified-since", b""),
94 HpackHeaderFieldRef::new(b"last-modified", b""),
95 HpackHeaderFieldRef::new(b"link", b""),
96 HpackHeaderFieldRef::new(b"location", b""),
97 HpackHeaderFieldRef::new(b"max-forwards", b""),
98 HpackHeaderFieldRef::new(b"proxy-authenticate", b""),
99 HpackHeaderFieldRef::new(b"proxy-authorization", b""),
100 HpackHeaderFieldRef::new(b"range", b""),
101 HpackHeaderFieldRef::new(b"referer", b""),
102 HpackHeaderFieldRef::new(b"refresh", b""),
103 HpackHeaderFieldRef::new(b"retry-after", b""),
104 HpackHeaderFieldRef::new(b"server", b""),
105 HpackHeaderFieldRef::new(b"set-cookie", b""),
106 HpackHeaderFieldRef::new(b"strict-transport-security", b""),
107 HpackHeaderFieldRef::new(b"transfer-encoding", b""),
108 HpackHeaderFieldRef::new(b"user-agent", b""),
109 HpackHeaderFieldRef::new(b"vary", b""),
110 HpackHeaderFieldRef::new(b"via", b""),
111 HpackHeaderFieldRef::new(b"www-authenticate", b""),
112];
113
114#[derive(Clone, Copy, Debug, Eq, PartialEq)]
119pub struct HpackDynamicTableEntry {
120 offset: usize,
121 name_len: usize,
122 value_len: usize,
123}
124
125impl HpackDynamicTableEntry {
126 pub const EMPTY: Self = Self {
128 offset: 0,
129 name_len: 0,
130 value_len: 0,
131 };
132}
133
134#[derive(Clone, Copy, Debug, Eq, PartialEq)]
136pub enum HpackDynamicTableError {
137 MaximumSizeExceedsCapacity {
139 requested: usize,
141 capacity: usize,
143 },
144 EntrySizeOverflow,
146}
147
148#[derive(Clone, Copy, Debug, Eq, PartialEq)]
150pub enum HpackDynamicTableInsertResult {
151 Inserted,
153 NotInsertedOversized,
155}
156
157pub struct HpackDynamicTable<'storage, 'entries> {
164 storage: &'storage mut [u8],
165 entries: &'entries mut [HpackDynamicTableEntry],
166 count: usize,
167 size: usize,
168 maximum_size: usize,
169 capacity: usize,
170}
171
172impl<'storage, 'entries> HpackDynamicTable<'storage, 'entries> {
173 pub fn new(
177 storage: &'storage mut [u8],
178 entries: &'entries mut [HpackDynamicTableEntry],
179 maximum_size: usize,
180 ) -> Result<Self, HpackDynamicTableError> {
181 let capacity = Self::storage_capacity(storage.len(), entries.len());
182 if maximum_size > capacity {
183 return Err(HpackDynamicTableError::MaximumSizeExceedsCapacity {
184 requested: maximum_size,
185 capacity,
186 });
187 }
188 Ok(Self {
189 storage,
190 entries,
191 count: 0,
192 size: 0,
193 maximum_size,
194 capacity,
195 })
196 }
197
198 pub const fn capacity(&self) -> usize {
200 self.capacity
201 }
202
203 pub const fn len(&self) -> usize {
205 self.count
206 }
207
208 pub const fn is_empty(&self) -> bool {
210 self.count == 0
211 }
212
213 pub const fn size(&self) -> usize {
215 self.size
216 }
217
218 pub const fn maximum_size(&self) -> usize {
220 self.maximum_size
221 }
222
223 pub fn get(&self, index: usize) -> Option<HpackHeaderFieldRef<'_>> {
225 let slot = index.checked_sub(1)?;
226 if slot >= self.count {
227 return None;
228 }
229 let entry = self.entries.get(slot)?;
230 let name_end = entry.offset.checked_add(entry.name_len)?;
231 let value_end = name_end.checked_add(entry.value_len)?;
232 Some(HpackHeaderFieldRef::new(
233 self.storage.get(entry.offset..name_end)?,
234 self.storage.get(name_end..value_end)?,
235 ))
236 }
237
238 pub fn clear(&mut self) {
240 self.count = 0;
241 self.size = 0;
242 }
243
244 pub fn set_maximum_size(&mut self, maximum_size: usize) -> Result<(), HpackDynamicTableError> {
246 if maximum_size > self.capacity {
247 return Err(HpackDynamicTableError::MaximumSizeExceedsCapacity {
248 requested: maximum_size,
249 capacity: self.capacity,
250 });
251 }
252 self.set_maximum_size_prevalidated(maximum_size);
253 Ok(())
254 }
255
256 pub(super) fn set_maximum_size_prevalidated(&mut self, maximum_size: usize) {
258 let mut count = self.count;
259 let mut size = self.size;
260 while count > 0 && size > maximum_size {
261 count -= 1;
262 size -= Self::entry_size_from_slot(self.entries[count]);
263 }
264 self.count = count;
265 self.size = size;
266 self.maximum_size = maximum_size;
267 }
268
269 pub fn entry_size(name: &[u8], value: &[u8]) -> Result<usize, HpackDynamicTableError> {
271 name.len()
272 .checked_add(value.len())
273 .and_then(|length| length.checked_add(32))
274 .ok_or(HpackDynamicTableError::EntrySizeOverflow)
275 }
276
277 pub fn insert(
279 &mut self,
280 name: &[u8],
281 value: &[u8],
282 ) -> Result<HpackDynamicTableInsertResult, HpackDynamicTableError> {
283 let entry_size = Self::entry_size(name, value)?;
284 Ok(self.insert_prevalidated(name, value, entry_size))
285 }
286
287 pub(super) fn insert_prevalidated(
292 &mut self,
293 name: &[u8],
294 value: &[u8],
295 entry_size: usize,
296 ) -> HpackDynamicTableInsertResult {
297 if entry_size > self.maximum_size {
298 self.clear();
299 return HpackDynamicTableInsertResult::NotInsertedOversized;
300 }
301
302 let byte_len = entry_size - 32;
303 let mut retained_count = self.count;
304 let mut retained_size = self.size;
305 while retained_count > 0 && retained_size > self.maximum_size - entry_size {
306 retained_count -= 1;
307 retained_size -= Self::entry_size_from_slot(self.entries[retained_count]);
308 }
309 let retained_bytes = if retained_count == 0 {
310 0
311 } else {
312 let last = self.entries[retained_count - 1];
313 last.offset + last.name_len + last.value_len
314 };
315
316 self.storage.copy_within(0..retained_bytes, byte_len);
318 if retained_count > 0 {
319 self.entries.copy_within(0..retained_count, 1);
320 for entry in &mut self.entries[1..=retained_count] {
321 entry.offset += byte_len;
322 }
323 }
324 self.storage[..name.len()].copy_from_slice(name);
325 self.storage[name.len()..byte_len].copy_from_slice(value);
326 self.entries[0] = HpackDynamicTableEntry {
327 offset: 0,
328 name_len: name.len(),
329 value_len: value.len(),
330 };
331 self.count = retained_count + 1;
332 self.size = retained_size + entry_size;
333 HpackDynamicTableInsertResult::Inserted
334 }
335
336 const fn storage_capacity(storage_len: usize, entry_capacity: usize) -> usize {
337 let bytes = storage_len.saturating_add(32);
338 let entries = entry_capacity.saturating_mul(32).saturating_add(31);
339 if bytes < entries { bytes } else { entries }
340 }
341
342 const fn entry_size_from_slot(entry: HpackDynamicTableEntry) -> usize {
343 entry.name_len + entry.value_len + 32
344 }
345}