// Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use crate::prefix::{ BASE_PREFIX_NEGATIVE, BASE_PREFIX_POSITIVE, HEADER_FIELD_INDEX_DYNAMIC, HEADER_FIELD_INDEX_DYNAMIC_POST, HEADER_FIELD_INDEX_STATIC, HEADER_FIELD_LITERAL_NAME_LITERAL, HEADER_FIELD_LITERAL_NAME_REF_DYNAMIC, HEADER_FIELD_LITERAL_NAME_REF_DYNAMIC_POST, HEADER_FIELD_LITERAL_NAME_REF_STATIC, NO_PREFIX, }; use crate::qpack_send_buf::QpackData; use crate::reader::{to_string, ReceiverBufferWrapper}; use crate::table::HeaderTable; use crate::{Error, Res}; use neqo_common::{qtrace, Header}; use std::mem; use std::ops::{Deref, Div}; #[derive(Default, Debug, PartialEq)] pub struct HeaderEncoder { buf: QpackData, base: u64, use_huffman: bool, max_entries: u64, max_dynamic_index_ref: Option, } impl ::std::fmt::Display for HeaderEncoder { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { write!(f, "HeaderEncoder") } } impl HeaderEncoder { pub fn new(base: u64, use_huffman: bool, max_entries: u64) -> Self { Self { buf: QpackData::default(), base, use_huffman, max_entries, max_dynamic_index_ref: None, } } pub fn len(&self) -> usize { self.buf.len() } pub fn read(&mut self, r: usize) { self.buf.read(r); } pub fn encode_indexed_static(&mut self, index: u64) { qtrace!([self], "encode static index {}.", index); self.buf .encode_prefixed_encoded_int(HEADER_FIELD_INDEX_STATIC, index); } fn new_ref(&mut self, index: u64) { if let Some(r) = self.max_dynamic_index_ref { if r < index { self.max_dynamic_index_ref = Some(index); } } else { self.max_dynamic_index_ref = Some(index); } } pub fn encode_indexed_dynamic(&mut self, index: u64) { qtrace!([self], "encode dynamic index {}.", index); if index < self.base { self.buf .encode_prefixed_encoded_int(HEADER_FIELD_INDEX_DYNAMIC, self.base - index - 1); } else { self.buf .encode_prefixed_encoded_int(HEADER_FIELD_INDEX_DYNAMIC_POST, index - self.base); } self.new_ref(index); } pub fn encode_literal_with_name_ref(&mut self, is_static: bool, index: u64, value: &[u8]) { qtrace!( [self], "encode literal with name ref - index={}, static={}, value={:x?}", index, is_static, value ); if is_static { self.buf .encode_prefixed_encoded_int(HEADER_FIELD_LITERAL_NAME_REF_STATIC, index); } else if index < self.base { self.buf.encode_prefixed_encoded_int( HEADER_FIELD_LITERAL_NAME_REF_DYNAMIC, self.base - index - 1, ); self.new_ref(index); } else { self.buf.encode_prefixed_encoded_int( HEADER_FIELD_LITERAL_NAME_REF_DYNAMIC_POST, index - self.base, ); self.new_ref(index); } self.buf.encode_literal(self.use_huffman, NO_PREFIX, value); } pub fn encode_literal_with_name_literal(&mut self, name: &[u8], value: &[u8]) { qtrace!( [self], "encode literal with name literal - name={:x?}, value={:x?}.", name, value ); self.buf .encode_literal(self.use_huffman, HEADER_FIELD_LITERAL_NAME_LITERAL, name); self.buf.encode_literal(self.use_huffman, NO_PREFIX, value); } pub fn encode_header_block_prefix(&mut self) { let tmp = mem::take(&mut self.buf); let (enc_insert_cnt, delta, prefix) = self.max_dynamic_index_ref .map_or((0, self.base, BASE_PREFIX_POSITIVE), |r| { let req_insert_cnt = r + 1; if req_insert_cnt <= self.base { ( req_insert_cnt % (2 * self.max_entries) + 1, self.base - req_insert_cnt, BASE_PREFIX_POSITIVE, ) } else { ( req_insert_cnt % (2 * self.max_entries) + 1, req_insert_cnt - self.base - 1, BASE_PREFIX_NEGATIVE, ) } }); qtrace!( [self], "encode header block prefix max_dynamic_index_ref={:?}, base={}, enc_insert_cnt={}, delta={}, prefix={:?}.", self.max_dynamic_index_ref, self.base, enc_insert_cnt, delta, prefix ); self.buf .encode_prefixed_encoded_int(NO_PREFIX, enc_insert_cnt); self.buf.encode_prefixed_encoded_int(prefix, delta); self.buf.write_bytes(&tmp); } } impl Deref for HeaderEncoder { type Target = [u8]; fn deref(&self) -> &Self::Target { &self.buf } } pub(crate) struct HeaderDecoder<'a> { buf: ReceiverBufferWrapper<'a>, base: u64, req_insert_cnt: u64, } impl<'a> ::std::fmt::Display for HeaderDecoder<'a> { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { write!(f, "HeaderDecoder") } } #[derive(Debug, PartialEq, Eq)] pub enum HeaderDecoderResult { Blocked(u64), Headers(Vec
), } impl<'a> HeaderDecoder<'a> { pub fn new(buf: &'a [u8]) -> Self { Self { buf: ReceiverBufferWrapper::new(buf), base: 0, req_insert_cnt: 0, } } pub fn refers_dynamic_table( &mut self, max_entries: u64, total_num_of_inserts: u64, ) -> Res { Error::map_error( self.read_base(max_entries, total_num_of_inserts), Error::DecompressionFailed, )?; Ok(self.req_insert_cnt != 0) } pub fn decode_header_block( &mut self, table: &HeaderTable, max_entries: u64, total_num_of_inserts: u64, ) -> Res { Error::map_error( self.read_base(max_entries, total_num_of_inserts), Error::DecompressionFailed, )?; if table.base() < self.req_insert_cnt { qtrace!( [self], "decoding is blocked, requested inserts count={}", self.req_insert_cnt ); return Ok(HeaderDecoderResult::Blocked(self.req_insert_cnt)); } let mut h: Vec
= Vec::new(); while !self.buf.done() { let b = Error::map_error(self.buf.peek(), Error::DecompressionFailed)?; if HEADER_FIELD_INDEX_STATIC.cmp_prefix(b) { h.push(Error::map_error( self.read_indexed_static(), Error::DecompressionFailed, )?); } else if HEADER_FIELD_INDEX_DYNAMIC.cmp_prefix(b) { h.push(Error::map_error( self.read_indexed_dynamic(table), Error::DecompressionFailed, )?); } else if HEADER_FIELD_INDEX_DYNAMIC_POST.cmp_prefix(b) { h.push(Error::map_error( self.read_indexed_dynamic_post(table), Error::DecompressionFailed, )?); } else if HEADER_FIELD_LITERAL_NAME_REF_STATIC.cmp_prefix(b) { h.push(Error::map_error( self.read_literal_with_name_ref_static(), Error::DecompressionFailed, )?); } else if HEADER_FIELD_LITERAL_NAME_REF_DYNAMIC.cmp_prefix(b) { h.push(Error::map_error( self.read_literal_with_name_ref_dynamic(table), Error::DecompressionFailed, )?); } else if HEADER_FIELD_LITERAL_NAME_LITERAL.cmp_prefix(b) { h.push(Error::map_error( self.read_literal_with_name_literal(), Error::DecompressionFailed, )?); } else if HEADER_FIELD_LITERAL_NAME_REF_DYNAMIC_POST.cmp_prefix(b) { h.push(Error::map_error( self.read_literal_with_name_ref_dynamic_post(table), Error::DecompressionFailed, )?); } else { unreachable!("All prefixes are covered"); } } qtrace!([self], "done decoding header block."); Ok(HeaderDecoderResult::Headers(h)) } pub fn get_req_insert_cnt(&self) -> u64 { self.req_insert_cnt } fn read_base(&mut self, max_entries: u64, total_num_of_inserts: u64) -> Res<()> { let insert_cnt = self.buf.read_prefixed_int(0)?; self.req_insert_cnt = HeaderDecoder::calc_req_insert_cnt(insert_cnt, max_entries, total_num_of_inserts)?; let s = self.buf.peek()? & 0x80 != 0; let base_delta = self.buf.read_prefixed_int(1)?; self.base = if s { if self.req_insert_cnt <= base_delta { return Err(Error::DecompressionFailed); } self.req_insert_cnt - base_delta - 1 } else { self.req_insert_cnt .checked_add(base_delta) .ok_or(Error::DecompressionFailed)? }; qtrace!( [self], "requested inserts count is {} and base is {}", self.req_insert_cnt, self.base ); Ok(()) } fn calc_req_insert_cnt(encoded: u64, max_entries: u64, total_num_of_inserts: u64) -> Res { if encoded == 0 { Ok(0) } else if max_entries == 0 { Err(Error::DecompressionFailed) } else { let full_range = 2 * max_entries; if encoded > full_range { return Err(Error::DecompressionFailed); } let max_value = total_num_of_inserts + max_entries; let max_wrapped = max_value.div(full_range) * full_range; let mut req_insert_cnt = max_wrapped + encoded - 1; if req_insert_cnt > max_value { if req_insert_cnt < full_range { return Err(Error::DecompressionFailed); } req_insert_cnt -= full_range; } Ok(req_insert_cnt) } } fn read_indexed_static(&mut self) -> Res
{ let index = self .buf .read_prefixed_int(HEADER_FIELD_INDEX_STATIC.len())?; qtrace!([self], "decoder static indexed {}.", index); let entry = HeaderTable::get_static(index)?; Ok(Header::new( to_string(entry.name())?, to_string(entry.value())?, )) } fn read_indexed_dynamic(&mut self, table: &HeaderTable) -> Res
{ let index = self .buf .read_prefixed_int(HEADER_FIELD_INDEX_DYNAMIC.len())?; qtrace!([self], "decoder dynamic indexed {}.", index); let entry = table.get_dynamic(index, self.base, false)?; Ok(Header::new( to_string(entry.name())?, to_string(entry.value())?, )) } fn read_indexed_dynamic_post(&mut self, table: &HeaderTable) -> Res
{ let index = self .buf .read_prefixed_int(HEADER_FIELD_INDEX_DYNAMIC_POST.len())?; qtrace!([self], "decode post-based {}.", index); let entry = table.get_dynamic(index, self.base, true)?; Ok(Header::new( to_string(entry.name())?, to_string(entry.value())?, )) } fn read_literal_with_name_ref_static(&mut self) -> Res
{ qtrace!( [self], "read literal with name reference to the static table." ); let index = self .buf .read_prefixed_int(HEADER_FIELD_LITERAL_NAME_REF_STATIC.len())?; Ok(Header::new( to_string(HeaderTable::get_static(index)?.name())?, self.buf.read_literal_from_buffer(0)?, )) } fn read_literal_with_name_ref_dynamic(&mut self, table: &HeaderTable) -> Res
{ qtrace!( [self], "read literal with name reference ot the dynamic table." ); let index = self .buf .read_prefixed_int(HEADER_FIELD_LITERAL_NAME_REF_DYNAMIC.len())?; Ok(Header::new( to_string(table.get_dynamic(index, self.base, false)?.name())?, self.buf.read_literal_from_buffer(0)?, )) } fn read_literal_with_name_ref_dynamic_post(&mut self, table: &HeaderTable) -> Res
{ qtrace!([self], "decoder literal with post-based index."); let index = self .buf .read_prefixed_int(HEADER_FIELD_LITERAL_NAME_REF_DYNAMIC_POST.len())?; Ok(Header::new( to_string(table.get_dynamic(index, self.base, true)?.name())?, self.buf.read_literal_from_buffer(0)?, )) } fn read_literal_with_name_literal(&mut self) -> Res
{ qtrace!([self], "decode literal with name literal."); let name = self .buf .read_literal_from_buffer(HEADER_FIELD_LITERAL_NAME_LITERAL.len())?; Ok(Header::new(name, self.buf.read_literal_from_buffer(0)?)) } } #[cfg(test)] mod tests { use super::{HeaderDecoder, HeaderDecoderResult, HeaderEncoder, HeaderTable}; use crate::Error; const INDEX_STATIC_TEST: &[(u64, &[u8], &str, &str)] = &[ (0, &[0x0, 0x0, 0xc0], ":authority", ""), (10, &[0x0, 0x0, 0xca], "last-modified", ""), (15, &[0x0, 0x0, 0xcf], ":method", "CONNECT"), (65, &[0x0, 0x0, 0xff, 0x02], ":status", "206"), ]; const INDEX_DYNAMIC_TEST: &[(u64, &[u8], &str, &str)] = &[ (0, &[0x02, 0x41, 0xbf, 0x2], "header0", "0"), (10, &[0x0c, 0x37, 0xb7], "header10", "10"), (15, &[0x11, 0x32, 0xb2], "header15", "15"), (65, &[0x43, 0x0, 0x80], "header65", "65"), ]; const INDEX_DYNAMIC_POST_TEST: &[(u64, &[u8], &str, &str)] = &[ (0, &[0x02, 0x80, 0x10], "header0", "0"), (10, &[0x0c, 0x8a, 0x1a], "header10", "10"), (15, &[0x11, 0x8f, 0x1f, 0x00], "header15", "15"), (65, &[0x43, 0xc1, 0x1f, 0x32], "header65", "65"), ]; const NAME_REF_STATIC: &[(u64, &[u8], &str, &str)] = &[ ( 0, &[ 0x00, 0x00, 0x50, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79, ], ":authority", "custom-key", ), ( 10, &[ 0x00, 0x00, 0x5a, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79, ], "last-modified", "custom-key", ), ( 15, &[ 0x00, 0x00, 0x5f, 0x00, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79, ], ":method", "custom-key", ), ( 65, &[ 0x00, 0x00, 0x5f, 0x32, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79, ], ":status", "custom-key", ), ]; const NAME_REF_DYNAMIC: &[(u64, &[u8], &str, &str)] = &[ ( 0, &[ 0x02, 0x41, 0x4f, 0x32, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79, ], "header0", "custom-key", ), ( 10, &[ 0x0c, 0x37, 0x4f, 0x28, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79, ], "header10", "custom-key", ), ( 15, &[ 0x11, 0x32, 0x4f, 0x23, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79, ], "header15", "custom-key", ), ( 65, &[ 0x43, 0x00, 0x40, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79, ], "header65", "custom-key", ), ]; const NAME_REF_DYNAMIC_POST: &[(u64, &[u8], &str, &str)] = &[ ( 0, &[ 0x02, 0x80, 0x00, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79, ], "header0", "custom-key", ), ( 10, &[ 0x0c, 0x8a, 0x07, 0x03, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79, ], "header10", "custom-key", ), ( 15, &[ 0x11, 0x8f, 0x07, 0x08, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79, ], "header15", "custom-key", ), ( 65, &[ 0x43, 0xc1, 0x07, 0x3a, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79, ], "header65", "custom-key", ), ]; const NAME_REF_DYNAMIC_HUFFMAN: &[(u64, &[u8], &str, &str)] = &[ ( 0, &[ 0x02, 0x41, 0x4f, 0x32, 0x88, 0x25, 0xa8, 0x49, 0xe9, 0x5b, 0xa9, 0x7d, 0x7f, ], "header0", "custom-key", ), ( 10, &[ 0x0c, 0x37, 0x4f, 0x28, 0x88, 0x25, 0xa8, 0x49, 0xe9, 0x5b, 0xa9, 0x7d, 0x7f, ], "header10", "custom-key", ), ( 15, &[ 0x11, 0x32, 0x4f, 0x23, 0x88, 0x25, 0xa8, 0x49, 0xe9, 0x5b, 0xa9, 0x7d, 0x7f, ], "header15", "custom-key", ), ( 65, &[ 0x43, 0x00, 0x40, 0x88, 0x25, 0xa8, 0x49, 0xe9, 0x5b, 0xa9, 0x7d, 0x7f, ], "header65", "custom-key", ), ]; const VALUE: &[u8] = &[0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79]; const LITERAL_LITERAL: &[u8] = &[ 0x0, 0x42, 0x27, 0x03, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79, ]; const LITERAL_LITERAL_HUFFMAN: &[u8] = &[ 0x0, 0x42, 0x2f, 0x01, 0x25, 0xa8, 0x49, 0xe9, 0x5b, 0xa9, 0x7d, 0x7f, 0x88, 0x25, 0xa8, 0x49, 0xe9, 0x5b, 0xa9, 0x7d, 0x7f, ]; const LITERAL_VALUE: &str = "custom-key"; #[test] fn test_encode_indexed_static() { for (index, result, _, _) in INDEX_STATIC_TEST { let mut encoded_h = HeaderEncoder::new(0, true, 1000); encoded_h.encode_indexed_static(*index); encoded_h.encode_header_block_prefix(); assert_eq!(&&*encoded_h, result); } } #[test] fn test_encode_indexed_dynamic() { for (index, result, _, _) in INDEX_DYNAMIC_TEST { let mut encoded_h = HeaderEncoder::new(66, true, 1000); encoded_h.encode_indexed_dynamic(*index); encoded_h.encode_header_block_prefix(); assert_eq!(&&*encoded_h, result); } } #[test] fn test_encode_indexed_dynamic_post() { for (index, result, _, _) in INDEX_DYNAMIC_POST_TEST { let mut encoded_h = HeaderEncoder::new(0, true, 1000); encoded_h.encode_indexed_dynamic(*index); encoded_h.encode_header_block_prefix(); assert_eq!(&&*encoded_h, result); } } #[test] fn test_encode_literal_with_name_ref_static() { for (index, result, _, _) in NAME_REF_STATIC { let mut encoded_h = HeaderEncoder::new(0, false, 1000); encoded_h.encode_literal_with_name_ref(true, *index, VALUE); encoded_h.encode_header_block_prefix(); assert_eq!(&&*encoded_h, result); } } #[test] fn test_encode_literal_with_name_ref_dynamic() { for (index, result, _, _) in NAME_REF_DYNAMIC { let mut encoded_h = HeaderEncoder::new(66, false, 1000); encoded_h.encode_literal_with_name_ref(false, *index, VALUE); encoded_h.encode_header_block_prefix(); assert_eq!(&&*encoded_h, result); } } #[test] fn test_encode_literal_with_name_ref_dynamic_post() { for (index, result, _, _) in NAME_REF_DYNAMIC_POST { let mut encoded_h = HeaderEncoder::new(0, false, 1000); encoded_h.encode_literal_with_name_ref(false, *index, VALUE); encoded_h.encode_header_block_prefix(); assert_eq!(&&*encoded_h, result); } } #[test] fn test_encode_literal_with_name_ref_dynamic_huffman() { for (index, result, _, _) in NAME_REF_DYNAMIC_HUFFMAN { let mut encoded_h = HeaderEncoder::new(66, true, 1000); encoded_h.encode_literal_with_name_ref(false, *index, VALUE); encoded_h.encode_header_block_prefix(); assert_eq!(&&*encoded_h, result); } } #[test] fn test_encode_literal_with_literal() { let mut encoded_h = HeaderEncoder::new(66, false, 1000); encoded_h.encode_literal_with_name_literal(VALUE, VALUE); encoded_h.encode_header_block_prefix(); assert_eq!(&*encoded_h, LITERAL_LITERAL); let mut encoded_h = HeaderEncoder::new(66, true, 1000); encoded_h.encode_literal_with_name_literal(VALUE, VALUE); encoded_h.encode_header_block_prefix(); assert_eq!(&*encoded_h, LITERAL_LITERAL_HUFFMAN); } #[test] fn decode_indexed_static() { for (_, encoded, decoded1, decoded2) in INDEX_STATIC_TEST { let table = HeaderTable::new(false); let mut decoder_h = HeaderDecoder::new(encoded); if let HeaderDecoderResult::Headers(result) = decoder_h.decode_header_block(&table, 1000, 0).unwrap() { assert_eq!(result.len(), 1); assert_eq!(result[0].name(), *decoded1); assert_eq!(result[0].value(), *decoded2); } else { panic!("No headers"); } } } fn fill_table(table: &mut HeaderTable) { table.set_capacity(10000).unwrap(); for i in 0..66 { let mut v = b"header".to_vec(); let mut num = i.to_string().as_bytes().to_vec(); v.append(&mut num); table.insert(&v[..], i.to_string().as_bytes()).unwrap(); } } #[test] fn decode_indexed_dynamic() { for (_, encoded, decoded1, decoded2) in INDEX_DYNAMIC_TEST { let mut table = HeaderTable::new(false); fill_table(&mut table); let mut decoder_h = HeaderDecoder::new(encoded); if let HeaderDecoderResult::Headers(result) = decoder_h.decode_header_block(&table, 1000, 0).unwrap() { assert_eq!(result.len(), 1); assert_eq!(result[0].name(), *decoded1); assert_eq!(result[0].value(), *decoded2); } else { panic!("No headers"); } } } #[test] fn decode_indexed_dynamic_post() { for (_, encoded, decoded1, decoded2) in INDEX_DYNAMIC_POST_TEST { let mut table = HeaderTable::new(false); fill_table(&mut table); let mut decoder_h = HeaderDecoder::new(encoded); if let HeaderDecoderResult::Headers(result) = decoder_h.decode_header_block(&table, 1000, 0).unwrap() { assert_eq!(result.len(), 1); assert_eq!(result[0].name(), *decoded1); assert_eq!(result[0].value(), *decoded2); } else { panic!("No headers"); } } } #[test] fn decode_literal_with_name_ref_static() { for (_, encoded, decoded1, decoded2) in NAME_REF_STATIC { let table = HeaderTable::new(false); let mut decoder_h = HeaderDecoder::new(encoded); if let HeaderDecoderResult::Headers(result) = decoder_h.decode_header_block(&table, 1000, 0).unwrap() { assert_eq!(result.len(), 1); assert_eq!(result[0].name(), *decoded1); assert_eq!(result[0].value(), *decoded2); } else { panic!("No headers"); } } } #[test] fn decode_literal_with_name_ref_dynamic() { for (_, encoded, decoded1, decoded2) in NAME_REF_DYNAMIC { let mut table = HeaderTable::new(false); fill_table(&mut table); let mut decoder_h = HeaderDecoder::new(encoded); if let HeaderDecoderResult::Headers(result) = decoder_h.decode_header_block(&table, 1000, 0).unwrap() { assert_eq!(result.len(), 1); assert_eq!(result[0].name(), *decoded1); assert_eq!(result[0].value(), *decoded2); } else { panic!("No headers"); } } } #[test] fn decode_literal_with_name_ref_dynamic_post() { for (_, encoded, decoded1, decoded2) in NAME_REF_DYNAMIC_POST { let mut table = HeaderTable::new(false); fill_table(&mut table); let mut decoder_h = HeaderDecoder::new(encoded); if let HeaderDecoderResult::Headers(result) = decoder_h.decode_header_block(&table, 1000, 0).unwrap() { assert_eq!(result.len(), 1); assert_eq!(result[0].name(), *decoded1); assert_eq!(result[0].value(), *decoded2); } else { panic!("No headers"); } } } #[test] fn decode_literal_with_name_ref_dynamic_huffman() { for (_, encoded, decoded1, decoded2) in NAME_REF_DYNAMIC_HUFFMAN { let mut table = HeaderTable::new(false); fill_table(&mut table); let mut decoder_h = HeaderDecoder::new(encoded); if let HeaderDecoderResult::Headers(result) = decoder_h.decode_header_block(&table, 1000, 0).unwrap() { assert_eq!(result.len(), 1); assert_eq!(result[0].name(), *decoded1); assert_eq!(result[0].value(), *decoded2); } else { panic!("No headers"); } } } #[test] fn decode_literal_literal() { let mut table = HeaderTable::new(false); fill_table(&mut table); let mut decoder_h = HeaderDecoder::new(LITERAL_LITERAL); if let HeaderDecoderResult::Headers(result) = decoder_h.decode_header_block(&table, 1000, 0).unwrap() { assert_eq!(result.len(), 1); assert_eq!(result[0].name(), LITERAL_VALUE); assert_eq!(result[0].value(), LITERAL_VALUE); } else { panic!("No headers"); } let mut decoder_h = HeaderDecoder::new(LITERAL_LITERAL_HUFFMAN); if let HeaderDecoderResult::Headers(result) = decoder_h.decode_header_block(&table, 1000, 0).unwrap() { assert_eq!(result.len(), 1); assert_eq!(result[0].name(), LITERAL_VALUE); assert_eq!(result[0].value(), LITERAL_VALUE); } else { panic!("No headers"); } } // Test that we are ignoring N-bit. #[test] fn decode_ignore_n_bit() { const TEST_N_BIT: &[(&[u8], &str, &str)] = &[ ( &[ 0x02, 0x41, 0x6f, 0x32, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79, ], "header0", "custom-key", ), ( &[ 0x02, 0x80, 0x08, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79, ], "header0", "custom-key", ), ( &[ 0x0, 0x42, 0x37, 0x03, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79, ], "custom-key", "custom-key", ), ( &[ 0x0, 0x42, 0x3f, 0x01, 0x25, 0xa8, 0x49, 0xe9, 0x5b, 0xa9, 0x7d, 0x7f, 0x88, 0x25, 0xa8, 0x49, 0xe9, 0x5b, 0xa9, 0x7d, 0x7f, ], "custom-key", "custom-key", ), ]; for (encoded, decoded1, decoded2) in TEST_N_BIT { let mut table = HeaderTable::new(false); fill_table(&mut table); let mut decoder_h = HeaderDecoder::new(encoded); if let HeaderDecoderResult::Headers(result) = decoder_h.decode_header_block(&table, 1000, 0).unwrap() { assert_eq!(result.len(), 1); assert_eq!(result[0].name(), *decoded1); assert_eq!(result[0].value(), *decoded2); } else { panic!("No headers"); } } } /// If the base calculation goes negative, that is an error. #[test] fn negative_base() { let mut table = HeaderTable::new(false); fill_table(&mut table); let mut decoder_h = HeaderDecoder::new(&[0x0, 0x87, 0x01, 0x02, 0x03]); assert_eq!( Error::DecompressionFailed, decoder_h.decode_header_block(&table, 1000, 0).unwrap_err() ); } /// If the base calculation overflows the largest value we support (`u64::MAX`), /// then that is an error. #[test] fn overflow_base() { let mut table = HeaderTable::new(false); fill_table(&mut table); // A small required insert count is necessary, but we can set the // base delta to u64::MAX. let mut decoder_h = HeaderDecoder::new(&[ 0xff, 0x01, 0x7f, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x02, 0x03, ]); assert_eq!( Error::DecompressionFailed, decoder_h.decode_header_block(&table, 1000, 0).unwrap_err() ); } }