Work on huffman decoding
This commit is contained in:
@@ -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!(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
5
src/hpack/huffman.rs
Normal 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
21254
src/hpack/huffman_table.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,8 @@
|
||||
mod encoder;
|
||||
mod decoder;
|
||||
mod entry;
|
||||
mod huffman;
|
||||
mod huffman_table;
|
||||
// mod table;
|
||||
|
||||
pub use self::encoder::Encoder;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user