|  | use super::{header::BytesStr, huffman, Header}; | 
|  | use crate::frame; | 
|  |  | 
|  | use bytes::{Buf, Bytes, BytesMut}; | 
|  | use http::header; | 
|  | use http::method::{self, Method}; | 
|  | use http::status::{self, StatusCode}; | 
|  |  | 
|  | use std::cmp; | 
|  | use std::collections::VecDeque; | 
|  | use std::io::Cursor; | 
|  | use std::str::Utf8Error; | 
|  |  | 
|  | /// Decodes headers using HPACK | 
|  | #[derive(Debug)] | 
|  | pub struct Decoder { | 
|  | // Protocol indicated that the max table size will update | 
|  | max_size_update: Option<usize>, | 
|  | last_max_update: usize, | 
|  | table: Table, | 
|  | buffer: BytesMut, | 
|  | } | 
|  |  | 
|  | /// Represents all errors that can be encountered while performing the decoding | 
|  | /// of an HPACK header set. | 
|  | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | 
|  | pub enum DecoderError { | 
|  | InvalidRepresentation, | 
|  | InvalidIntegerPrefix, | 
|  | InvalidTableIndex, | 
|  | InvalidHuffmanCode, | 
|  | InvalidUtf8, | 
|  | InvalidStatusCode, | 
|  | InvalidPseudoheader, | 
|  | InvalidMaxDynamicSize, | 
|  | IntegerOverflow, | 
|  | NeedMore(NeedMore), | 
|  | } | 
|  |  | 
|  | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | 
|  | pub enum NeedMore { | 
|  | UnexpectedEndOfStream, | 
|  | IntegerUnderflow, | 
|  | StringUnderflow, | 
|  | } | 
|  |  | 
|  | enum Representation { | 
|  | /// Indexed header field representation | 
|  | /// | 
|  | /// An indexed header field representation identifies an entry in either the | 
|  | /// static table or the dynamic table (see Section 2.3). | 
|  | /// | 
|  | /// # Header encoding | 
|  | /// | 
|  | /// ```text | 
|  | ///   0   1   2   3   4   5   6   7 | 
|  | /// +---+---+---+---+---+---+---+---+ | 
|  | /// | 1 |        Index (7+)         | | 
|  | /// +---+---------------------------+ | 
|  | /// ``` | 
|  | Indexed, | 
|  |  | 
|  | /// Literal Header Field with Incremental Indexing | 
|  | /// | 
|  | /// A literal header field with incremental indexing representation results | 
|  | /// in appending a header field to the decoded header list and inserting it | 
|  | /// as a new entry into the dynamic table. | 
|  | /// | 
|  | /// # Header encoding | 
|  | /// | 
|  | /// ```text | 
|  | ///   0   1   2   3   4   5   6   7 | 
|  | /// +---+---+---+---+---+---+---+---+ | 
|  | /// | 0 | 1 |      Index (6+)       | | 
|  | /// +---+---+-----------------------+ | 
|  | /// | H |     Value Length (7+)     | | 
|  | /// +---+---------------------------+ | 
|  | /// | Value String (Length octets)  | | 
|  | /// +-------------------------------+ | 
|  | /// ``` | 
|  | LiteralWithIndexing, | 
|  |  | 
|  | /// Literal Header Field without Indexing | 
|  | /// | 
|  | /// A literal header field without indexing representation results in | 
|  | /// appending a header field to the decoded header list without altering the | 
|  | /// dynamic table. | 
|  | /// | 
|  | /// # Header encoding | 
|  | /// | 
|  | /// ```text | 
|  | ///   0   1   2   3   4   5   6   7 | 
|  | /// +---+---+---+---+---+---+---+---+ | 
|  | /// | 0 | 0 | 0 | 0 |  Index (4+)   | | 
|  | /// +---+---+-----------------------+ | 
|  | /// | H |     Value Length (7+)     | | 
|  | /// +---+---------------------------+ | 
|  | /// | Value String (Length octets)  | | 
|  | /// +-------------------------------+ | 
|  | /// ``` | 
|  | LiteralWithoutIndexing, | 
|  |  | 
|  | /// Literal Header Field Never Indexed | 
|  | /// | 
|  | /// A literal header field never-indexed representation results in appending | 
|  | /// a header field to the decoded header list without altering the dynamic | 
|  | /// table. Intermediaries MUST use the same representation for encoding this | 
|  | /// header field. | 
|  | /// | 
|  | /// ```text | 
|  | ///   0   1   2   3   4   5   6   7 | 
|  | /// +---+---+---+---+---+---+---+---+ | 
|  | /// | 0 | 0 | 0 | 1 |  Index (4+)   | | 
|  | /// +---+---+-----------------------+ | 
|  | /// | H |     Value Length (7+)     | | 
|  | /// +---+---------------------------+ | 
|  | /// | Value String (Length octets)  | | 
|  | /// +-------------------------------+ | 
|  | /// ``` | 
|  | LiteralNeverIndexed, | 
|  |  | 
|  | /// Dynamic Table Size Update | 
|  | /// | 
|  | /// A dynamic table size update signals a change to the size of the dynamic | 
|  | /// table. | 
|  | /// | 
|  | /// # Header encoding | 
|  | /// | 
|  | /// ```text | 
|  | ///   0   1   2   3   4   5   6   7 | 
|  | /// +---+---+---+---+---+---+---+---+ | 
|  | /// | 0 | 0 | 1 |   Max size (5+)   | | 
|  | /// +---+---------------------------+ | 
|  | /// ``` | 
|  | SizeUpdate, | 
|  | } | 
|  |  | 
|  | #[derive(Debug)] | 
|  | struct Table { | 
|  | entries: VecDeque<Header>, | 
|  | size: usize, | 
|  | max_size: usize, | 
|  | } | 
|  |  | 
|  | struct StringMarker { | 
|  | offset: usize, | 
|  | len: usize, | 
|  | string: Option<Bytes>, | 
|  | } | 
|  |  | 
|  | // ===== impl Decoder ===== | 
|  |  | 
|  | impl Decoder { | 
|  | /// Creates a new `Decoder` with all settings set to default values. | 
|  | pub fn new(size: usize) -> Decoder { | 
|  | Decoder { | 
|  | max_size_update: None, | 
|  | last_max_update: size, | 
|  | table: Table::new(size), | 
|  | buffer: BytesMut::with_capacity(4096), | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Queues a potential size update | 
|  | #[allow(dead_code)] | 
|  | pub fn queue_size_update(&mut self, size: usize) { | 
|  | let size = match self.max_size_update { | 
|  | Some(v) => cmp::max(v, size), | 
|  | None => size, | 
|  | }; | 
|  |  | 
|  | self.max_size_update = Some(size); | 
|  | } | 
|  |  | 
|  | /// Decodes the headers found in the given buffer. | 
|  | pub fn decode<F>( | 
|  | &mut self, | 
|  | src: &mut Cursor<&mut BytesMut>, | 
|  | mut f: F, | 
|  | ) -> Result<(), DecoderError> | 
|  | where | 
|  | F: FnMut(Header), | 
|  | { | 
|  | use self::Representation::*; | 
|  |  | 
|  | let mut can_resize = true; | 
|  |  | 
|  | if let Some(size) = self.max_size_update.take() { | 
|  | self.last_max_update = size; | 
|  | } | 
|  |  | 
|  | let span = tracing::trace_span!("hpack::decode"); | 
|  | let _e = span.enter(); | 
|  |  | 
|  | tracing::trace!("decode"); | 
|  |  | 
|  | while let Some(ty) = peek_u8(src) { | 
|  | // At this point we are always at the beginning of the next block | 
|  | // within the HPACK data. The type of the block can always be | 
|  | // determined from the first byte. | 
|  | match Representation::load(ty)? { | 
|  | Indexed => { | 
|  | tracing::trace!(rem = src.remaining(), kind = %"Indexed"); | 
|  | can_resize = false; | 
|  | let entry = self.decode_indexed(src)?; | 
|  | consume(src); | 
|  | f(entry); | 
|  | } | 
|  | LiteralWithIndexing => { | 
|  | tracing::trace!(rem = src.remaining(), kind = %"LiteralWithIndexing"); | 
|  | can_resize = false; | 
|  | let entry = self.decode_literal(src, true)?; | 
|  |  | 
|  | // Insert the header into the table | 
|  | self.table.insert(entry.clone()); | 
|  | consume(src); | 
|  |  | 
|  | f(entry); | 
|  | } | 
|  | LiteralWithoutIndexing => { | 
|  | tracing::trace!(rem = src.remaining(), kind = %"LiteralWithoutIndexing"); | 
|  | can_resize = false; | 
|  | let entry = self.decode_literal(src, false)?; | 
|  | consume(src); | 
|  | f(entry); | 
|  | } | 
|  | LiteralNeverIndexed => { | 
|  | tracing::trace!(rem = src.remaining(), kind = %"LiteralNeverIndexed"); | 
|  | can_resize = false; | 
|  | let entry = self.decode_literal(src, false)?; | 
|  | consume(src); | 
|  |  | 
|  | // TODO: Track that this should never be indexed | 
|  |  | 
|  | f(entry); | 
|  | } | 
|  | SizeUpdate => { | 
|  | tracing::trace!(rem = src.remaining(), kind = %"SizeUpdate"); | 
|  | if !can_resize { | 
|  | return Err(DecoderError::InvalidMaxDynamicSize); | 
|  | } | 
|  |  | 
|  | // Handle the dynamic table size update | 
|  | self.process_size_update(src)?; | 
|  | consume(src); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | Ok(()) | 
|  | } | 
|  |  | 
|  | fn process_size_update(&mut self, buf: &mut Cursor<&mut BytesMut>) -> Result<(), DecoderError> { | 
|  | let new_size = decode_int(buf, 5)?; | 
|  |  | 
|  | if new_size > self.last_max_update { | 
|  | return Err(DecoderError::InvalidMaxDynamicSize); | 
|  | } | 
|  |  | 
|  | tracing::debug!( | 
|  | from = self.table.size(), | 
|  | to = new_size, | 
|  | "Decoder changed max table size" | 
|  | ); | 
|  |  | 
|  | self.table.set_max_size(new_size); | 
|  |  | 
|  | Ok(()) | 
|  | } | 
|  |  | 
|  | fn decode_indexed(&self, buf: &mut Cursor<&mut BytesMut>) -> Result<Header, DecoderError> { | 
|  | let index = decode_int(buf, 7)?; | 
|  | self.table.get(index) | 
|  | } | 
|  |  | 
|  | fn decode_literal( | 
|  | &mut self, | 
|  | buf: &mut Cursor<&mut BytesMut>, | 
|  | index: bool, | 
|  | ) -> Result<Header, DecoderError> { | 
|  | let prefix = if index { 6 } else { 4 }; | 
|  |  | 
|  | // Extract the table index for the name, or 0 if not indexed | 
|  | let table_idx = decode_int(buf, prefix)?; | 
|  |  | 
|  | // First, read the header name | 
|  | if table_idx == 0 { | 
|  | let old_pos = buf.position(); | 
|  | let name_marker = self.try_decode_string(buf)?; | 
|  | let value_marker = self.try_decode_string(buf)?; | 
|  | buf.set_position(old_pos); | 
|  | // Read the name as a literal | 
|  | let name = name_marker.consume(buf); | 
|  | let value = value_marker.consume(buf); | 
|  | Header::new(name, value) | 
|  | } else { | 
|  | let e = self.table.get(table_idx)?; | 
|  | let value = self.decode_string(buf)?; | 
|  |  | 
|  | e.name().into_entry(value) | 
|  | } | 
|  | } | 
|  |  | 
|  | fn try_decode_string( | 
|  | &mut self, | 
|  | buf: &mut Cursor<&mut BytesMut>, | 
|  | ) -> Result<StringMarker, DecoderError> { | 
|  | let old_pos = buf.position(); | 
|  | const HUFF_FLAG: u8 = 0b1000_0000; | 
|  |  | 
|  | // The first bit in the first byte contains the huffman encoded flag. | 
|  | let huff = match peek_u8(buf) { | 
|  | Some(hdr) => (hdr & HUFF_FLAG) == HUFF_FLAG, | 
|  | None => return Err(DecoderError::NeedMore(NeedMore::UnexpectedEndOfStream)), | 
|  | }; | 
|  |  | 
|  | // Decode the string length using 7 bit prefix | 
|  | let len = decode_int(buf, 7)?; | 
|  |  | 
|  | if len > buf.remaining() { | 
|  | tracing::trace!(len, remaining = buf.remaining(), "decode_string underflow",); | 
|  | return Err(DecoderError::NeedMore(NeedMore::StringUnderflow)); | 
|  | } | 
|  |  | 
|  | let offset = (buf.position() - old_pos) as usize; | 
|  | if huff { | 
|  | let ret = { | 
|  | let raw = &buf.chunk()[..len]; | 
|  | huffman::decode(raw, &mut self.buffer).map(|buf| StringMarker { | 
|  | offset, | 
|  | len, | 
|  | string: Some(BytesMut::freeze(buf)), | 
|  | }) | 
|  | }; | 
|  |  | 
|  | buf.advance(len); | 
|  | ret | 
|  | } else { | 
|  | buf.advance(len); | 
|  | Ok(StringMarker { | 
|  | offset, | 
|  | len, | 
|  | string: None, | 
|  | }) | 
|  | } | 
|  | } | 
|  |  | 
|  | fn decode_string(&mut self, buf: &mut Cursor<&mut BytesMut>) -> Result<Bytes, DecoderError> { | 
|  | let old_pos = buf.position(); | 
|  | let marker = self.try_decode_string(buf)?; | 
|  | buf.set_position(old_pos); | 
|  | Ok(marker.consume(buf)) | 
|  | } | 
|  | } | 
|  |  | 
|  | impl Default for Decoder { | 
|  | fn default() -> Decoder { | 
|  | Decoder::new(4096) | 
|  | } | 
|  | } | 
|  |  | 
|  | // ===== impl Representation ===== | 
|  |  | 
|  | impl Representation { | 
|  | pub fn load(byte: u8) -> Result<Representation, DecoderError> { | 
|  | const INDEXED: u8 = 0b1000_0000; | 
|  | const LITERAL_WITH_INDEXING: u8 = 0b0100_0000; | 
|  | const LITERAL_WITHOUT_INDEXING: u8 = 0b1111_0000; | 
|  | const LITERAL_NEVER_INDEXED: u8 = 0b0001_0000; | 
|  | const SIZE_UPDATE_MASK: u8 = 0b1110_0000; | 
|  | const SIZE_UPDATE: u8 = 0b0010_0000; | 
|  |  | 
|  | // TODO: What did I even write here? | 
|  |  | 
|  | if byte & INDEXED == INDEXED { | 
|  | Ok(Representation::Indexed) | 
|  | } else if byte & LITERAL_WITH_INDEXING == LITERAL_WITH_INDEXING { | 
|  | Ok(Representation::LiteralWithIndexing) | 
|  | } else if byte & LITERAL_WITHOUT_INDEXING == 0 { | 
|  | Ok(Representation::LiteralWithoutIndexing) | 
|  | } else if byte & LITERAL_WITHOUT_INDEXING == LITERAL_NEVER_INDEXED { | 
|  | Ok(Representation::LiteralNeverIndexed) | 
|  | } else if byte & SIZE_UPDATE_MASK == SIZE_UPDATE { | 
|  | Ok(Representation::SizeUpdate) | 
|  | } else { | 
|  | Err(DecoderError::InvalidRepresentation) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | fn decode_int<B: Buf>(buf: &mut B, prefix_size: u8) -> Result<usize, DecoderError> { | 
|  | // The octet limit is chosen such that the maximum allowed *value* can | 
|  | // never overflow an unsigned 32-bit integer. The maximum value of any | 
|  | // integer that can be encoded with 5 octets is ~2^28 | 
|  | const MAX_BYTES: usize = 5; | 
|  | const VARINT_MASK: u8 = 0b0111_1111; | 
|  | const VARINT_FLAG: u8 = 0b1000_0000; | 
|  |  | 
|  | if prefix_size < 1 || prefix_size > 8 { | 
|  | return Err(DecoderError::InvalidIntegerPrefix); | 
|  | } | 
|  |  | 
|  | if !buf.has_remaining() { | 
|  | return Err(DecoderError::NeedMore(NeedMore::IntegerUnderflow)); | 
|  | } | 
|  |  | 
|  | let mask = if prefix_size == 8 { | 
|  | 0xFF | 
|  | } else { | 
|  | (1u8 << prefix_size).wrapping_sub(1) | 
|  | }; | 
|  |  | 
|  | let mut ret = (buf.get_u8() & mask) as usize; | 
|  |  | 
|  | if ret < mask as usize { | 
|  | // Value fits in the prefix bits | 
|  | return Ok(ret); | 
|  | } | 
|  |  | 
|  | // The int did not fit in the prefix bits, so continue reading. | 
|  | // | 
|  | // The total number of bytes used to represent the int. The first byte was | 
|  | // the prefix, so start at 1. | 
|  | let mut bytes = 1; | 
|  |  | 
|  | // The rest of the int is stored as a varint -- 7 bits for the value and 1 | 
|  | // bit to indicate if it is the last byte. | 
|  | let mut shift = 0; | 
|  |  | 
|  | while buf.has_remaining() { | 
|  | let b = buf.get_u8(); | 
|  |  | 
|  | bytes += 1; | 
|  | ret += ((b & VARINT_MASK) as usize) << shift; | 
|  | shift += 7; | 
|  |  | 
|  | if b & VARINT_FLAG == 0 { | 
|  | return Ok(ret); | 
|  | } | 
|  |  | 
|  | if bytes == MAX_BYTES { | 
|  | // The spec requires that this situation is an error | 
|  | return Err(DecoderError::IntegerOverflow); | 
|  | } | 
|  | } | 
|  |  | 
|  | Err(DecoderError::NeedMore(NeedMore::IntegerUnderflow)) | 
|  | } | 
|  |  | 
|  | fn peek_u8<B: Buf>(buf: &B) -> Option<u8> { | 
|  | if buf.has_remaining() { | 
|  | Some(buf.chunk()[0]) | 
|  | } else { | 
|  | None | 
|  | } | 
|  | } | 
|  |  | 
|  | fn take(buf: &mut Cursor<&mut BytesMut>, n: usize) -> Bytes { | 
|  | let pos = buf.position() as usize; | 
|  | let mut head = buf.get_mut().split_to(pos + n); | 
|  | buf.set_position(0); | 
|  | head.advance(pos); | 
|  | head.freeze() | 
|  | } | 
|  |  | 
|  | impl StringMarker { | 
|  | fn consume(self, buf: &mut Cursor<&mut BytesMut>) -> Bytes { | 
|  | buf.advance(self.offset); | 
|  | match self.string { | 
|  | Some(string) => { | 
|  | buf.advance(self.len); | 
|  | string | 
|  | } | 
|  | None => take(buf, self.len), | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | fn consume(buf: &mut Cursor<&mut BytesMut>) { | 
|  | // remove bytes from the internal BytesMut when they have been successfully | 
|  | // decoded. This is a more permanent cursor position, which will be | 
|  | // used to resume if decoding was only partial. | 
|  | take(buf, 0); | 
|  | } | 
|  |  | 
|  | // ===== impl Table ===== | 
|  |  | 
|  | impl Table { | 
|  | fn new(max_size: usize) -> Table { | 
|  | Table { | 
|  | entries: VecDeque::new(), | 
|  | size: 0, | 
|  | max_size, | 
|  | } | 
|  | } | 
|  |  | 
|  | fn size(&self) -> usize { | 
|  | self.size | 
|  | } | 
|  |  | 
|  | /// Returns the entry located at the given index. | 
|  | /// | 
|  | /// The table is 1-indexed and constructed in such a way that the first | 
|  | /// entries belong to the static table, followed by entries in the dynamic | 
|  | /// table. They are merged into a single index address space, though. | 
|  | /// | 
|  | /// This is according to the [HPACK spec, section 2.3.3.] | 
|  | /// (http://http2.github.io/http2-spec/compression.html#index.address.space) | 
|  | pub fn get(&self, index: usize) -> Result<Header, DecoderError> { | 
|  | if index == 0 { | 
|  | return Err(DecoderError::InvalidTableIndex); | 
|  | } | 
|  |  | 
|  | if index <= 61 { | 
|  | return Ok(get_static(index)); | 
|  | } | 
|  |  | 
|  | // Convert the index for lookup in the entries structure. | 
|  | match self.entries.get(index - 62) { | 
|  | Some(e) => Ok(e.clone()), | 
|  | None => Err(DecoderError::InvalidTableIndex), | 
|  | } | 
|  | } | 
|  |  | 
|  | fn insert(&mut self, entry: Header) { | 
|  | let len = entry.len(); | 
|  |  | 
|  | self.reserve(len); | 
|  |  | 
|  | if self.size + len <= self.max_size { | 
|  | self.size += len; | 
|  |  | 
|  | // Track the entry | 
|  | self.entries.push_front(entry); | 
|  | } | 
|  | } | 
|  |  | 
|  | fn set_max_size(&mut self, size: usize) { | 
|  | self.max_size = size; | 
|  | // Make the table size fit within the new constraints. | 
|  | self.consolidate(); | 
|  | } | 
|  |  | 
|  | fn reserve(&mut self, size: usize) { | 
|  | while self.size + size > self.max_size { | 
|  | match self.entries.pop_back() { | 
|  | Some(last) => { | 
|  | self.size -= last.len(); | 
|  | } | 
|  | None => return, | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | fn consolidate(&mut self) { | 
|  | while self.size > self.max_size { | 
|  | { | 
|  | let last = match self.entries.back() { | 
|  | Some(x) => x, | 
|  | None => { | 
|  | // Can never happen as the size of the table must reach | 
|  | // 0 by the time we've exhausted all elements. | 
|  | panic!("Size of table != 0, but no headers left!"); | 
|  | } | 
|  | }; | 
|  |  | 
|  | self.size -= last.len(); | 
|  | } | 
|  |  | 
|  | self.entries.pop_back(); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // ===== impl DecoderError ===== | 
|  |  | 
|  | impl From<Utf8Error> for DecoderError { | 
|  | fn from(_: Utf8Error) -> DecoderError { | 
|  | // TODO: Better error? | 
|  | DecoderError::InvalidUtf8 | 
|  | } | 
|  | } | 
|  |  | 
|  | impl From<header::InvalidHeaderValue> for DecoderError { | 
|  | fn from(_: header::InvalidHeaderValue) -> DecoderError { | 
|  | // TODO: Better error? | 
|  | DecoderError::InvalidUtf8 | 
|  | } | 
|  | } | 
|  |  | 
|  | impl From<header::InvalidHeaderName> for DecoderError { | 
|  | fn from(_: header::InvalidHeaderName) -> DecoderError { | 
|  | // TODO: Better error | 
|  | DecoderError::InvalidUtf8 | 
|  | } | 
|  | } | 
|  |  | 
|  | impl From<method::InvalidMethod> for DecoderError { | 
|  | fn from(_: method::InvalidMethod) -> DecoderError { | 
|  | // TODO: Better error | 
|  | DecoderError::InvalidUtf8 | 
|  | } | 
|  | } | 
|  |  | 
|  | impl From<status::InvalidStatusCode> for DecoderError { | 
|  | fn from(_: status::InvalidStatusCode) -> DecoderError { | 
|  | // TODO: Better error | 
|  | DecoderError::InvalidUtf8 | 
|  | } | 
|  | } | 
|  |  | 
|  | impl From<DecoderError> for frame::Error { | 
|  | fn from(src: DecoderError) -> Self { | 
|  | frame::Error::Hpack(src) | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Get an entry from the static table | 
|  | pub fn get_static(idx: usize) -> Header { | 
|  | use http::header::HeaderValue; | 
|  |  | 
|  | match idx { | 
|  | 1 => Header::Authority(BytesStr::from_static("")), | 
|  | 2 => Header::Method(Method::GET), | 
|  | 3 => Header::Method(Method::POST), | 
|  | 4 => Header::Path(BytesStr::from_static("/")), | 
|  | 5 => Header::Path(BytesStr::from_static("/index.html")), | 
|  | 6 => Header::Scheme(BytesStr::from_static("http")), | 
|  | 7 => Header::Scheme(BytesStr::from_static("https")), | 
|  | 8 => Header::Status(StatusCode::OK), | 
|  | 9 => Header::Status(StatusCode::NO_CONTENT), | 
|  | 10 => Header::Status(StatusCode::PARTIAL_CONTENT), | 
|  | 11 => Header::Status(StatusCode::NOT_MODIFIED), | 
|  | 12 => Header::Status(StatusCode::BAD_REQUEST), | 
|  | 13 => Header::Status(StatusCode::NOT_FOUND), | 
|  | 14 => Header::Status(StatusCode::INTERNAL_SERVER_ERROR), | 
|  | 15 => Header::Field { | 
|  | name: header::ACCEPT_CHARSET, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 16 => Header::Field { | 
|  | name: header::ACCEPT_ENCODING, | 
|  | value: HeaderValue::from_static("gzip, deflate"), | 
|  | }, | 
|  | 17 => Header::Field { | 
|  | name: header::ACCEPT_LANGUAGE, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 18 => Header::Field { | 
|  | name: header::ACCEPT_RANGES, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 19 => Header::Field { | 
|  | name: header::ACCEPT, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 20 => Header::Field { | 
|  | name: header::ACCESS_CONTROL_ALLOW_ORIGIN, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 21 => Header::Field { | 
|  | name: header::AGE, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 22 => Header::Field { | 
|  | name: header::ALLOW, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 23 => Header::Field { | 
|  | name: header::AUTHORIZATION, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 24 => Header::Field { | 
|  | name: header::CACHE_CONTROL, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 25 => Header::Field { | 
|  | name: header::CONTENT_DISPOSITION, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 26 => Header::Field { | 
|  | name: header::CONTENT_ENCODING, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 27 => Header::Field { | 
|  | name: header::CONTENT_LANGUAGE, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 28 => Header::Field { | 
|  | name: header::CONTENT_LENGTH, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 29 => Header::Field { | 
|  | name: header::CONTENT_LOCATION, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 30 => Header::Field { | 
|  | name: header::CONTENT_RANGE, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 31 => Header::Field { | 
|  | name: header::CONTENT_TYPE, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 32 => Header::Field { | 
|  | name: header::COOKIE, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 33 => Header::Field { | 
|  | name: header::DATE, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 34 => Header::Field { | 
|  | name: header::ETAG, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 35 => Header::Field { | 
|  | name: header::EXPECT, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 36 => Header::Field { | 
|  | name: header::EXPIRES, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 37 => Header::Field { | 
|  | name: header::FROM, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 38 => Header::Field { | 
|  | name: header::HOST, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 39 => Header::Field { | 
|  | name: header::IF_MATCH, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 40 => Header::Field { | 
|  | name: header::IF_MODIFIED_SINCE, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 41 => Header::Field { | 
|  | name: header::IF_NONE_MATCH, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 42 => Header::Field { | 
|  | name: header::IF_RANGE, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 43 => Header::Field { | 
|  | name: header::IF_UNMODIFIED_SINCE, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 44 => Header::Field { | 
|  | name: header::LAST_MODIFIED, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 45 => Header::Field { | 
|  | name: header::LINK, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 46 => Header::Field { | 
|  | name: header::LOCATION, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 47 => Header::Field { | 
|  | name: header::MAX_FORWARDS, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 48 => Header::Field { | 
|  | name: header::PROXY_AUTHENTICATE, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 49 => Header::Field { | 
|  | name: header::PROXY_AUTHORIZATION, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 50 => Header::Field { | 
|  | name: header::RANGE, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 51 => Header::Field { | 
|  | name: header::REFERER, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 52 => Header::Field { | 
|  | name: header::REFRESH, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 53 => Header::Field { | 
|  | name: header::RETRY_AFTER, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 54 => Header::Field { | 
|  | name: header::SERVER, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 55 => Header::Field { | 
|  | name: header::SET_COOKIE, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 56 => Header::Field { | 
|  | name: header::STRICT_TRANSPORT_SECURITY, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 57 => Header::Field { | 
|  | name: header::TRANSFER_ENCODING, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 58 => Header::Field { | 
|  | name: header::USER_AGENT, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 59 => Header::Field { | 
|  | name: header::VARY, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 60 => Header::Field { | 
|  | name: header::VIA, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | 61 => Header::Field { | 
|  | name: header::WWW_AUTHENTICATE, | 
|  | value: HeaderValue::from_static(""), | 
|  | }, | 
|  | _ => unreachable!(), | 
|  | } | 
|  | } | 
|  |  | 
|  | #[cfg(test)] | 
|  | mod test { | 
|  | use super::*; | 
|  |  | 
|  | #[test] | 
|  | fn test_peek_u8() { | 
|  | let b = 0xff; | 
|  | let mut buf = Cursor::new(vec![b]); | 
|  | assert_eq!(peek_u8(&buf), Some(b)); | 
|  | assert_eq!(buf.get_u8(), b); | 
|  | assert_eq!(peek_u8(&buf), None); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn test_decode_string_empty() { | 
|  | let mut de = Decoder::new(0); | 
|  | let mut buf = BytesMut::new(); | 
|  | let err = de.decode_string(&mut Cursor::new(&mut buf)).unwrap_err(); | 
|  | assert_eq!(err, DecoderError::NeedMore(NeedMore::UnexpectedEndOfStream)); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn test_decode_empty() { | 
|  | let mut de = Decoder::new(0); | 
|  | let mut buf = BytesMut::new(); | 
|  | let _: () = de.decode(&mut Cursor::new(&mut buf), |_| {}).unwrap(); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn test_decode_indexed_larger_than_table() { | 
|  | let mut de = Decoder::new(0); | 
|  |  | 
|  | let mut buf = BytesMut::new(); | 
|  | buf.extend([0b01000000, 0x80 | 2]); | 
|  | buf.extend(huff_encode(b"foo")); | 
|  | buf.extend([0x80 | 3]); | 
|  | buf.extend(huff_encode(b"bar")); | 
|  |  | 
|  | let mut res = vec![]; | 
|  | de.decode(&mut Cursor::new(&mut buf), |h| { | 
|  | res.push(h); | 
|  | }) | 
|  | .unwrap(); | 
|  |  | 
|  | assert_eq!(res.len(), 1); | 
|  | assert_eq!(de.table.size(), 0); | 
|  |  | 
|  | match res[0] { | 
|  | Header::Field { | 
|  | ref name, | 
|  | ref value, | 
|  | } => { | 
|  | assert_eq!(name, "foo"); | 
|  | assert_eq!(value, "bar"); | 
|  | } | 
|  | _ => panic!(), | 
|  | } | 
|  | } | 
|  |  | 
|  | fn huff_encode(src: &[u8]) -> BytesMut { | 
|  | let mut buf = BytesMut::new(); | 
|  | huffman::encode(src, &mut buf); | 
|  | buf | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn test_decode_continuation_header_with_non_huff_encoded_name() { | 
|  | let mut de = Decoder::new(0); | 
|  | let value = huff_encode(b"bar"); | 
|  | let mut buf = BytesMut::new(); | 
|  | // header name is non_huff encoded | 
|  | buf.extend([0b01000000, 3]); | 
|  | buf.extend(b"foo"); | 
|  | // header value is partial | 
|  | buf.extend([0x80 | 3]); | 
|  | buf.extend(&value[0..1]); | 
|  |  | 
|  | let mut res = vec![]; | 
|  | let e = de | 
|  | .decode(&mut Cursor::new(&mut buf), |h| { | 
|  | res.push(h); | 
|  | }) | 
|  | .unwrap_err(); | 
|  | // decode error because the header value is partial | 
|  | assert_eq!(e, DecoderError::NeedMore(NeedMore::StringUnderflow)); | 
|  |  | 
|  | // extend buf with the remaining header value | 
|  | buf.extend(&value[1..]); | 
|  | de.decode(&mut Cursor::new(&mut buf), |h| { | 
|  | res.push(h); | 
|  | }) | 
|  | .unwrap(); | 
|  |  | 
|  | assert_eq!(res.len(), 1); | 
|  | assert_eq!(de.table.size(), 0); | 
|  |  | 
|  | match res[0] { | 
|  | Header::Field { | 
|  | ref name, | 
|  | ref value, | 
|  | } => { | 
|  | assert_eq!(name, "foo"); | 
|  | assert_eq!(value, "bar"); | 
|  | } | 
|  | _ => panic!(), | 
|  | } | 
|  | } | 
|  | } |