More work on HPACK decoding

This commit is contained in:
Carl Lerche
2017-05-30 21:56:50 -07:00
parent 3c850c2a34
commit b9da06a576
5 changed files with 92 additions and 49 deletions

View File

@@ -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<Bytes, DecoderError> {
}
{
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<header::FromBytesError> for DecoderError {
}
}
impl From<status::FromStrError> 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};

View File

@@ -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)

View File

@@ -1,39 +0,0 @@
use hpack::Entry;
use tower::http::{HeaderName, StatusCode, Method, Str};
use std::collections::VecDeque;
/*
pub struct Table {
entries: VecDeque<HeaderPair>,
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)
}
}
*/

61
src/util/byte_str.rs Normal file
View File

@@ -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<ByteStr, FromUtf8Error> {
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<String> 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) }
}
}

1
src/util/mod.rs Normal file
View File

@@ -0,0 +1 @@
pub mod byte_str;