1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 use std::collections::VecDeque;
15 use std::ops::Add;
16 
17 /// `TableSearcher` is used to find specified content in static and dynamic
18 /// tables.
19 pub(crate) struct TableSearcher<'a> {
20     dynamic: &'a DynamicTable,
21 }
22 
23 impl<'a> TableSearcher<'a> {
new(dynamic: &'a DynamicTable) -> Self24     pub(crate) fn new(dynamic: &'a DynamicTable) -> Self {
25         Self { dynamic }
26     }
27 
28     /// Searches `HeaderName` in static and dynamic tables.
search_header_name(&self, index: usize) -> Option<Header>29     pub(crate) fn search_header_name(&self, index: usize) -> Option<Header> {
30         if index <= 61 {
31             StaticTable::header_name(index)
32         } else {
33             self.dynamic.header_name(index - 62)
34         }
35     }
36 
37     /// Searches `Header` in static and dynamic tables.
search_header(&self, index: usize) -> Option<(Header, String)>38     pub(crate) fn search_header(&self, index: usize) -> Option<(Header, String)> {
39         if index <= 61 {
40             StaticTable::header(index)
41         } else {
42             self.dynamic.header(index - 62)
43         }
44     }
45 
46     /// Searches index in static and dynamic tables.
index(&self, header: &Header, value: &str) -> Option<TableIndex>47     pub(crate) fn index(&self, header: &Header, value: &str) -> Option<TableIndex> {
48         match (
49             StaticTable::index(header, value),
50             self.dynamic.index(header, value),
51         ) {
52             (x @ Some(TableIndex::Header(_)), _) => x,
53             (_, Some(TableIndex::Header(i))) => Some(TableIndex::Header(i + 62)),
54             (x @ Some(TableIndex::HeaderName(_)), _) => x,
55             (_, Some(TableIndex::HeaderName(i))) => Some(TableIndex::Header(i + 62)),
56             _ => None,
57         }
58     }
59 }
60 
61 pub(crate) enum TableIndex {
62     Header(usize),
63     HeaderName(usize),
64 }
65 
66 /// The [`Dynamic Table`][dynamic_table] implementation of [HPACK].
67 ///
68 /// [dynamic_table]: https://httpwg.org/specs/rfc7541.html#dynamic.table
69 /// [HPACK]: https://httpwg.org/specs/rfc7541.html
70 ///
71 /// # Introduction
72 /// The dynamic table consists of a list of header fields maintained in
73 /// first-in, first-out order. The first and newest entry in a dynamic table is
74 /// at the lowest index, and the oldest entry of a dynamic table is at the
75 /// highest index.
76 ///
77 /// The dynamic table is initially empty. Entries are added as each header block
78 /// is decompressed.
79 ///
80 /// The dynamic table can contain duplicate entries (i.e., entries with the same
81 /// name and same value). Therefore, duplicate entries MUST NOT be treated as an
82 /// error by a decoder.
83 ///
84 /// The encoder decides how to update the dynamic table and as such can control
85 /// how much memory is used by the dynamic table. To limit the memory
86 /// requirements of the decoder, the dynamic table size is strictly bounded.
87 ///
88 /// The decoder updates the dynamic table during the processing of a list of
89 /// header field representations.
90 pub(crate) struct DynamicTable {
91     queue: VecDeque<(Header, String)>,
92     curr_size: usize,
93     max_size: usize,
94 }
95 
96 impl DynamicTable {
97     /// Creates a `Dynamic Table` based on the size limit.
with_max_size(max_size: usize) -> Self98     pub(crate) fn with_max_size(max_size: usize) -> Self {
99         Self {
100             queue: VecDeque::new(),
101             curr_size: 0,
102             max_size,
103         }
104     }
105 
curr_size(&self) -> usize106     pub(crate) fn curr_size(&self) -> usize {
107         self.curr_size
108     }
109 
max_size(&self) -> usize110     pub(crate) fn max_size(&self) -> usize {
111         self.max_size
112     }
113 
114     /// Gets a `Header` by the given index.
header_name(&self, index: usize) -> Option<Header>115     pub(crate) fn header_name(&self, index: usize) -> Option<Header> {
116         self.queue.get(index).map(|(h, _)| h.clone())
117     }
118 
119     /// Gets a `Header` and a value by the given index.
header(&self, index: usize) -> Option<(Header, String)>120     pub(crate) fn header(&self, index: usize) -> Option<(Header, String)> {
121         self.queue.get(index).cloned()
122     }
123 
124     /// Updates `DynamicTable` by a given `Header` and value pair.
update(&mut self, header: Header, value: String)125     pub(crate) fn update(&mut self, header: Header, value: String) {
126         // RFC7541-4.1: The additional 32 octets account for an estimated
127         // overhead associated with an entry. For example, an entry
128         // structure using two 64-bit pointers to reference the name and the
129         // value of the entry and two 64-bit integers for counting the
130         // number of references to the name and value would have 32 octets
131         // of overhead.
132         self.curr_size += header.len() + value.len() + 32;
133         self.queue.push_front((header, value));
134         self.fit_size();
135     }
136 
137     /// Updates `DynamicTable`'s size.
update_size(&mut self, max_size: usize)138     pub(crate) fn update_size(&mut self, max_size: usize) {
139         self.max_size = max_size;
140         self.fit_size();
141     }
142 
143     /// Adjusts dynamic table content to fit its size.
fit_size(&mut self)144     fn fit_size(&mut self) {
145         while self.curr_size > self.max_size && !self.queue.is_empty() {
146             let (key, string) = self.queue.pop_back().unwrap();
147             self.curr_size -= key.len() + string.len() + 32;
148         }
149     }
150 
151     /// Tries get the index of a `Header`.
index(&self, header: &Header, value: &str) -> Option<TableIndex>152     fn index(&self, header: &Header, value: &str) -> Option<TableIndex> {
153         let mut index = None;
154         for (n, (h, v)) in self.queue.iter().enumerate() {
155             match (header == h, value == v, &index) {
156                 (true, true, _) => return Some(TableIndex::Header(n)),
157                 (true, false, None) => index = Some(TableIndex::HeaderName(n)),
158                 _ => {}
159             }
160         }
161         index
162     }
163 }
164 
165 /// The [`Static Table`][static_table] implementation of [HPACK].
166 ///
167 /// [static_table]: https://httpwg.org/specs/rfc7541.html#static.table
168 /// [HPACK]: https://httpwg.org/specs/rfc7541.html
169 ///
170 /// # Introduction
171 /// The static table consists of a predefined static list of header fields.
172 ///
173 /// # List
174 /// | Index | Header Name                   | Header Value  |
175 /// | :---: | :---:                         | :---:         |
176 /// | 1     | :authority                    |               |
177 /// | 2     | :method                       | GET           |
178 /// | 3     | :method                       | POST          |
179 /// | 4     | :path                         | /             |
180 /// | 5     | :path                         | /index.html   |
181 /// | 6     | :scheme                       | http          |
182 /// | 7     | :scheme                       | https         |
183 /// | 8     | :status                       | 200           |
184 /// | 9     | :status                       | 204           |
185 /// | 10    | :status                       | 206           |
186 /// | 11    | :status                       | 304           |
187 /// | 12    | :status                       | 400           |
188 /// | 13    | :status                       | 404           |
189 /// | 14    | :status                       | 500           |
190 /// | 15    | accept-charset                |               |
191 /// | 16    | accept-encoding               | gzip, deflate |
192 /// | 17    | accept-language               |               |
193 /// | 18    | accept-ranges                 |               |
194 /// | 19    | accept                        |               |
195 /// | 20    | access-control-allow-origin   |               |
196 /// | 21    | age                           |               |
197 /// | 22    | allow                         |               |
198 /// | 23    | authorization                 |               |
199 /// | 24    | cache-control                 |               |
200 /// | 25    | content-disposition           |               |
201 /// | 26    | content-encoding              |               |
202 /// | 27    | content-language              |               |
203 /// | 28    | content-length                |               |
204 /// | 29    | content-location              |               |
205 /// | 30    | content-range                 |               |
206 /// | 31    | content-type                  |               |
207 /// | 32    | cookie                        |               |
208 /// | 33    | date                          |               |
209 /// | 34    | etag                          |               |
210 /// | 35    | expect                        |               |
211 /// | 36    | expires                       |               |
212 /// | 37    | from                          |               |
213 /// | 38    | host                          |               |
214 /// | 39    | if-match                      |               |
215 /// | 40    | if-modified-since             |               |
216 /// | 41    | if-none-match                 |               |
217 /// | 42    | if-range                      |               |
218 /// | 43    | if-unmodified-since           |               |
219 /// | 44    | last-modified                 |               |
220 /// | 45    | link                          |               |
221 /// | 46    | location                      |               |
222 /// | 47    | max-forwards                  |               |
223 /// | 48    | proxy-authenticate            |               |
224 /// | 49    | proxy-authorization           |               |
225 /// | 50    | range                         |               |
226 /// | 51    | referer                       |               |
227 /// | 52    | refresh                       |               |
228 /// | 53    | retry-after                   |               |
229 /// | 54    | server                        |               |
230 /// | 55    | set-cookie                    |               |
231 /// | 56    | strict-transport-security     |               |
232 /// | 57    | transfer-encoding             |               |
233 /// | 58    | user-agent                    |               |
234 /// | 59    | vary                          |               |
235 /// | 60    | via                           |               |
236 /// | 61    | www-authenticate              |               |
237 struct StaticTable;
238 
239 impl StaticTable {
240     /// Gets a `Header` by the given index.
header_name(index: usize) -> Option<Header>241     fn header_name(index: usize) -> Option<Header> {
242         match index {
243             1 => Some(Header::Authority),
244             2..=3 => Some(Header::Method),
245             4..=5 => Some(Header::Path),
246             6..=7 => Some(Header::Scheme),
247             8..=14 => Some(Header::Status),
248             15 => Some(Header::Other(String::from("accept-charset"))),
249             16 => Some(Header::Other(String::from("accept-encoding"))),
250             17 => Some(Header::Other(String::from("accept-language"))),
251             18 => Some(Header::Other(String::from("accept-ranges"))),
252             19 => Some(Header::Other(String::from("accept"))),
253             20 => Some(Header::Other(String::from("access-control-allow-origin"))),
254             21 => Some(Header::Other(String::from("age"))),
255             22 => Some(Header::Other(String::from("allow"))),
256             23 => Some(Header::Other(String::from("authorization"))),
257             24 => Some(Header::Other(String::from("cache-control"))),
258             25 => Some(Header::Other(String::from("content-disposition"))),
259             26 => Some(Header::Other(String::from("content-encoding"))),
260             27 => Some(Header::Other(String::from("content-language"))),
261             28 => Some(Header::Other(String::from("content-length"))),
262             29 => Some(Header::Other(String::from("content-location"))),
263             30 => Some(Header::Other(String::from("content-range"))),
264             31 => Some(Header::Other(String::from("content-type"))),
265             32 => Some(Header::Other(String::from("cookie"))),
266             33 => Some(Header::Other(String::from("date"))),
267             34 => Some(Header::Other(String::from("etag"))),
268             35 => Some(Header::Other(String::from("expect"))),
269             36 => Some(Header::Other(String::from("expires"))),
270             37 => Some(Header::Other(String::from("from"))),
271             38 => Some(Header::Other(String::from("host"))),
272             39 => Some(Header::Other(String::from("if-match"))),
273             40 => Some(Header::Other(String::from("if-modified-since"))),
274             41 => Some(Header::Other(String::from("if-none-match"))),
275             42 => Some(Header::Other(String::from("if-range"))),
276             43 => Some(Header::Other(String::from("if-unmodified-since"))),
277             44 => Some(Header::Other(String::from("last-modified"))),
278             45 => Some(Header::Other(String::from("link"))),
279             46 => Some(Header::Other(String::from("location"))),
280             47 => Some(Header::Other(String::from("max-forwards"))),
281             48 => Some(Header::Other(String::from("proxy-authenticate"))),
282             49 => Some(Header::Other(String::from("proxy-authorization"))),
283             50 => Some(Header::Other(String::from("range"))),
284             51 => Some(Header::Other(String::from("referer"))),
285             52 => Some(Header::Other(String::from("refresh"))),
286             53 => Some(Header::Other(String::from("retry-after"))),
287             54 => Some(Header::Other(String::from("server"))),
288             55 => Some(Header::Other(String::from("set-cookie"))),
289             56 => Some(Header::Other(String::from("strict-transport-security"))),
290             57 => Some(Header::Other(String::from("transfer-encoding"))),
291             58 => Some(Header::Other(String::from("user-agent"))),
292             59 => Some(Header::Other(String::from("vary"))),
293             60 => Some(Header::Other(String::from("via"))),
294             61 => Some(Header::Other(String::from("www-authenticate"))),
295             _ => None,
296         }
297     }
298 
299     /// Tries to get a `Header` and a value by the given index.
header(index: usize) -> Option<(Header, String)>300     fn header(index: usize) -> Option<(Header, String)> {
301         match index {
302             2 => Some((Header::Method, String::from("GET"))),
303             3 => Some((Header::Method, String::from("POST"))),
304             4 => Some((Header::Path, String::from("/"))),
305             5 => Some((Header::Path, String::from("/index.html"))),
306             6 => Some((Header::Scheme, String::from("http"))),
307             7 => Some((Header::Scheme, String::from("https"))),
308             8 => Some((Header::Status, String::from("200"))),
309             9 => Some((Header::Status, String::from("204"))),
310             10 => Some((Header::Status, String::from("206"))),
311             11 => Some((Header::Status, String::from("304"))),
312             12 => Some((Header::Status, String::from("400"))),
313             13 => Some((Header::Status, String::from("404"))),
314             14 => Some((Header::Status, String::from("500"))),
315             16 => Some((
316                 Header::Other(String::from("accept-encoding")),
317                 String::from("gzip, deflate"),
318             )),
319             _ => None,
320         }
321     }
322 
323     /// Tries to get a `Index` by the given header and value.
index(header: &Header, value: &str) -> Option<TableIndex>324     fn index(header: &Header, value: &str) -> Option<TableIndex> {
325         // TODO: 优化此处的比较逻辑,考虑使用单例哈希表。
326         match (header, value) {
327             (Header::Authority, _) => Some(TableIndex::HeaderName(1)),
328             (Header::Method, "GET") => Some(TableIndex::Header(2)),
329             (Header::Method, "POST") => Some(TableIndex::Header(3)),
330             (Header::Method, _) => Some(TableIndex::HeaderName(2)),
331             (Header::Path, "/") => Some(TableIndex::Header(4)),
332             (Header::Path, "/index.html") => Some(TableIndex::Header(5)),
333             (Header::Path, _) => Some(TableIndex::HeaderName(4)),
334             (Header::Scheme, "http") => Some(TableIndex::Header(6)),
335             (Header::Scheme, "https") => Some(TableIndex::Header(7)),
336             (Header::Scheme, _) => Some(TableIndex::HeaderName(6)),
337             (Header::Status, "200") => Some(TableIndex::Header(8)),
338             (Header::Status, "204") => Some(TableIndex::Header(9)),
339             (Header::Status, "206") => Some(TableIndex::Header(10)),
340             (Header::Status, "304") => Some(TableIndex::Header(11)),
341             (Header::Status, "400") => Some(TableIndex::Header(12)),
342             (Header::Status, "404") => Some(TableIndex::Header(13)),
343             (Header::Status, "500") => Some(TableIndex::Header(14)),
344             (Header::Status, _) => Some(TableIndex::HeaderName(8)),
345             (Header::Other(s), v) => Self::index_headers(s.as_str(), v),
346         }
347     }
348 
index_headers(key: &str, value: &str) -> Option<TableIndex>349     fn index_headers(key: &str, value: &str) -> Option<TableIndex> {
350         match (key, value) {
351             ("accept-charset", _) => Some(TableIndex::HeaderName(15)),
352             ("accept-encoding", "gzip, deflate") => Some(TableIndex::Header(16)),
353             ("accept-encoding", _) => Some(TableIndex::HeaderName(16)),
354             ("accept-language", _) => Some(TableIndex::HeaderName(17)),
355             ("accept-ranges", _) => Some(TableIndex::HeaderName(18)),
356             ("accept", _) => Some(TableIndex::HeaderName(19)),
357             ("access-control-allow-origin", _) => Some(TableIndex::HeaderName(20)),
358             ("age", _) => Some(TableIndex::HeaderName(21)),
359             ("allow", _) => Some(TableIndex::HeaderName(22)),
360             ("authorization", _) => Some(TableIndex::HeaderName(23)),
361             ("cache-control", _) => Some(TableIndex::HeaderName(24)),
362             ("content-disposition", _) => Some(TableIndex::HeaderName(25)),
363             ("content-encoding", _) => Some(TableIndex::HeaderName(26)),
364             ("content-language", _) => Some(TableIndex::HeaderName(27)),
365             ("content-length", _) => Some(TableIndex::HeaderName(28)),
366             ("content-location", _) => Some(TableIndex::HeaderName(29)),
367             ("content-range", _) => Some(TableIndex::HeaderName(30)),
368             ("content-type", _) => Some(TableIndex::HeaderName(31)),
369             ("cookie", _) => Some(TableIndex::HeaderName(32)),
370             ("date", _) => Some(TableIndex::HeaderName(33)),
371             ("etag", _) => Some(TableIndex::HeaderName(34)),
372             ("expect", _) => Some(TableIndex::HeaderName(35)),
373             ("expires", _) => Some(TableIndex::HeaderName(36)),
374             ("from", _) => Some(TableIndex::HeaderName(37)),
375             ("host", _) => Some(TableIndex::HeaderName(38)),
376             ("if-match", _) => Some(TableIndex::HeaderName(39)),
377             ("if-modified-since", _) => Some(TableIndex::HeaderName(40)),
378             ("if-none-match", _) => Some(TableIndex::HeaderName(41)),
379             ("if-range", _) => Some(TableIndex::HeaderName(42)),
380             ("if-unmodified-since", _) => Some(TableIndex::HeaderName(43)),
381             ("last-modified", _) => Some(TableIndex::HeaderName(44)),
382             ("link", _) => Some(TableIndex::HeaderName(45)),
383             ("location", _) => Some(TableIndex::HeaderName(46)),
384             ("max-forwards", _) => Some(TableIndex::HeaderName(47)),
385             ("proxy-authenticate", _) => Some(TableIndex::HeaderName(48)),
386             ("proxy-authorization", _) => Some(TableIndex::HeaderName(49)),
387             ("range", _) => Some(TableIndex::HeaderName(50)),
388             ("referer", _) => Some(TableIndex::HeaderName(51)),
389             ("refresh", _) => Some(TableIndex::HeaderName(52)),
390             ("retry-after", _) => Some(TableIndex::HeaderName(53)),
391             ("server", _) => Some(TableIndex::HeaderName(54)),
392             ("set-cookie", _) => Some(TableIndex::HeaderName(55)),
393             ("strict-transport-security", _) => Some(TableIndex::HeaderName(56)),
394             ("transfer-encoding", _) => Some(TableIndex::HeaderName(57)),
395             ("user-agent", _) => Some(TableIndex::HeaderName(58)),
396             ("vary", _) => Some(TableIndex::HeaderName(59)),
397             ("via", _) => Some(TableIndex::HeaderName(60)),
398             ("www-authenticate", _) => Some(TableIndex::HeaderName(61)),
399             _ => None,
400         }
401     }
402 }
403 
404 /// Possible header types in `Dynamic Table` and `Static Table`.
405 #[derive(Clone, PartialEq, Eq)]
406 pub(crate) enum Header {
407     Authority,
408     Method,
409     Path,
410     Scheme,
411     Status,
412     Other(String),
413 }
414 
415 impl Header {
len(&self) -> usize416     pub(crate) fn len(&self) -> usize {
417         match self {
418             // 10 is the length of ":authority".
419             Header::Authority => 10,
420             // 7 is the length of ":method".
421             Header::Method => 7,
422             // 5 is the length of ":path".
423             Header::Path => 5,
424             // 7 is the length of "scheme".
425             Header::Scheme => 7,
426             // 7 is the length of "status".
427             Header::Status => 7,
428             Header::Other(s) => s.len(),
429         }
430     }
431 
into_string(self) -> String432     pub(crate) fn into_string(self) -> String {
433         match self {
434             Header::Authority => String::from(":authority"),
435             Header::Method => String::from(":method"),
436             Header::Path => String::from(":path"),
437             Header::Scheme => String::from(":scheme"),
438             Header::Status => String::from(":status"),
439             Header::Other(s) => s,
440         }
441     }
442 }
443 
444 #[cfg(test)]
445 mod ut_dynamic_table {
446     use crate::h2::hpack::table::{DynamicTable, Header, StaticTable};
447 
448     /// UT test cases for `DynamicTable::with_max_size`.
449     ///
450     /// # Brief
451     /// 1. Calls `DynamicTable::with_max_size` to create a `DynamicTable`.
452     /// 2. Checks the results.
453     #[test]
ut_dynamic_table_with_max_size()454     fn ut_dynamic_table_with_max_size() {
455         let table = DynamicTable::with_max_size(4096);
456         assert_eq!(table.queue.len(), 0);
457         assert_eq!(table.curr_size, 0);
458         assert_eq!(table.max_size, 4096);
459     }
460 
461     /// UT test cases for `DynamicTable::header_name`.
462     ///
463     /// # Brief
464     /// 1. Creates a `DynamicTable`.
465     /// 2. Calls `DynamicTable::header_name` to get a header name.
466     /// 3. Checks the results.
467     #[test]
ut_dynamic_table_header_name()468     fn ut_dynamic_table_header_name() {
469         let mut table = DynamicTable::with_max_size(52);
470         assert!(table.header_name(0).is_none());
471 
472         assert!(table.header_name(0).is_none());
473         table.update(Header::Authority, String::from("Authority"));
474         match table.header_name(0) {
475             Some(Header::Authority) => {}
476             _ => panic!("DynamicTable::header_name() failed!"),
477         }
478     }
479 
480     /// UT test cases for `DynamicTable::header`.
481     ///
482     /// # Brief
483     /// 1. Creates a `DynamicTable`.
484     /// 2. Calls `DynamicTable::header` to get a header and a value.
485     /// 3. Checks the results.
486     #[test]
ut_dynamic_table_header()487     fn ut_dynamic_table_header() {
488         let mut table = DynamicTable::with_max_size(52);
489         assert!(table.header(0).is_none());
490 
491         assert!(table.header(0).is_none());
492         table.update(Header::Authority, String::from("Authority"));
493         match table.header(0) {
494             Some((Header::Authority, x)) if x == *"Authority" => {}
495             _ => panic!("DynamicTable::header() failed!"),
496         }
497     }
498 
499     /// UT test cases for `DynamicTable::update`.
500     ///
501     /// # Brief
502     /// 1. Creates a `DynamicTable`.
503     /// 2. Calls `DynamicTable::update` to insert a header and a value.
504     /// 3. Checks the results.
505     #[test]
ut_dynamic_table_update()506     fn ut_dynamic_table_update() {
507         let mut table = DynamicTable::with_max_size(52);
508         table.update(Header::Authority, String::from("Authority"));
509         assert_eq!(table.queue.len(), 1);
510         match table.header(0) {
511             Some((Header::Authority, x)) if x == *"Authority" => {}
512             _ => panic!("DynamicTable::header() failed!"),
513         }
514 
515         table.update(Header::Method, String::from("Method"));
516         assert_eq!(table.queue.len(), 1);
517         match table.header(0) {
518             Some((Header::Method, x)) if x == *"Method" => {}
519             _ => panic!("DynamicTable::header() failed!"),
520         }
521     }
522 
523     /// UT test cases for `DynamicTable::update_size`.
524     ///
525     /// # Brief
526     /// 1. Creates a `DynamicTable`.
527     /// 2. Calls `DynamicTable::update_size` to update its max size.
528     /// 3. Checks the results.
529     #[test]
ut_dynamic_table_update_size()530     fn ut_dynamic_table_update_size() {
531         let mut table = DynamicTable::with_max_size(52);
532         table.update(Header::Authority, String::from("Authority"));
533         assert_eq!(table.queue.len(), 1);
534         match table.header(0) {
535             Some((Header::Authority, x)) if x == *"Authority" => {}
536             _ => panic!("DynamicTable::header() failed!"),
537         }
538 
539         table.update_size(0);
540         assert_eq!(table.queue.len(), 0);
541         assert!(table.header(0).is_none());
542     }
543 
544     /// UT test cases for `StaticTable::header_name` and `StaticTable::header`.
545     ///
546     /// # Brief
547     /// 1. Iterates over a range of indices, testing both
548     ///    `StaticTable::header_name` and `StaticTable::header`.
549     /// 2. Verifies the presence or absence of header names and headers based on
550     ///    the given index.
551     #[test]
ut_static_table()552     fn ut_static_table() {
553         // Checking header names for indices 1 to 64
554         for index in 1..65 {
555             if index < 62 {
556                 assert!(StaticTable::header_name(index).is_some())
557             } else {
558                 assert!(StaticTable::header_name(index).is_none())
559             }
560         }
561 
562         // Checking headers for indices 2 to 19
563         for index in 2..20 {
564             if index < 17 && index != 15 {
565                 assert!(StaticTable::header(index).is_some())
566             } else {
567                 assert!(StaticTable::header(index).is_none())
568             }
569         }
570     }
571 }
572