Work on huffman decoding

This commit is contained in:
Carl Lerche
2017-03-13 14:00:22 -07:00
parent 490ae8c05d
commit 73706494ef
7 changed files with 22052 additions and 223 deletions

View File

@@ -1,6 +1,6 @@
use super::Entry;
use tower::http::{HeaderName, Str};
use tower::http::{HeaderName, StatusCode, Method, Str};
use bytes::{Buf, Bytes};
use std::io::Cursor;
@@ -19,6 +19,7 @@ pub struct Decoder {
pub enum DecoderError {
InvalidRepresentation,
InvalidIntegerPrefix,
InvalidTableIndex,
IntegerUnderflow,
IntegerOverflow,
}
@@ -133,7 +134,7 @@ impl Decoder {
/// Decodes the headers found in the given buffer.
pub fn decode<F>(&mut self, src: &Bytes, mut f: F) -> Result<(), DecoderError>
where F: FnMut(HeaderName, Str)
where F: FnMut(Entry)
{
use self::Representation::*;
@@ -145,7 +146,7 @@ impl Decoder {
// determined from the first byte.
match try!(Representation::load(peek_u8(&mut buf))) {
Indexed => {
unimplemented!();
f(try!(self.decode_indexed(&mut buf)));
}
LiteralWithIndexing => {
unimplemented!();
@@ -167,12 +168,20 @@ impl Decoder {
fn decode_indexed(&self, buf: &mut Cursor<&Bytes>) -> Result<Entry, DecoderError> {
let index = try!(decode_int(buf, 7));
self.get_from_table(index)
self.table.get(index)
}
fn get_from_table(&self, index: usize) -> Result<Entry, DecoderError> {
fn decode_literal(&self, buf: &mut Cursor<&Bytes>, index: bool) -> Result<Entry, DecoderError> {
let prefix = if index {
6
} else {
4
};
// Extract the table index for the name, or 0 if not indexed
let table_idx = try!(decode_int(buf, prefix));
unimplemented!();
// self.header_table.get(index).o
}
}
@@ -280,21 +289,261 @@ impl Table {
self.max_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<Entry, 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: 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.reserve(len);
self.size += len;
// Track the entry
self.entries.push_front(entry);
}
fn reserve(&mut self, size: usize) {
debug_assert!(size <= self.max_size);
while self.size + size > self.max_size {
let last = self.entries.pop_back()
.expect("size of table != 0, but no headers left!");
self.size -= last.len();
}
}
}
/// Get an entry from the static table
pub fn get_static(idx: usize) -> Entry {
use tower::http::StandardHeader::*;
match idx {
1 => Entry::Authority(Str::new()),
2 => Entry::Method(Method::Get),
3 => Entry::Method(Method::Post),
4 => Entry::Path(Str::from_static("/")),
5 => Entry::Path(Str::from_static("/index.html")),
6 => Entry::Scheme(Str::from_static("http")),
7 => Entry::Scheme(Str::from_static("https")),
8 => Entry::Status(StatusCode::Ok),
9 => Entry::Status(StatusCode::NoContent),
10 => Entry::Status(StatusCode::PartialContent),
11 => Entry::Status(StatusCode::NotModified),
12 => Entry::Status(StatusCode::BadRequest),
13 => Entry::Status(StatusCode::NotFound),
14 => Entry::Status(StatusCode::InternalServerError),
15 => Entry::Header {
name: AcceptCharset.into(),
value: Str::new(),
},
16 => Entry::Header {
name: AcceptEncoding.into(),
value: Str::from_static("gzip, deflate"),
},
17 => Entry::Header {
name: AcceptLanguage.into(),
value: Str::new(),
},
18 => Entry::Header {
name: AcceptRanges.into(),
value: Str::new(),
},
19 => Entry::Header {
name: Accept.into(),
value: Str::new(),
},
20 => Entry::Header {
name: AccessControlAllowOrigin.into(),
value: Str::new(),
},
21 => Entry::Header {
name: Age.into(),
value: Str::new(),
},
22 => Entry::Header {
name: Allow.into(),
value: Str::new(),
},
23 => Entry::Header {
name: Authorization.into(),
value: Str::new(),
},
24 => Entry::Header {
name: CacheControl.into(),
value: Str::new(),
},
25 => Entry::Header {
name: ContentDisposition.into(),
value: Str::new(),
},
26 => Entry::Header {
name: ContentEncoding.into(),
value: Str::new(),
},
27 => Entry::Header {
name: ContentLanguage.into(),
value: Str::new(),
},
28 => Entry::Header {
name: ContentLength.into(),
value: Str::new(),
},
29 => Entry::Header {
name: ContentLocation.into(),
value: Str::new(),
},
30 => Entry::Header {
name: ContentRange.into(),
value: Str::new(),
},
31 => Entry::Header {
name: ContentType.into(),
value: Str::new(),
},
32 => Entry::Header {
name: Cookie.into(),
value: Str::new(),
},
33 => Entry::Header {
name: Date.into(),
value: Str::new(),
},
34 => Entry::Header {
name: Etag.into(),
value: Str::new(),
},
35 => Entry::Header {
name: Expect.into(),
value: Str::new(),
},
36 => Entry::Header {
name: Expires.into(),
value: Str::new(),
},
37 => Entry::Header {
name: From.into(),
value: Str::new(),
},
38 => Entry::Header {
name: Host.into(),
value: Str::new(),
},
39 => Entry::Header {
name: IfMatch.into(),
value: Str::new(),
},
40 => Entry::Header {
name: IfModifiedSince.into(),
value: Str::new(),
},
41 => Entry::Header {
name: IfNoneMatch.into(),
value: Str::new(),
},
42 => Entry::Header {
name: IfRange.into(),
value: Str::new(),
},
43 => Entry::Header {
name: IfUnmodifiedSince.into(),
value: Str::new(),
},
44 => Entry::Header {
name: LastModified.into(),
value: Str::new(),
},
45 => Entry::Header {
name: Link.into(),
value: Str::new(),
},
46 => Entry::Header {
name: Location.into(),
value: Str::new(),
},
47 => Entry::Header {
name: MaxForwards.into(),
value: Str::new(),
},
48 => Entry::Header {
name: ProxyAuthenticate.into(),
value: Str::new(),
},
49 => Entry::Header {
name: ProxyAuthorization.into(),
value: Str::new(),
},
50 => Entry::Header {
name: Range.into(),
value: Str::new(),
},
51 => Entry::Header {
name: Referer.into(),
value: Str::new(),
},
52 => Entry::Header {
name: Refresh.into(),
value: Str::new(),
},
53 => Entry::Header {
name: RetryAfter.into(),
value: Str::new(),
},
54 => Entry::Header {
name: Server.into(),
value: Str::new(),
},
55 => Entry::Header {
name: SetCookie.into(),
value: Str::new(),
},
56 => Entry::Header {
name: StrictTransportSecurity.into(),
value: Str::new(),
},
57 => Entry::Header {
name: TransferEncoding.into(),
value: Str::new(),
},
58 => Entry::Header {
name: UserAgent.into(),
value: Str::new(),
},
59 => Entry::Header {
name: Vary.into(),
value: Str::new(),
},
60 => Entry::Header {
name: Via.into(),
value: Str::new(),
},
61 => Entry::Header {
name: WwwAuthenticate.into(),
value: Str::new(),
},
_ => unreachable!(),
}
}

View File

@@ -1,6 +1,7 @@
use tower::http::{HeaderName, Method, StatusCode, Str};
/// HPack table entry
#[derive(Debug, Clone)]
pub enum Entry {
Header {
name: HeaderName,

5
src/hpack/huffman.rs Normal file
View File

@@ -0,0 +1,5 @@
pub struct HuffmanState {
pub next: usize,
pub byte: u8,
pub flags: u8,
}

21254
src/hpack/huffman_table.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,8 @@
mod encoder;
mod decoder;
mod entry;
mod huffman;
mod huffman_table;
// mod table;
pub use self::encoder::Encoder;

View File

@@ -3,216 +3,7 @@ use hpack::Entry;
use tower::http::{HeaderName, StatusCode, Method, Str};
use std::collections::VecDeque;
/// Get an entry from the static table
pub fn get_static(idx: usize) -> Entry {
use tower::http::StandardHeader::*;
match idx {
1 => Entry::Authority(Str::new()),
2 => Entry::Method(Method::Get),
3 => Entry::Method(Method::Post),
4 => Entry::Path(Str::from_static("/")),
5 => Entry::Path(Str::from_static("/index.html")),
6 => Entry::Scheme(Str::from_static("http")),
7 => Entry::Scheme(Str::from_static("https")),
8 => Entry::Status(StatusCode::Ok),
9 => Entry::Status(StatusCode::NoContent),
10 => Entry::Status(StatusCode::PartialContent),
11 => Entry::Status(StatusCode::NotModified),
12 => Entry::Status(StatusCode::BadRequest),
13 => Entry::Status(StatusCode::NotFound),
14 => Entry::Status(StatusCode::InternalServerError),
15 => Entry::Header {
name: AcceptCharset.into(),
value: Str::new(),
},
16 => Entry::Header {
name: AcceptEncoding.into(),
value: Str::from_static("gzip, deflate"),
},
17 => Entry::Header {
name: AcceptLanguage.into(),
value: Str::new(),
},
18 => Entry::Header {
name: AcceptRanges.into(),
value: Str::new(),
},
19 => Entry::Header {
name: Accept.into(),
value: Str::new(),
},
20 => Entry::Header {
name: AccessControlAllowOrigin.into(),
value: Str::new(),
},
21 => Entry::Header {
name: Age.into(),
value: Str::new(),
},
22 => Entry::Header {
name: Allow.into(),
value: Str::new(),
},
23 => Entry::Header {
name: Authorization.into(),
value: Str::new(),
},
24 => Entry::Header {
name: CacheControl.into(),
value: Str::new(),
},
25 => Entry::Header {
name: ContentDisposition.into(),
value: Str::new(),
},
26 => Entry::Header {
name: ContentEncoding.into(),
value: Str::new(),
},
27 => Entry::Header {
name: ContentLanguage.into(),
value: Str::new(),
},
28 => Entry::Header {
name: ContentLength.into(),
value: Str::new(),
},
29 => Entry::Header {
name: ContentLocation.into(),
value: Str::new(),
},
30 => Entry::Header {
name: ContentRange.into(),
value: Str::new(),
},
31 => Entry::Header {
name: ContentType.into(),
value: Str::new(),
},
32 => Entry::Header {
name: Cookie.into(),
value: Str::new(),
},
33 => Entry::Header {
name: Date.into(),
value: Str::new(),
},
34 => Entry::Header {
name: Etag.into(),
value: Str::new(),
},
35 => Entry::Header {
name: Expect.into(),
value: Str::new(),
},
36 => Entry::Header {
name: Expires.into(),
value: Str::new(),
},
37 => Entry::Header {
name: From.into(),
value: Str::new(),
},
38 => Entry::Header {
name: Host.into(),
value: Str::new(),
},
39 => Entry::Header {
name: IfMatch.into(),
value: Str::new(),
},
40 => Entry::Header {
name: IfModifiedSince.into(),
value: Str::new(),
},
41 => Entry::Header {
name: IfNoneMatch.into(),
value: Str::new(),
},
42 => Entry::Header {
name: IfRange.into(),
value: Str::new(),
},
43 => Entry::Header {
name: IfUnmodifiedSince.into(),
value: Str::new(),
},
44 => Entry::Header {
name: LastModified.into(),
value: Str::new(),
},
45 => Entry::Header {
name: Link.into(),
value: Str::new(),
},
46 => Entry::Header {
name: Location.into(),
value: Str::new(),
},
47 => Entry::Header {
name: MaxForwards.into(),
value: Str::new(),
},
48 => Entry::Header {
name: ProxyAuthenticate.into(),
value: Str::new(),
},
49 => Entry::Header {
name: ProxyAuthorization.into(),
value: Str::new(),
},
50 => Entry::Header {
name: Range.into(),
value: Str::new(),
},
51 => Entry::Header {
name: Referer.into(),
value: Str::new(),
},
52 => Entry::Header {
name: Refresh.into(),
value: Str::new(),
},
53 => Entry::Header {
name: RetryAfter.into(),
value: Str::new(),
},
54 => Entry::Header {
name: Server.into(),
value: Str::new(),
},
55 => Entry::Header {
name: SetCookie.into(),
value: Str::new(),
},
56 => Entry::Header {
name: StrictTransportSecurity.into(),
value: Str::new(),
},
57 => Entry::Header {
name: TransferEncoding.into(),
value: Str::new(),
},
58 => Entry::Header {
name: UserAgent.into(),
value: Str::new(),
},
59 => Entry::Header {
name: Vary.into(),
value: Str::new(),
},
60 => Entry::Header {
name: Via.into(),
value: Str::new(),
},
61 => Entry::Header {
name: WwwAuthenticate.into(),
value: Str::new(),
},
_ => unreachable!(),
}
}
/*
pub struct Table {