1use std::borrow::Cow;
50use std::num::Wrapping;
51
52use tracing::trace;
53
54use super::huffman::HuffmanDecoder;
55use super::huffman::HuffmanDecoderError;
56
57use super::STATIC_TABLE;
58use super::{HeaderTable, StaticTable};
59
60fn decode_integer(buf: &[u8], prefix_size: u8) -> Result<(usize, usize), DecoderError> {
68 if !(1..=8).contains(&prefix_size) {
69 return Err(DecoderError::IntegerDecodingError(
70 IntegerDecodingError::InvalidPrefix,
71 ));
72 }
73 if buf.is_empty() {
74 return Err(DecoderError::IntegerDecodingError(
75 IntegerDecodingError::NotEnoughOctets,
76 ));
77 }
78
79 let Wrapping(mask) = if prefix_size == 8 {
81 Wrapping(0xFF)
82 } else {
83 Wrapping(1u8 << prefix_size) - Wrapping(1)
84 };
85 let mut value = (buf[0] & mask) as usize;
86 if value < (mask as usize) {
87 return Ok((value, 1));
89 }
90
91 let mut total = 1;
95 let mut m = 0;
96 let octet_limit = 5;
100
101 for &b in buf[1..].iter() {
102 total += 1;
103 value += ((b & 127) as usize) * (1 << m);
104 m += 7;
105
106 if b & 128 != 128 {
107 return Ok((value, total));
109 }
110
111 if total == octet_limit {
112 return Err(DecoderError::IntegerDecodingError(
115 IntegerDecodingError::TooManyOctets,
116 ));
117 }
118 }
119
120 Err(DecoderError::IntegerDecodingError(
123 IntegerDecodingError::NotEnoughOctets,
124 ))
125}
126
127fn decode_string(buf: &[u8]) -> Result<(Cow<'_, [u8]>, usize), DecoderError> {
136 let (len, consumed) = decode_integer(buf, 7)?;
137 trace!("decode_string: Consumed = {}, len = {}", consumed, len);
138 if consumed + len > buf.len() {
139 return Err(DecoderError::StringDecodingError(
140 StringDecodingError::NotEnoughOctets,
141 ));
142 }
143 let raw_string = &buf[consumed..consumed + len];
144 if buf[0] & 128 == 128 {
145 trace!("decode_string: Using the Huffman code");
146 let mut decoder = HuffmanDecoder::new();
149 let decoded = match decoder.decode(raw_string) {
150 Err(e) => {
151 return Err(DecoderError::StringDecodingError(
152 StringDecodingError::HuffmanDecoderError(e),
153 ));
154 }
155 Ok(res) => res,
156 };
157 Ok((Cow::Owned(decoded), consumed + len))
158 } else {
159 trace!("decode_string: Raw octet string received");
161 Ok((Cow::Borrowed(raw_string), consumed + len))
162 }
163}
164
165enum FieldRepresentation {
168 Indexed,
169 LiteralWithIncrementalIndexing,
170 SizeUpdate,
171 LiteralNeverIndexed,
172 LiteralWithoutIndexing,
173}
174
175impl FieldRepresentation {
176 fn new(octet: u8) -> FieldRepresentation {
181 if octet & 128 == 128 {
182 FieldRepresentation::Indexed
184 } else if octet & 64 == 64 {
185 FieldRepresentation::LiteralWithIncrementalIndexing
187 } else if octet & 32 == 32 {
188 FieldRepresentation::SizeUpdate
190 } else if octet & 16 == 16 {
191 FieldRepresentation::LiteralNeverIndexed
193 } else {
194 FieldRepresentation::LiteralWithoutIndexing
196 }
197 }
198}
199
200#[derive(PartialEq, Copy, Clone, Debug, thiserror::Error)]
203#[non_exhaustive]
204pub enum IntegerDecodingError {
205 #[error("Too many octets in the integer encoding")]
210 TooManyOctets,
211 #[error("Integer value too large")]
214 ValueTooLarge,
215 #[error("Not enough octets in the buffer")]
218 NotEnoughOctets,
219 #[error("Invalid prefix")]
221 InvalidPrefix,
222}
223
224#[derive(PartialEq, Copy, Clone, Debug, thiserror::Error)]
225#[non_exhaustive]
226pub enum StringDecodingError {
227 #[error("Not enough octets in the buffer")]
228 NotEnoughOctets,
229 #[error("Huffman decoder error: {0}")]
230 HuffmanDecoderError(HuffmanDecoderError),
231}
232
233#[derive(PartialEq, Copy, Clone, Debug, thiserror::Error)]
236#[non_exhaustive]
237pub enum DecoderError {
238 #[error("Header index out of bounds")]
239 HeaderIndexOutOfBounds,
240 #[error("Integer decoding error: {0}")]
241 IntegerDecodingError(IntegerDecodingError),
242 #[error("String decoding error: {0}")]
243 StringDecodingError(StringDecodingError),
244 #[error("Dynamic table size exceeds the maximum size")]
248 InvalidMaxDynamicSize,
249 #[error("Dynamic table size update at the end of a header block")]
252 SizeUpdateAtEnd,
253}
254
255pub enum DecoderOrCallbackError<E> {
258 DecoderError(DecoderError),
259 CallbackError(E),
260}
261
262impl<E> From<DecoderError> for DecoderOrCallbackError<E> {
263 fn from(err: DecoderError) -> Self {
264 Self::DecoderError(err)
265 }
266}
267
268pub type DecoderResult = Result<Vec<(Vec<u8>, Vec<u8>)>, DecoderError>;
270
271pub struct Decoder<'a> {
277 header_table: HeaderTable<'a>,
279
280 max_allowed_table_size: Option<usize>,
281
282 #[cfg(test)]
284 pub(crate) allow_trailing_size_updates: bool,
285}
286
287impl Default for Decoder<'_> {
288 fn default() -> Decoder<'static> {
289 Decoder::with_static_table(STATIC_TABLE)
290 }
291}
292
293type DecodedLiteralCow<'a> = ((Cow<'a, [u8]>, Cow<'a, [u8]>), usize);
294type DecodedLiteralSlice<'a> = ((&'a [u8], &'a [u8]), usize);
295
296impl<'a> Decoder<'a> {
299 pub fn new() -> Decoder<'a> {
301 Default::default()
302 }
303
304 fn with_static_table(static_table: StaticTable<'a>) -> Decoder<'a> {
314 Decoder {
315 header_table: HeaderTable::with_static_table(static_table),
316 max_allowed_table_size: None,
317 #[cfg(test)]
318 allow_trailing_size_updates: false,
319 }
320 }
321
322 pub fn set_max_table_size(&mut self, new_max_size: usize) {
326 if let Some(max_allowed_size) = self.max_allowed_table_size {
327 assert!(
330 new_max_size <= max_allowed_size,
331 "new_max_size ({}) > max_allowed_size ({})",
332 new_max_size,
333 max_allowed_size
334 );
335 }
336
337 self.header_table
338 .dynamic_table
339 .set_max_table_size(new_max_size);
340 }
341
342 pub fn set_max_allowed_table_size(&mut self, max_allowed_size: usize) {
346 self.max_allowed_table_size = Some(max_allowed_size);
347 }
348
349 pub fn decode_with_cb(
369 &mut self,
370 buf: &[u8],
371 mut cb: impl FnMut(Cow<[u8]>, Cow<[u8]>),
372 ) -> Result<(), DecoderError> {
373 let mut current_octet_index = 0;
374
375 let mut last_was_size_update = false;
376 while current_octet_index < buf.len() {
377 let initial_octet = buf[current_octet_index];
382 let buffer_leftover = &buf[current_octet_index..];
383 let field_representation = FieldRepresentation::new(initial_octet);
384 last_was_size_update = matches!(field_representation, FieldRepresentation::SizeUpdate);
385
386 let consumed = match field_representation {
387 FieldRepresentation::Indexed => {
388 let ((name, value), consumed) = self.decode_indexed(buffer_leftover)?;
389 cb(Cow::Borrowed(name), Cow::Borrowed(value));
390
391 consumed
392 }
393 FieldRepresentation::LiteralWithIncrementalIndexing => {
394 let ((name, value), consumed) = {
395 let ((name, value), consumed) =
396 self.decode_literal(buffer_leftover, true)?;
397 cb(Cow::Borrowed(&name), Cow::Borrowed(&value));
398
399 let name = name.into_owned();
402 let value = value.into_owned();
403
404 ((name, value), consumed)
405 };
406 self.header_table.add_header(name, value);
412
413 consumed
414 }
415 FieldRepresentation::LiteralWithoutIndexing => {
416 let ((name, value), consumed) = self.decode_literal(buffer_leftover, false)?;
417 cb(name, value);
418
419 consumed
420 }
421 FieldRepresentation::LiteralNeverIndexed => {
422 let ((name, value), consumed) = self.decode_literal(buffer_leftover, false)?;
427 cb(name, value);
428
429 consumed
430 }
431 FieldRepresentation::SizeUpdate => {
432 self.update_max_dynamic_size(buffer_leftover)?
434 }
435 };
436
437 current_octet_index += consumed;
438 }
439
440 if last_was_size_update {
441 #[cfg(test)]
442 if self.allow_trailing_size_updates {
443 return Ok(());
444 }
445
446 return Err(DecoderError::SizeUpdateAtEnd);
447 }
448
449 Ok(())
450 }
451
452 pub fn decode(&mut self, buf: &[u8]) -> DecoderResult {
462 let mut header_list = Vec::new();
463
464 self.decode_with_cb(buf, |n, v| {
465 header_list.push((n.into_owned(), v.into_owned()))
466 })?;
467
468 Ok(header_list)
469 }
470
471 fn decode_indexed(&self, buf: &[u8]) -> Result<DecodedLiteralSlice<'_>, DecoderError> {
473 let (index, consumed) = decode_integer(buf, 7)?;
474 trace!(
475 "Decoding indexed: index = {}, consumed = {}",
476 index,
477 consumed
478 );
479
480 let (name, value) = self.get_from_table(index)?;
481
482 Ok(((name, value), consumed))
483 }
484
485 fn get_from_table(&self, index: usize) -> Result<(&[u8], &[u8]), DecoderError> {
491 self.header_table
492 .get_from_table(index)
493 .ok_or(DecoderError::HeaderIndexOutOfBounds)
494 }
495
496 fn decode_literal<'b>(
503 &'b self,
504 buf: &'b [u8],
505 index: bool,
506 ) -> Result<DecodedLiteralCow<'b>, DecoderError> {
507 let prefix = if index { 6 } else { 4 };
508 let (table_index, mut consumed) = decode_integer(buf, prefix)?;
509
510 let name = if table_index == 0 {
512 let (name, name_len) = decode_string(&buf[consumed..])?;
514 consumed += name_len;
515 name
516 } else {
517 let (name, _) = self.get_from_table(table_index)?;
519 Cow::Borrowed(name)
520 };
521
522 let (value, value_len) = decode_string(&buf[consumed..])?;
524 consumed += value_len;
525
526 Ok(((name, value), consumed))
527 }
528
529 fn update_max_dynamic_size(&mut self, buf: &[u8]) -> Result<usize, DecoderError> {
538 let (new_size, consumed) = decode_integer(buf, 5)?;
539 if let Some(max_size) = self.max_allowed_table_size {
540 if new_size > max_size {
541 return Err(DecoderError::InvalidMaxDynamicSize);
542 }
543 }
544 self.header_table.dynamic_table.set_max_table_size(new_size);
545
546 trace!(
547 "Decoder changed max table size from {} to {}",
548 self.header_table.dynamic_table.get_size(),
549 new_size
550 );
551
552 Ok(consumed)
553 }
554}
555
556#[cfg(test)]
557mod tests {
558 use super::decode_integer;
559
560 use std::borrow::Cow;
561
562 use super::super::encoder::encode_integer;
563 use super::super::huffman::HuffmanDecoderError;
564 use super::decode_string;
565 use super::Decoder;
566 use super::FieldRepresentation;
567 use super::{DecoderError, DecoderResult};
568 use super::{IntegerDecodingError, StringDecodingError};
569
570 #[test]
572 fn test_decode_integer() {
573 assert_eq!((10, 1), decode_integer(&[10], 5).ok().unwrap());
574 assert_eq!((1337, 3), decode_integer(&[31, 154, 10], 5).ok().unwrap());
575 assert_eq!(
576 (1337, 3),
577 decode_integer(&[31 + 32, 154, 10], 5).ok().unwrap()
578 );
579 assert_eq!(
580 (1337, 3),
581 decode_integer(&[31 + 64, 154, 10], 5).ok().unwrap()
582 );
583 assert_eq!(
584 (1337, 3),
585 decode_integer(&[31, 154, 10, 111, 22], 5).ok().unwrap()
586 );
587
588 assert_eq!((127, 2), decode_integer(&[255, 0], 7).ok().unwrap());
589 assert_eq!((127, 2), decode_integer(&[127, 0], 7).ok().unwrap());
590 assert_eq!((255, 3), decode_integer(&[127, 128, 1], 7).ok().unwrap());
591 assert_eq!((255, 2), decode_integer(&[255, 0], 8).unwrap());
592 assert_eq!((254, 1), decode_integer(&[254], 8).unwrap());
593 assert_eq!((1, 1), decode_integer(&[1], 8).unwrap());
594 assert_eq!((0, 1), decode_integer(&[0], 8).unwrap());
595 assert_eq!(
597 (268435710, 5),
598 decode_integer(&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF - 128], 8)
599 .ok()
600 .unwrap()
601 );
602 }
603
604 macro_rules! assert_integer_err (
607 ($err_type:expr, $decoder_result:expr) => (
608 assert_eq!($err_type, match $decoder_result {
609 Err(DecoderError::IntegerDecodingError(e)) => e,
610 _ => panic!("Expected a decoding error"),
611 });
612 );
613 );
614
615 #[test]
618 fn test_decode_integer_errors() {
619 assert_integer_err!(
620 IntegerDecodingError::NotEnoughOctets,
621 decode_integer(&[], 5)
622 );
623 assert_integer_err!(
624 IntegerDecodingError::NotEnoughOctets,
625 decode_integer(&[0xFF, 0xFF], 5)
626 );
627 assert_integer_err!(
628 IntegerDecodingError::TooManyOctets,
629 decode_integer(
630 &[0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80],
631 1
632 )
633 );
634 assert_integer_err!(
635 IntegerDecodingError::TooManyOctets,
636 decode_integer(&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0], 8)
637 );
638 assert_integer_err!(
639 IntegerDecodingError::InvalidPrefix,
640 decode_integer(&[10], 0)
641 );
642 assert_integer_err!(
643 IntegerDecodingError::InvalidPrefix,
644 decode_integer(&[10], 9)
645 );
646 }
647
648 #[test]
649 fn test_detect_literal_without_indexing() {
650 assert!(matches!(
651 FieldRepresentation::new(0),
652 FieldRepresentation::LiteralWithoutIndexing
653 ));
654 assert!(matches!(
655 FieldRepresentation::new((1 << 4) - 1),
656 FieldRepresentation::LiteralWithoutIndexing
657 ));
658 assert!(matches!(
659 FieldRepresentation::new(2),
660 FieldRepresentation::LiteralWithoutIndexing
661 ));
662 }
663
664 #[test]
665 fn test_detect_literal_never_indexed() {
666 assert!(matches!(
667 FieldRepresentation::new(1 << 4),
668 FieldRepresentation::LiteralNeverIndexed
669 ));
670 assert!(matches!(
671 FieldRepresentation::new((1 << 4) + 15),
672 FieldRepresentation::LiteralNeverIndexed
673 ));
674 }
675
676 #[test]
677 fn test_detect_literal_incremental_indexing() {
678 assert!(matches!(
679 FieldRepresentation::new(1 << 6),
680 FieldRepresentation::LiteralWithIncrementalIndexing
681 ));
682 assert!(matches!(
683 FieldRepresentation::new((1 << 6) + (1 << 4)),
684 FieldRepresentation::LiteralWithIncrementalIndexing
685 ));
686 assert!(matches!(
687 FieldRepresentation::new((1 << 7) - 1),
688 FieldRepresentation::LiteralWithIncrementalIndexing
689 ));
690 }
691
692 #[test]
693 fn test_detect_indexed() {
694 assert!(matches!(
695 FieldRepresentation::new(1 << 7),
696 FieldRepresentation::Indexed
697 ));
698 assert!(matches!(
699 FieldRepresentation::new((1 << 7) + (1 << 4)),
700 FieldRepresentation::Indexed
701 ));
702 assert!(matches!(
703 FieldRepresentation::new((1 << 7) + (1 << 5)),
704 FieldRepresentation::Indexed
705 ));
706 assert!(matches!(
707 FieldRepresentation::new((1 << 7) + (1 << 6)),
708 FieldRepresentation::Indexed
709 ));
710 assert!(matches!(
711 FieldRepresentation::new(255),
712 FieldRepresentation::Indexed
713 ));
714 }
715
716 #[test]
717 fn test_detect_dynamic_table_size_update() {
718 assert!(matches!(
719 FieldRepresentation::new(1 << 5),
720 FieldRepresentation::SizeUpdate
721 ));
722 assert!(matches!(
723 FieldRepresentation::new((1 << 5) + (1 << 4)),
724 FieldRepresentation::SizeUpdate
725 ));
726 assert!(matches!(
727 FieldRepresentation::new((1 << 6) - 1),
728 FieldRepresentation::SizeUpdate
729 ));
730 }
731
732 #[test]
733 fn test_decode_string_no_huffman() {
734 fn assert_borrowed_eq(expected: (&[u8], usize), result: (Cow<'_, [u8]>, usize)) {
737 let (expected_str, expected_len) = expected;
738 let (actual_str, actual_len) = result;
739 assert_eq!(expected_len, actual_len);
740 match actual_str {
741 Cow::Borrowed(actual) => assert_eq!(actual, expected_str),
742 _ => panic!("Expected the result to be borrowed!"),
743 };
744 }
745
746 assert_eq!(
747 (Cow::Borrowed(&b"abc"[..]), 4),
748 decode_string(&[3, b'a', b'b', b'c']).ok().unwrap()
749 );
750 assert_eq!(
751 (Cow::Borrowed(&b"a"[..]), 2),
752 decode_string(&[1, b'a']).ok().unwrap()
753 );
754 assert_eq!(
755 (Cow::Borrowed(&b""[..]), 1),
756 decode_string(&[0, b'a']).ok().unwrap()
757 );
758
759 assert_borrowed_eq(
760 (&b"abc"[..], 4),
761 decode_string(&[3, b'a', b'b', b'c']).ok().unwrap(),
762 );
763 assert_borrowed_eq((&b"a"[..], 2), decode_string(&[1, b'a']).ok().unwrap());
764 assert_borrowed_eq((&b""[..], 1), decode_string(&[0, b'a']).ok().unwrap());
765
766 assert_eq!(
768 StringDecodingError::NotEnoughOctets,
769 match decode_string(&[3, b'a', b'b']) {
770 Err(DecoderError::StringDecodingError(e)) => e,
771 _ => panic!("Expected NotEnoughOctets error!"),
772 }
773 );
774 }
775
776 #[test]
779 fn test_decode_string_no_huffman_long() {
780 {
781 let full_string: Vec<u8> = (0u8..200).collect();
782 let mut encoded = encode_integer(full_string.len(), 7);
783 encoded.extend(full_string.clone());
784
785 assert_eq!(
786 (Cow::Owned(full_string), encoded.len()),
787 decode_string(&encoded).ok().unwrap()
788 );
789 }
790 {
791 let full_string: Vec<u8> = (0u8..127).collect();
792 let mut encoded = encode_integer(full_string.len(), 7);
793 encoded.extend(full_string.clone());
794
795 assert_eq!(
796 (Cow::Owned(full_string), encoded.len()),
797 decode_string(&encoded).ok().unwrap()
798 );
799 }
800 }
801
802 #[test]
806 fn test_decode_fully_in_static_table() {
807 let mut decoder = Decoder::new();
808
809 let header_list = decoder.decode(&[0x82]).ok().unwrap();
810
811 assert_eq!(vec![(b":method".to_vec(), b"GET".to_vec())], header_list);
812 }
813
814 #[test]
815 fn test_decode_multiple_fully_in_static_table() {
816 let mut decoder = Decoder::new();
817
818 let header_list = decoder.decode(&[0x82, 0x86, 0x84]).ok().unwrap();
819
820 assert_eq!(
821 header_list,
822 [
823 (b":method".to_vec(), b"GET".to_vec()),
824 (b":scheme".to_vec(), b"http".to_vec()),
825 (b":path".to_vec(), b"/".to_vec()),
826 ]
827 );
828 }
829
830 #[test]
834 fn test_decode_literal_indexed_name() {
835 let mut decoder = Decoder::new();
836 let hex_dump = [
837 0x04, 0x0c, 0x2f, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x70, 0x61, 0x74, 0x68,
838 ];
839
840 let header_list = decoder.decode(&hex_dump).ok().unwrap();
841
842 assert_eq!(
843 header_list,
844 [(b":path".to_vec(), b"/sample/path".to_vec()),]
845 );
846 assert_eq!(decoder.header_table.dynamic_table.len(), 0);
848 }
849
850 #[test]
854 fn test_decode_literal_both() {
855 let mut decoder = Decoder::new();
856 let hex_dump = [
857 0x40, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79, 0x0d, 0x63,
858 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72,
859 ];
860
861 let header_list = decoder.decode(&hex_dump).ok().unwrap();
862
863 assert_eq!(
864 header_list,
865 [(b"custom-key".to_vec(), b"custom-header".to_vec()),]
866 );
867 assert_eq!(decoder.header_table.dynamic_table.len(), 1);
869 let expected_table = vec![(b"custom-key".to_vec(), b"custom-header".to_vec())];
870 let actual = decoder.header_table.dynamic_table.to_vec();
871 assert_eq!(actual, expected_table);
872 }
873
874 #[test]
877 fn test_decode_literal_name_in_dynamic() {
878 let mut decoder = Decoder::new();
879 {
880 let hex_dump = [
882 0x40, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79, 0x0d, 0x63,
883 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72,
884 ];
885
886 let header_list = decoder.decode(&hex_dump).ok().unwrap();
887
888 assert_eq!(
889 header_list,
890 [(b"custom-key".to_vec(), b"custom-header".to_vec()),]
891 );
892 assert_eq!(decoder.header_table.dynamic_table.len(), 1);
894 let expected_table = vec![(b"custom-key".to_vec(), b"custom-header".to_vec())];
895 let actual = decoder.header_table.dynamic_table.to_vec();
896 assert_eq!(actual, expected_table);
897 }
898 {
899 let hex_dump = [
900 0x40 + 62, 0x0e,
902 0x63,
903 0x75,
904 0x73,
905 0x74,
906 0x6f,
907 0x6d,
908 0x2d,
909 0x68,
910 0x65,
911 0x61,
912 0x64,
913 0x65,
914 0x72,
915 0x2d,
916 ];
917
918 let header_list = decoder.decode(&hex_dump).ok().unwrap();
919
920 assert_eq!(
921 header_list,
922 [(b"custom-key".to_vec(), b"custom-header-".to_vec()),]
923 );
924 assert_eq!(decoder.header_table.dynamic_table.len(), 2);
926 let expected_table = vec![
927 (b"custom-key".to_vec(), b"custom-header-".to_vec()),
928 (b"custom-key".to_vec(), b"custom-header".to_vec()),
929 ];
930 let actual = decoder.header_table.dynamic_table.to_vec();
931 assert_eq!(actual, expected_table);
932 }
933 }
934
935 #[test]
939 fn test_decode_literal_field_never_indexed() {
940 let mut decoder = Decoder::new();
941 let hex_dump = [
942 0x10, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x06, 0x73, 0x65, 0x63,
943 0x72, 0x65, 0x74,
944 ];
945
946 let header_list = decoder.decode(&hex_dump).ok().unwrap();
947
948 assert_eq!(header_list, [(b"password".to_vec(), b"secret".to_vec()),]);
949 assert_eq!(decoder.header_table.dynamic_table.len(), 0);
951 }
952
953 #[test]
957 fn test_request_sequence_no_huffman() {
958 let mut decoder = Decoder::new();
959 {
960 let hex_dump = [
962 0x82, 0x86, 0x84, 0x41, 0x0f, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70,
963 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
964 ];
965
966 let header_list = decoder.decode(&hex_dump).ok().unwrap();
967
968 assert_eq!(
969 header_list,
970 [
971 (b":method".to_vec(), b"GET".to_vec()),
972 (b":scheme".to_vec(), b"http".to_vec()),
973 (b":path".to_vec(), b"/".to_vec()),
974 (b":authority".to_vec(), b"www.example.com".to_vec()),
975 ]
976 );
977 assert_eq!(decoder.header_table.dynamic_table.len(), 1);
979 let expected_table = vec![(b":authority".to_vec(), b"www.example.com".to_vec())];
980 let actual = decoder.header_table.dynamic_table.to_vec();
981 assert_eq!(actual, expected_table);
982 }
983 {
984 let hex_dump = [
986 0x82, 0x86, 0x84, 0xbe, 0x58, 0x08, 0x6e, 0x6f, 0x2d, 0x63, 0x61, 0x63, 0x68, 0x65,
987 ];
988
989 let header_list = decoder.decode(&hex_dump).ok().unwrap();
990
991 assert_eq!(
992 header_list,
993 [
994 (b":method".to_vec(), b"GET".to_vec()),
995 (b":scheme".to_vec(), b"http".to_vec()),
996 (b":path".to_vec(), b"/".to_vec()),
997 (b":authority".to_vec(), b"www.example.com".to_vec()),
998 (b"cache-control".to_vec(), b"no-cache".to_vec()),
999 ]
1000 );
1001 let expected_table = vec![
1003 (b"cache-control".to_vec(), b"no-cache".to_vec()),
1004 (b":authority".to_vec(), b"www.example.com".to_vec()),
1005 ];
1006 let actual = decoder.header_table.dynamic_table.to_vec();
1007 assert_eq!(actual, expected_table);
1008 }
1009 {
1010 let hex_dump = [
1012 0x82, 0x87, 0x85, 0xbf, 0x40, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b,
1013 0x65, 0x79, 0x0c, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x76, 0x61, 0x6c, 0x75,
1014 0x65,
1015 ];
1016
1017 let header_list = decoder.decode(&hex_dump).ok().unwrap();
1018
1019 assert_eq!(
1020 header_list,
1021 [
1022 (b":method".to_vec(), b"GET".to_vec()),
1023 (b":scheme".to_vec(), b"https".to_vec()),
1024 (b":path".to_vec(), b"/index.html".to_vec()),
1025 (b":authority".to_vec(), b"www.example.com".to_vec()),
1026 (b"custom-key".to_vec(), b"custom-value".to_vec()),
1027 ]
1028 );
1029 let expected_table = vec![
1032 (b"custom-key".to_vec(), b"custom-value".to_vec()),
1033 (b"cache-control".to_vec(), b"no-cache".to_vec()),
1034 (b":authority".to_vec(), b"www.example.com".to_vec()),
1035 ];
1036 let actual = decoder.header_table.dynamic_table.to_vec();
1037 assert_eq!(actual, expected_table);
1038 }
1039 }
1040
1041 #[test]
1045 fn response_sequence_no_huffman() {
1046 let mut decoder = Decoder::new();
1047 decoder.set_max_table_size(256);
1049 {
1050 let hex_dump = [
1052 0x48, 0x03, 0x33, 0x30, 0x32, 0x58, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65,
1053 0x61, 0x1d, 0x4d, 0x6f, 0x6e, 0x2c, 0x20, 0x32, 0x31, 0x20, 0x4f, 0x63, 0x74, 0x20,
1054 0x32, 0x30, 0x31, 0x33, 0x20, 0x32, 0x30, 0x3a, 0x31, 0x33, 0x3a, 0x32, 0x31, 0x20,
1055 0x47, 0x4d, 0x54, 0x6e, 0x17, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77,
1056 0x77, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
1057 ];
1058
1059 let header_list = decoder.decode(&hex_dump).ok().unwrap();
1060
1061 assert_eq!(
1062 header_list,
1063 [
1064 (b":status".to_vec(), b"302".to_vec()),
1065 (b"cache-control".to_vec(), b"private".to_vec()),
1066 (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1067 (b"location".to_vec(), b"https://www.example.com".to_vec()),
1068 ]
1069 );
1070 let expected_table = vec![
1072 (b"location".to_vec(), b"https://www.example.com".to_vec()),
1073 (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1074 (b"cache-control".to_vec(), b"private".to_vec()),
1075 (b":status".to_vec(), b"302".to_vec()),
1076 ];
1077 let actual = decoder.header_table.dynamic_table.to_vec();
1078 assert_eq!(actual, expected_table);
1079 }
1080 {
1081 let hex_dump = [0x48, 0x03, 0x33, 0x30, 0x37, 0xc1, 0xc0, 0xbf];
1083
1084 let header_list = decoder.decode(&hex_dump).ok().unwrap();
1085
1086 assert_eq!(
1087 header_list,
1088 [
1089 (b":status".to_vec(), b"307".to_vec()),
1090 (b"cache-control".to_vec(), b"private".to_vec()),
1091 (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1092 (b"location".to_vec(), b"https://www.example.com".to_vec()),
1093 ]
1094 );
1095 let expected_table = vec![
1098 (b":status".to_vec(), b"307".to_vec()),
1099 (b"location".to_vec(), b"https://www.example.com".to_vec()),
1100 (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1101 (b"cache-control".to_vec(), b"private".to_vec()),
1102 ];
1103 let actual = decoder.header_table.dynamic_table.to_vec();
1104 assert_eq!(actual, expected_table);
1105 }
1106 {
1107 let hex_dump = [
1109 0x88, 0xc1, 0x61, 0x1d, 0x4d, 0x6f, 0x6e, 0x2c, 0x20, 0x32, 0x31, 0x20, 0x4f, 0x63,
1110 0x74, 0x20, 0x32, 0x30, 0x31, 0x33, 0x20, 0x32, 0x30, 0x3a, 0x31, 0x33, 0x3a, 0x32,
1111 0x32, 0x20, 0x47, 0x4d, 0x54, 0xc0, 0x5a, 0x04, 0x67, 0x7a, 0x69, 0x70, 0x77, 0x38,
1112 0x66, 0x6f, 0x6f, 0x3d, 0x41, 0x53, 0x44, 0x4a, 0x4b, 0x48, 0x51, 0x4b, 0x42, 0x5a,
1113 0x58, 0x4f, 0x51, 0x57, 0x45, 0x4f, 0x50, 0x49, 0x55, 0x41, 0x58, 0x51, 0x57, 0x45,
1114 0x4f, 0x49, 0x55, 0x3b, 0x20, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65, 0x3d, 0x33,
1115 0x36, 0x30, 0x30, 0x3b, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3d, 0x31,
1116 ];
1117
1118 let header_list = decoder.decode(&hex_dump).ok().unwrap();
1119
1120 let expected_header_list = [
1121 (b":status".to_vec(), b"200".to_vec()),
1122 (b"cache-control".to_vec(), b"private".to_vec()),
1123 (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:22 GMT".to_vec()),
1124 (b"location".to_vec(), b"https://www.example.com".to_vec()),
1125 (b"content-encoding".to_vec(), b"gzip".to_vec()),
1126 (
1127 b"set-cookie".to_vec(),
1128 b"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1".to_vec(),
1129 ),
1130 ];
1131 assert_eq!(header_list, expected_header_list);
1132 let expected_table = vec![
1135 (
1136 b"set-cookie".to_vec(),
1137 b"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1".to_vec(),
1138 ),
1139 (b"content-encoding".to_vec(), b"gzip".to_vec()),
1140 (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:22 GMT".to_vec()),
1141 ];
1142 let actual = decoder.header_table.dynamic_table.to_vec();
1143 assert_eq!(actual, expected_table);
1144 }
1145 }
1146
1147 #[test]
1150 fn test_decoder_clear_dynamic_table() {
1151 let mut decoder = Decoder::new();
1152 decoder.allow_trailing_size_updates = true;
1153
1154 {
1155 let hex_dump = [
1156 0x48, 0x03, 0x33, 0x30, 0x32, 0x58, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65,
1157 0x61, 0x1d, 0x4d, 0x6f, 0x6e, 0x2c, 0x20, 0x32, 0x31, 0x20, 0x4f, 0x63, 0x74, 0x20,
1158 0x32, 0x30, 0x31, 0x33, 0x20, 0x32, 0x30, 0x3a, 0x31, 0x33, 0x3a, 0x32, 0x31, 0x20,
1159 0x47, 0x4d, 0x54, 0x6e, 0x17, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77,
1160 0x77, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
1161 ];
1162
1163 let header_list = decoder.decode(&hex_dump).ok().unwrap();
1164
1165 assert_eq!(
1166 header_list,
1167 [
1168 (b":status".to_vec(), b"302".to_vec()),
1169 (b"cache-control".to_vec(), b"private".to_vec()),
1170 (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1171 (b"location".to_vec(), b"https://www.example.com".to_vec()),
1172 ]
1173 );
1174 let expected_table = vec![
1176 (b"location".to_vec(), b"https://www.example.com".to_vec()),
1177 (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1178 (b"cache-control".to_vec(), b"private".to_vec()),
1179 (b":status".to_vec(), b"302".to_vec()),
1180 ];
1181 let actual = decoder.header_table.dynamic_table.to_vec();
1182 assert_eq!(actual, expected_table);
1183 }
1184 {
1185 let hex_dump = [
1186 0x48, 0x03, 0x33, 0x30, 0x37, 0xc1, 0xc0, 0xbf,
1187 0x20,
1191 ];
1192
1193 let header_list = decoder.decode(&hex_dump).ok().unwrap();
1194
1195 assert_eq!(
1197 header_list,
1198 [
1199 (b":status".to_vec(), b"307".to_vec()),
1200 (b"cache-control".to_vec(), b"private".to_vec()),
1201 (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1202 (b"location".to_vec(), b"https://www.example.com".to_vec()),
1203 ]
1204 );
1205 let expected_table = vec![];
1207 let actual = decoder.header_table.dynamic_table.to_vec();
1208 assert_eq!(actual, expected_table);
1209 assert_eq!(0, decoder.header_table.dynamic_table.get_max_table_size());
1210 }
1211 }
1212
1213 #[test]
1217 fn request_sequence_huffman() {
1218 let mut decoder = Decoder::new();
1219 {
1220 let hex_dump = [
1222 0x82, 0x86, 0x84, 0x41, 0x8c, 0xf1, 0xe3, 0xc2, 0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab,
1223 0x90, 0xf4, 0xff,
1224 ];
1225
1226 let header_list = decoder.decode(&hex_dump).ok().unwrap();
1227
1228 assert_eq!(
1229 header_list,
1230 [
1231 (b":method".to_vec(), b"GET".to_vec()),
1232 (b":scheme".to_vec(), b"http".to_vec()),
1233 (b":path".to_vec(), b"/".to_vec()),
1234 (b":authority".to_vec(), b"www.example.com".to_vec()),
1235 ]
1236 );
1237 assert_eq!(decoder.header_table.dynamic_table.len(), 1);
1239 let expected_table = vec![(b":authority".to_vec(), b"www.example.com".to_vec())];
1240 let actual = decoder.header_table.dynamic_table.to_vec();
1241 assert_eq!(actual, expected_table);
1242 }
1243 {
1244 let hex_dump = [
1246 0x82, 0x86, 0x84, 0xbe, 0x58, 0x86, 0xa8, 0xeb, 0x10, 0x64, 0x9c, 0xbf,
1247 ];
1248
1249 let header_list = decoder.decode(&hex_dump).ok().unwrap();
1250
1251 assert_eq!(
1252 header_list,
1253 [
1254 (b":method".to_vec(), b"GET".to_vec()),
1255 (b":scheme".to_vec(), b"http".to_vec()),
1256 (b":path".to_vec(), b"/".to_vec()),
1257 (b":authority".to_vec(), b"www.example.com".to_vec()),
1258 (b"cache-control".to_vec(), b"no-cache".to_vec()),
1259 ]
1260 );
1261 let expected_table = vec![
1263 (b"cache-control".to_vec(), b"no-cache".to_vec()),
1264 (b":authority".to_vec(), b"www.example.com".to_vec()),
1265 ];
1266 let actual = decoder.header_table.dynamic_table.to_vec();
1267 assert_eq!(actual, expected_table);
1268 }
1269 {
1270 let hex_dump = [
1272 0x82, 0x87, 0x85, 0xbf, 0x40, 0x88, 0x25, 0xa8, 0x49, 0xe9, 0x5b, 0xa9, 0x7d, 0x7f,
1273 0x89, 0x25, 0xa8, 0x49, 0xe9, 0x5b, 0xb8, 0xe8, 0xb4, 0xbf,
1274 ];
1275
1276 let header_list = decoder.decode(&hex_dump).ok().unwrap();
1277
1278 assert_eq!(
1279 header_list,
1280 [
1281 (b":method".to_vec(), b"GET".to_vec()),
1282 (b":scheme".to_vec(), b"https".to_vec()),
1283 (b":path".to_vec(), b"/index.html".to_vec()),
1284 (b":authority".to_vec(), b"www.example.com".to_vec()),
1285 (b"custom-key".to_vec(), b"custom-value".to_vec()),
1286 ]
1287 );
1288 let expected_table = vec![
1291 (b"custom-key".to_vec(), b"custom-value".to_vec()),
1292 (b"cache-control".to_vec(), b"no-cache".to_vec()),
1293 (b":authority".to_vec(), b"www.example.com".to_vec()),
1294 ];
1295 let actual = decoder.header_table.dynamic_table.to_vec();
1296 assert_eq!(actual, expected_table);
1297 }
1298 }
1299
1300 #[test]
1304 fn response_sequence_huffman() {
1305 let mut decoder = Decoder::new();
1306 decoder.set_max_table_size(256);
1308 {
1309 let hex_dump = [
1311 0x48, 0x82, 0x64, 0x02, 0x58, 0x85, 0xae, 0xc3, 0x77, 0x1a, 0x4b, 0x61, 0x96, 0xd0,
1312 0x7a, 0xbe, 0x94, 0x10, 0x54, 0xd4, 0x44, 0xa8, 0x20, 0x05, 0x95, 0x04, 0x0b, 0x81,
1313 0x66, 0xe0, 0x82, 0xa6, 0x2d, 0x1b, 0xff, 0x6e, 0x91, 0x9d, 0x29, 0xad, 0x17, 0x18,
1314 0x63, 0xc7, 0x8f, 0x0b, 0x97, 0xc8, 0xe9, 0xae, 0x82, 0xae, 0x43, 0xd3,
1315 ];
1316
1317 let header_list = decoder.decode(&hex_dump).ok().unwrap();
1318
1319 assert_eq!(
1320 header_list,
1321 [
1322 (b":status".to_vec(), b"302".to_vec()),
1323 (b"cache-control".to_vec(), b"private".to_vec()),
1324 (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1325 (b"location".to_vec(), b"https://www.example.com".to_vec()),
1326 ]
1327 );
1328 let expected_table = vec![
1330 (b"location".to_vec(), b"https://www.example.com".to_vec()),
1331 (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1332 (b"cache-control".to_vec(), b"private".to_vec()),
1333 (b":status".to_vec(), b"302".to_vec()),
1334 ];
1335 let actual = decoder.header_table.dynamic_table.to_vec();
1336 assert_eq!(actual, expected_table);
1337 }
1338 {
1339 let hex_dump = [0x48, 0x83, 0x64, 0x0e, 0xff, 0xc1, 0xc0, 0xbf];
1341
1342 let header_list = decoder.decode(&hex_dump).ok().unwrap();
1343
1344 assert_eq!(
1345 header_list,
1346 [
1347 (b":status".to_vec(), b"307".to_vec()),
1348 (b"cache-control".to_vec(), b"private".to_vec()),
1349 (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1350 (b"location".to_vec(), b"https://www.example.com".to_vec()),
1351 ]
1352 );
1353 let expected_table = vec![
1356 (b":status".to_vec(), b"307".to_vec()),
1357 (b"location".to_vec(), b"https://www.example.com".to_vec()),
1358 (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1359 (b"cache-control".to_vec(), b"private".to_vec()),
1360 ];
1361 let actual = decoder.header_table.dynamic_table.to_vec();
1362 assert_eq!(actual, expected_table);
1363 }
1364 {
1365 let hex_dump = [
1367 0x88, 0xc1, 0x61, 0x96, 0xd0, 0x7a, 0xbe, 0x94, 0x10, 0x54, 0xd4, 0x44, 0xa8, 0x20,
1368 0x05, 0x95, 0x04, 0x0b, 0x81, 0x66, 0xe0, 0x84, 0xa6, 0x2d, 0x1b, 0xff, 0xc0, 0x5a,
1369 0x83, 0x9b, 0xd9, 0xab, 0x77, 0xad, 0x94, 0xe7, 0x82, 0x1d, 0xd7, 0xf2, 0xe6, 0xc7,
1370 0xb3, 0x35, 0xdf, 0xdf, 0xcd, 0x5b, 0x39, 0x60, 0xd5, 0xaf, 0x27, 0x08, 0x7f, 0x36,
1371 0x72, 0xc1, 0xab, 0x27, 0x0f, 0xb5, 0x29, 0x1f, 0x95, 0x87, 0x31, 0x60, 0x65, 0xc0,
1372 0x03, 0xed, 0x4e, 0xe5, 0xb1, 0x06, 0x3d, 0x50, 0x07,
1373 ];
1374
1375 let header_list = decoder.decode(&hex_dump).ok().unwrap();
1376
1377 let expected_header_list = [
1378 (b":status".to_vec(), b"200".to_vec()),
1379 (b"cache-control".to_vec(), b"private".to_vec()),
1380 (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:22 GMT".to_vec()),
1381 (b"location".to_vec(), b"https://www.example.com".to_vec()),
1382 (b"content-encoding".to_vec(), b"gzip".to_vec()),
1383 (
1384 b"set-cookie".to_vec(),
1385 b"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1".to_vec(),
1386 ),
1387 ];
1388 assert_eq!(header_list, expected_header_list);
1389 let expected_table = vec![
1392 (
1393 b"set-cookie".to_vec(),
1394 b"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1".to_vec(),
1395 ),
1396 (b"content-encoding".to_vec(), b"gzip".to_vec()),
1397 (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:22 GMT".to_vec()),
1398 ];
1399 let actual = decoder.header_table.dynamic_table.to_vec();
1400 assert_eq!(actual, expected_table);
1401 }
1402 }
1403
1404 fn is_decoder_error(err: &DecoderError, result: &DecoderResult) -> bool {
1407 match *result {
1408 Err(ref e) => e == err,
1409 _ => false,
1410 }
1411 }
1412
1413 #[test]
1417 fn test_index_out_of_bounds() {
1418 let mut decoder = Decoder::new();
1419 let raw_messages = [
1422 vec![0x80],
1425 vec![0xbe],
1430 vec![126, 1, 65],
1433 ];
1434
1435 for raw_message in raw_messages.iter() {
1437 assert!(
1438 is_decoder_error(
1439 &DecoderError::HeaderIndexOutOfBounds,
1440 &decoder.decode(raw_message)
1441 ),
1442 "Expected index out of bounds"
1443 );
1444 }
1445 }
1446
1447 #[test]
1451 fn test_invalid_literal_huffman_string() {
1452 let mut decoder = Decoder::new();
1453 let hex_dump = [
1455 0x82, 0x86, 0x84, 0x41, 0x8c, 0xf1, 0xe3, 0xc2, 0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab,
1456 0x90, 0xf4, 0xfe,
1457 ];
1458
1459 assert!(matches!(
1460 decoder.decode(&hex_dump),
1461 Err(DecoderError::StringDecodingError(
1462 StringDecodingError::HuffmanDecoderError(HuffmanDecoderError::InvalidPadding,)
1463 ))
1464 ));
1465 }
1466
1467 #[test]
1470 fn test_literal_header_key_incomplete() {
1471 let mut decoder = Decoder::new();
1472 let hex_dump = [
1475 0x40, 0x0a, b'c', b'u', b's', b't', b'o', b'm', b'-', b'k', b'e',
1476 ];
1477
1478 let result = decoder.decode(&hex_dump);
1479
1480 assert!(matches!(
1481 result,
1482 Err(DecoderError::StringDecodingError(
1483 StringDecodingError::NotEnoughOctets
1484 ))
1485 ));
1486 }
1487
1488 #[test]
1491 fn test_literal_header_missing_value() {
1492 let mut decoder = Decoder::new();
1493 let hex_dump = [
1496 0x40, 0x0a, b'c', b'u', b's', b't', b'o', b'm', b'-', b'k', b'e', b'y',
1497 ];
1498
1499 let result = decoder.decode(&hex_dump);
1500
1501 assert!(matches!(
1502 result,
1503 Err(DecoderError::IntegerDecodingError(
1504 IntegerDecodingError::NotEnoughOctets
1505 ))
1506 ));
1507 }
1508}
1509
1510#[cfg(test)]
1515#[cfg(feature = "interop-tests")]
1516mod interop_tests {
1517 use std::fs;
1518 use std::path::{Path, PathBuf};
1519 use std::{borrow::Cow, collections::HashMap};
1520
1521 use serde::Deserialize;
1522 use tracing::trace;
1523
1524 use super::Decoder;
1525
1526 #[derive(Deserialize)]
1527 struct RawTestStory<'a> {
1528 cases: Vec<RawTestFixture<'a>>,
1529 }
1530
1531 #[derive(Deserialize)]
1532 struct RawTestFixture<'a> {
1533 wire: Cow<'a, str>,
1535
1536 headers: Vec<HashMap<Cow<'a, str>, Cow<'a, str>>>,
1538 }
1539
1540 struct TestFixture {
1543 wire_bytes: Vec<u8>,
1544 headers: Vec<(Vec<u8>, Vec<u8>)>,
1545 }
1546
1547 struct TestStory {
1550 cases: Vec<TestFixture>,
1551 }
1552
1553 #[derive(Debug, thiserror::Error)]
1554 enum DecodeError {
1555 #[error("Failed to parse hex-encoded bytes: {0}")]
1556 FromHex(#[from] hex::FromHexError),
1557 }
1558
1559 impl TryFrom<RawTestStory<'_>> for TestStory {
1560 type Error = DecodeError;
1561
1562 fn try_from(raw_story: RawTestStory) -> Result<Self, Self::Error> {
1563 let mut cases = Vec::with_capacity(raw_story.cases.len());
1564 for raw_case in raw_story.cases {
1565 let wire_bytes = hex::decode(raw_case.wire.as_bytes())?;
1566
1567 let headers: Vec<_> = raw_case
1568 .headers
1569 .into_iter()
1570 .flat_map(|h| {
1571 h.into_iter().map(|(k, v)| {
1572 (k.into_owned().into_bytes(), v.into_owned().into_bytes())
1573 })
1574 })
1575 .collect();
1576
1577 cases.push(TestFixture {
1578 wire_bytes,
1579 headers,
1580 });
1581 }
1582
1583 Ok(TestStory { cases })
1584 }
1585 }
1586
1587 #[test]
1590 fn test_story_parser_sanity_check() {
1591 let raw_json = r#"
1592 {
1593 "cases": [
1594 {
1595 "seqno": 0,
1596 "wire": "82864188f439ce75c875fa5784",
1597 "headers": [
1598 {
1599 ":method": "GET"
1600 },
1601 {
1602 ":scheme": "http"
1603 },
1604 {
1605 ":authority": "yahoo.co.jp"
1606 },
1607 {
1608 ":path": "/"
1609 }
1610 ]
1611 },
1612 {
1613 "seqno": 1,
1614 "wire": "8286418cf1e3c2fe8739ceb90ebf4aff84",
1615 "headers": [
1616 {
1617 ":method": "GET"
1618 },
1619 {
1620 ":scheme": "http"
1621 },
1622 {
1623 ":authority": "www.yahoo.co.jp"
1624 },
1625 {
1626 ":path": "/"
1627 }
1628 ]
1629 }
1630 ],
1631 "draft": 9
1632 }
1633 "#;
1634
1635 let decoded: RawTestStory = serde_json::from_str(raw_json).unwrap();
1636 let decoded = TestStory::try_from(decoded).unwrap();
1637
1638 assert_eq!(decoded.cases.len(), 2);
1639 assert_eq!(
1640 decoded.cases[0].wire_bytes,
1641 vec![0x82, 0x86, 0x41, 0x88, 0xf4, 0x39, 0xce, 0x75, 0xc8, 0x75, 0xfa, 0x57, 0x84]
1642 );
1643 assert_eq!(
1644 decoded.cases[0].headers,
1645 vec![
1646 (b":method".to_vec(), b"GET".to_vec()),
1647 (b":scheme".to_vec(), b"http".to_vec()),
1648 (b":authority".to_vec(), b"yahoo.co.jp".to_vec()),
1649 (b":path".to_vec(), b"/".to_vec()),
1650 ]
1651 );
1652 }
1653
1654 fn test_story(story_file_name: PathBuf) {
1662 let story: TestStory = {
1664 let buf = std::fs::read_to_string(story_file_name);
1665 let raw_story: RawTestStory = serde_json::from_str(&buf.unwrap()).unwrap();
1666 raw_story.try_into().unwrap()
1667 };
1668 let mut decoder = Decoder::new();
1670 for case in story.cases.iter() {
1674 let decoded = decoder.decode(&case.wire_bytes).unwrap();
1675 assert_eq!(decoded, case.headers);
1676 }
1677 }
1678
1679 fn test_fixture_set(fixture_dir: &str) {
1685 let files = fs::read_dir(Path::new(fixture_dir)).unwrap();
1686
1687 for fixture in files {
1688 let file_name = fixture.unwrap().path();
1689 trace!("Testing fixture: {:?}", file_name);
1690 test_story(file_name);
1691 }
1692 }
1693
1694 #[test]
1695 fn test_nghttp2_interop() {
1696 test_fixture_set("fixtures/hpack/interop/nghttp2");
1697 }
1698
1699 #[test]
1700 fn test_nghttp2_change_table_size_interop() {
1701 test_fixture_set("fixtures/hpack/interop/nghttp2-change-table-size");
1702 }
1703
1704 #[test]
1705 fn test_go_hpack_interop() {
1706 test_fixture_set("fixtures/hpack/interop/go-hpack");
1707 }
1708
1709 #[test]
1710 fn test_node_http2_hpack_interop() {
1711 test_fixture_set("fixtures/hpack/interop/node-http2-hpack");
1712 }
1713
1714 #[test]
1715 fn test_haskell_http2_linear_huffman() {
1716 test_fixture_set("fixtures/hpack/interop/haskell-http2-linear-huffman");
1717 }
1718}