diff --git a/src/hpack/decoder.rs b/src/hpack/decoder.rs index 150d45a..46c5f29 100644 --- a/src/hpack/decoder.rs +++ b/src/hpack/decoder.rs @@ -1,7 +1,7 @@ use super::{huffman, Entry, Key}; use util::byte_str::FromUtf8Error; -use http::{method, header, StatusCode, Method}; +use http::{method, header, status, StatusCode, Method}; use bytes::{Buf, Bytes}; use std::io::Cursor; @@ -132,10 +132,10 @@ struct Table { impl Decoder { /// Creates a new `Decoder` with all settings set to default values. - pub fn new() -> Decoder { + pub fn new(size: usize) -> Decoder { Decoder { max_size_update: None, - table: Table::new(4_096), + table: Table::new(size), } } @@ -238,6 +238,7 @@ impl Decoder { if table_idx == 0 { // Read the name as a literal let name = try!(decode_string(buf)); + let value = try!(decode_string(buf)); Entry::new(name, value) @@ -249,6 +250,12 @@ impl Decoder { } } +impl Default for Decoder { + fn default() -> Decoder { + Decoder::new(4096) + } +} + // ===== impl Representation ===== impl Representation { @@ -264,7 +271,7 @@ impl Representation { } else if byte & LITERAL_WITH_INDEXING == LITERAL_WITH_INDEXING { Ok(Representation::LiteralWithIndexing) } else if byte & LITERAL_WITHOUT_INDEXING == 0 { - Ok(Representation::LiteralWithIndexing) + Ok(Representation::LiteralWithoutIndexing) } else if byte & LITERAL_NEVER_INDEXED == LITERAL_NEVER_INDEXED { Ok(Representation::LiteralNeverIndexed) } else if byte & SIZE_UPDATE == SIZE_UPDATE { @@ -344,10 +351,14 @@ fn decode_string(buf: &mut Cursor<&Bytes>) -> Result { } { - let raw = &buf.bytes()[..len]; + if peek_u8(buf) & HUFF_FLAG == HUFF_FLAG { + let ret = { + let raw = &buf.bytes()[..len]; + huffman::decode(raw).map(Into::into) + }; - if raw[0] & HUFF_FLAG == HUFF_FLAG { - return huffman::decode(raw).map(Into::into); + buf.advance(len); + return ret; } } @@ -484,6 +495,12 @@ impl From for DecoderError { } } +impl From for DecoderError { + fn from(src: status::FromStrError) -> DecoderError { + DecoderError::InvalidUtf8 + } +} + /// Get an entry from the static table pub fn get_static(idx: usize) -> Entry { use http::{status, method, header}; diff --git a/src/hpack/entry.rs b/src/hpack/entry.rs index 940b2da..92f511b 100644 --- a/src/hpack/entry.rs +++ b/src/hpack/entry.rs @@ -42,13 +42,16 @@ impl Entry { Ok(Entry::Method(method)) } b"scheme" => { - unimplemented!(); + let value = try!(ByteStr::from_utf8(value)); + Ok(Entry::Scheme(value)) } b"path" => { - unimplemented!(); + let value = try!(ByteStr::from_utf8(value)); + Ok(Entry::Path(value)) } b"status" => { - unimplemented!(); + let status = try!(StatusCode::from_slice(&value)); + Ok(Entry::Status(status)) } _ => { Err(DecoderError::InvalidPseudoheader) diff --git a/src/hpack/table.rs b/src/hpack/table.rs deleted file mode 100644 index d1ead56..0000000 --- a/src/hpack/table.rs +++ /dev/null @@ -1,39 +0,0 @@ -use hpack::Entry; - -use tower::http::{HeaderName, StatusCode, Method, Str}; -use std::collections::VecDeque; - - - -/* -pub struct Table { - entries: VecDeque, - max_size: usize, -} - -pub enum Entry { - Header { - name: HeaderName, - value: Str, - }, - Authority(Str), - Scheme(Str), - Path(Str), - Status(StatusCode), -} -impl Table { - pub fn new(max_size: usize) -> Table { - Table { - entries: VecDeque::new(), - max_size: max_size, - } - } -} - -impl Default for Table { - fn default() -> Table { - // Default maximum size from the HTTP/2.0 spec. - Table::new(4_096) - } -} -*/ diff --git a/src/util/byte_str.rs b/src/util/byte_str.rs new file mode 100644 index 0000000..fd6981e --- /dev/null +++ b/src/util/byte_str.rs @@ -0,0 +1,61 @@ +use bytes::Bytes; + +use std::{ops, str}; +use std::str::Utf8Error; + +#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct ByteStr { + bytes: Bytes, +} + +pub struct FromUtf8Error { + err: Utf8Error, + val: Bytes, +} + +impl ByteStr { + #[inline] + pub fn from_static(val: &'static str) -> ByteStr { + ByteStr { bytes: Bytes::from_static(val.as_bytes()) } + } + + #[inline] + pub unsafe fn from_utf8_unchecked(bytes: Bytes) -> ByteStr { + ByteStr { bytes: bytes } + } + + pub fn from_utf8(bytes: Bytes) -> Result { + if let Err(e) = str::from_utf8(&bytes[..]) { + return Err(FromUtf8Error { + err: e, + val: bytes, + }); + } + + Ok(ByteStr { bytes: bytes }) + } +} + +impl ops::Deref for ByteStr { + type Target = str; + + #[inline] + fn deref(&self) -> &str { + let b: &[u8] = self.bytes.as_ref(); + unsafe { str::from_utf8_unchecked(b) } + } +} + +impl From for ByteStr { + #[inline] + fn from(src: String) -> ByteStr { + ByteStr { bytes: Bytes::from(src) } + } +} + +impl<'a> From<&'a str> for ByteStr { + #[inline] + fn from(src: &'a str) -> ByteStr { + ByteStr { bytes: Bytes::from(src) } + } +} diff --git a/src/util/mod.rs b/src/util/mod.rs new file mode 100644 index 0000000..8b8e497 --- /dev/null +++ b/src/util/mod.rs @@ -0,0 +1 @@ +pub mod byte_str;