diff --git a/src/hpack/decoder.rs b/src/hpack/decoder.rs index 6ab6c62..cedb0ff 100644 --- a/src/hpack/decoder.rs +++ b/src/hpack/decoder.rs @@ -4,11 +4,13 @@ use tower::http::{HeaderName, Str}; use bytes::{Buf, Bytes}; use std::io::Cursor; +use std::collections::VecDeque; /// Decodes headers using HPACK pub struct Decoder { // Protocol indicated that the max table size will update max_size_update: Option, + table: Table, } /// Represents all errors that can be encountered while performing the decoding @@ -112,6 +114,12 @@ enum Representation { SizeUpdate, } +struct Table { + entries: VecDeque, + size: usize, + max_size: usize, +} + // ===== impl Decoder ===== impl Decoder { @@ -119,6 +127,7 @@ impl Decoder { pub fn new() -> Decoder { Decoder { max_size_update: None, + table: Table::new(4_096), } } @@ -193,8 +202,6 @@ impl Representation { } } -// ===== Utils ===== - fn decode_int(buf: &mut B, prefix_size: u8) -> Result { // The octet limit is chosen such that the maximum allowed *value* can // never overflow an unsigned 32-bit integer. The maximum value of any @@ -257,3 +264,37 @@ fn decode_int(buf: &mut B, prefix_size: u8) -> Result(buf: &mut B) -> u8 { buf.bytes()[0] } + +// ===== impl Table ===== + +impl Table { + fn new(max_size: usize) -> Table { + Table { + entries: VecDeque::new(), + size: 0, + max_size: max_size, + } + } + + fn max_size(&self) -> usize { + self.max_size + } + + fn insert(&mut self, entry: Entry) { + let len = entry.len(); + + debug_assert!(len <= self.max_size); + + while self.size + len > self.max_size { + let last = self.entries.pop_back() + .expect("size of table != 0, but no headers left!"); + + self.size -= last.len(); + } + + self.size += len; + + // Track the entry + self.entries.push_front(entry); + } +} diff --git a/src/hpack/entry.rs b/src/hpack/entry.rs new file mode 100644 index 0000000..577d84f --- /dev/null +++ b/src/hpack/entry.rs @@ -0,0 +1,40 @@ +use tower::http::{HeaderName, Method, StatusCode, Str}; + +/// HPack table entry +pub enum Entry { + Header { + name: HeaderName, + value: Str, + }, + Authority(Str), + Method(Method), + Scheme(Str), + Path(Str), + Status(StatusCode), +} + +impl Entry { + pub fn len(&self) -> usize { + match *self { + Entry::Header { ref name, ref value } => { + let n: &str = name.as_ref(); + 32 + n.len() + value.len() + } + Entry::Authority(ref v) => { + 32 + 10 + v.len() + } + Entry::Method(ref v) => { + 32 + 7 + v.as_ref().len() + } + Entry::Scheme(ref v) => { + 32 + 7 + v.len() + } + Entry::Path(ref v) => { + 32 + 5 + v.len() + } + Entry::Status(ref v) => { + 32 + 7 + 3 + } + } + } +} diff --git a/src/hpack/mod.rs b/src/hpack/mod.rs index 51d2398..f41f946 100644 --- a/src/hpack/mod.rs +++ b/src/hpack/mod.rs @@ -1,7 +1,9 @@ mod encoder; mod decoder; -mod table; +mod entry; +// mod table; pub use self::encoder::Encoder; +pub use self::entry::Entry; pub use self::decoder::Decoder; -pub use self::table::Entry; +// pub use self::table::Entry; diff --git a/src/hpack/table.rs b/src/hpack/table.rs index 4737b5f..2d9eb5f 100644 --- a/src/hpack/table.rs +++ b/src/hpack/table.rs @@ -1,19 +1,8 @@ +use hpack::Entry; + use tower::http::{HeaderName, StatusCode, Method, Str}; use std::collections::VecDeque; -/// HPack table entry -pub enum Entry { - Header { - name: HeaderName, - value: Str, - }, - Authority(Str), - Method(Method), - Scheme(Str), - Path(Str), - Status(StatusCode), -} - /// Get an entry from the static table pub fn get_static(idx: usize) -> Entry { use tower::http::StandardHeader::*;