1pub const STATIC_TABLE: &[(&str, &str)] = &[
19 (":authority", ""),
20 (":method", "GET"),
21 (":method", "POST"),
22 (":path", "/"),
23 (":path", "/index.html"),
24 (":scheme", "http"),
25 (":scheme", "https"),
26 (":status", "200"),
27 (":status", "204"),
28 (":status", "206"),
29 (":status", "304"),
30 (":status", "400"),
31 (":status", "404"),
32 (":status", "500"),
33 ("accept-charset", ""),
34 ("accept-encoding", "gzip, deflate"),
35 ("accept-language", ""),
36 ("accept-ranges", ""),
37 ("accept", ""),
38 ("access-control-allow-origin", ""),
39 ("age", ""),
40 ("allow", ""),
41 ("authorization", ""),
42 ("cache-control", ""),
43 ("content-disposition", ""),
44 ("content-encoding", ""),
45 ("content-language", ""),
46 ("content-length", ""),
47 ("content-location", ""),
48 ("content-range", ""),
49 ("content-type", ""),
50 ("cookie", ""),
51 ("date", ""),
52 ("etag", ""),
53 ("expect", ""),
54 ("expires", ""),
55 ("from", ""),
56 ("host", ""),
57 ("if-match", ""),
58 ("if-modified-since", ""),
59 ("if-none-match", ""),
60 ("if-range", ""),
61 ("if-unmodified-since", ""),
62 ("last-modified", ""),
63 ("link", ""),
64 ("location", ""),
65 ("max-forwards", ""),
66 ("proxy-authenticate", ""),
67 ("proxy-authorization", ""),
68 ("range", ""),
69 ("referer", ""),
70 ("refresh", ""),
71 ("retry-after", ""),
72 ("server", ""),
73 ("set-cookie", ""),
74 ("strict-transport-security", ""),
75 ("transfer-encoding", ""),
76 ("user-agent", ""),
77 ("vary", ""),
78 ("via", ""),
79 ("www-authenticate", ""),
80];
81
82#[rustfmt::skip]
92pub const HUFFMAN_TABLE: &[(u32, u8)] = &[
93 (0x1ff8, 13), (0x7fffd8, 23), (0xfffffe2, 28), (0xfffffe3, 28), (0xfffffe4, 28), (0xfffffe5, 28), (0xfffffe6, 28), (0xfffffe7, 28), (0xfffffe8, 28), (0xffffea, 24), (0x3ffffffc, 30), (0xfffffe9, 28), (0xfffffea, 28), (0x3ffffffd, 30), (0xfffffeb, 28), (0xfffffec, 28), (0xfffffed, 28), (0xfffffee, 28), (0xfffffef, 28), (0xffffff0, 28), (0xffffff1, 28), (0xffffff2, 28), (0x3ffffffe, 30), (0xffffff3, 28), (0xffffff4, 28), (0xffffff5, 28), (0xffffff6, 28), (0xffffff7, 28), (0xffffff8, 28), (0xffffff9, 28), (0xffffffa, 28), (0xffffffb, 28), (0x14, 6), (0x3f8, 10), (0x3f9, 10), (0xffa, 12), (0x1ff9, 13), (0x15, 6), (0xf8, 8), (0x7fa, 11), (0x3fa, 10), (0x3fb, 10), (0xf9, 8), (0x7fb, 11), (0xfa, 8), (0x16, 6), (0x17, 6), (0x18, 6), (0x00, 5), (0x01, 5), (0x02, 5), (0x19, 6), (0x1a, 6), (0x1b, 6), (0x1c, 6), (0x1d, 6), (0x1e, 6), (0x1f, 6), (0x5c, 7), (0xfb, 8), (0x7ffc, 15), (0x20, 6), (0xffb, 12), (0x3fc, 10), (0x1ffa, 13), (0x21, 6), (0x5d, 7), (0x5e, 7), (0x5f, 7), (0x60, 7), (0x61, 7), (0x62, 7), (0x63, 7), (0x64, 7), (0x65, 7), (0x66, 7), (0x67, 7), (0x68, 7), (0x69, 7), (0x6a, 7), (0x6b, 7), (0x6c, 7), (0x6d, 7), (0x6e, 7), (0x6f, 7), (0x70, 7), (0x71, 7), (0x72, 7), (0xfc, 8), (0x73, 7), (0xfd, 8), (0x1ffb, 13), (0x7fff0, 19), (0x1ffc, 13), (0x3ffc, 14), (0x22, 6), (0x7ffd, 15), (0x03, 5), (0x23, 6), (0x04, 5), (0x24, 6), (0x05, 5), (0x25, 6), (0x26, 6), (0x27, 6), (0x06, 5), (0x74, 7), (0x75, 7), (0x28, 6), (0x29, 6), (0x2a, 6), (0x07, 5), (0x2b, 6), (0x76, 7), (0x2c, 6), (0x08, 5), (0x09, 5), (0x2d, 6), (0x77, 7), (0x78, 7), (0x79, 7), (0x7a, 7), (0x7b, 7), (0x7ffe, 15), (0x7fc, 11), (0x3ffd, 14), (0x1ffd, 13), (0xffffffc, 28), (0xfffe6, 20), (0x3fffd2, 22), (0xfffe7, 20), (0xfffe8, 20), (0x3fffd3, 22), (0x3fffd4, 22), (0x3fffd5, 22), (0x7fffd9, 23), (0x3fffd6, 22), (0x7fffda, 23), (0x7fffdb, 23), (0x7fffdc, 23), (0x7fffdd, 23), (0x7fffde, 23), (0xffffeb, 24), (0x7fffdf, 23), (0xffffec, 24), (0xffffed, 24), (0x3fffd7, 22), (0x7fffe0, 23), (0xffffee, 24), (0x7fffe1, 23), (0x7fffe2, 23), (0x7fffe3, 23), (0x7fffe4, 23), (0x1fffdc, 21), (0x3fffd8, 22), (0x7fffe5, 23), (0x3fffd9, 22), (0x7fffe6, 23), (0x7fffe7, 23), (0xffffef, 24), (0x3fffda, 22), (0x1fffdd, 21), (0xfffe9, 20), (0x3fffdb, 22), (0x3fffdc, 22), (0x7fffe8, 23), (0x7fffe9, 23), (0x1fffde, 21), (0x7fffea, 23), (0x3fffdd, 22), (0x3fffde, 22), (0xfffff0, 24), (0x1fffdf, 21), (0x3fffdf, 22), (0x7fffeb, 23), (0x7fffec, 23), (0x1fffe0, 21), (0x1fffe1, 21), (0x3fffe0, 22), (0x1fffe2, 21), (0x7fffed, 23), (0x3fffe1, 22), (0x7fffee, 23), (0x7fffef, 23), (0xfffea, 20), (0x3fffe2, 22), (0x3fffe3, 22), (0x3fffe4, 22), (0x7ffff0, 23), (0x3fffe5, 22), (0x3fffe6, 22), (0x7ffff1, 23), (0x3ffffe0, 26), (0x3ffffe1, 26), (0xfffeb, 20), (0x7fff1, 19), (0x3fffe7, 22), (0x7ffff2, 23), (0x3fffe8, 22), (0x1ffffec, 25), (0x3ffffe2, 26), (0x3ffffe3, 26), (0x3ffffe4, 26), (0x7ffffde, 27), (0x7ffffdf, 27), (0x3ffffe5, 26), (0xfffff1, 24), (0x1ffffed, 25), (0x7fff2, 19), (0x1fffe3, 21), (0x3ffffe6, 26), (0x7ffffe0, 27), (0x7ffffe1, 27), (0x3ffffe7, 26), (0x7ffffe2, 27), (0xfffff2, 24), (0x1fffe4, 21), (0x1fffe5, 21), (0x3ffffe8, 26), (0x3ffffe9, 26), (0xffffffd, 28), (0x7ffffe3, 27), (0x7ffffe4, 27), (0x7ffffe5, 27), (0xfffec, 20), (0xfffff3, 24), (0xfffed, 20), (0x1fffe6, 21), (0x3fffe9, 22), (0x1fffe7, 21), (0x1fffe8, 21), (0x7ffff3, 23), (0x3fffea, 22), (0x3fffeb, 22), (0x1ffffee, 25), (0x1ffffef, 25), (0xfffff4, 24), (0xfffff5, 24), (0x3ffffea, 26), (0x7ffff4, 23), (0x3ffffeb, 26), (0x7ffffe6, 27), (0x3ffffec, 26), (0x3ffffed, 26), (0x7ffffe7, 27), (0x7ffffe8, 27), (0x7ffffe9, 27), (0x7ffffea, 27), (0x7ffffeb, 27), (0xffffffe, 28), (0x7ffffec, 27), (0x7ffffed, 27), (0x7ffffee, 27), (0x7ffffef, 27), (0x7fffff0, 27), (0x3ffffee, 26), (0x3fffffff, 30), ];
351
352pub fn decode_integer(buf: &[u8], prefix_bits: u8) -> Option<(u64, usize)> {
369 if buf.is_empty() || prefix_bits == 0 || prefix_bits > 8 {
370 return None;
371 }
372
373 let prefix_max = (1u32 << prefix_bits) - 1;
374 let first = (buf[0] & (prefix_max as u8)) as u64;
375
376 if first < prefix_max as u64 {
377 return Some((first, 1));
379 }
380
381 let mut value = prefix_max as u64;
383 let mut shift = 0u64;
384 let mut i = 1;
385
386 loop {
387 if i >= buf.len() {
388 return None;
389 }
390 let byte = buf[i];
391 i += 1;
392 value += ((byte & 0x7F) as u64) << shift;
393 shift += 7;
394
395 if (byte & 0x80) == 0 {
396 break;
397 }
398
399 if shift > 63 {
400 return None;
402 }
403 }
404
405 Some((value, i))
406}
407
408pub fn encode_integer(value: u64, prefix_bits: u8, prefix_byte: u8) -> Vec<u8> {
418 let prefix_max = (1u64 << prefix_bits) - 1;
419
420 if value < prefix_max {
421 return vec![prefix_byte | (value as u8)];
423 }
424
425 let mut out = vec![prefix_byte | (prefix_max as u8)];
427 let mut remaining = value - prefix_max;
428
429 loop {
430 if remaining < 128 {
431 out.push(remaining as u8);
432 break;
433 }
434 out.push((remaining & 0x7F) as u8 | 0x80);
435 remaining >>= 7;
436 }
437
438 out
439}
440
441#[derive(Default)]
447struct HuffmanNode {
448 symbol: Option<u16>, children: [Option<Box<HuffmanNode>>; 2],
450}
451
452impl HuffmanNode {
453 fn new() -> Self {
454 HuffmanNode {
455 symbol: None,
456 children: [None, None],
457 }
458 }
459}
460
461fn build_huffman_tree() -> HuffmanNode {
463 let mut root = HuffmanNode::new();
464
465 for (sym, &(code, nbits)) in HUFFMAN_TABLE.iter().enumerate() {
466 if nbits == 0 || nbits > 32 {
467 continue;
468 }
469 let mut node = &mut root;
471 for bit_idx in (0..nbits).rev() {
472 let bit = ((code >> bit_idx) & 1) as usize;
473 if node.children[bit].is_none() {
474 node.children[bit] = Some(Box::new(HuffmanNode::new()));
475 }
476 node = node.children[bit].as_mut().unwrap();
477 }
478 node.symbol = Some(sym as u16);
479 }
480
481 root
482}
483
484pub fn huffman_decode(encoded: &[u8]) -> Option<Vec<u8>> {
493 let root = build_huffman_tree();
494 let mut output = Vec::new();
495 let mut node = &root;
496
497 for &byte in encoded {
498 for bit_idx in (0..8).rev() {
499 let bit = ((byte >> bit_idx) & 1) as usize;
500 node = node.children[bit].as_ref()?;
501
502 if let Some(sym) = node.symbol {
503 if sym == 256 {
504 return None;
506 }
507 output.push(sym as u8);
508 node = &root;
509 }
510 }
511 }
512
513 Some(output)
522}
523
524pub fn huffman_encode(data: &[u8]) -> Vec<u8> {
528 let mut bit_buf: u64 = 0;
529 let mut bit_count = 0u32;
530 let mut output = Vec::new();
531
532 for &byte in data {
533 let (code, nbits) = HUFFMAN_TABLE[byte as usize];
534 let nbits = nbits as u32;
535
536 bit_buf = (bit_buf << nbits) | (code as u64);
537 bit_count += nbits;
538
539 while bit_count >= 8 {
540 bit_count -= 8;
541 output.push(((bit_buf >> bit_count) & 0xFF) as u8);
542 }
543 }
544
545 if bit_count > 0 {
547 let padding = 8 - bit_count;
548 bit_buf = (bit_buf << padding) | ((1u64 << padding) - 1);
549 output.push((bit_buf & 0xFF) as u8);
550 }
551
552 output
553}
554
555pub fn decode_string(buf: &[u8]) -> Option<(Vec<u8>, usize)> {
573 if buf.is_empty() {
574 return None;
575 }
576
577 let huffman_flag = (buf[0] & 0x80) != 0;
578 let (length, consumed) = decode_integer(buf, 7)?;
579 let length = length as usize;
580
581 if consumed + length > buf.len() {
582 return None;
583 }
584
585 let string_data = &buf[consumed..consumed + length];
586
587 let result = if huffman_flag {
588 huffman_decode(string_data)?
589 } else {
590 string_data.to_vec()
591 };
592
593 Some((result, consumed + length))
594}
595
596pub fn encode_string_literal(data: &[u8]) -> Vec<u8> {
600 let mut out = encode_integer(data.len() as u64, 7, 0x00); out.extend_from_slice(data);
602 out
603}
604
605pub fn encode_string_huffman(data: &[u8]) -> Vec<u8> {
609 let encoded = huffman_encode(data);
610 let mut out = encode_integer(encoded.len() as u64, 7, 0x80); out.extend_from_slice(&encoded);
612 out
613}
614
615fn entry_size(name: &str, value: &str) -> usize {
621 name.len() + value.len() + 32
622}
623
624pub struct HpackDecoder {
629 dynamic_table: Vec<(String, String)>,
631 max_table_size: usize,
633 current_size: usize,
635}
636
637impl Default for HpackDecoder {
638 fn default() -> Self {
639 Self::new()
640 }
641}
642
643impl HpackDecoder {
644 pub fn new() -> Self {
646 HpackDecoder {
647 dynamic_table: Vec::new(),
648 max_table_size: 4096,
649 current_size: 0,
650 }
651 }
652
653 pub fn with_max_size(max_table_size: usize) -> Self {
655 HpackDecoder {
656 dynamic_table: Vec::new(),
657 max_table_size,
658 current_size: 0,
659 }
660 }
661
662 pub fn set_max_table_size(&mut self, size: usize) {
664 self.max_table_size = size;
665 self.evict_to_fit(0);
666 }
667
668 pub fn dynamic_table_len(&self) -> usize {
670 self.dynamic_table.len()
671 }
672
673 pub fn dynamic_table_current_size(&self) -> usize {
675 self.current_size
676 }
677
678 pub fn dynamic_table_entries(&self) -> &[(String, String)] {
681 &self.dynamic_table
682 }
683
684 pub fn decode(&mut self, buf: &[u8]) -> Result<Vec<(String, String)>, String> {
688 let mut headers = Vec::new();
689 let mut pos = 0;
690
691 while pos < buf.len() {
692 let first = buf[pos];
693
694 if (first & 0x80) != 0 {
695 let (idx, consumed) = decode_integer(&buf[pos..], 7)
698 .ok_or_else(|| "Failed to decode indexed header index".to_string())?;
699 pos += consumed;
700
701 let (name, value) = self
702 .table_entry(idx as usize)
703 .ok_or_else(|| format!("Invalid header table index: {}", idx))?;
704 headers.push((name, value));
705 } else if (first & 0x40) != 0 {
706 let (idx, consumed) = decode_integer(&buf[pos..], 6)
709 .ok_or_else(|| "Failed to decode literal indexed name index".to_string())?;
710 pos += consumed;
711
712 let name = if idx == 0 {
713 let (name_bytes, nc) = decode_string(&buf[pos..])
715 .ok_or_else(|| "Failed to decode literal name string".to_string())?;
716 pos += nc;
717 String::from_utf8(name_bytes)
718 .map_err(|e| format!("Invalid UTF-8 in header name: {}", e))?
719 } else {
720 let (n, _) = self
721 .table_entry(idx as usize)
722 .ok_or_else(|| format!("Invalid header table index: {}", idx))?;
723 n
724 };
725
726 let (value_bytes, vc) = decode_string(&buf[pos..])
727 .ok_or_else(|| "Failed to decode literal value string".to_string())?;
728 pos += vc;
729 let value = String::from_utf8(value_bytes)
730 .map_err(|e| format!("Invalid UTF-8 in header value: {}", e))?;
731
732 self.add_to_dynamic_table(name.clone(), value.clone());
733 headers.push((name, value));
734 } else if (first & 0x20) != 0 {
735 let (new_size, consumed) = decode_integer(&buf[pos..], 5)
738 .ok_or_else(|| "Failed to decode table size update".to_string())?;
739 pos += consumed;
740
741 if new_size as usize > self.max_table_size {
742 return Err(format!(
743 "Table size update {} exceeds max {}",
744 new_size, self.max_table_size
745 ));
746 }
747 self.evict_to_fit(0);
748 while self.current_size > new_size as usize {
750 if let Some(entry) = self.dynamic_table.pop() {
751 self.current_size = self
752 .current_size
753 .saturating_sub(entry_size(&entry.0, &entry.1));
754 } else {
755 break;
756 }
757 }
758 } else if (first & 0x10) != 0 {
759 let (idx, consumed) = decode_integer(&buf[pos..], 4)
762 .ok_or_else(|| "Failed to decode never-indexed name index".to_string())?;
763 pos += consumed;
764
765 let name = if idx == 0 {
766 let (name_bytes, nc) = decode_string(&buf[pos..])
767 .ok_or_else(|| "Failed to decode never-indexed name string".to_string())?;
768 pos += nc;
769 String::from_utf8(name_bytes)
770 .map_err(|e| format!("Invalid UTF-8 in header name: {}", e))?
771 } else {
772 let (n, _) = self
773 .table_entry(idx as usize)
774 .ok_or_else(|| format!("Invalid header table index: {}", idx))?;
775 n
776 };
777
778 let (value_bytes, vc) = decode_string(&buf[pos..])
779 .ok_or_else(|| "Failed to decode never-indexed value string".to_string())?;
780 pos += vc;
781 let value = String::from_utf8(value_bytes)
782 .map_err(|e| format!("Invalid UTF-8 in header value: {}", e))?;
783
784 headers.push((name, value));
786 } else {
787 let (idx, consumed) = decode_integer(&buf[pos..], 4)
790 .ok_or_else(|| "Failed to decode without-indexing name index".to_string())?;
791 pos += consumed;
792
793 let name = if idx == 0 {
794 let (name_bytes, nc) = decode_string(&buf[pos..]).ok_or_else(|| {
795 "Failed to decode without-indexing name string".to_string()
796 })?;
797 pos += nc;
798 String::from_utf8(name_bytes)
799 .map_err(|e| format!("Invalid UTF-8 in header name: {}", e))?
800 } else {
801 let (n, _) = self
802 .table_entry(idx as usize)
803 .ok_or_else(|| format!("Invalid header table index: {}", idx))?;
804 n
805 };
806
807 let (value_bytes, vc) = decode_string(&buf[pos..])
808 .ok_or_else(|| "Failed to decode without-indexing value string".to_string())?;
809 pos += vc;
810 let value = String::from_utf8(value_bytes)
811 .map_err(|e| format!("Invalid UTF-8 in header value: {}", e))?;
812
813 headers.push((name, value));
815 }
816 }
817
818 Ok(headers)
819 }
820
821 fn dynamic_table_entry(&self, index: usize) -> Option<(&str, &str)> {
823 self.dynamic_table
824 .get(index)
825 .map(|(n, v)| (n.as_str(), v.as_str()))
826 }
827
828 fn static_table_entry(index: usize) -> Option<(&'static str, &'static str)> {
830 if index >= 1 && index <= STATIC_TABLE.len() {
831 Some(STATIC_TABLE[index - 1])
832 } else {
833 None
834 }
835 }
836
837 fn table_entry(&self, index: usize) -> Option<(String, String)> {
841 if index == 0 {
842 return None;
843 }
844
845 if index <= STATIC_TABLE.len() {
846 let (n, v) = Self::static_table_entry(index)?;
847 return Some((n.to_string(), v.to_string()));
848 }
849
850 let dynamic_idx = index - STATIC_TABLE.len() - 1;
851 let (n, v) = self.dynamic_table_entry(dynamic_idx)?;
852 Some((n.to_string(), v.to_string()))
853 }
854
855 fn add_to_dynamic_table(&mut self, name: String, value: String) {
857 let size = entry_size(&name, &value);
858 self.evict_to_fit(size);
859 if size <= self.max_table_size {
860 self.current_size += size;
861 self.dynamic_table.insert(0, (name, value));
862 }
863 }
864
865 fn evict_to_fit(&mut self, new_entry_size: usize) {
868 while !self.dynamic_table.is_empty()
869 && self.current_size + new_entry_size > self.max_table_size
870 {
871 if let Some(entry) = self.dynamic_table.pop() {
872 self.current_size = self
873 .current_size
874 .saturating_sub(entry_size(&entry.0, &entry.1));
875 }
876 }
877 }
878}
879
880pub struct HpackEncoder {
890 #[allow(dead_code)]
892 dynamic_table: Vec<(String, String)>,
893 #[allow(dead_code)]
895 max_table_size: usize,
896}
897
898impl Default for HpackEncoder {
899 fn default() -> Self {
900 Self::new()
901 }
902}
903
904impl HpackEncoder {
905 pub fn new() -> Self {
907 HpackEncoder {
908 dynamic_table: Vec::new(),
909 max_table_size: 4096,
910 }
911 }
912
913 pub fn encode(&self, headers: &[(&str, &str)]) -> Vec<u8> {
919 let mut out = Vec::new();
920
921 for &(name, value) in headers {
922 if let Some(static_idx) = self.find_static_exact(name, value) {
924 out.extend_from_slice(&encode_integer(static_idx as u64, 7, 0x80));
927 continue;
928 }
929
930 if let Some(name_idx) = self.find_static_name(name) {
932 out.extend_from_slice(&encode_integer(name_idx as u64, 6, 0x40));
935 out.extend_from_slice(&encode_string_literal(value.as_bytes()));
936 continue;
937 }
938
939 out.push(0x00);
942 out.extend_from_slice(&encode_string_literal(name.as_bytes()));
943 out.extend_from_slice(&encode_string_literal(value.as_bytes()));
944 }
945
946 out
947 }
948
949 pub fn encode_huffman(&self, headers: &[(&str, &str)]) -> Vec<u8> {
951 let mut out = Vec::new();
952
953 for &(name, value) in headers {
954 if let Some(static_idx) = self.find_static_exact(name, value) {
956 out.extend_from_slice(&encode_integer(static_idx as u64, 7, 0x80));
957 continue;
958 }
959
960 out.push(0x00);
962 out.extend_from_slice(&encode_string_huffman(name.as_bytes()));
963 out.extend_from_slice(&encode_string_huffman(value.as_bytes()));
964 }
965
966 out
967 }
968
969 fn find_static_exact(&self, name: &str, value: &str) -> Option<usize> {
972 for (i, &(n, v)) in STATIC_TABLE.iter().enumerate() {
973 if n == name && v == value {
974 return Some(i + 1);
975 }
976 }
977 None
978 }
979
980 fn find_static_name(&self, name: &str) -> Option<usize> {
983 for (i, &(n, _)) in STATIC_TABLE.iter().enumerate() {
984 if n == name {
985 return Some(i + 1);
986 }
987 }
988 None
989 }
990}
991
992#[cfg(test)]
997mod tests {
998 use super::*;
999
1000 #[test]
1005 fn test_decode_integer_small() {
1006 let buf = [0x05u8];
1008 let (val, consumed) = decode_integer(&buf, 5).unwrap();
1009 assert_eq!(val, 5);
1010 assert_eq!(consumed, 1);
1011 }
1012
1013 #[test]
1014 fn test_decode_integer_multi_byte() {
1015 let buf = [0b00011111u8, 0x9A, 0x0A];
1024 let (val, consumed) = decode_integer(&buf, 5).unwrap();
1025 assert_eq!(val, 1337);
1026 assert_eq!(consumed, 3);
1027 }
1028
1029 #[test]
1030 fn test_encode_integer_small() {
1031 let encoded = encode_integer(5, 5, 0x00);
1032 assert_eq!(encoded, vec![0x05]);
1033 }
1034
1035 #[test]
1036 fn test_encode_integer_large() {
1037 let encoded = encode_integer(1337, 5, 0x00);
1039 assert_eq!(encoded, vec![0b00011111, 0x9A, 0x0A]);
1040 }
1041
1042 #[test]
1043 fn test_encode_decode_integer_roundtrip() {
1044 for val in [0u64, 1, 30, 31, 127, 128, 255, 1000, 65535, 1337] {
1045 for prefix in [4u8, 5, 6, 7] {
1046 let encoded = encode_integer(val, prefix, 0x00);
1047 let (decoded, _) = decode_integer(&encoded, prefix).unwrap();
1048 assert_eq!(
1049 val, decoded,
1050 "Roundtrip failed for val={} prefix={}",
1051 val, prefix
1052 );
1053 }
1054 }
1055 }
1056
1057 #[test]
1062 fn test_decode_string_literal() {
1063 let mut buf = vec![0x05u8]; buf.extend_from_slice(b"hello");
1066 let (s, consumed) = decode_string(&buf).unwrap();
1067 assert_eq!(s, b"hello");
1068 assert_eq!(consumed, 6);
1069 }
1070
1071 #[test]
1072 fn test_huffman_encode_decode_roundtrip() {
1073 let original = b"www.example.com";
1074 let encoded = huffman_encode(original);
1075 let decoded = huffman_decode(&encoded).unwrap();
1076 assert_eq!(decoded, original);
1077 }
1078
1079 #[test]
1080 fn test_huffman_encode_empty() {
1081 let encoded = huffman_encode(b"");
1082 assert!(encoded.is_empty());
1083 }
1084
1085 #[test]
1086 fn test_huffman_decode_rfc7541_example() {
1087 let encoded = [
1090 0xf1u8, 0xe3, 0xc2, 0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab, 0x90, 0xf4, 0xff,
1091 ];
1092 let decoded = huffman_decode(&encoded).unwrap();
1093 assert_eq!(decoded, b"www.example.com");
1094 }
1095
1096 #[test]
1097 fn test_decode_string_huffman() {
1098 let original = b"no-cache";
1099 let encoded = huffman_encode(original);
1100 let mut buf = encode_integer(encoded.len() as u64, 7, 0x80);
1102 buf.extend_from_slice(&encoded);
1103 let (decoded, _) = decode_string(&buf).unwrap();
1104 assert_eq!(decoded, original);
1105 }
1106
1107 #[test]
1112 fn test_static_table_size() {
1113 assert_eq!(STATIC_TABLE.len(), 61);
1114 }
1115
1116 #[test]
1117 fn test_static_table_first_entry() {
1118 assert_eq!(STATIC_TABLE[0], (":authority", ""));
1119 }
1120
1121 #[test]
1122 fn test_static_table_method_get() {
1123 assert_eq!(STATIC_TABLE[1], (":method", "GET"));
1124 }
1125
1126 #[test]
1131 fn test_decoder_indexed_static() {
1132 let buf = [0x82u8];
1135 let mut decoder = HpackDecoder::new();
1136 let headers = decoder.decode(&buf).unwrap();
1137 assert_eq!(headers.len(), 1);
1138 assert_eq!(headers[0], (":method".to_string(), "GET".to_string()));
1139 }
1140
1141 #[test]
1142 fn test_decoder_literal_with_indexing() {
1143 let mut buf = vec![0x40u8]; buf.extend_from_slice(&encode_string_literal(b"custom-key"));
1147 buf.extend_from_slice(&encode_string_literal(b"custom-header"));
1148
1149 let mut decoder = HpackDecoder::new();
1150 let headers = decoder.decode(&buf).unwrap();
1151 assert_eq!(headers.len(), 1);
1152 assert_eq!(
1153 headers[0],
1154 ("custom-key".to_string(), "custom-header".to_string())
1155 );
1156 }
1157
1158 #[test]
1159 fn test_decoder_literal_without_indexing() {
1160 let mut buf = vec![0x00u8];
1162 buf.extend_from_slice(&encode_string_literal(b"x-custom"));
1163 buf.extend_from_slice(&encode_string_literal(b"value"));
1164
1165 let mut decoder = HpackDecoder::new();
1166 let headers = decoder.decode(&buf).unwrap();
1167 assert_eq!(headers.len(), 1);
1168 assert_eq!(headers[0], ("x-custom".to_string(), "value".to_string()));
1169 }
1170
1171 #[test]
1172 fn test_decoder_dynamic_table_eviction() {
1173 let mut decoder = HpackDecoder::with_max_size(64);
1174 let mut buf = vec![0x40u8];
1176 buf.extend_from_slice(&encode_string_literal(b"x-a"));
1177 buf.extend_from_slice(&encode_string_literal(b"b"));
1178 decoder.decode(&buf).unwrap();
1179 assert_eq!(decoder.dynamic_table.len(), 1);
1180
1181 let mut buf2 = vec![0x40u8];
1183 buf2.extend_from_slice(&encode_string_literal(b"x-c"));
1184 buf2.extend_from_slice(&encode_string_literal(b"d"));
1185 decoder.decode(&buf2).unwrap();
1186 assert!(decoder.dynamic_table.len() <= 2);
1188 }
1189
1190 #[test]
1195 fn test_encoder_static_exact_match() {
1196 let encoder = HpackEncoder::new();
1197 let encoded = encoder.encode(&[(":method", "GET")]);
1199 assert_eq!(encoded, vec![0x82]);
1200 }
1201
1202 #[test]
1203 fn test_encoder_static_name_match() {
1204 let encoder = HpackEncoder::new();
1205 let encoded = encoder.encode(&[(":method", "DELETE")]);
1207 assert_eq!(encoded[0], 0x42); }
1210
1211 #[test]
1212 fn test_encoder_roundtrip() {
1213 let encoder = HpackEncoder::new();
1214 let mut decoder = HpackDecoder::new();
1215
1216 let headers = vec![
1217 (":method", "GET"),
1218 (":path", "/"),
1219 (":scheme", "https"),
1220 ("user-agent", "test/1.0"),
1221 ("x-custom", "value"),
1222 ];
1223 let encoded = encoder.encode(&headers);
1224 let decoded = decoder.decode(&encoded).unwrap();
1225
1226 assert_eq!(decoded.len(), headers.len());
1227 for (i, (name, value)) in headers.iter().enumerate() {
1228 assert_eq!(decoded[i].0, *name);
1229 assert_eq!(decoded[i].1, *value);
1230 }
1231 }
1232
1233 #[test]
1234 fn test_encoder_huffman_roundtrip() {
1235 let encoder = HpackEncoder::new();
1236 let mut decoder = HpackDecoder::new();
1237
1238 let headers = vec![
1239 ("x-request-id", "abc-123"),
1240 ("content-type", "application/json"),
1241 ];
1242 let encoded = encoder.encode_huffman(&headers);
1243 let decoded = decoder.decode(&encoded).unwrap();
1244
1245 assert_eq!(decoded.len(), headers.len());
1246 for (i, (name, value)) in headers.iter().enumerate() {
1247 assert_eq!(decoded[i].0, *name);
1248 assert_eq!(decoded[i].1, *value);
1249 }
1250 }
1251}