1use std::borrow::Cow;
49use std::num::Wrapping;
50
51use tracing::{debug, trace};
52
53use super::huffman::HuffmanDecoder;
54use super::huffman::HuffmanDecoderError;
55
56use super::STATIC_TABLE;
57use super::{HeaderTable, StaticTable};
58
59fn decode_integer(buf: &[u8], prefix_size: u8) -> Result<(usize, usize), DecoderError> {
67 if !(1..=8).contains(&prefix_size) {
68 return Err(DecoderError::IntegerDecodingError(
69 IntegerDecodingError::InvalidPrefix,
70 ));
71 }
72 if buf.is_empty() {
73 return Err(DecoderError::IntegerDecodingError(
74 IntegerDecodingError::NotEnoughOctets,
75 ));
76 }
77
78 let Wrapping(mask) = if prefix_size == 8 {
80 Wrapping(0xFF)
81 } else {
82 Wrapping(1u8 << prefix_size) - Wrapping(1)
83 };
84 let mut value = (buf[0] & mask) as usize;
85 if value < (mask as usize) {
86 return Ok((value, 1));
88 }
89
90 let mut total = 1;
94 let mut m = 0;
95 let octet_limit = 5;
99
100 for &b in buf[1..].iter() {
101 total += 1;
102 value += ((b & 127) as usize) * (1 << m);
103 m += 7;
104
105 if b & 128 != 128 {
106 return Ok((value, total));
108 }
109
110 if total == octet_limit {
111 return Err(DecoderError::IntegerDecodingError(
114 IntegerDecodingError::TooManyOctets,
115 ));
116 }
117 }
118
119 Err(DecoderError::IntegerDecodingError(
122 IntegerDecodingError::NotEnoughOctets,
123 ))
124}
125
126fn decode_string(buf: &[u8]) -> Result<(Cow<'_, [u8]>, usize), DecoderError> {
135 let (len, consumed) = decode_integer(buf, 7)?;
136 debug!("decode_string: Consumed = {}, len = {}", consumed, len);
137 if consumed + len > buf.len() {
138 return Err(DecoderError::StringDecodingError(
139 StringDecodingError::NotEnoughOctets,
140 ));
141 }
142 let raw_string = &buf[consumed..consumed + len];
143 if buf[0] & 128 == 128 {
144 debug!("decode_string: Using the Huffman code");
145 let mut decoder = HuffmanDecoder::new();
148 let decoded = match decoder.decode(raw_string) {
149 Err(e) => {
150 return Err(DecoderError::StringDecodingError(
151 StringDecodingError::HuffmanDecoderError(e),
152 ));
153 }
154 Ok(res) => res,
155 };
156 Ok((Cow::Owned(decoded), consumed + len))
157 } else {
158 debug!("decode_string: Raw octet string received");
160 Ok((Cow::Borrowed(raw_string), consumed + len))
161 }
162}
163
164enum FieldRepresentation {
167 Indexed,
168 LiteralWithIncrementalIndexing,
169 SizeUpdate,
170 LiteralNeverIndexed,
171 LiteralWithoutIndexing,
172}
173
174impl FieldRepresentation {
175 fn new(octet: u8) -> FieldRepresentation {
180 if octet & 128 == 128 {
181 FieldRepresentation::Indexed
183 } else if octet & 64 == 64 {
184 FieldRepresentation::LiteralWithIncrementalIndexing
186 } else if octet & 32 == 32 {
187 FieldRepresentation::SizeUpdate
189 } else if octet & 16 == 16 {
190 FieldRepresentation::LiteralNeverIndexed
192 } else {
193 FieldRepresentation::LiteralWithoutIndexing
195 }
196 }
197}
198
199#[derive(PartialEq, Copy, Clone, Debug)]
202pub enum IntegerDecodingError {
203 TooManyOctets,
208 ValueTooLarge,
211 NotEnoughOctets,
214 InvalidPrefix,
216}
217
218#[derive(PartialEq, Copy, Clone, Debug)]
221pub enum StringDecodingError {
222 NotEnoughOctets,
223 HuffmanDecoderError(HuffmanDecoderError),
224}
225
226#[derive(PartialEq, Copy, Clone, Debug)]
229pub enum DecoderError {
230 HeaderIndexOutOfBounds,
231 IntegerDecodingError(IntegerDecodingError),
232 StringDecodingError(StringDecodingError),
233 InvalidMaxDynamicSize,
237 SizeUpdateAtEnd,
240}
241
242pub type DecoderResult = Result<Vec<(Vec<u8>, Vec<u8>)>, DecoderError>;
244
245pub struct Decoder<'a> {
251 header_table: HeaderTable<'a>,
253
254 max_allowed_table_size: Option<usize>,
255
256 #[cfg(test)]
258 pub(crate) allow_trailing_size_updates: bool,
259}
260
261impl Default for Decoder<'_> {
262 fn default() -> Decoder<'static> {
263 Decoder::with_static_table(STATIC_TABLE)
264 }
265}
266
267type DecodedLiteralCow<'a> = ((Cow<'a, [u8]>, Cow<'a, [u8]>), usize);
268type DecodedLiteralSlice<'a> = ((&'a [u8], &'a [u8]), usize);
269
270impl<'a> Decoder<'a> {
273 pub fn new() -> Decoder<'a> {
275 Default::default()
276 }
277
278 fn with_static_table(static_table: StaticTable<'a>) -> Decoder<'a> {
288 Decoder {
289 header_table: HeaderTable::with_static_table(static_table),
290 max_allowed_table_size: None,
291 #[cfg(test)]
292 allow_trailing_size_updates: false,
293 }
294 }
295
296 pub fn set_max_table_size(&mut self, new_max_size: usize) {
300 if let Some(max_allowed_size) = self.max_allowed_table_size {
301 assert!(
304 new_max_size <= max_allowed_size,
305 "new_max_size ({}) > max_allowed_size ({})",
306 new_max_size,
307 max_allowed_size
308 );
309 }
310
311 self.header_table
312 .dynamic_table
313 .set_max_table_size(new_max_size);
314 }
315
316 pub fn set_max_allowed_table_size(&mut self, max_allowed_size: usize) {
320 self.max_allowed_table_size = Some(max_allowed_size);
321 }
322
323 pub fn decode_with_cb<F>(&mut self, buf: &[u8], mut cb: F) -> Result<(), DecoderError>
339 where
340 F: FnMut(Cow<[u8]>, Cow<[u8]>),
341 {
342 let mut current_octet_index = 0;
343
344 let mut last_was_size_update = false;
345 while current_octet_index < buf.len() {
346 let initial_octet = buf[current_octet_index];
351 let buffer_leftover = &buf[current_octet_index..];
352 let field_representation = FieldRepresentation::new(initial_octet);
353 last_was_size_update = matches!(field_representation, FieldRepresentation::SizeUpdate);
354
355 let consumed = match field_representation {
356 FieldRepresentation::Indexed => {
357 let ((name, value), consumed) = self.decode_indexed(buffer_leftover)?;
358 cb(Cow::Borrowed(name), Cow::Borrowed(value));
359
360 consumed
361 }
362 FieldRepresentation::LiteralWithIncrementalIndexing => {
363 let ((name, value), consumed) = {
364 let ((name, value), consumed) =
365 self.decode_literal(buffer_leftover, true)?;
366 cb(Cow::Borrowed(&name), Cow::Borrowed(&value));
367
368 let name = name.into_owned();
371 let value = value.into_owned();
372
373 ((name, value), consumed)
374 };
375 self.header_table.add_header(name, value);
381
382 consumed
383 }
384 FieldRepresentation::LiteralWithoutIndexing => {
385 let ((name, value), consumed) = self.decode_literal(buffer_leftover, false)?;
386 cb(name, value);
387
388 consumed
389 }
390 FieldRepresentation::LiteralNeverIndexed => {
391 let ((name, value), consumed) = self.decode_literal(buffer_leftover, false)?;
396 cb(name, value);
397
398 consumed
399 }
400 FieldRepresentation::SizeUpdate => {
401 self.update_max_dynamic_size(buffer_leftover)?
403 }
404 };
405
406 current_octet_index += consumed;
407 }
408
409 if last_was_size_update {
410 #[cfg(test)]
411 if self.allow_trailing_size_updates {
412 return Ok(());
413 }
414
415 return Err(DecoderError::SizeUpdateAtEnd);
416 }
417
418 Ok(())
419 }
420
421 pub fn decode(&mut self, buf: &[u8]) -> DecoderResult {
430 let mut header_list = Vec::new();
431
432 self.decode_with_cb(buf, |n, v| {
433 header_list.push((n.into_owned(), v.into_owned()))
434 })?;
435
436 Ok(header_list)
437 }
438
439 fn decode_indexed(&self, buf: &[u8]) -> Result<DecodedLiteralSlice<'_>, DecoderError> {
441 let (index, consumed) = decode_integer(buf, 7)?;
442 debug!(
443 "Decoding indexed: index = {}, consumed = {}",
444 index, consumed
445 );
446
447 let (name, value) = self.get_from_table(index)?;
448
449 Ok(((name, value), consumed))
450 }
451
452 fn get_from_table(&self, index: usize) -> Result<(&[u8], &[u8]), DecoderError> {
458 self.header_table
459 .get_from_table(index)
460 .ok_or(DecoderError::HeaderIndexOutOfBounds)
461 }
462
463 fn decode_literal<'b>(
470 &'b self,
471 buf: &'b [u8],
472 index: bool,
473 ) -> Result<DecodedLiteralCow<'b>, DecoderError> {
474 let prefix = if index { 6 } else { 4 };
475 let (table_index, mut consumed) = decode_integer(buf, prefix)?;
476
477 let name = if table_index == 0 {
479 let (name, name_len) = decode_string(&buf[consumed..])?;
481 consumed += name_len;
482 name
483 } else {
484 let (name, _) = self.get_from_table(table_index)?;
486 Cow::Borrowed(name)
487 };
488
489 let (value, value_len) = decode_string(&buf[consumed..])?;
491 consumed += value_len;
492
493 Ok(((name, value), consumed))
494 }
495
496 fn update_max_dynamic_size(&mut self, buf: &[u8]) -> Result<usize, DecoderError> {
505 let (new_size, consumed) = decode_integer(buf, 5).ok().unwrap();
506 if let Some(max_size) = self.max_allowed_table_size {
507 if new_size > max_size {
508 return Err(DecoderError::InvalidMaxDynamicSize);
509 }
510 }
511 self.header_table.dynamic_table.set_max_table_size(new_size);
512
513 trace!(
514 "Decoder changed max table size from {} to {}",
515 self.header_table.dynamic_table.get_size(),
516 new_size
517 );
518
519 Ok(consumed)
520 }
521}
522
523#[cfg(test)]
524mod tests {
525 use super::decode_integer;
526
527 use std::borrow::Cow;
528
529 use super::super::encoder::encode_integer;
530 use super::super::huffman::HuffmanDecoderError;
531 use super::decode_string;
532 use super::Decoder;
533 use super::FieldRepresentation;
534 use super::{DecoderError, DecoderResult};
535 use super::{IntegerDecodingError, StringDecodingError};
536
537 #[test]
539 fn test_decode_integer() {
540 assert_eq!((10, 1), decode_integer(&[10], 5).ok().unwrap());
541 assert_eq!((1337, 3), decode_integer(&[31, 154, 10], 5).ok().unwrap());
542 assert_eq!(
543 (1337, 3),
544 decode_integer(&[31 + 32, 154, 10], 5).ok().unwrap()
545 );
546 assert_eq!(
547 (1337, 3),
548 decode_integer(&[31 + 64, 154, 10], 5).ok().unwrap()
549 );
550 assert_eq!(
551 (1337, 3),
552 decode_integer(&[31, 154, 10, 111, 22], 5).ok().unwrap()
553 );
554
555 assert_eq!((127, 2), decode_integer(&[255, 0], 7).ok().unwrap());
556 assert_eq!((127, 2), decode_integer(&[127, 0], 7).ok().unwrap());
557 assert_eq!((255, 3), decode_integer(&[127, 128, 1], 7).ok().unwrap());
558 assert_eq!((255, 2), decode_integer(&[255, 0], 8).unwrap());
559 assert_eq!((254, 1), decode_integer(&[254], 8).unwrap());
560 assert_eq!((1, 1), decode_integer(&[1], 8).unwrap());
561 assert_eq!((0, 1), decode_integer(&[0], 8).unwrap());
562 assert_eq!(
564 (268435710, 5),
565 decode_integer(&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF - 128], 8)
566 .ok()
567 .unwrap()
568 );
569 }
570
571 macro_rules! assert_integer_err (
574 ($err_type:expr, $decoder_result:expr) => (
575 assert_eq!($err_type, match $decoder_result {
576 Err(DecoderError::IntegerDecodingError(e)) => e,
577 _ => panic!("Expected a decoding error"),
578 });
579 );
580 );
581
582 #[test]
585 fn test_decode_integer_errors() {
586 assert_integer_err!(
587 IntegerDecodingError::NotEnoughOctets,
588 decode_integer(&[], 5)
589 );
590 assert_integer_err!(
591 IntegerDecodingError::NotEnoughOctets,
592 decode_integer(&[0xFF, 0xFF], 5)
593 );
594 assert_integer_err!(
595 IntegerDecodingError::TooManyOctets,
596 decode_integer(
597 &[0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80],
598 1
599 )
600 );
601 assert_integer_err!(
602 IntegerDecodingError::TooManyOctets,
603 decode_integer(&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0], 8)
604 );
605 assert_integer_err!(
606 IntegerDecodingError::InvalidPrefix,
607 decode_integer(&[10], 0)
608 );
609 assert_integer_err!(
610 IntegerDecodingError::InvalidPrefix,
611 decode_integer(&[10], 9)
612 );
613 }
614
615 #[test]
616 fn test_detect_literal_without_indexing() {
617 assert!(matches!(
618 FieldRepresentation::new(0),
619 FieldRepresentation::LiteralWithoutIndexing
620 ));
621 assert!(matches!(
622 FieldRepresentation::new((1 << 4) - 1),
623 FieldRepresentation::LiteralWithoutIndexing
624 ));
625 assert!(matches!(
626 FieldRepresentation::new(2),
627 FieldRepresentation::LiteralWithoutIndexing
628 ));
629 }
630
631 #[test]
632 fn test_detect_literal_never_indexed() {
633 assert!(matches!(
634 FieldRepresentation::new(1 << 4),
635 FieldRepresentation::LiteralNeverIndexed
636 ));
637 assert!(matches!(
638 FieldRepresentation::new((1 << 4) + 15),
639 FieldRepresentation::LiteralNeverIndexed
640 ));
641 }
642
643 #[test]
644 fn test_detect_literal_incremental_indexing() {
645 assert!(matches!(
646 FieldRepresentation::new(1 << 6),
647 FieldRepresentation::LiteralWithIncrementalIndexing
648 ));
649 assert!(matches!(
650 FieldRepresentation::new((1 << 6) + (1 << 4)),
651 FieldRepresentation::LiteralWithIncrementalIndexing
652 ));
653 assert!(matches!(
654 FieldRepresentation::new((1 << 7) - 1),
655 FieldRepresentation::LiteralWithIncrementalIndexing
656 ));
657 }
658
659 #[test]
660 fn test_detect_indexed() {
661 assert!(matches!(
662 FieldRepresentation::new(1 << 7),
663 FieldRepresentation::Indexed
664 ));
665 assert!(matches!(
666 FieldRepresentation::new((1 << 7) + (1 << 4)),
667 FieldRepresentation::Indexed
668 ));
669 assert!(matches!(
670 FieldRepresentation::new((1 << 7) + (1 << 5)),
671 FieldRepresentation::Indexed
672 ));
673 assert!(matches!(
674 FieldRepresentation::new((1 << 7) + (1 << 6)),
675 FieldRepresentation::Indexed
676 ));
677 assert!(matches!(
678 FieldRepresentation::new(255),
679 FieldRepresentation::Indexed
680 ));
681 }
682
683 #[test]
684 fn test_detect_dynamic_table_size_update() {
685 assert!(matches!(
686 FieldRepresentation::new(1 << 5),
687 FieldRepresentation::SizeUpdate
688 ));
689 assert!(matches!(
690 FieldRepresentation::new((1 << 5) + (1 << 4)),
691 FieldRepresentation::SizeUpdate
692 ));
693 assert!(matches!(
694 FieldRepresentation::new((1 << 6) - 1),
695 FieldRepresentation::SizeUpdate
696 ));
697 }
698
699 #[test]
700 fn test_decode_string_no_huffman() {
701 fn assert_borrowed_eq(expected: (&[u8], usize), result: (Cow<'_, [u8]>, usize)) {
703 let (expected_str, expected_len) = expected;
704 let (actual_str, actual_len) = result;
705 assert_eq!(expected_len, actual_len);
706 match actual_str {
707 Cow::Borrowed(actual) => assert_eq!(actual, expected_str),
708 _ => panic!("Expected the result to be borrowed!"),
709 };
710 }
711
712 assert_eq!(
713 (Cow::Borrowed(&b"abc"[..]), 4),
714 decode_string(&[3, b'a', b'b', b'c']).ok().unwrap()
715 );
716 assert_eq!(
717 (Cow::Borrowed(&b"a"[..]), 2),
718 decode_string(&[1, b'a']).ok().unwrap()
719 );
720 assert_eq!(
721 (Cow::Borrowed(&b""[..]), 1),
722 decode_string(&[0, b'a']).ok().unwrap()
723 );
724
725 assert_borrowed_eq(
726 (&b"abc"[..], 4),
727 decode_string(&[3, b'a', b'b', b'c']).ok().unwrap(),
728 );
729 assert_borrowed_eq((&b"a"[..], 2), decode_string(&[1, b'a']).ok().unwrap());
730 assert_borrowed_eq((&b""[..], 1), decode_string(&[0, b'a']).ok().unwrap());
731
732 assert_eq!(
734 StringDecodingError::NotEnoughOctets,
735 match decode_string(&[3, b'a', b'b']) {
736 Err(DecoderError::StringDecodingError(e)) => e,
737 _ => panic!("Expected NotEnoughOctets error!"),
738 }
739 );
740 }
741
742 #[test]
745 fn test_decode_string_no_huffman_long() {
746 {
747 let full_string: Vec<u8> = (0u8..200).collect();
748 let mut encoded = encode_integer(full_string.len(), 7);
749 encoded.extend(full_string.clone());
750
751 assert_eq!(
752 (Cow::Owned(full_string), encoded.len()),
753 decode_string(&encoded).ok().unwrap()
754 );
755 }
756 {
757 let full_string: Vec<u8> = (0u8..127).collect();
758 let mut encoded = encode_integer(full_string.len(), 7);
759 encoded.extend(full_string.clone());
760
761 assert_eq!(
762 (Cow::Owned(full_string), encoded.len()),
763 decode_string(&encoded).ok().unwrap()
764 );
765 }
766 }
767
768 #[test]
772 fn test_decode_fully_in_static_table() {
773 let mut decoder = Decoder::new();
774
775 let header_list = decoder.decode(&[0x82]).ok().unwrap();
776
777 assert_eq!(vec![(b":method".to_vec(), b"GET".to_vec())], header_list);
778 }
779
780 #[test]
781 fn test_decode_multiple_fully_in_static_table() {
782 let mut decoder = Decoder::new();
783
784 let header_list = decoder.decode(&[0x82, 0x86, 0x84]).ok().unwrap();
785
786 assert_eq!(
787 header_list,
788 [
789 (b":method".to_vec(), b"GET".to_vec()),
790 (b":scheme".to_vec(), b"http".to_vec()),
791 (b":path".to_vec(), b"/".to_vec()),
792 ]
793 );
794 }
795
796 #[test]
800 fn test_decode_literal_indexed_name() {
801 let mut decoder = Decoder::new();
802 let hex_dump = [
803 0x04, 0x0c, 0x2f, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x70, 0x61, 0x74, 0x68,
804 ];
805
806 let header_list = decoder.decode(&hex_dump).ok().unwrap();
807
808 assert_eq!(
809 header_list,
810 [(b":path".to_vec(), b"/sample/path".to_vec()),]
811 );
812 assert_eq!(decoder.header_table.dynamic_table.len(), 0);
814 }
815
816 #[test]
820 fn test_decode_literal_both() {
821 let mut decoder = Decoder::new();
822 let hex_dump = [
823 0x40, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79, 0x0d, 0x63,
824 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72,
825 ];
826
827 let header_list = decoder.decode(&hex_dump).ok().unwrap();
828
829 assert_eq!(
830 header_list,
831 [(b"custom-key".to_vec(), b"custom-header".to_vec()),]
832 );
833 assert_eq!(decoder.header_table.dynamic_table.len(), 1);
835 let expected_table = vec![(b"custom-key".to_vec(), b"custom-header".to_vec())];
836 let actual = decoder.header_table.dynamic_table.to_vec();
837 assert_eq!(actual, expected_table);
838 }
839
840 #[test]
843 fn test_decode_literal_name_in_dynamic() {
844 let mut decoder = Decoder::new();
845 {
846 let hex_dump = [
848 0x40, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79, 0x0d, 0x63,
849 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72,
850 ];
851
852 let header_list = decoder.decode(&hex_dump).ok().unwrap();
853
854 assert_eq!(
855 header_list,
856 [(b"custom-key".to_vec(), b"custom-header".to_vec()),]
857 );
858 assert_eq!(decoder.header_table.dynamic_table.len(), 1);
860 let expected_table = vec![(b"custom-key".to_vec(), b"custom-header".to_vec())];
861 let actual = decoder.header_table.dynamic_table.to_vec();
862 assert_eq!(actual, expected_table);
863 }
864 {
865 let hex_dump = [
866 0x40 + 62, 0x0e,
868 0x63,
869 0x75,
870 0x73,
871 0x74,
872 0x6f,
873 0x6d,
874 0x2d,
875 0x68,
876 0x65,
877 0x61,
878 0x64,
879 0x65,
880 0x72,
881 0x2d,
882 ];
883
884 let header_list = decoder.decode(&hex_dump).ok().unwrap();
885
886 assert_eq!(
887 header_list,
888 [(b"custom-key".to_vec(), b"custom-header-".to_vec()),]
889 );
890 assert_eq!(decoder.header_table.dynamic_table.len(), 2);
892 let expected_table = vec![
893 (b"custom-key".to_vec(), b"custom-header-".to_vec()),
894 (b"custom-key".to_vec(), b"custom-header".to_vec()),
895 ];
896 let actual = decoder.header_table.dynamic_table.to_vec();
897 assert_eq!(actual, expected_table);
898 }
899 }
900
901 #[test]
905 fn test_decode_literal_field_never_indexed() {
906 let mut decoder = Decoder::new();
907 let hex_dump = [
908 0x10, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x06, 0x73, 0x65, 0x63,
909 0x72, 0x65, 0x74,
910 ];
911
912 let header_list = decoder.decode(&hex_dump).ok().unwrap();
913
914 assert_eq!(header_list, [(b"password".to_vec(), b"secret".to_vec()),]);
915 assert_eq!(decoder.header_table.dynamic_table.len(), 0);
917 }
918
919 #[test]
923 fn test_request_sequence_no_huffman() {
924 let mut decoder = Decoder::new();
925 {
926 let hex_dump = [
928 0x82, 0x86, 0x84, 0x41, 0x0f, 0x77, 0x77, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70,
929 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
930 ];
931
932 let header_list = decoder.decode(&hex_dump).ok().unwrap();
933
934 assert_eq!(
935 header_list,
936 [
937 (b":method".to_vec(), b"GET".to_vec()),
938 (b":scheme".to_vec(), b"http".to_vec()),
939 (b":path".to_vec(), b"/".to_vec()),
940 (b":authority".to_vec(), b"www.example.com".to_vec()),
941 ]
942 );
943 assert_eq!(decoder.header_table.dynamic_table.len(), 1);
945 let expected_table = vec![(b":authority".to_vec(), b"www.example.com".to_vec())];
946 let actual = decoder.header_table.dynamic_table.to_vec();
947 assert_eq!(actual, expected_table);
948 }
949 {
950 let hex_dump = [
952 0x82, 0x86, 0x84, 0xbe, 0x58, 0x08, 0x6e, 0x6f, 0x2d, 0x63, 0x61, 0x63, 0x68, 0x65,
953 ];
954
955 let header_list = decoder.decode(&hex_dump).ok().unwrap();
956
957 assert_eq!(
958 header_list,
959 [
960 (b":method".to_vec(), b"GET".to_vec()),
961 (b":scheme".to_vec(), b"http".to_vec()),
962 (b":path".to_vec(), b"/".to_vec()),
963 (b":authority".to_vec(), b"www.example.com".to_vec()),
964 (b"cache-control".to_vec(), b"no-cache".to_vec()),
965 ]
966 );
967 let expected_table = vec![
969 (b"cache-control".to_vec(), b"no-cache".to_vec()),
970 (b":authority".to_vec(), b"www.example.com".to_vec()),
971 ];
972 let actual = decoder.header_table.dynamic_table.to_vec();
973 assert_eq!(actual, expected_table);
974 }
975 {
976 let hex_dump = [
978 0x82, 0x87, 0x85, 0xbf, 0x40, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b,
979 0x65, 0x79, 0x0c, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x76, 0x61, 0x6c, 0x75,
980 0x65,
981 ];
982
983 let header_list = decoder.decode(&hex_dump).ok().unwrap();
984
985 assert_eq!(
986 header_list,
987 [
988 (b":method".to_vec(), b"GET".to_vec()),
989 (b":scheme".to_vec(), b"https".to_vec()),
990 (b":path".to_vec(), b"/index.html".to_vec()),
991 (b":authority".to_vec(), b"www.example.com".to_vec()),
992 (b"custom-key".to_vec(), b"custom-value".to_vec()),
993 ]
994 );
995 let expected_table = vec![
998 (b"custom-key".to_vec(), b"custom-value".to_vec()),
999 (b"cache-control".to_vec(), b"no-cache".to_vec()),
1000 (b":authority".to_vec(), b"www.example.com".to_vec()),
1001 ];
1002 let actual = decoder.header_table.dynamic_table.to_vec();
1003 assert_eq!(actual, expected_table);
1004 }
1005 }
1006
1007 #[test]
1011 fn response_sequence_no_huffman() {
1012 let mut decoder = Decoder::new();
1013 decoder.set_max_table_size(256);
1015 {
1016 let hex_dump = [
1018 0x48, 0x03, 0x33, 0x30, 0x32, 0x58, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65,
1019 0x61, 0x1d, 0x4d, 0x6f, 0x6e, 0x2c, 0x20, 0x32, 0x31, 0x20, 0x4f, 0x63, 0x74, 0x20,
1020 0x32, 0x30, 0x31, 0x33, 0x20, 0x32, 0x30, 0x3a, 0x31, 0x33, 0x3a, 0x32, 0x31, 0x20,
1021 0x47, 0x4d, 0x54, 0x6e, 0x17, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77,
1022 0x77, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
1023 ];
1024
1025 let header_list = decoder.decode(&hex_dump).ok().unwrap();
1026
1027 assert_eq!(
1028 header_list,
1029 [
1030 (b":status".to_vec(), b"302".to_vec()),
1031 (b"cache-control".to_vec(), b"private".to_vec()),
1032 (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1033 (b"location".to_vec(), b"https://www.example.com".to_vec()),
1034 ]
1035 );
1036 let expected_table = vec![
1038 (b"location".to_vec(), b"https://www.example.com".to_vec()),
1039 (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1040 (b"cache-control".to_vec(), b"private".to_vec()),
1041 (b":status".to_vec(), b"302".to_vec()),
1042 ];
1043 let actual = decoder.header_table.dynamic_table.to_vec();
1044 assert_eq!(actual, expected_table);
1045 }
1046 {
1047 let hex_dump = [0x48, 0x03, 0x33, 0x30, 0x37, 0xc1, 0xc0, 0xbf];
1049
1050 let header_list = decoder.decode(&hex_dump).ok().unwrap();
1051
1052 assert_eq!(
1053 header_list,
1054 [
1055 (b":status".to_vec(), b"307".to_vec()),
1056 (b"cache-control".to_vec(), b"private".to_vec()),
1057 (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1058 (b"location".to_vec(), b"https://www.example.com".to_vec()),
1059 ]
1060 );
1061 let expected_table = vec![
1064 (b":status".to_vec(), b"307".to_vec()),
1065 (b"location".to_vec(), b"https://www.example.com".to_vec()),
1066 (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1067 (b"cache-control".to_vec(), b"private".to_vec()),
1068 ];
1069 let actual = decoder.header_table.dynamic_table.to_vec();
1070 assert_eq!(actual, expected_table);
1071 }
1072 {
1073 let hex_dump = [
1075 0x88, 0xc1, 0x61, 0x1d, 0x4d, 0x6f, 0x6e, 0x2c, 0x20, 0x32, 0x31, 0x20, 0x4f, 0x63,
1076 0x74, 0x20, 0x32, 0x30, 0x31, 0x33, 0x20, 0x32, 0x30, 0x3a, 0x31, 0x33, 0x3a, 0x32,
1077 0x32, 0x20, 0x47, 0x4d, 0x54, 0xc0, 0x5a, 0x04, 0x67, 0x7a, 0x69, 0x70, 0x77, 0x38,
1078 0x66, 0x6f, 0x6f, 0x3d, 0x41, 0x53, 0x44, 0x4a, 0x4b, 0x48, 0x51, 0x4b, 0x42, 0x5a,
1079 0x58, 0x4f, 0x51, 0x57, 0x45, 0x4f, 0x50, 0x49, 0x55, 0x41, 0x58, 0x51, 0x57, 0x45,
1080 0x4f, 0x49, 0x55, 0x3b, 0x20, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65, 0x3d, 0x33,
1081 0x36, 0x30, 0x30, 0x3b, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3d, 0x31,
1082 ];
1083
1084 let header_list = decoder.decode(&hex_dump).ok().unwrap();
1085
1086 let expected_header_list = [
1087 (b":status".to_vec(), b"200".to_vec()),
1088 (b"cache-control".to_vec(), b"private".to_vec()),
1089 (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:22 GMT".to_vec()),
1090 (b"location".to_vec(), b"https://www.example.com".to_vec()),
1091 (b"content-encoding".to_vec(), b"gzip".to_vec()),
1092 (
1093 b"set-cookie".to_vec(),
1094 b"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1".to_vec(),
1095 ),
1096 ];
1097 assert_eq!(header_list, expected_header_list);
1098 let expected_table = vec![
1101 (
1102 b"set-cookie".to_vec(),
1103 b"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1".to_vec(),
1104 ),
1105 (b"content-encoding".to_vec(), b"gzip".to_vec()),
1106 (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:22 GMT".to_vec()),
1107 ];
1108 let actual = decoder.header_table.dynamic_table.to_vec();
1109 assert_eq!(actual, expected_table);
1110 }
1111 }
1112
1113 #[test]
1116 fn test_decoder_clear_dynamic_table() {
1117 let mut decoder = Decoder::new();
1118 decoder.allow_trailing_size_updates = true;
1119
1120 {
1121 let hex_dump = [
1122 0x48, 0x03, 0x33, 0x30, 0x32, 0x58, 0x07, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65,
1123 0x61, 0x1d, 0x4d, 0x6f, 0x6e, 0x2c, 0x20, 0x32, 0x31, 0x20, 0x4f, 0x63, 0x74, 0x20,
1124 0x32, 0x30, 0x31, 0x33, 0x20, 0x32, 0x30, 0x3a, 0x31, 0x33, 0x3a, 0x32, 0x31, 0x20,
1125 0x47, 0x4d, 0x54, 0x6e, 0x17, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77,
1126 0x77, 0x77, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
1127 ];
1128
1129 let header_list = decoder.decode(&hex_dump).ok().unwrap();
1130
1131 assert_eq!(
1132 header_list,
1133 [
1134 (b":status".to_vec(), b"302".to_vec()),
1135 (b"cache-control".to_vec(), b"private".to_vec()),
1136 (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1137 (b"location".to_vec(), b"https://www.example.com".to_vec()),
1138 ]
1139 );
1140 let expected_table = vec![
1142 (b"location".to_vec(), b"https://www.example.com".to_vec()),
1143 (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1144 (b"cache-control".to_vec(), b"private".to_vec()),
1145 (b":status".to_vec(), b"302".to_vec()),
1146 ];
1147 let actual = decoder.header_table.dynamic_table.to_vec();
1148 assert_eq!(actual, expected_table);
1149 }
1150 {
1151 let hex_dump = [
1152 0x48, 0x03, 0x33, 0x30, 0x37, 0xc1, 0xc0, 0xbf,
1153 0x20,
1157 ];
1158
1159 let header_list = decoder.decode(&hex_dump).ok().unwrap();
1160
1161 assert_eq!(
1163 header_list,
1164 [
1165 (b":status".to_vec(), b"307".to_vec()),
1166 (b"cache-control".to_vec(), b"private".to_vec()),
1167 (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1168 (b"location".to_vec(), b"https://www.example.com".to_vec()),
1169 ]
1170 );
1171 let expected_table = vec![];
1173 let actual = decoder.header_table.dynamic_table.to_vec();
1174 assert_eq!(actual, expected_table);
1175 assert_eq!(0, decoder.header_table.dynamic_table.get_max_table_size());
1176 }
1177 }
1178
1179 #[test]
1183 fn request_sequence_huffman() {
1184 let mut decoder = Decoder::new();
1185 {
1186 let hex_dump = [
1188 0x82, 0x86, 0x84, 0x41, 0x8c, 0xf1, 0xe3, 0xc2, 0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab,
1189 0x90, 0xf4, 0xff,
1190 ];
1191
1192 let header_list = decoder.decode(&hex_dump).ok().unwrap();
1193
1194 assert_eq!(
1195 header_list,
1196 [
1197 (b":method".to_vec(), b"GET".to_vec()),
1198 (b":scheme".to_vec(), b"http".to_vec()),
1199 (b":path".to_vec(), b"/".to_vec()),
1200 (b":authority".to_vec(), b"www.example.com".to_vec()),
1201 ]
1202 );
1203 assert_eq!(decoder.header_table.dynamic_table.len(), 1);
1205 let expected_table = vec![(b":authority".to_vec(), b"www.example.com".to_vec())];
1206 let actual = decoder.header_table.dynamic_table.to_vec();
1207 assert_eq!(actual, expected_table);
1208 }
1209 {
1210 let hex_dump = [
1212 0x82, 0x86, 0x84, 0xbe, 0x58, 0x86, 0xa8, 0xeb, 0x10, 0x64, 0x9c, 0xbf,
1213 ];
1214
1215 let header_list = decoder.decode(&hex_dump).ok().unwrap();
1216
1217 assert_eq!(
1218 header_list,
1219 [
1220 (b":method".to_vec(), b"GET".to_vec()),
1221 (b":scheme".to_vec(), b"http".to_vec()),
1222 (b":path".to_vec(), b"/".to_vec()),
1223 (b":authority".to_vec(), b"www.example.com".to_vec()),
1224 (b"cache-control".to_vec(), b"no-cache".to_vec()),
1225 ]
1226 );
1227 let expected_table = vec![
1229 (b"cache-control".to_vec(), b"no-cache".to_vec()),
1230 (b":authority".to_vec(), b"www.example.com".to_vec()),
1231 ];
1232 let actual = decoder.header_table.dynamic_table.to_vec();
1233 assert_eq!(actual, expected_table);
1234 }
1235 {
1236 let hex_dump = [
1238 0x82, 0x87, 0x85, 0xbf, 0x40, 0x88, 0x25, 0xa8, 0x49, 0xe9, 0x5b, 0xa9, 0x7d, 0x7f,
1239 0x89, 0x25, 0xa8, 0x49, 0xe9, 0x5b, 0xb8, 0xe8, 0xb4, 0xbf,
1240 ];
1241
1242 let header_list = decoder.decode(&hex_dump).ok().unwrap();
1243
1244 assert_eq!(
1245 header_list,
1246 [
1247 (b":method".to_vec(), b"GET".to_vec()),
1248 (b":scheme".to_vec(), b"https".to_vec()),
1249 (b":path".to_vec(), b"/index.html".to_vec()),
1250 (b":authority".to_vec(), b"www.example.com".to_vec()),
1251 (b"custom-key".to_vec(), b"custom-value".to_vec()),
1252 ]
1253 );
1254 let expected_table = vec![
1257 (b"custom-key".to_vec(), b"custom-value".to_vec()),
1258 (b"cache-control".to_vec(), b"no-cache".to_vec()),
1259 (b":authority".to_vec(), b"www.example.com".to_vec()),
1260 ];
1261 let actual = decoder.header_table.dynamic_table.to_vec();
1262 assert_eq!(actual, expected_table);
1263 }
1264 }
1265
1266 #[test]
1270 fn response_sequence_huffman() {
1271 let mut decoder = Decoder::new();
1272 decoder.set_max_table_size(256);
1274 {
1275 let hex_dump = [
1277 0x48, 0x82, 0x64, 0x02, 0x58, 0x85, 0xae, 0xc3, 0x77, 0x1a, 0x4b, 0x61, 0x96, 0xd0,
1278 0x7a, 0xbe, 0x94, 0x10, 0x54, 0xd4, 0x44, 0xa8, 0x20, 0x05, 0x95, 0x04, 0x0b, 0x81,
1279 0x66, 0xe0, 0x82, 0xa6, 0x2d, 0x1b, 0xff, 0x6e, 0x91, 0x9d, 0x29, 0xad, 0x17, 0x18,
1280 0x63, 0xc7, 0x8f, 0x0b, 0x97, 0xc8, 0xe9, 0xae, 0x82, 0xae, 0x43, 0xd3,
1281 ];
1282
1283 let header_list = decoder.decode(&hex_dump).ok().unwrap();
1284
1285 assert_eq!(
1286 header_list,
1287 [
1288 (b":status".to_vec(), b"302".to_vec()),
1289 (b"cache-control".to_vec(), b"private".to_vec()),
1290 (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1291 (b"location".to_vec(), b"https://www.example.com".to_vec()),
1292 ]
1293 );
1294 let expected_table = vec![
1296 (b"location".to_vec(), b"https://www.example.com".to_vec()),
1297 (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1298 (b"cache-control".to_vec(), b"private".to_vec()),
1299 (b":status".to_vec(), b"302".to_vec()),
1300 ];
1301 let actual = decoder.header_table.dynamic_table.to_vec();
1302 assert_eq!(actual, expected_table);
1303 }
1304 {
1305 let hex_dump = [0x48, 0x83, 0x64, 0x0e, 0xff, 0xc1, 0xc0, 0xbf];
1307
1308 let header_list = decoder.decode(&hex_dump).ok().unwrap();
1309
1310 assert_eq!(
1311 header_list,
1312 [
1313 (b":status".to_vec(), b"307".to_vec()),
1314 (b"cache-control".to_vec(), b"private".to_vec()),
1315 (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1316 (b"location".to_vec(), b"https://www.example.com".to_vec()),
1317 ]
1318 );
1319 let expected_table = vec![
1322 (b":status".to_vec(), b"307".to_vec()),
1323 (b"location".to_vec(), b"https://www.example.com".to_vec()),
1324 (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:21 GMT".to_vec()),
1325 (b"cache-control".to_vec(), b"private".to_vec()),
1326 ];
1327 let actual = decoder.header_table.dynamic_table.to_vec();
1328 assert_eq!(actual, expected_table);
1329 }
1330 {
1331 let hex_dump = [
1333 0x88, 0xc1, 0x61, 0x96, 0xd0, 0x7a, 0xbe, 0x94, 0x10, 0x54, 0xd4, 0x44, 0xa8, 0x20,
1334 0x05, 0x95, 0x04, 0x0b, 0x81, 0x66, 0xe0, 0x84, 0xa6, 0x2d, 0x1b, 0xff, 0xc0, 0x5a,
1335 0x83, 0x9b, 0xd9, 0xab, 0x77, 0xad, 0x94, 0xe7, 0x82, 0x1d, 0xd7, 0xf2, 0xe6, 0xc7,
1336 0xb3, 0x35, 0xdf, 0xdf, 0xcd, 0x5b, 0x39, 0x60, 0xd5, 0xaf, 0x27, 0x08, 0x7f, 0x36,
1337 0x72, 0xc1, 0xab, 0x27, 0x0f, 0xb5, 0x29, 0x1f, 0x95, 0x87, 0x31, 0x60, 0x65, 0xc0,
1338 0x03, 0xed, 0x4e, 0xe5, 0xb1, 0x06, 0x3d, 0x50, 0x07,
1339 ];
1340
1341 let header_list = decoder.decode(&hex_dump).ok().unwrap();
1342
1343 let expected_header_list = [
1344 (b":status".to_vec(), b"200".to_vec()),
1345 (b"cache-control".to_vec(), b"private".to_vec()),
1346 (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:22 GMT".to_vec()),
1347 (b"location".to_vec(), b"https://www.example.com".to_vec()),
1348 (b"content-encoding".to_vec(), b"gzip".to_vec()),
1349 (
1350 b"set-cookie".to_vec(),
1351 b"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1".to_vec(),
1352 ),
1353 ];
1354 assert_eq!(header_list, expected_header_list);
1355 let expected_table = vec![
1358 (
1359 b"set-cookie".to_vec(),
1360 b"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1".to_vec(),
1361 ),
1362 (b"content-encoding".to_vec(), b"gzip".to_vec()),
1363 (b"date".to_vec(), b"Mon, 21 Oct 2013 20:13:22 GMT".to_vec()),
1364 ];
1365 let actual = decoder.header_table.dynamic_table.to_vec();
1366 assert_eq!(actual, expected_table);
1367 }
1368 }
1369
1370 fn is_decoder_error(err: &DecoderError, result: &DecoderResult) -> bool {
1373 match *result {
1374 Err(ref e) => e == err,
1375 _ => false,
1376 }
1377 }
1378
1379 #[test]
1383 fn test_index_out_of_bounds() {
1384 let mut decoder = Decoder::new();
1385 let raw_messages = [
1388 vec![0x80],
1391 vec![0xbe],
1396 vec![126, 1, 65],
1399 ];
1400
1401 for raw_message in raw_messages.iter() {
1403 assert!(
1404 is_decoder_error(
1405 &DecoderError::HeaderIndexOutOfBounds,
1406 &decoder.decode(raw_message)
1407 ),
1408 "Expected index out of bounds"
1409 );
1410 }
1411 }
1412
1413 #[test]
1417 fn test_invalid_literal_huffman_string() {
1418 let mut decoder = Decoder::new();
1419 let hex_dump = [
1421 0x82, 0x86, 0x84, 0x41, 0x8c, 0xf1, 0xe3, 0xc2, 0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab,
1422 0x90, 0xf4, 0xfe,
1423 ];
1424
1425 assert!(matches!(
1426 decoder.decode(&hex_dump),
1427 Err(DecoderError::StringDecodingError(
1428 StringDecodingError::HuffmanDecoderError(HuffmanDecoderError::InvalidPadding,)
1429 ))
1430 ));
1431 }
1432
1433 #[test]
1436 fn test_literal_header_key_incomplete() {
1437 let mut decoder = Decoder::new();
1438 let hex_dump = [
1441 0x40, 0x0a, b'c', b'u', b's', b't', b'o', b'm', b'-', b'k', b'e',
1442 ];
1443
1444 let result = decoder.decode(&hex_dump);
1445
1446 assert!(matches!(
1447 result,
1448 Err(DecoderError::StringDecodingError(
1449 StringDecodingError::NotEnoughOctets
1450 ))
1451 ));
1452 }
1453
1454 #[test]
1457 fn test_literal_header_missing_value() {
1458 let mut decoder = Decoder::new();
1459 let hex_dump = [
1462 0x40, 0x0a, b'c', b'u', b's', b't', b'o', b'm', b'-', b'k', b'e', b'y',
1463 ];
1464
1465 let result = decoder.decode(&hex_dump);
1466
1467 assert!(matches!(
1468 result,
1469 Err(DecoderError::IntegerDecodingError(
1470 IntegerDecodingError::NotEnoughOctets
1471 ))
1472 ));
1473 }
1474}
1475
1476#[cfg(test)]
1481#[cfg(feature = "interop-tests")]
1482mod interop_tests {
1483 use std::fs;
1484 use std::path::{Path, PathBuf};
1485 use std::{borrow::Cow, collections::HashMap};
1486
1487 use serde::Deserialize;
1488 use tracing::debug;
1489
1490 use super::Decoder;
1491
1492 #[derive(Deserialize)]
1493 struct RawTestStory<'a> {
1494 cases: Vec<RawTestFixture<'a>>,
1495 }
1496
1497 #[derive(Deserialize)]
1498 struct RawTestFixture<'a> {
1499 wire: Cow<'a, str>,
1501
1502 headers: Vec<HashMap<Cow<'a, str>, Cow<'a, str>>>,
1504 }
1505
1506 struct TestFixture {
1509 wire_bytes: Vec<u8>,
1510 headers: Vec<(Vec<u8>, Vec<u8>)>,
1511 }
1512
1513 struct TestStory {
1516 cases: Vec<TestFixture>,
1517 }
1518
1519 #[derive(Debug, thiserror::Error)]
1520 enum DecodeError {
1521 #[error("Failed to parse hex-encoded bytes: {0}")]
1522 FromHex(#[from] hex::FromHexError),
1523 }
1524
1525 impl TryFrom<RawTestStory<'_>> for TestStory {
1526 type Error = DecodeError;
1527
1528 fn try_from(raw_story: RawTestStory) -> Result<Self, Self::Error> {
1529 let mut cases = Vec::with_capacity(raw_story.cases.len());
1530 for raw_case in raw_story.cases {
1531 let wire_bytes = hex::decode(raw_case.wire.as_bytes())?;
1532
1533 let headers: Vec<_> = raw_case
1534 .headers
1535 .into_iter()
1536 .flat_map(|h| {
1537 h.into_iter().map(|(k, v)| {
1538 (k.into_owned().into_bytes(), v.into_owned().into_bytes())
1539 })
1540 })
1541 .collect();
1542
1543 cases.push(TestFixture {
1544 wire_bytes,
1545 headers,
1546 });
1547 }
1548
1549 Ok(TestStory { cases })
1550 }
1551 }
1552
1553 #[test]
1556 fn test_story_parser_sanity_check() {
1557 let raw_json = r#"
1558 {
1559 "cases": [
1560 {
1561 "seqno": 0,
1562 "wire": "82864188f439ce75c875fa5784",
1563 "headers": [
1564 {
1565 ":method": "GET"
1566 },
1567 {
1568 ":scheme": "http"
1569 },
1570 {
1571 ":authority": "yahoo.co.jp"
1572 },
1573 {
1574 ":path": "/"
1575 }
1576 ]
1577 },
1578 {
1579 "seqno": 1,
1580 "wire": "8286418cf1e3c2fe8739ceb90ebf4aff84",
1581 "headers": [
1582 {
1583 ":method": "GET"
1584 },
1585 {
1586 ":scheme": "http"
1587 },
1588 {
1589 ":authority": "www.yahoo.co.jp"
1590 },
1591 {
1592 ":path": "/"
1593 }
1594 ]
1595 }
1596 ],
1597 "draft": 9
1598 }
1599 "#;
1600
1601 let decoded: RawTestStory = serde_json::from_str(raw_json).unwrap();
1602 let decoded = TestStory::try_from(decoded).unwrap();
1603
1604 assert_eq!(decoded.cases.len(), 2);
1605 assert_eq!(
1606 decoded.cases[0].wire_bytes,
1607 vec![0x82, 0x86, 0x41, 0x88, 0xf4, 0x39, 0xce, 0x75, 0xc8, 0x75, 0xfa, 0x57, 0x84]
1608 );
1609 assert_eq!(
1610 decoded.cases[0].headers,
1611 vec![
1612 (b":method".to_vec(), b"GET".to_vec()),
1613 (b":scheme".to_vec(), b"http".to_vec()),
1614 (b":authority".to_vec(), b"yahoo.co.jp".to_vec()),
1615 (b":path".to_vec(), b"/".to_vec()),
1616 ]
1617 );
1618 }
1619
1620 fn test_story(story_file_name: PathBuf) {
1628 let story: TestStory = {
1630 let buf = std::fs::read_to_string(story_file_name);
1631 let raw_story: RawTestStory = serde_json::from_str(&buf.unwrap()).unwrap();
1632 raw_story.try_into().unwrap()
1633 };
1634 let mut decoder = Decoder::new();
1636 for case in story.cases.iter() {
1640 let decoded = decoder.decode(&case.wire_bytes).unwrap();
1641 assert_eq!(decoded, case.headers);
1642 }
1643 }
1644
1645 fn test_fixture_set(fixture_dir: &str) {
1651 let files = fs::read_dir(Path::new(fixture_dir)).unwrap();
1652
1653 for fixture in files {
1654 let file_name = fixture.unwrap().path();
1655 debug!("Testing fixture: {:?}", file_name);
1656 test_story(file_name);
1657 }
1658 }
1659
1660 #[test]
1661 fn test_nghttp2_interop() {
1662 test_fixture_set("fixtures/hpack/interop/nghttp2");
1663 }
1664
1665 #[test]
1666 fn test_nghttp2_change_table_size_interop() {
1667 test_fixture_set("fixtures/hpack/interop/nghttp2-change-table-size");
1668 }
1669
1670 #[test]
1671 fn test_go_hpack_interop() {
1672 test_fixture_set("fixtures/hpack/interop/go-hpack");
1673 }
1674
1675 #[test]
1676 fn test_node_http2_hpack_interop() {
1677 test_fixture_set("fixtures/hpack/interop/node-http2-hpack");
1678 }
1679
1680 #[test]
1681 fn test_haskell_http2_linear_huffman() {
1682 test_fixture_set("fixtures/hpack/interop/haskell-http2-linear-huffman");
1683 }
1684}