More encoding work
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
use super::{huffman, Entry, Key};
|
use super::{huffman, header as h2_header, Header};
|
||||||
use util::byte_str::FromUtf8Error;
|
use util::byte_str::FromUtf8Error;
|
||||||
|
|
||||||
use http::{method, header, status, StatusCode, Method};
|
use http::{method, header, status, StatusCode, Method};
|
||||||
@@ -124,7 +124,7 @@ enum Representation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct Table {
|
struct Table {
|
||||||
entries: VecDeque<Entry>,
|
entries: VecDeque<Header>,
|
||||||
size: usize,
|
size: usize,
|
||||||
max_size: usize,
|
max_size: usize,
|
||||||
}
|
}
|
||||||
@@ -152,7 +152,7 @@ impl Decoder {
|
|||||||
|
|
||||||
/// Decodes the headers found in the given buffer.
|
/// Decodes the headers found in the given buffer.
|
||||||
pub fn decode<F>(&mut self, src: &Bytes, mut f: F) -> Result<(), DecoderError>
|
pub fn decode<F>(&mut self, src: &Bytes, mut f: F) -> Result<(), DecoderError>
|
||||||
where F: FnMut(Entry)
|
where F: FnMut(Header)
|
||||||
{
|
{
|
||||||
use self::Representation::*;
|
use self::Representation::*;
|
||||||
|
|
||||||
@@ -227,14 +227,14 @@ impl Decoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn decode_indexed(&self, buf: &mut Cursor<&Bytes>)
|
fn decode_indexed(&self, buf: &mut Cursor<&Bytes>)
|
||||||
-> Result<Entry, DecoderError>
|
-> Result<Header, DecoderError>
|
||||||
{
|
{
|
||||||
let index = try!(decode_int(buf, 7));
|
let index = try!(decode_int(buf, 7));
|
||||||
self.table.get(index)
|
self.table.get(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_literal(&self, buf: &mut Cursor<&Bytes>, index: bool)
|
fn decode_literal(&self, buf: &mut Cursor<&Bytes>, index: bool)
|
||||||
-> Result<Entry, DecoderError>
|
-> Result<Header, DecoderError>
|
||||||
{
|
{
|
||||||
let prefix = if index {
|
let prefix = if index {
|
||||||
6
|
6
|
||||||
@@ -251,12 +251,12 @@ impl Decoder {
|
|||||||
let name = try!(decode_string(buf));
|
let name = try!(decode_string(buf));
|
||||||
let value = try!(decode_string(buf));
|
let value = try!(decode_string(buf));
|
||||||
|
|
||||||
Entry::new(name, value)
|
Header::new(name, value)
|
||||||
} else {
|
} else {
|
||||||
let e = try!(self.table.get(table_idx));
|
let e = try!(self.table.get(table_idx));
|
||||||
let value = try!(decode_string(buf));
|
let value = try!(decode_string(buf));
|
||||||
|
|
||||||
e.key().into_entry(value)
|
e.name().into_entry(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -419,7 +419,7 @@ impl Table {
|
|||||||
///
|
///
|
||||||
/// This is according to the [HPACK spec, section 2.3.3.]
|
/// This is according to the [HPACK spec, section 2.3.3.]
|
||||||
/// (http://http2.github.io/http2-spec/compression.html#index.address.space)
|
/// (http://http2.github.io/http2-spec/compression.html#index.address.space)
|
||||||
pub fn get(&self, index: usize) -> Result<Entry, DecoderError> {
|
pub fn get(&self, index: usize) -> Result<Header, DecoderError> {
|
||||||
if index == 0 {
|
if index == 0 {
|
||||||
return Err(DecoderError::InvalidTableIndex);
|
return Err(DecoderError::InvalidTableIndex);
|
||||||
}
|
}
|
||||||
@@ -435,7 +435,7 @@ impl Table {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert(&mut self, entry: Entry) {
|
fn insert(&mut self, entry: Header) {
|
||||||
let len = entry.len();
|
let len = entry.len();
|
||||||
|
|
||||||
self.reserve(len);
|
self.reserve(len);
|
||||||
@@ -518,211 +518,211 @@ impl From<status::FromStrError> for DecoderError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get an entry from the static table
|
/// Get an entry from the static table
|
||||||
pub fn get_static(idx: usize) -> Entry {
|
pub fn get_static(idx: usize) -> Header {
|
||||||
use http::{status, method, header};
|
use http::{status, method, header};
|
||||||
use http::header::HeaderValue;
|
use http::header::HeaderValue;
|
||||||
use util::byte_str::ByteStr;
|
use util::byte_str::ByteStr;
|
||||||
|
|
||||||
match idx {
|
match idx {
|
||||||
1 => Entry::Authority(ByteStr::from_static("")),
|
1 => Header::Authority(ByteStr::from_static("")),
|
||||||
2 => Entry::Method(method::GET),
|
2 => Header::Method(method::GET),
|
||||||
3 => Entry::Method(method::POST),
|
3 => Header::Method(method::POST),
|
||||||
4 => Entry::Path(ByteStr::from_static("/")),
|
4 => Header::Path(ByteStr::from_static("/")),
|
||||||
5 => Entry::Path(ByteStr::from_static("/index.html")),
|
5 => Header::Path(ByteStr::from_static("/index.html")),
|
||||||
6 => Entry::Scheme(ByteStr::from_static("http")),
|
6 => Header::Scheme(ByteStr::from_static("http")),
|
||||||
7 => Entry::Scheme(ByteStr::from_static("https")),
|
7 => Header::Scheme(ByteStr::from_static("https")),
|
||||||
8 => Entry::Status(status::OK),
|
8 => Header::Status(status::OK),
|
||||||
9 => Entry::Status(status::NO_CONTENT),
|
9 => Header::Status(status::NO_CONTENT),
|
||||||
10 => Entry::Status(status::PARTIAL_CONTENT),
|
10 => Header::Status(status::PARTIAL_CONTENT),
|
||||||
11 => Entry::Status(status::NOT_MODIFIED),
|
11 => Header::Status(status::NOT_MODIFIED),
|
||||||
12 => Entry::Status(status::BAD_REQUEST),
|
12 => Header::Status(status::BAD_REQUEST),
|
||||||
13 => Entry::Status(status::NOT_FOUND),
|
13 => Header::Status(status::NOT_FOUND),
|
||||||
14 => Entry::Status(status::INTERNAL_SERVER_ERROR),
|
14 => Header::Status(status::INTERNAL_SERVER_ERROR),
|
||||||
15 => Entry::Header {
|
15 => Header::Field {
|
||||||
name: header::ACCEPT_CHARSET,
|
name: header::ACCEPT_CHARSET,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
16 => Entry::Header {
|
16 => Header::Field {
|
||||||
name: header::ACCEPT_ENCODING,
|
name: header::ACCEPT_ENCODING,
|
||||||
value: HeaderValue::from_static("gzip, deflate"),
|
value: HeaderValue::from_static("gzip, deflate"),
|
||||||
},
|
},
|
||||||
17 => Entry::Header {
|
17 => Header::Field {
|
||||||
name: header::ACCEPT_LANGUAGE,
|
name: header::ACCEPT_LANGUAGE,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
18 => Entry::Header {
|
18 => Header::Field {
|
||||||
name: header::ACCEPT_RANGES,
|
name: header::ACCEPT_RANGES,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
19 => Entry::Header {
|
19 => Header::Field {
|
||||||
name: header::ACCEPT,
|
name: header::ACCEPT,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
20 => Entry::Header {
|
20 => Header::Field {
|
||||||
name: header::ACCESS_CONTROL_ALLOW_ORIGIN,
|
name: header::ACCESS_CONTROL_ALLOW_ORIGIN,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
21 => Entry::Header {
|
21 => Header::Field {
|
||||||
name: header::AGE,
|
name: header::AGE,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
22 => Entry::Header {
|
22 => Header::Field {
|
||||||
name: header::ALLOW,
|
name: header::ALLOW,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
23 => Entry::Header {
|
23 => Header::Field {
|
||||||
name: header::AUTHORIZATION,
|
name: header::AUTHORIZATION,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
24 => Entry::Header {
|
24 => Header::Field {
|
||||||
name: header::CACHE_CONTROL,
|
name: header::CACHE_CONTROL,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
25 => Entry::Header {
|
25 => Header::Field {
|
||||||
name: header::CONTENT_DISPOSITION,
|
name: header::CONTENT_DISPOSITION,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
26 => Entry::Header {
|
26 => Header::Field {
|
||||||
name: header::CONTENT_ENCODING,
|
name: header::CONTENT_ENCODING,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
27 => Entry::Header {
|
27 => Header::Field {
|
||||||
name: header::CONTENT_LANGUAGE,
|
name: header::CONTENT_LANGUAGE,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
28 => Entry::Header {
|
28 => Header::Field {
|
||||||
name: header::CONTENT_LENGTH,
|
name: header::CONTENT_LENGTH,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
29 => Entry::Header {
|
29 => Header::Field {
|
||||||
name: header::CONTENT_LOCATION,
|
name: header::CONTENT_LOCATION,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
30 => Entry::Header {
|
30 => Header::Field {
|
||||||
name: header::CONTENT_RANGE,
|
name: header::CONTENT_RANGE,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
31 => Entry::Header {
|
31 => Header::Field {
|
||||||
name: header::CONTENT_TYPE,
|
name: header::CONTENT_TYPE,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
32 => Entry::Header {
|
32 => Header::Field {
|
||||||
name: header::COOKIE,
|
name: header::COOKIE,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
33 => Entry::Header {
|
33 => Header::Field {
|
||||||
name: header::DATE,
|
name: header::DATE,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
34 => Entry::Header {
|
34 => Header::Field {
|
||||||
name: header::ETAG,
|
name: header::ETAG,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
35 => Entry::Header {
|
35 => Header::Field {
|
||||||
name: header::EXPECT,
|
name: header::EXPECT,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
36 => Entry::Header {
|
36 => Header::Field {
|
||||||
name: header::EXPIRES,
|
name: header::EXPIRES,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
37 => Entry::Header {
|
37 => Header::Field {
|
||||||
name: header::FROM,
|
name: header::FROM,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
38 => Entry::Header {
|
38 => Header::Field {
|
||||||
name: header::HOST,
|
name: header::HOST,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
39 => Entry::Header {
|
39 => Header::Field {
|
||||||
name: header::IF_MATCH,
|
name: header::IF_MATCH,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
40 => Entry::Header {
|
40 => Header::Field {
|
||||||
name: header::IF_MODIFIED_SINCE,
|
name: header::IF_MODIFIED_SINCE,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
41 => Entry::Header {
|
41 => Header::Field {
|
||||||
name: header::IF_NONE_MATCH,
|
name: header::IF_NONE_MATCH,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
42 => Entry::Header {
|
42 => Header::Field {
|
||||||
name: header::IF_RANGE,
|
name: header::IF_RANGE,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
43 => Entry::Header {
|
43 => Header::Field {
|
||||||
name: header::IF_UNMODIFIED_SINCE,
|
name: header::IF_UNMODIFIED_SINCE,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
44 => Entry::Header {
|
44 => Header::Field {
|
||||||
name: header::LAST_MODIFIED,
|
name: header::LAST_MODIFIED,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
45 => Entry::Header {
|
45 => Header::Field {
|
||||||
name: header::LINK,
|
name: header::LINK,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
46 => Entry::Header {
|
46 => Header::Field {
|
||||||
name: header::LOCATION,
|
name: header::LOCATION,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
47 => Entry::Header {
|
47 => Header::Field {
|
||||||
name: header::MAX_FORWARDS,
|
name: header::MAX_FORWARDS,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
48 => Entry::Header {
|
48 => Header::Field {
|
||||||
name: header::PROXY_AUTHENTICATE,
|
name: header::PROXY_AUTHENTICATE,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
49 => Entry::Header {
|
49 => Header::Field {
|
||||||
name: header::PROXY_AUTHORIZATION,
|
name: header::PROXY_AUTHORIZATION,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
50 => Entry::Header {
|
50 => Header::Field {
|
||||||
name: header::RANGE,
|
name: header::RANGE,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
51 => Entry::Header {
|
51 => Header::Field {
|
||||||
name: header::REFERER,
|
name: header::REFERER,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
52 => Entry::Header {
|
52 => Header::Field {
|
||||||
name: header::REFRESH,
|
name: header::REFRESH,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
53 => Entry::Header {
|
53 => Header::Field {
|
||||||
name: header::RETRY_AFTER,
|
name: header::RETRY_AFTER,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
54 => Entry::Header {
|
54 => Header::Field {
|
||||||
name: header::SERVER,
|
name: header::SERVER,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
55 => Entry::Header {
|
55 => Header::Field {
|
||||||
name: header::SET_COOKIE,
|
name: header::SET_COOKIE,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
56 => Entry::Header {
|
56 => Header::Field {
|
||||||
name: header::STRICT_TRANSPORT_SECURITY,
|
name: header::STRICT_TRANSPORT_SECURITY,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
57 => Entry::Header {
|
57 => Header::Field {
|
||||||
name: header::TRANSFER_ENCODING,
|
name: header::TRANSFER_ENCODING,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
58 => Entry::Header {
|
58 => Header::Field {
|
||||||
name: header::USER_AGENT,
|
name: header::USER_AGENT,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
59 => Entry::Header {
|
59 => Header::Field {
|
||||||
name: header::VARY,
|
name: header::VARY,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
60 => Entry::Header {
|
60 => Header::Field {
|
||||||
name: header::VIA,
|
name: header::VIA,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
61 => Entry::Header {
|
61 => Header::Field {
|
||||||
name: header::WWW_AUTHENTICATE,
|
name: header::WWW_AUTHENTICATE,
|
||||||
value: HeaderValue::from_static(""),
|
value: HeaderValue::from_static(""),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use super::entry;
|
use super::{huffman, Header};
|
||||||
use super::table::Table;
|
use super::table::{Table, Index};
|
||||||
|
|
||||||
use http::header::{HeaderName, HeaderValue};
|
use http::header::{HeaderName, HeaderValue};
|
||||||
use bytes::BytesMut;
|
use bytes::{BytesMut, BufMut};
|
||||||
|
|
||||||
pub struct Encoder {
|
pub struct Encoder {
|
||||||
table: Table,
|
table: Table,
|
||||||
@@ -24,7 +24,7 @@ impl Encoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn encode<'a, I>(&mut self, headers: I, dst: &mut BytesMut) -> Result<(), EncoderError>
|
pub fn encode<'a, I>(&mut self, headers: I, dst: &mut BytesMut) -> Result<(), EncoderError>
|
||||||
where I: IntoIterator<Item=Entry>,
|
where I: IntoIterator<Item=Header>,
|
||||||
{
|
{
|
||||||
if let Some(max_size_update) = self.max_size_update.take() {
|
if let Some(max_size_update) = self.max_size_update.take() {
|
||||||
// Write size update frame
|
// Write size update frame
|
||||||
@@ -38,31 +38,118 @@ impl Encoder {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode_header(&mut self, entry: Entry, dst: &mut BytesMut)
|
fn encode_header(&mut self, header: Header, dst: &mut BytesMut)
|
||||||
-> Result<(), EncoderError>
|
-> Result<(), EncoderError>
|
||||||
{
|
{
|
||||||
if is_sensitive(&e) {
|
if header.is_sensitive() {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
match self.table.index(header) {
|
||||||
match self.table.entry(name, val) {
|
Index::Indexed(idx, _header) => {
|
||||||
Entry::Indexed(idx) => {
|
encode_int(idx, 7, 0x80, dst);
|
||||||
unimplemented!();
|
|
||||||
}
|
}
|
||||||
Entry::Name(idx) => {
|
Index::Name(idx, header) => {
|
||||||
unimplemented!();
|
encode_int(idx, 4, 0, dst);
|
||||||
|
encode_str(header.value_slice(), dst);
|
||||||
}
|
}
|
||||||
Entry::NotIndexed => {
|
Index::Inserted(header) => {
|
||||||
unimplemented!();
|
dst.put_u8(0b01000000);
|
||||||
|
encode_str(header.name().as_slice(), dst);
|
||||||
|
encode_str(header.value_slice(), dst);
|
||||||
|
}
|
||||||
|
Index::InsertedValue(idx, header) => {
|
||||||
|
encode_int(idx, 6, 0b01000000, dst);
|
||||||
|
encode_str(header.value_slice(), dst);
|
||||||
|
}
|
||||||
|
Index::NotIndexed(header) => {
|
||||||
|
dst.put_u8(0);
|
||||||
|
encode_str(header.name().as_slice(), dst);
|
||||||
|
encode_str(header.value_slice(), dst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
unimplemented!();
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_sensitive(e: &Entry) -> bool {
|
fn encode_str(val: &[u8], dst: &mut BytesMut) {
|
||||||
false
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
if val.len() != 0 {
|
||||||
|
let idx = dst.len();
|
||||||
|
|
||||||
|
// Push a placeholder byte for the length header
|
||||||
|
dst.put_u8(0);
|
||||||
|
|
||||||
|
// Encode with huffman
|
||||||
|
huffman::encode(val, dst);
|
||||||
|
|
||||||
|
let huff_len = dst.len() - (idx + 1);
|
||||||
|
|
||||||
|
if encode_int_one_byte(huff_len, 7) {
|
||||||
|
// Write the string head
|
||||||
|
dst[idx] = (0x80 | huff_len as u8);
|
||||||
|
} else {
|
||||||
|
// Write the head to a placeholer
|
||||||
|
let mut buf = [0; 8];
|
||||||
|
|
||||||
|
let head_len = {
|
||||||
|
let mut head_dst = Cursor::new(&mut buf);
|
||||||
|
encode_int(huff_len, 7, 0x80, &mut head_dst);
|
||||||
|
head_dst.position() as usize
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is just done to reserve space in the destination
|
||||||
|
dst.put_slice(&buf[1..head_len]);
|
||||||
|
|
||||||
|
// Shift the header forward
|
||||||
|
for i in 0..huff_len {
|
||||||
|
dst[idx + head_len + (huff_len - i)] = dst[idx + 1 + (huff_len - 1)];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy in the head
|
||||||
|
for i in 0..head_len {
|
||||||
|
dst[idx + i] = buf[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Write an empty string
|
||||||
|
dst.put_u8(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Encode an integer into the given destination buffer
|
||||||
|
fn encode_int<B: BufMut>(
|
||||||
|
mut value: usize, // The integer to encode
|
||||||
|
prefix_bits: usize, // The number of bits in the prefix
|
||||||
|
first_byte: u8, // The base upon which to start encoding the int
|
||||||
|
dst: &mut B) // The destination buffer
|
||||||
|
{
|
||||||
|
if encode_int_one_byte(value, prefix_bits) {
|
||||||
|
dst.put_u8(first_byte | value as u8);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let low = (1 << prefix_bits) - 1;
|
||||||
|
|
||||||
|
value -= low;
|
||||||
|
|
||||||
|
if value > 0x0fffffff {
|
||||||
|
panic!("value out of range");
|
||||||
|
}
|
||||||
|
|
||||||
|
dst.put_u8(first_byte | low as u8);
|
||||||
|
|
||||||
|
while value >= 128 {
|
||||||
|
dst.put_u8(0b10000000 | value as u8);
|
||||||
|
value = value >> 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
dst.put_u8(value as u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the in the int can be fully encoded in the first byte.
|
||||||
|
fn encode_int_one_byte(value: usize, prefix_bits: usize) -> bool {
|
||||||
|
value < (1 << prefix_bits) - 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ use http::{Method, StatusCode};
|
|||||||
use http::header::{HeaderName, HeaderValue};
|
use http::header::{HeaderName, HeaderValue};
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
|
|
||||||
/// HPack table entry
|
/// HTTP/2.0 Header
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Entry {
|
pub enum Header {
|
||||||
Header {
|
Field {
|
||||||
name: HeaderName,
|
name: HeaderName,
|
||||||
value: HeaderValue,
|
value: HeaderValue,
|
||||||
},
|
},
|
||||||
@@ -19,10 +19,10 @@ pub enum Entry {
|
|||||||
Status(StatusCode),
|
Status(StatusCode),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The name component of an Entry
|
/// The header field name
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
pub enum Key<'a> {
|
pub enum Name<'a> {
|
||||||
Header(&'a HeaderName),
|
Field(&'a HeaderName),
|
||||||
Authority,
|
Authority,
|
||||||
Method,
|
Method,
|
||||||
Scheme,
|
Scheme,
|
||||||
@@ -35,29 +35,29 @@ pub fn len(name: &HeaderName, value: &HeaderValue) -> usize {
|
|||||||
32 + n.len() + value.len()
|
32 + n.len() + value.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Entry {
|
impl Header {
|
||||||
pub fn new(name: Bytes, value: Bytes) -> Result<Entry, DecoderError> {
|
pub fn new(name: Bytes, value: Bytes) -> Result<Header, DecoderError> {
|
||||||
if name[0] == b':' {
|
if name[0] == b':' {
|
||||||
match &name[1..] {
|
match &name[1..] {
|
||||||
b"authority" => {
|
b"authority" => {
|
||||||
let value = try!(ByteStr::from_utf8(value));
|
let value = try!(ByteStr::from_utf8(value));
|
||||||
Ok(Entry::Authority(value))
|
Ok(Header::Authority(value))
|
||||||
}
|
}
|
||||||
b"method" => {
|
b"method" => {
|
||||||
let method = try!(Method::from_bytes(&value));
|
let method = try!(Method::from_bytes(&value));
|
||||||
Ok(Entry::Method(method))
|
Ok(Header::Method(method))
|
||||||
}
|
}
|
||||||
b"scheme" => {
|
b"scheme" => {
|
||||||
let value = try!(ByteStr::from_utf8(value));
|
let value = try!(ByteStr::from_utf8(value));
|
||||||
Ok(Entry::Scheme(value))
|
Ok(Header::Scheme(value))
|
||||||
}
|
}
|
||||||
b"path" => {
|
b"path" => {
|
||||||
let value = try!(ByteStr::from_utf8(value));
|
let value = try!(ByteStr::from_utf8(value));
|
||||||
Ok(Entry::Path(value))
|
Ok(Header::Path(value))
|
||||||
}
|
}
|
||||||
b"status" => {
|
b"status" => {
|
||||||
let status = try!(StatusCode::from_slice(&value));
|
let status = try!(StatusCode::from_slice(&value));
|
||||||
Ok(Entry::Status(status))
|
Ok(Header::Status(status))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
Err(DecoderError::InvalidPseudoheader)
|
Err(DecoderError::InvalidPseudoheader)
|
||||||
@@ -67,91 +67,107 @@ impl Entry {
|
|||||||
let name = try!(HeaderName::from_bytes(&name));
|
let name = try!(HeaderName::from_bytes(&name));
|
||||||
let value = try!(HeaderValue::try_from_slice(&value));
|
let value = try!(HeaderValue::try_from_slice(&value));
|
||||||
|
|
||||||
Ok(Entry::Header { name: name, value: value })
|
Ok(Header::Field { name: name, value: value })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
match *self {
|
match *self {
|
||||||
Entry::Header { ref name, ref value } => {
|
Header::Field { ref name, ref value } => {
|
||||||
len(name, value)
|
len(name, value)
|
||||||
}
|
}
|
||||||
Entry::Authority(ref v) => {
|
Header::Authority(ref v) => {
|
||||||
32 + 10 + v.len()
|
32 + 10 + v.len()
|
||||||
}
|
}
|
||||||
Entry::Method(ref v) => {
|
Header::Method(ref v) => {
|
||||||
32 + 7 + v.as_ref().len()
|
32 + 7 + v.as_ref().len()
|
||||||
}
|
}
|
||||||
Entry::Scheme(ref v) => {
|
Header::Scheme(ref v) => {
|
||||||
32 + 7 + v.len()
|
32 + 7 + v.len()
|
||||||
}
|
}
|
||||||
Entry::Path(ref v) => {
|
Header::Path(ref v) => {
|
||||||
32 + 5 + v.len()
|
32 + 5 + v.len()
|
||||||
}
|
}
|
||||||
Entry::Status(ref v) => {
|
Header::Status(ref v) => {
|
||||||
32 + 7 + 3
|
32 + 7 + 3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn key(&self) -> Key {
|
/// Returns the header name
|
||||||
|
pub fn name(&self) -> Name {
|
||||||
match *self {
|
match *self {
|
||||||
Entry::Header { ref name, .. } => Key::Header(name),
|
Header::Field { ref name, .. } => Name::Field(name),
|
||||||
Entry::Authority(..) => Key::Authority,
|
Header::Authority(..) => Name::Authority,
|
||||||
Entry::Method(..) => Key::Method,
|
Header::Method(..) => Name::Method,
|
||||||
Entry::Scheme(..) => Key::Scheme,
|
Header::Scheme(..) => Name::Scheme,
|
||||||
Entry::Path(..) => Key::Path,
|
Header::Path(..) => Name::Path,
|
||||||
Entry::Status(..) => Key::Status,
|
Header::Status(..) => Name::Status,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn value_eq(&self, other: &Entry) -> bool {
|
pub fn value_slice(&self) -> &[u8] {
|
||||||
match *self {
|
match *self {
|
||||||
Entry::Header { ref value, .. } => {
|
Header::Field { ref value, .. } => value.as_ref(),
|
||||||
|
Header::Authority(ref v) => v.as_ref(),
|
||||||
|
Header::Method(ref v) => v.as_ref().as_ref(),
|
||||||
|
Header::Scheme(ref v) => v.as_ref(),
|
||||||
|
Header::Path(ref v) => v.as_ref(),
|
||||||
|
Header::Status(ref v) => v.as_str().as_ref(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value_eq(&self, other: &Header) -> bool {
|
||||||
|
match *self {
|
||||||
|
Header::Field { ref value, .. } => {
|
||||||
let a = value;
|
let a = value;
|
||||||
match *other {
|
match *other {
|
||||||
Entry::Header { ref value, .. } => a == value,
|
Header::Field { ref value, .. } => a == value,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Entry::Authority(ref a) => {
|
Header::Authority(ref a) => {
|
||||||
match *other {
|
match *other {
|
||||||
Entry::Authority(ref b) => a == b,
|
Header::Authority(ref b) => a == b,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Entry::Method(ref a) => {
|
Header::Method(ref a) => {
|
||||||
match *other {
|
match *other {
|
||||||
Entry::Method(ref b) => a == b,
|
Header::Method(ref b) => a == b,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Entry::Scheme(ref a) => {
|
Header::Scheme(ref a) => {
|
||||||
match *other {
|
match *other {
|
||||||
Entry::Scheme(ref b) => a == b,
|
Header::Scheme(ref b) => a == b,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Entry::Path(ref a) => {
|
Header::Path(ref a) => {
|
||||||
match *other {
|
match *other {
|
||||||
Entry::Path(ref b) => a == b,
|
Header::Path(ref b) => a == b,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Entry::Status(ref a) => {
|
Header::Status(ref a) => {
|
||||||
match *other {
|
match *other {
|
||||||
Entry::Status(ref b) => a == b,
|
Header::Status(ref b) => a == b,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_sensitive(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
pub fn skip_value_index(&self) -> bool {
|
pub fn skip_value_index(&self) -> bool {
|
||||||
use http::header;
|
use http::header;
|
||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
Entry::Header { ref name, .. } => {
|
Header::Field { ref name, .. } => {
|
||||||
match *name {
|
match *name {
|
||||||
header::AGE |
|
header::AGE |
|
||||||
header::AUTHORIZATION |
|
header::AUTHORIZATION |
|
||||||
@@ -165,40 +181,51 @@ impl Entry {
|
|||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Entry::Path(..) => true,
|
Header::Path(..) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Key<'a> {
|
impl<'a> Name<'a> {
|
||||||
pub fn into_entry(self, value: Bytes) -> Result<Entry, DecoderError> {
|
pub fn into_entry(self, value: Bytes) -> Result<Header, DecoderError> {
|
||||||
match self {
|
match self {
|
||||||
Key::Header(name) => {
|
Name::Field(name) => {
|
||||||
Ok(Entry::Header {
|
Ok(Header::Field {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
value: try!(HeaderValue::try_from_slice(&*value)),
|
value: try!(HeaderValue::try_from_slice(&*value)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Key::Authority => {
|
Name::Authority => {
|
||||||
Ok(Entry::Authority(try!(ByteStr::from_utf8(value))))
|
Ok(Header::Authority(try!(ByteStr::from_utf8(value))))
|
||||||
}
|
}
|
||||||
Key::Method => {
|
Name::Method => {
|
||||||
Ok(Entry::Scheme(try!(ByteStr::from_utf8(value))))
|
Ok(Header::Scheme(try!(ByteStr::from_utf8(value))))
|
||||||
}
|
}
|
||||||
Key::Scheme => {
|
Name::Scheme => {
|
||||||
Ok(Entry::Scheme(try!(ByteStr::from_utf8(value))))
|
Ok(Header::Scheme(try!(ByteStr::from_utf8(value))))
|
||||||
}
|
}
|
||||||
Key::Path => {
|
Name::Path => {
|
||||||
Ok(Entry::Path(try!(ByteStr::from_utf8(value))))
|
Ok(Header::Path(try!(ByteStr::from_utf8(value))))
|
||||||
}
|
}
|
||||||
Key::Status => {
|
Name::Status => {
|
||||||
match StatusCode::from_slice(&value) {
|
match StatusCode::from_slice(&value) {
|
||||||
Ok(status) => Ok(Entry::Status(status)),
|
Ok(status) => Ok(Header::Status(status)),
|
||||||
// TODO: better error handling
|
// TODO: better error handling
|
||||||
Err(_) => Err(DecoderError::InvalidStatusCode),
|
Err(_) => Err(DecoderError::InvalidStatusCode),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_slice(&self) -> &[u8] {
|
||||||
|
match *self {
|
||||||
|
Name::Field(ref name) => name.as_ref(),
|
||||||
|
Name::Authority => b":authority",
|
||||||
|
Name::Method => b":method",
|
||||||
|
Name::Scheme => b":scheme",
|
||||||
|
Name::Path => b":path",
|
||||||
|
Name::Status => b":status",
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -42,8 +42,7 @@ pub fn decode(src: &[u8]) -> Result<BytesMut, DecoderError> {
|
|||||||
Ok(dst)
|
Ok(dst)
|
||||||
}
|
}
|
||||||
|
|
||||||
// To avoid panics, the destination buffer must have src.len() remaining
|
// TODO: return error when there is not enough room to encode the value
|
||||||
// capacity.
|
|
||||||
pub fn encode<B: BufMut>(src: &[u8], dst: &mut B) {
|
pub fn encode<B: BufMut>(src: &[u8], dst: &mut B) {
|
||||||
let mut bits: u64 = 0;
|
let mut bits: u64 = 0;
|
||||||
let mut bits_left = 40;
|
let mut bits_left = 40;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
mod encoder;
|
mod encoder;
|
||||||
mod decoder;
|
mod decoder;
|
||||||
mod entry;
|
mod header;
|
||||||
mod huffman;
|
mod huffman;
|
||||||
mod table;
|
mod table;
|
||||||
|
|
||||||
@@ -8,5 +8,5 @@ mod table;
|
|||||||
mod test;
|
mod test;
|
||||||
|
|
||||||
pub use self::encoder::Encoder;
|
pub use self::encoder::Encoder;
|
||||||
pub use self::entry::{Entry, Key};
|
pub use self::header::Header;
|
||||||
pub use self::decoder::{Decoder, DecoderError};
|
pub use self::decoder::{Decoder, DecoderError};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use super::Entry;
|
use super::Header;
|
||||||
|
|
||||||
use fnv::FnvHasher;
|
use fnv::FnvHasher;
|
||||||
use http::method;
|
use http::method;
|
||||||
@@ -22,22 +22,25 @@ pub struct Table {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Index<'a> {
|
pub enum Index<'a> {
|
||||||
// The entry is already fully indexed
|
// The header is already fully indexed
|
||||||
Indexed(usize),
|
Indexed(usize, Header),
|
||||||
|
|
||||||
// The name is indexed, but not the value
|
// The name is indexed, but not the value
|
||||||
Name(usize, Entry),
|
Name(usize, Header),
|
||||||
|
|
||||||
// The full entry has been inserted into the table.
|
// The full header has been inserted into the table.
|
||||||
Inserted(&'a Entry),
|
Inserted(&'a Header),
|
||||||
|
|
||||||
// The entry is not indexed by this table
|
// Only the value has been inserted
|
||||||
NotIndexed(Entry),
|
InsertedValue(usize, Header),
|
||||||
|
|
||||||
|
// The header is not indexed by this table
|
||||||
|
NotIndexed(Header),
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Slot {
|
struct Slot {
|
||||||
hash: HashValue,
|
hash: HashValue,
|
||||||
entry: Entry,
|
header: Header,
|
||||||
next: Option<usize>,
|
next: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,33 +97,33 @@ impl Table {
|
|||||||
usable_capacity(self.indices.len())
|
usable_capacity(self.indices.len())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Index the entry in the HPACK table.
|
/// Index the header in the HPACK table.
|
||||||
pub fn index(&mut self, entry: Entry) -> Index {
|
pub fn index(&mut self, header: Header) -> Index {
|
||||||
// Check the static table
|
// Check the static table
|
||||||
let statik = index_static(&entry);
|
let statik = index_static(&header);
|
||||||
|
|
||||||
// Don't index certain headers. This logic is borrowed from nghttp2.
|
// Don't index certain headers. This logic is borrowed from nghttp2.
|
||||||
if entry.skip_value_index() {
|
if header.skip_value_index() {
|
||||||
return Index::new(statik, entry);
|
return Index::new(statik, header);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the header is already indexed by the static table, return that
|
// If the header is already indexed by the static table, return that
|
||||||
if let Some((n, true)) = statik {
|
if let Some((n, true)) = statik {
|
||||||
return Index::Indexed(n);
|
return Index::Indexed(n, header);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't index large headers
|
// Don't index large headers
|
||||||
if entry.len() * 4 > self.max_size * 3 {
|
if header.len() * 4 > self.max_size * 3 {
|
||||||
return Index::new(statik, entry);
|
return Index::new(statik, header);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.index_dynamic(entry, statik)
|
self.index_dynamic(header, statik)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn index_dynamic(&mut self, entry: Entry, statik: Option<(usize, bool)>) -> Index {
|
fn index_dynamic(&mut self, header: Header, statik: Option<(usize, bool)>) -> Index {
|
||||||
self.reserve_one();
|
self.reserve_one();
|
||||||
|
|
||||||
let hash = hash_entry(&entry);
|
let hash = hash_header(&header);
|
||||||
|
|
||||||
let desired_pos = desired_pos(self.mask, hash);
|
let desired_pos = desired_pos(self.mask, hash);
|
||||||
let mut probe = desired_pos;
|
let mut probe = desired_pos;
|
||||||
@@ -135,20 +138,20 @@ impl Table {
|
|||||||
|
|
||||||
if their_dist < dist {
|
if their_dist < dist {
|
||||||
// Index robinhood
|
// Index robinhood
|
||||||
return self.index_vacant(entry, hash, desired_pos, probe);
|
return self.index_vacant(header, hash, desired_pos, probe);
|
||||||
} else if pos.hash == hash && self.slots[pos.index].entry.key() == entry.key() {
|
} else if pos.hash == hash && self.slots[pos.index].header.name() == header.name() {
|
||||||
// Matching key, check values
|
// Matching name, check values
|
||||||
return self.index_occupied(entry, pos.index, statik);
|
return self.index_occupied(header, pos.index, statik);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return self.index_vacant(entry, hash, desired_pos, probe);
|
return self.index_vacant(header, hash, desired_pos, probe);
|
||||||
}
|
}
|
||||||
|
|
||||||
dist += 1;
|
dist += 1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn index_occupied(&mut self, entry: Entry, mut index: usize, statik: Option<(usize, bool)>)
|
fn index_occupied(&mut self, header: Header, mut index: usize, statik: Option<(usize, bool)>)
|
||||||
-> Index
|
-> Index
|
||||||
{
|
{
|
||||||
// There already is a match for the given header name. Check if a value
|
// There already is a match for the given header name. Check if a value
|
||||||
@@ -158,13 +161,13 @@ impl Table {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn index_vacant(&mut self,
|
fn index_vacant(&mut self,
|
||||||
entry: Entry,
|
header: Header,
|
||||||
hash: HashValue,
|
hash: HashValue,
|
||||||
desired: usize,
|
desired: usize,
|
||||||
probe: usize)
|
probe: usize)
|
||||||
-> Index
|
-> Index
|
||||||
{
|
{
|
||||||
if self.maybe_evict(entry.len()) {
|
if self.maybe_evict(header.len()) {
|
||||||
// Maybe step back
|
// Maybe step back
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
@@ -175,7 +178,7 @@ impl Table {
|
|||||||
|
|
||||||
self.slots.push_back(Slot {
|
self.slots.push_back(Slot {
|
||||||
hash: hash,
|
hash: hash,
|
||||||
entry: entry,
|
header: header,
|
||||||
next: None,
|
next: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -199,7 +202,7 @@ impl Table {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Index::Inserted(&self.slots[slot_idx].entry)
|
Index::Inserted(&self.slots[slot_idx].header)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maybe_evict(&mut self, len: usize) -> bool {
|
fn maybe_evict(&mut self, len: usize) -> bool {
|
||||||
@@ -217,7 +220,7 @@ impl Table {
|
|||||||
fn evict(&mut self) {
|
fn evict(&mut self) {
|
||||||
debug_assert!(!self.slots.is_empty());
|
debug_assert!(!self.slots.is_empty());
|
||||||
|
|
||||||
// Remove the entry
|
// Remove the header
|
||||||
let slot = self.slots.pop_front().unwrap();
|
let slot = self.slots.pop_front().unwrap();
|
||||||
let mut probe = desired_pos(self.mask, slot.hash);
|
let mut probe = desired_pos(self.mask, slot.hash);
|
||||||
|
|
||||||
@@ -242,7 +245,7 @@ impl Table {
|
|||||||
self.evicted = self.evicted.wrapping_add(1);
|
self.evicted = self.evicted.wrapping_add(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shifts all indices that were displaced by the entry that has just been
|
// Shifts all indices that were displaced by the header that has just been
|
||||||
// removed.
|
// removed.
|
||||||
fn remove_phase_two(&mut self, probe: usize) {
|
fn remove_phase_two(&mut self, probe: usize) {
|
||||||
let mut last_probe = probe;
|
let mut last_probe = probe;
|
||||||
@@ -326,10 +329,10 @@ impl Table {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Index<'a> {
|
impl<'a> Index<'a> {
|
||||||
fn new(v: Option<(usize, bool)>, e: Entry) -> Index<'a> {
|
fn new(v: Option<(usize, bool)>, e: Header) -> Index<'a> {
|
||||||
match v {
|
match v {
|
||||||
None => Index::NotIndexed(e),
|
None => Index::NotIndexed(e),
|
||||||
Some((n, true)) => Index::Indexed(n),
|
Some((n, true)) => Index::Indexed(n, e),
|
||||||
Some((n, false)) => Index::Name(n, e),
|
Some((n, false)) => Index::Name(n, e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -355,19 +358,19 @@ fn probe_distance(mask: usize, hash: HashValue, current: usize) -> usize {
|
|||||||
current.wrapping_sub(desired_pos(mask, hash)) & mask as usize
|
current.wrapping_sub(desired_pos(mask, hash)) & mask as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hash_entry(entry: &Entry) -> HashValue {
|
fn hash_header(header: &Header) -> HashValue {
|
||||||
const MASK: u64 = (MAX_SIZE as u64) - 1;
|
const MASK: u64 = (MAX_SIZE as u64) - 1;
|
||||||
|
|
||||||
let mut h = FnvHasher::default();
|
let mut h = FnvHasher::default();
|
||||||
entry.key().hash(&mut h);
|
header.name().hash(&mut h);
|
||||||
HashValue((h.finish() & MASK) as usize)
|
HashValue((h.finish() & MASK) as usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks the static table for the entry. If found, returns the index and a
|
/// Checks the static table for the header. If found, returns the index and a
|
||||||
/// boolean representing if the value matched as well.
|
/// boolean representing if the value matched as well.
|
||||||
fn index_static(entry: &Entry) -> Option<(usize, bool)> {
|
fn index_static(header: &Header) -> Option<(usize, bool)> {
|
||||||
match *entry {
|
match *header {
|
||||||
Entry::Header { ref name, ref value } => {
|
Header::Field { ref name, ref value } => {
|
||||||
match *name {
|
match *name {
|
||||||
header::ACCEPT_CHARSET => Some((15, false)),
|
header::ACCEPT_CHARSET => Some((15, false)),
|
||||||
header::ACCEPT_ENCODING => {
|
header::ACCEPT_ENCODING => {
|
||||||
@@ -425,29 +428,29 @@ fn index_static(entry: &Entry) -> Option<(usize, bool)> {
|
|||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Entry::Authority(ref v) => Some((1, false)),
|
Header::Authority(ref v) => Some((1, false)),
|
||||||
Entry::Method(ref v) => {
|
Header::Method(ref v) => {
|
||||||
match *v {
|
match *v {
|
||||||
method::GET => Some((2, true)),
|
method::GET => Some((2, true)),
|
||||||
method::POST => Some((3, true)),
|
method::POST => Some((3, true)),
|
||||||
_ => Some((2, false)),
|
_ => Some((2, false)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Entry::Scheme(ref v) => {
|
Header::Scheme(ref v) => {
|
||||||
match &**v {
|
match &**v {
|
||||||
"http" => Some((6, true)),
|
"http" => Some((6, true)),
|
||||||
"https" => Some((7, true)),
|
"https" => Some((7, true)),
|
||||||
_ => Some((6, false)),
|
_ => Some((6, false)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Entry::Path(ref v) => {
|
Header::Path(ref v) => {
|
||||||
match &**v {
|
match &**v {
|
||||||
"/" => Some((4, true)),
|
"/" => Some((4, true)),
|
||||||
"/index.html" => Some((5, true)),
|
"/index.html" => Some((5, true)),
|
||||||
_ => Some((4, false)),
|
_ => Some((4, false)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Entry::Status(ref v) => {
|
Header::Status(ref v) => {
|
||||||
match u16::from(*v) {
|
match u16::from(*v) {
|
||||||
200 => Some((8, true)),
|
200 => Some((8, true)),
|
||||||
204 => Some((9, true)),
|
204 => Some((9, true)),
|
||||||
|
|||||||
Reference in New Issue
Block a user