Use rustfmt to enforce consistent formatting
This change adds a .rustfmt.toml that includes ALL supported settings, 12 of which we have overridden to attempt to cater to our own proclivities. rustfmt is checked in the rust-nightly CI job.
This commit is contained in:
@@ -1,15 +1,15 @@
|
||||
use super::{huffman, Header};
|
||||
use frame;
|
||||
|
||||
use http::{header};
|
||||
use bytes::{Buf, Bytes, BytesMut};
|
||||
use http::header;
|
||||
use http::method::{self, Method};
|
||||
use http::status::{self, StatusCode};
|
||||
use bytes::{Buf, Bytes, BytesMut};
|
||||
use string::String;
|
||||
|
||||
use std::cmp;
|
||||
use std::io::Cursor;
|
||||
use std::collections::VecDeque;
|
||||
use std::io::Cursor;
|
||||
use std::str::Utf8Error;
|
||||
|
||||
/// Decodes headers using HPACK
|
||||
@@ -164,7 +164,8 @@ impl Decoder {
|
||||
|
||||
/// Decodes the headers found in the given buffer.
|
||||
pub fn decode<F>(&mut self, src: &mut Cursor<Bytes>, mut f: F) -> Result<(), DecoderError>
|
||||
where F: FnMut(Header)
|
||||
where
|
||||
F: FnMut(Header),
|
||||
{
|
||||
use self::Representation::*;
|
||||
|
||||
@@ -180,16 +181,16 @@ impl Decoder {
|
||||
// At this point we are always at the beginning of the next block
|
||||
// within the HPACK data. The type of the block can always be
|
||||
// determined from the first byte.
|
||||
match try!(Representation::load(peek_u8(src))) {
|
||||
match Representation::load(peek_u8(src))? {
|
||||
Indexed => {
|
||||
trace!(" Indexed; rem={:?}", src.remaining());
|
||||
can_resize = false;
|
||||
f(try!(self.decode_indexed(src)));
|
||||
f(self.decode_indexed(src)?);
|
||||
}
|
||||
LiteralWithIndexing => {
|
||||
trace!(" LiteralWithIndexing; rem={:?}", src.remaining());
|
||||
can_resize = false;
|
||||
let entry = try!(self.decode_literal(src, true));
|
||||
let entry = self.decode_literal(src, true)?;
|
||||
|
||||
// Insert the header into the table
|
||||
self.table.insert(entry.clone());
|
||||
@@ -199,13 +200,13 @@ impl Decoder {
|
||||
LiteralWithoutIndexing => {
|
||||
trace!(" LiteralWithoutIndexing; rem={:?}", src.remaining());
|
||||
can_resize = false;
|
||||
let entry = try!(self.decode_literal(src, false));
|
||||
let entry = self.decode_literal(src, false)?;
|
||||
f(entry);
|
||||
}
|
||||
LiteralNeverIndexed => {
|
||||
trace!(" LiteralNeverIndexed; rem={:?}", src.remaining());
|
||||
can_resize = false;
|
||||
let entry = try!(self.decode_literal(src, false));
|
||||
let entry = self.decode_literal(src, false)?;
|
||||
|
||||
// TODO: Track that this should never be indexed
|
||||
|
||||
@@ -218,7 +219,7 @@ impl Decoder {
|
||||
}
|
||||
|
||||
// Handle the dynamic table size update
|
||||
try!(self.process_size_update(src));
|
||||
self.process_size_update(src)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -226,52 +227,47 @@ impl Decoder {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_size_update(&mut self, buf: &mut Cursor<Bytes>)
|
||||
-> Result<(), DecoderError>
|
||||
{
|
||||
let new_size = try!(decode_int(buf, 5));
|
||||
fn process_size_update(&mut self, buf: &mut Cursor<Bytes>) -> Result<(), DecoderError> {
|
||||
let new_size = decode_int(buf, 5)?;
|
||||
|
||||
if new_size > self.last_max_update {
|
||||
return Err(DecoderError::InvalidMaxDynamicSize);
|
||||
}
|
||||
|
||||
debug!("Decoder changed max table size from {} to {}",
|
||||
self.table.size(), new_size);
|
||||
self.table.size(),
|
||||
new_size);
|
||||
|
||||
self.table.set_max_size(new_size);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn decode_indexed(&self, buf: &mut Cursor<Bytes>)
|
||||
-> Result<Header, DecoderError>
|
||||
{
|
||||
let index = try!(decode_int(buf, 7));
|
||||
fn decode_indexed(&self, buf: &mut Cursor<Bytes>) -> Result<Header, DecoderError> {
|
||||
let index = decode_int(buf, 7)?;
|
||||
self.table.get(index)
|
||||
}
|
||||
|
||||
fn decode_literal(&mut self, buf: &mut Cursor<Bytes>, index: bool)
|
||||
-> Result<Header, DecoderError>
|
||||
{
|
||||
let prefix = if index {
|
||||
6
|
||||
} else {
|
||||
4
|
||||
};
|
||||
fn decode_literal(
|
||||
&mut self,
|
||||
buf: &mut Cursor<Bytes>,
|
||||
index: bool,
|
||||
) -> Result<Header, 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));
|
||||
let table_idx = decode_int(buf, prefix)?;
|
||||
|
||||
// First, read the header name
|
||||
if table_idx == 0 {
|
||||
// Read the name as a literal
|
||||
let name = try!(self.decode_string(buf));
|
||||
let value = try!(self.decode_string(buf));
|
||||
let name = self.decode_string(buf)?;
|
||||
let value = self.decode_string(buf)?;
|
||||
|
||||
Header::new(name, value)
|
||||
} else {
|
||||
let e = try!(self.table.get(table_idx));
|
||||
let value = try!(self.decode_string(buf));
|
||||
let e = self.table.get(table_idx)?;
|
||||
let value = self.decode_string(buf)?;
|
||||
|
||||
e.name().into_entry(value)
|
||||
}
|
||||
@@ -288,10 +284,12 @@ impl Decoder {
|
||||
let huff = peek_u8(buf) & HUFF_FLAG == HUFF_FLAG;
|
||||
|
||||
// Decode the string length using 7 bit prefix
|
||||
let len = try!(decode_int(buf, 7));
|
||||
let len = decode_int(buf, 7)?;
|
||||
|
||||
if len > buf.remaining() {
|
||||
trace!("decode_string underflow; len={}; remaining={}", len, buf.remaining());
|
||||
trace!("decode_string underflow; len={}; remaining={}",
|
||||
len,
|
||||
buf.remaining());
|
||||
return Err(DecoderError::StringUnderflow);
|
||||
}
|
||||
|
||||
@@ -319,12 +317,12 @@ impl Default for Decoder {
|
||||
|
||||
impl Representation {
|
||||
pub fn load(byte: u8) -> Result<Representation, DecoderError> {
|
||||
const INDEXED: u8 = 0b10000000;
|
||||
const LITERAL_WITH_INDEXING: u8 = 0b01000000;
|
||||
const INDEXED: u8 = 0b10000000;
|
||||
const LITERAL_WITH_INDEXING: u8 = 0b01000000;
|
||||
const LITERAL_WITHOUT_INDEXING: u8 = 0b11110000;
|
||||
const LITERAL_NEVER_INDEXED: u8 = 0b00010000;
|
||||
const SIZE_UPDATE_MASK: u8 = 0b11100000;
|
||||
const SIZE_UPDATE: u8 = 0b00100000;
|
||||
const LITERAL_NEVER_INDEXED: u8 = 0b00010000;
|
||||
const SIZE_UPDATE_MASK: u8 = 0b11100000;
|
||||
const SIZE_UPDATE: u8 = 0b00100000;
|
||||
|
||||
// TODO: What did I even write here?
|
||||
|
||||
@@ -474,7 +472,8 @@ impl Table {
|
||||
debug_assert!(size <= self.max_size);
|
||||
|
||||
while self.size + size > self.max_size {
|
||||
let last = self.entries.pop_back()
|
||||
let last = self.entries
|
||||
.pop_back()
|
||||
.expect("size of table != 0, but no headers left!");
|
||||
|
||||
self.size -= last.len();
|
||||
@@ -564,194 +563,288 @@ pub fn get_static(idx: usize) -> Header {
|
||||
12 => Header::Status(StatusCode::BAD_REQUEST),
|
||||
13 => Header::Status(StatusCode::NOT_FOUND),
|
||||
14 => Header::Status(StatusCode::INTERNAL_SERVER_ERROR),
|
||||
15 => Header::Field {
|
||||
name: header::ACCEPT_CHARSET,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
16 => Header::Field {
|
||||
name: header::ACCEPT_ENCODING,
|
||||
value: HeaderValue::from_static("gzip, deflate"),
|
||||
},
|
||||
17 => Header::Field {
|
||||
name: header::ACCEPT_LANGUAGE,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
18 => Header::Field {
|
||||
name: header::ACCEPT_RANGES,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
19 => Header::Field {
|
||||
name: header::ACCEPT,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
20 => Header::Field {
|
||||
name: header::ACCESS_CONTROL_ALLOW_ORIGIN,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
21 => Header::Field {
|
||||
name: header::AGE,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
22 => Header::Field {
|
||||
name: header::ALLOW,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
23 => Header::Field {
|
||||
name: header::AUTHORIZATION,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
24 => Header::Field {
|
||||
name: header::CACHE_CONTROL,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
25 => Header::Field {
|
||||
name: header::CONTENT_DISPOSITION,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
26 => Header::Field {
|
||||
name: header::CONTENT_ENCODING,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
27 => Header::Field {
|
||||
name: header::CONTENT_LANGUAGE,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
28 => Header::Field {
|
||||
name: header::CONTENT_LENGTH,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
29 => Header::Field {
|
||||
name: header::CONTENT_LOCATION,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
30 => Header::Field {
|
||||
name: header::CONTENT_RANGE,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
31 => Header::Field {
|
||||
name: header::CONTENT_TYPE,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
32 => Header::Field {
|
||||
name: header::COOKIE,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
33 => Header::Field {
|
||||
name: header::DATE,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
34 => Header::Field {
|
||||
name: header::ETAG,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
35 => Header::Field {
|
||||
name: header::EXPECT,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
36 => Header::Field {
|
||||
name: header::EXPIRES,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
37 => Header::Field {
|
||||
name: header::FROM,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
38 => Header::Field {
|
||||
name: header::HOST,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
39 => Header::Field {
|
||||
name: header::IF_MATCH,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
40 => Header::Field {
|
||||
name: header::IF_MODIFIED_SINCE,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
41 => Header::Field {
|
||||
name: header::IF_NONE_MATCH,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
42 => Header::Field {
|
||||
name: header::IF_RANGE,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
43 => Header::Field {
|
||||
name: header::IF_UNMODIFIED_SINCE,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
44 => Header::Field {
|
||||
name: header::LAST_MODIFIED,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
45 => Header::Field {
|
||||
name: header::LINK,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
46 => Header::Field {
|
||||
name: header::LOCATION,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
47 => Header::Field {
|
||||
name: header::MAX_FORWARDS,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
48 => Header::Field {
|
||||
name: header::PROXY_AUTHENTICATE,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
49 => Header::Field {
|
||||
name: header::PROXY_AUTHORIZATION,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
50 => Header::Field {
|
||||
name: header::RANGE,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
51 => Header::Field {
|
||||
name: header::REFERER,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
52 => Header::Field {
|
||||
name: header::REFRESH,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
53 => Header::Field {
|
||||
name: header::RETRY_AFTER,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
54 => Header::Field {
|
||||
name: header::SERVER,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
55 => Header::Field {
|
||||
name: header::SET_COOKIE,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
56 => Header::Field {
|
||||
name: header::STRICT_TRANSPORT_SECURITY,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
57 => Header::Field {
|
||||
name: header::TRANSFER_ENCODING,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
58 => Header::Field {
|
||||
name: header::USER_AGENT,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
59 => Header::Field {
|
||||
name: header::VARY,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
60 => Header::Field {
|
||||
name: header::VIA,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
61 => Header::Field {
|
||||
name: header::WWW_AUTHENTICATE,
|
||||
value: HeaderValue::from_static(""),
|
||||
},
|
||||
15 => {
|
||||
Header::Field {
|
||||
name: header::ACCEPT_CHARSET,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
16 => {
|
||||
Header::Field {
|
||||
name: header::ACCEPT_ENCODING,
|
||||
value: HeaderValue::from_static("gzip, deflate"),
|
||||
}
|
||||
}
|
||||
17 => {
|
||||
Header::Field {
|
||||
name: header::ACCEPT_LANGUAGE,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
18 => {
|
||||
Header::Field {
|
||||
name: header::ACCEPT_RANGES,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
19 => {
|
||||
Header::Field {
|
||||
name: header::ACCEPT,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
20 => {
|
||||
Header::Field {
|
||||
name: header::ACCESS_CONTROL_ALLOW_ORIGIN,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
21 => {
|
||||
Header::Field {
|
||||
name: header::AGE,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
22 => {
|
||||
Header::Field {
|
||||
name: header::ALLOW,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
23 => {
|
||||
Header::Field {
|
||||
name: header::AUTHORIZATION,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
24 => {
|
||||
Header::Field {
|
||||
name: header::CACHE_CONTROL,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
25 => {
|
||||
Header::Field {
|
||||
name: header::CONTENT_DISPOSITION,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
26 => {
|
||||
Header::Field {
|
||||
name: header::CONTENT_ENCODING,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
27 => {
|
||||
Header::Field {
|
||||
name: header::CONTENT_LANGUAGE,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
28 => {
|
||||
Header::Field {
|
||||
name: header::CONTENT_LENGTH,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
29 => {
|
||||
Header::Field {
|
||||
name: header::CONTENT_LOCATION,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
30 => {
|
||||
Header::Field {
|
||||
name: header::CONTENT_RANGE,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
31 => {
|
||||
Header::Field {
|
||||
name: header::CONTENT_TYPE,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
32 => {
|
||||
Header::Field {
|
||||
name: header::COOKIE,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
33 => {
|
||||
Header::Field {
|
||||
name: header::DATE,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
34 => {
|
||||
Header::Field {
|
||||
name: header::ETAG,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
35 => {
|
||||
Header::Field {
|
||||
name: header::EXPECT,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
36 => {
|
||||
Header::Field {
|
||||
name: header::EXPIRES,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
37 => {
|
||||
Header::Field {
|
||||
name: header::FROM,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
38 => {
|
||||
Header::Field {
|
||||
name: header::HOST,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
39 => {
|
||||
Header::Field {
|
||||
name: header::IF_MATCH,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
40 => {
|
||||
Header::Field {
|
||||
name: header::IF_MODIFIED_SINCE,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
41 => {
|
||||
Header::Field {
|
||||
name: header::IF_NONE_MATCH,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
42 => {
|
||||
Header::Field {
|
||||
name: header::IF_RANGE,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
43 => {
|
||||
Header::Field {
|
||||
name: header::IF_UNMODIFIED_SINCE,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
44 => {
|
||||
Header::Field {
|
||||
name: header::LAST_MODIFIED,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
45 => {
|
||||
Header::Field {
|
||||
name: header::LINK,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
46 => {
|
||||
Header::Field {
|
||||
name: header::LOCATION,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
47 => {
|
||||
Header::Field {
|
||||
name: header::MAX_FORWARDS,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
48 => {
|
||||
Header::Field {
|
||||
name: header::PROXY_AUTHENTICATE,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
49 => {
|
||||
Header::Field {
|
||||
name: header::PROXY_AUTHORIZATION,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
50 => {
|
||||
Header::Field {
|
||||
name: header::RANGE,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
51 => {
|
||||
Header::Field {
|
||||
name: header::REFERER,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
52 => {
|
||||
Header::Field {
|
||||
name: header::REFRESH,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
53 => {
|
||||
Header::Field {
|
||||
name: header::RETRY_AFTER,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
54 => {
|
||||
Header::Field {
|
||||
name: header::SERVER,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
55 => {
|
||||
Header::Field {
|
||||
name: header::SET_COOKIE,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
56 => {
|
||||
Header::Field {
|
||||
name: header::STRICT_TRANSPORT_SECURITY,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
57 => {
|
||||
Header::Field {
|
||||
name: header::TRANSFER_ENCODING,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
58 => {
|
||||
Header::Field {
|
||||
name: header::USER_AGENT,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
59 => {
|
||||
Header::Field {
|
||||
name: header::VARY,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
60 => {
|
||||
Header::Field {
|
||||
name: header::VIA,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
61 => {
|
||||
Header::Field {
|
||||
name: header::WWW_AUTHENTICATE,
|
||||
value: HeaderValue::from_static(""),
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use super::{huffman, Header};
|
||||
use super::table::{Table, Index};
|
||||
use super::table::{Index, Table};
|
||||
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use http::header::{HeaderName, HeaderValue};
|
||||
use bytes::{BytesMut, BufMut};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Encoder {
|
||||
@@ -76,9 +76,14 @@ impl Encoder {
|
||||
}
|
||||
|
||||
/// Encode a set of headers into the provide buffer
|
||||
pub fn encode<I>(&mut self, resume: Option<EncodeState>, headers: &mut I, dst: &mut BytesMut)
|
||||
-> Encode
|
||||
where I: Iterator<Item=Header<Option<HeaderName>>>,
|
||||
pub fn encode<I>(
|
||||
&mut self,
|
||||
resume: Option<EncodeState>,
|
||||
headers: &mut I,
|
||||
dst: &mut BytesMut,
|
||||
) -> Encode
|
||||
where
|
||||
I: Iterator<Item = Header<Option<HeaderName>>>,
|
||||
{
|
||||
let len = dst.len();
|
||||
|
||||
@@ -94,15 +99,8 @@ impl Encoder {
|
||||
let len = dst.len();
|
||||
|
||||
let res = match resume.value {
|
||||
Some(ref value) => {
|
||||
self.encode_header_without_name(
|
||||
&resume.index,
|
||||
value,
|
||||
dst)
|
||||
}
|
||||
None => {
|
||||
self.encode_header(&resume.index, dst)
|
||||
}
|
||||
Some(ref value) => self.encode_header_without_name(&resume.index, value, dst),
|
||||
None => self.encode_header(&resume.index, dst),
|
||||
};
|
||||
|
||||
if res.is_err() {
|
||||
@@ -126,9 +124,9 @@ impl Encoder {
|
||||
if res.is_err() {
|
||||
dst.truncate(len);
|
||||
return Encode::Partial(EncodeState {
|
||||
index: index,
|
||||
value: None,
|
||||
});
|
||||
index: index,
|
||||
value: None,
|
||||
});
|
||||
}
|
||||
|
||||
last_index = Some(index);
|
||||
@@ -138,17 +136,15 @@ impl Encoder {
|
||||
// which case, we skip table lookup and just use the same index
|
||||
// as the previous entry.
|
||||
Err(value) => {
|
||||
let res = self.encode_header_without_name(
|
||||
last_index.as_ref().unwrap(),
|
||||
&value,
|
||||
dst);
|
||||
let res =
|
||||
self.encode_header_without_name(last_index.as_ref().unwrap(), &value, dst);
|
||||
|
||||
if res.is_err() {
|
||||
dst.truncate(len);
|
||||
return Encode::Partial(EncodeState {
|
||||
index: last_index.unwrap(),
|
||||
value: Some(value),
|
||||
});
|
||||
index: last_index.unwrap(),
|
||||
value: Some(value),
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -161,13 +157,13 @@ impl Encoder {
|
||||
match self.size_update.take() {
|
||||
Some(SizeUpdate::One(val)) => {
|
||||
self.table.resize(val);
|
||||
try!(encode_size_update(val, dst));
|
||||
encode_size_update(val, dst)?;
|
||||
}
|
||||
Some(SizeUpdate::Two(min, max)) => {
|
||||
self.table.resize(min);
|
||||
self.table.resize(max);
|
||||
try!(encode_size_update(min, dst));
|
||||
try!(encode_size_update(max, dst));
|
||||
encode_size_update(min, dst)?;
|
||||
encode_size_update(max, dst)?;
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
@@ -175,21 +171,15 @@ impl Encoder {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn encode_header(&mut self, index: &Index, dst: &mut BytesMut)
|
||||
-> Result<(), EncoderError>
|
||||
{
|
||||
fn encode_header(&mut self, index: &Index, dst: &mut BytesMut) -> Result<(), EncoderError> {
|
||||
match *index {
|
||||
Index::Indexed(idx, _) => {
|
||||
try!(encode_int(idx, 7, 0x80, dst));
|
||||
encode_int(idx, 7, 0x80, dst)?;
|
||||
}
|
||||
Index::Name(idx, _) => {
|
||||
let header = self.table.resolve(&index);
|
||||
|
||||
try!(encode_not_indexed(
|
||||
idx,
|
||||
header.value_slice(),
|
||||
header.is_sensitive(),
|
||||
dst));
|
||||
encode_not_indexed(idx, header.value_slice(), header.is_sensitive(), dst)?;
|
||||
}
|
||||
Index::Inserted(_) => {
|
||||
let header = self.table.resolve(&index);
|
||||
@@ -202,57 +192,52 @@ impl Encoder {
|
||||
|
||||
dst.put_u8(0b01000000);
|
||||
|
||||
try!(encode_str(header.name().as_slice(), dst));
|
||||
try!(encode_str(header.value_slice(), dst));
|
||||
encode_str(header.name().as_slice(), dst)?;
|
||||
encode_str(header.value_slice(), dst)?;
|
||||
}
|
||||
Index::InsertedValue(idx, _) => {
|
||||
let header = self.table.resolve(&index);
|
||||
|
||||
assert!(!header.is_sensitive());
|
||||
|
||||
try!(encode_int(idx, 6, 0b01000000, dst));
|
||||
try!(encode_str(header.value_slice(), dst));
|
||||
encode_int(idx, 6, 0b01000000, dst)?;
|
||||
encode_str(header.value_slice(), dst)?;
|
||||
}
|
||||
Index::NotIndexed(_) => {
|
||||
let header = self.table.resolve(&index);
|
||||
|
||||
try!(encode_not_indexed2(
|
||||
header.name().as_slice(),
|
||||
header.value_slice(),
|
||||
header.is_sensitive(),
|
||||
dst));
|
||||
encode_not_indexed2(header.name().as_slice(),
|
||||
header.value_slice(),
|
||||
header.is_sensitive(),
|
||||
dst)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn encode_header_without_name(&mut self, last: &Index,
|
||||
value: &HeaderValue, dst: &mut BytesMut)
|
||||
-> Result<(), EncoderError>
|
||||
{
|
||||
fn encode_header_without_name(
|
||||
&mut self,
|
||||
last: &Index,
|
||||
value: &HeaderValue,
|
||||
dst: &mut BytesMut,
|
||||
) -> Result<(), EncoderError> {
|
||||
match *last {
|
||||
Index::Indexed(..) |
|
||||
Index::Name(..) |
|
||||
Index::Inserted(..) |
|
||||
Index::InsertedValue(..) =>
|
||||
{
|
||||
Index::Name(..) |
|
||||
Index::Inserted(..) |
|
||||
Index::InsertedValue(..) => {
|
||||
let idx = self.table.resolve_idx(last);
|
||||
|
||||
try!(encode_not_indexed(
|
||||
idx,
|
||||
value.as_ref(),
|
||||
value.is_sensitive(),
|
||||
dst));
|
||||
encode_not_indexed(idx, value.as_ref(), value.is_sensitive(), dst)?;
|
||||
}
|
||||
Index::NotIndexed(_) => {
|
||||
let last = self.table.resolve(last);
|
||||
|
||||
try!(encode_not_indexed2(
|
||||
last.name().as_slice(),
|
||||
value.as_ref(),
|
||||
value.is_sensitive(),
|
||||
dst));
|
||||
encode_not_indexed2(last.name().as_slice(),
|
||||
value.as_ref(),
|
||||
value.is_sensitive(),
|
||||
dst)?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,24 +255,28 @@ fn encode_size_update<B: BufMut>(val: usize, dst: &mut B) -> Result<(), EncoderE
|
||||
encode_int(val, 5, 0b00100000, dst)
|
||||
}
|
||||
|
||||
fn encode_not_indexed(name: usize, value: &[u8],
|
||||
sensitive: bool, dst: &mut BytesMut)
|
||||
-> Result<(), EncoderError>
|
||||
{
|
||||
fn encode_not_indexed(
|
||||
name: usize,
|
||||
value: &[u8],
|
||||
sensitive: bool,
|
||||
dst: &mut BytesMut,
|
||||
) -> Result<(), EncoderError> {
|
||||
if sensitive {
|
||||
try!(encode_int(name, 4, 0b10000, dst));
|
||||
encode_int(name, 4, 0b10000, dst)?;
|
||||
} else {
|
||||
try!(encode_int(name, 4, 0, dst));
|
||||
encode_int(name, 4, 0, dst)?;
|
||||
}
|
||||
|
||||
try!(encode_str(value, dst));
|
||||
encode_str(value, dst)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn encode_not_indexed2(name: &[u8], value: &[u8],
|
||||
sensitive: bool, dst: &mut BytesMut)
|
||||
-> Result<(), EncoderError>
|
||||
{
|
||||
fn encode_not_indexed2(
|
||||
name: &[u8],
|
||||
value: &[u8],
|
||||
sensitive: bool,
|
||||
dst: &mut BytesMut,
|
||||
) -> Result<(), EncoderError> {
|
||||
if !dst.has_remaining_mut() {
|
||||
return Err(EncoderError::BufferOverflow);
|
||||
}
|
||||
@@ -298,8 +287,8 @@ fn encode_not_indexed2(name: &[u8], value: &[u8],
|
||||
dst.put_u8(0);
|
||||
}
|
||||
|
||||
try!(encode_str(name, dst));
|
||||
try!(encode_str(value, dst));
|
||||
encode_str(name, dst)?;
|
||||
encode_str(value, dst)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -317,7 +306,7 @@ fn encode_str(val: &[u8], dst: &mut BytesMut) -> Result<(), EncoderError> {
|
||||
dst.put_u8(0);
|
||||
|
||||
// Encode with huffman
|
||||
try!(huffman::encode(val, dst));
|
||||
huffman::encode(val, dst)?;
|
||||
|
||||
let huff_len = dst.len() - (idx + 1);
|
||||
|
||||
@@ -330,7 +319,7 @@ fn encode_str(val: &[u8], dst: &mut BytesMut) -> Result<(), EncoderError> {
|
||||
|
||||
let head_len = {
|
||||
let mut head_dst = Cursor::new(&mut buf);
|
||||
try!(encode_int(huff_len, 7, 0x80, &mut head_dst));
|
||||
encode_int(huff_len, 7, 0x80, &mut head_dst)?;
|
||||
head_dst.position() as usize
|
||||
};
|
||||
|
||||
@@ -343,8 +332,8 @@ fn encode_str(val: &[u8], dst: &mut BytesMut) -> Result<(), EncoderError> {
|
||||
|
||||
// Shift the header forward
|
||||
for i in 0..huff_len {
|
||||
let src_i = idx + 1 + (huff_len - (i+1));
|
||||
let dst_i = idx + head_len + (huff_len - (i+1));
|
||||
let src_i = idx + 1 + (huff_len - (i + 1));
|
||||
let dst_i = idx + head_len + (huff_len - (i + 1));
|
||||
dst[dst_i] = dst[src_i];
|
||||
}
|
||||
|
||||
@@ -366,9 +355,8 @@ 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
|
||||
-> Result<(), EncoderError>
|
||||
{
|
||||
dst: &mut B,
|
||||
) -> Result<(), EncoderError> {
|
||||
let mut rem = dst.remaining_mut();
|
||||
|
||||
if rem == 0 {
|
||||
@@ -444,7 +432,7 @@ mod test {
|
||||
let res = encode(&mut encoder, vec![method("PATCH")]);
|
||||
|
||||
assert_eq!(res[0], 0b01000000 | 2); // Incremental indexing w/ name pulled from table
|
||||
assert_eq!(res[1], 0x80 | 5); // header value w/ huffman coding
|
||||
assert_eq!(res[1], 0x80 | 5); // header value w/ huffman coding
|
||||
|
||||
assert_eq!("PATCH", huff_decode(&res[2..7]));
|
||||
assert_eq!(encoder.table.len(), 1);
|
||||
@@ -522,7 +510,7 @@ mod test {
|
||||
for i in 1..65 {
|
||||
let key = format!("x-hello-world-{:02}", i);
|
||||
let res = encode(&mut encoder, vec![header(&key, &key)]);
|
||||
assert_eq!(0x80 | (61 + (65-i)), res[0]);
|
||||
assert_eq!(0x80 | (61 + (65 - i)), res[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -547,7 +535,10 @@ mod test {
|
||||
let mut value = HeaderValue::from_bytes(b"12345").unwrap();
|
||||
value.set_sensitive(true);
|
||||
|
||||
let header = Header::Field { name: Some(name), value: value };
|
||||
let header = Header::Field {
|
||||
name: Some(name),
|
||||
value: value,
|
||||
};
|
||||
|
||||
// Now, try to encode the sensitive header
|
||||
|
||||
@@ -564,7 +555,10 @@ mod test {
|
||||
let mut value = HeaderValue::from_bytes(b"12345").unwrap();
|
||||
value.set_sensitive(true);
|
||||
|
||||
let header = Header::Field { name: Some(name), value: value };
|
||||
let header = Header::Field {
|
||||
name: Some(name),
|
||||
value: value,
|
||||
};
|
||||
|
||||
let mut encoder = Encoder::default();
|
||||
let res = encode(&mut encoder, vec![header]);
|
||||
@@ -576,13 +570,17 @@ mod test {
|
||||
// Using the name component of a previously indexed header (without
|
||||
// sensitive flag set)
|
||||
|
||||
let _ = encode(&mut encoder, vec![self::header("my-password", "not-so-secret")]);
|
||||
let _ = encode(&mut encoder,
|
||||
vec![self::header("my-password", "not-so-secret")]);
|
||||
|
||||
let name = "my-password".parse().unwrap();
|
||||
let mut value = HeaderValue::from_bytes(b"12345").unwrap();
|
||||
value.set_sensitive(true);
|
||||
|
||||
let header = Header::Field { name: Some(name), value: value };
|
||||
let header = Header::Field {
|
||||
name: Some(name),
|
||||
value: value,
|
||||
};
|
||||
let res = encode(&mut encoder, vec![header]);
|
||||
|
||||
assert_eq!(&[0b11111, 47], &res[..2]);
|
||||
@@ -743,16 +741,19 @@ mod test {
|
||||
fn test_nameless_header() {
|
||||
let mut encoder = Encoder::default();
|
||||
|
||||
let res = encode(&mut encoder, vec![
|
||||
Header::Field {
|
||||
name: Some("hello".parse().unwrap()),
|
||||
value: HeaderValue::from_bytes(b"world").unwrap(),
|
||||
},
|
||||
Header::Field {
|
||||
name: None,
|
||||
value: HeaderValue::from_bytes(b"zomg").unwrap(),
|
||||
},
|
||||
]);
|
||||
let res = encode(
|
||||
&mut encoder,
|
||||
vec![
|
||||
Header::Field {
|
||||
name: Some("hello".parse().unwrap()),
|
||||
value: HeaderValue::from_bytes(b"world").unwrap(),
|
||||
},
|
||||
Header::Field {
|
||||
name: None,
|
||||
value: HeaderValue::from_bytes(b"zomg").unwrap(),
|
||||
},
|
||||
],
|
||||
);
|
||||
|
||||
assert_eq!(&[0x40, 0x80 | 4], &res[0..2]);
|
||||
assert_eq!("hello", huff_decode(&res[2..6]));
|
||||
@@ -824,7 +825,10 @@ mod test {
|
||||
let name = HeaderName::from_bytes(name.as_bytes()).unwrap();
|
||||
let value = HeaderValue::from_bytes(val.as_bytes()).unwrap();
|
||||
|
||||
Header::Field { name: Some(name), value: value }
|
||||
Header::Field {
|
||||
name: Some(name),
|
||||
value: value,
|
||||
}
|
||||
}
|
||||
|
||||
fn huff_decode(src: &[u8]) -> BytesMut {
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
use super::DecoderError;
|
||||
|
||||
use bytes::Bytes;
|
||||
use http::{Method, StatusCode};
|
||||
use http::header::{HeaderName, HeaderValue};
|
||||
use bytes::Bytes;
|
||||
use string::{String, TryFrom};
|
||||
|
||||
/// HTTP/2.0 Header
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub enum Header<T = HeaderName> {
|
||||
Field {
|
||||
name: T,
|
||||
value: HeaderValue,
|
||||
},
|
||||
Field { name: T, value: HeaderValue },
|
||||
// TODO: Change these types to `http::uri` types.
|
||||
Authority(String<Bytes>),
|
||||
Method(Method),
|
||||
@@ -41,14 +38,25 @@ impl Header<Option<HeaderName>> {
|
||||
use self::Header::*;
|
||||
|
||||
Ok(match self {
|
||||
Field { name: Some(n), value } => Field { name: n, value: value },
|
||||
Field { name: None, value } => return Err(value),
|
||||
Authority(v) => Authority(v),
|
||||
Method(v) => Method(v),
|
||||
Scheme(v) => Scheme(v),
|
||||
Path(v) => Path(v),
|
||||
Status(v) => Status(v),
|
||||
})
|
||||
Field {
|
||||
name: Some(n),
|
||||
value,
|
||||
} => {
|
||||
Field {
|
||||
name: n,
|
||||
value: value,
|
||||
}
|
||||
}
|
||||
Field {
|
||||
name: None,
|
||||
value,
|
||||
} => return Err(value),
|
||||
Authority(v) => Authority(v),
|
||||
Method(v) => Method(v),
|
||||
Scheme(v) => Scheme(v),
|
||||
Path(v) => Path(v),
|
||||
Status(v) => Status(v),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,65 +65,59 @@ impl Header {
|
||||
if name[0] == b':' {
|
||||
match &name[1..] {
|
||||
b"authority" => {
|
||||
let value = try!(String::try_from(value));
|
||||
let value = String::try_from(value)?;
|
||||
Ok(Header::Authority(value))
|
||||
}
|
||||
b"method" => {
|
||||
let method = try!(Method::from_bytes(&value));
|
||||
let method = Method::from_bytes(&value)?;
|
||||
Ok(Header::Method(method))
|
||||
}
|
||||
b"scheme" => {
|
||||
let value = try!(String::try_from(value));
|
||||
let value = String::try_from(value)?;
|
||||
Ok(Header::Scheme(value))
|
||||
}
|
||||
b"path" => {
|
||||
let value = try!(String::try_from(value));
|
||||
let value = String::try_from(value)?;
|
||||
Ok(Header::Path(value))
|
||||
}
|
||||
b"status" => {
|
||||
let status = try!(StatusCode::from_bytes(&value));
|
||||
let status = StatusCode::from_bytes(&value)?;
|
||||
Ok(Header::Status(status))
|
||||
}
|
||||
_ => {
|
||||
Err(DecoderError::InvalidPseudoheader)
|
||||
}
|
||||
_ => Err(DecoderError::InvalidPseudoheader),
|
||||
}
|
||||
} else {
|
||||
// HTTP/2 requires lower case header names
|
||||
let name = try!(HeaderName::from_lowercase(&name));
|
||||
let value = try!(HeaderValue::from_bytes(&value));
|
||||
let name = HeaderName::from_lowercase(&name)?;
|
||||
let value = HeaderValue::from_bytes(&value)?;
|
||||
|
||||
Ok(Header::Field { name: name, value: value })
|
||||
Ok(Header::Field {
|
||||
name: name,
|
||||
value: value,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
match *self {
|
||||
Header::Field { ref name, ref value } => {
|
||||
len(name, value)
|
||||
}
|
||||
Header::Authority(ref v) => {
|
||||
32 + 10 + v.len()
|
||||
}
|
||||
Header::Method(ref v) => {
|
||||
32 + 7 + v.as_ref().len()
|
||||
}
|
||||
Header::Scheme(ref v) => {
|
||||
32 + 7 + v.len()
|
||||
}
|
||||
Header::Path(ref v) => {
|
||||
32 + 5 + v.len()
|
||||
}
|
||||
Header::Status(_) => {
|
||||
32 + 7 + 3
|
||||
}
|
||||
Header::Field {
|
||||
ref name,
|
||||
ref value,
|
||||
} => len(name, value),
|
||||
Header::Authority(ref v) => 32 + 10 + v.len(),
|
||||
Header::Method(ref v) => 32 + 7 + v.as_ref().len(),
|
||||
Header::Scheme(ref v) => 32 + 7 + v.len(),
|
||||
Header::Path(ref v) => 32 + 5 + v.len(),
|
||||
Header::Status(_) => 32 + 7 + 3,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the header name
|
||||
pub fn name(&self) -> Name {
|
||||
match *self {
|
||||
Header::Field { ref name, .. } => Name::Field(name),
|
||||
Header::Field {
|
||||
ref name, ..
|
||||
} => Name::Field(name),
|
||||
Header::Authority(..) => Name::Authority,
|
||||
Header::Method(..) => Name::Method,
|
||||
Header::Scheme(..) => Name::Scheme,
|
||||
@@ -126,7 +128,9 @@ impl Header {
|
||||
|
||||
pub fn value_slice(&self) -> &[u8] {
|
||||
match *self {
|
||||
Header::Field { ref value, .. } => value.as_ref(),
|
||||
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(),
|
||||
@@ -137,10 +141,14 @@ impl Header {
|
||||
|
||||
pub fn value_eq(&self, other: &Header) -> bool {
|
||||
match *self {
|
||||
Header::Field { ref value, .. } => {
|
||||
Header::Field {
|
||||
ref value, ..
|
||||
} => {
|
||||
let a = value;
|
||||
match *other {
|
||||
Header::Field { ref value, .. } => a == value,
|
||||
Header::Field {
|
||||
ref value, ..
|
||||
} => a == value,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@@ -179,7 +187,9 @@ impl Header {
|
||||
|
||||
pub fn is_sensitive(&self) -> bool {
|
||||
match *self {
|
||||
Header::Field { ref value, .. } => value.is_sensitive(),
|
||||
Header::Field {
|
||||
ref value, ..
|
||||
} => value.is_sensitive(),
|
||||
// TODO: Technically these other header values can be sensitive too.
|
||||
_ => false,
|
||||
}
|
||||
@@ -189,17 +199,19 @@ impl Header {
|
||||
use http::header;
|
||||
|
||||
match *self {
|
||||
Header::Field { ref name, .. } => {
|
||||
Header::Field {
|
||||
ref name, ..
|
||||
} => {
|
||||
match *name {
|
||||
header::AGE |
|
||||
header::AUTHORIZATION |
|
||||
header::CONTENT_LENGTH |
|
||||
header::ETAG |
|
||||
header::IF_MODIFIED_SINCE |
|
||||
header::IF_NONE_MATCH |
|
||||
header::LOCATION |
|
||||
header::COOKIE |
|
||||
header::SET_COOKIE => true,
|
||||
header::AUTHORIZATION |
|
||||
header::CONTENT_LENGTH |
|
||||
header::ETAG |
|
||||
header::IF_MODIFIED_SINCE |
|
||||
header::IF_NONE_MATCH |
|
||||
header::LOCATION |
|
||||
header::COOKIE |
|
||||
header::SET_COOKIE => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@@ -213,7 +225,15 @@ impl Header {
|
||||
impl From<Header> for Header<Option<HeaderName>> {
|
||||
fn from(src: Header) -> Self {
|
||||
match src {
|
||||
Header::Field { name, value } => Header::Field { name: Some(name), value },
|
||||
Header::Field {
|
||||
name,
|
||||
value,
|
||||
} => {
|
||||
Header::Field {
|
||||
name: Some(name),
|
||||
value,
|
||||
}
|
||||
}
|
||||
Header::Authority(v) => Header::Authority(v),
|
||||
Header::Method(v) => Header::Method(v),
|
||||
Header::Scheme(v) => Header::Scheme(v),
|
||||
@@ -228,22 +248,14 @@ impl<'a> Name<'a> {
|
||||
match self {
|
||||
Name::Field(name) => {
|
||||
Ok(Header::Field {
|
||||
name: name.clone(),
|
||||
value: try!(HeaderValue::from_bytes(&*value)),
|
||||
})
|
||||
}
|
||||
Name::Authority => {
|
||||
Ok(Header::Authority(try!(String::try_from(value))))
|
||||
}
|
||||
Name::Method => {
|
||||
Ok(Header::Method(try!(Method::from_bytes(&*value))))
|
||||
}
|
||||
Name::Scheme => {
|
||||
Ok(Header::Scheme(try!(String::try_from(value))))
|
||||
}
|
||||
Name::Path => {
|
||||
Ok(Header::Path(try!(String::try_from(value))))
|
||||
name: name.clone(),
|
||||
value: HeaderValue::from_bytes(&*value)?,
|
||||
})
|
||||
}
|
||||
Name::Authority => Ok(Header::Authority(String::try_from(value)?)),
|
||||
Name::Method => Ok(Header::Method(Method::from_bytes(&*value)?)),
|
||||
Name::Scheme => Ok(Header::Scheme(String::try_from(value)?)),
|
||||
Name::Path => Ok(Header::Path(String::try_from(value)?)),
|
||||
Name::Status => {
|
||||
match StatusCode::from_bytes(&value) {
|
||||
Ok(status) => Ok(Header::Status(status)),
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
mod table;
|
||||
|
||||
use self::table::{ENCODE_TABLE, DECODE_TABLE};
|
||||
use self::table::{DECODE_TABLE, ENCODE_TABLE};
|
||||
use hpack::{DecoderError, EncoderError};
|
||||
|
||||
use bytes::{BytesMut, BufMut};
|
||||
use bytes::{BufMut, BytesMut};
|
||||
|
||||
// Constructed in the generated `table.rs` file
|
||||
struct Decoder {
|
||||
@@ -24,11 +24,11 @@ pub fn decode(src: &[u8], buf: &mut BytesMut) -> Result<BytesMut, DecoderError>
|
||||
buf.reserve(src.len() << 1);
|
||||
|
||||
for b in src {
|
||||
if let Some(b) = try!(decoder.decode4(b >> 4)) {
|
||||
if let Some(b) = decoder.decode4(b >> 4)? {
|
||||
buf.put_u8(b);
|
||||
}
|
||||
|
||||
if let Some(b) = try!(decoder.decode4(b & 0xf)) {
|
||||
if let Some(b) = decoder.decode4(b & 0xf)? {
|
||||
buf.put_u8(b);
|
||||
}
|
||||
}
|
||||
@@ -161,10 +161,27 @@ mod test {
|
||||
#[test]
|
||||
fn encode_decode_str() {
|
||||
const DATA: &'static [&'static str] = &[
|
||||
"hello world", ":method", ":scheme", ":authority", "yahoo.co.jp", "GET", "http", ":path", "/images/top/sp2/cmn/logo-ns-130528.png",
|
||||
"example.com", "hpack-test", "xxxxxxx1", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0",
|
||||
"accept", "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "cookie", "B=76j09a189a6h4&b=3&s=0b",
|
||||
"TE", "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi non bibendum libero. Etiam ultrices lorem ut",
|
||||
"hello world",
|
||||
":method",
|
||||
":scheme",
|
||||
":authority",
|
||||
"yahoo.co.jp",
|
||||
"GET",
|
||||
"http",
|
||||
":path",
|
||||
"/images/top/sp2/cmn/logo-ns-130528.png",
|
||||
"example.com",
|
||||
"hpack-test",
|
||||
"xxxxxxx1",
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0",
|
||||
"accept",
|
||||
"Accept",
|
||||
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
||||
"cookie",
|
||||
"B=76j09a189a6h4&b=3&s=0b",
|
||||
"TE",
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi non bibendum libero. \
|
||||
Etiam ultrices lorem ut.",
|
||||
];
|
||||
|
||||
for s in DATA {
|
||||
@@ -180,9 +197,8 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn encode_decode_u8() {
|
||||
const DATA: &'static [&'static [u8]] = &[
|
||||
b"\0", b"\0\0\0", b"\0\x01\x02\x03\x04\x05", b"\xFF\xF8",
|
||||
];
|
||||
const DATA: &'static [&'static [u8]] =
|
||||
&[b"\0", b"\0\0\0", b"\0\x01\x02\x03\x04\x05", b"\xFF\xF8"];
|
||||
|
||||
for s in DATA {
|
||||
let mut dst = Vec::with_capacity(s.len());
|
||||
|
||||
@@ -7,6 +7,6 @@ mod table;
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
pub use self::encoder::{Encoder, Encode, EncoderError, EncodeState};
|
||||
pub use self::header::Header;
|
||||
pub use self::decoder::{Decoder, DecoderError};
|
||||
pub use self::encoder::{Encode, EncodeState, Encoder, EncoderError};
|
||||
pub use self::header::Header;
|
||||
|
||||
@@ -83,9 +83,7 @@ impl Table {
|
||||
max_size: max_size,
|
||||
}
|
||||
} else {
|
||||
let capacity = cmp::max(
|
||||
to_raw_capacity(capacity).next_power_of_two(),
|
||||
8);
|
||||
let capacity = cmp::max(to_raw_capacity(capacity).next_power_of_two(), 8);
|
||||
|
||||
Table {
|
||||
mask: capacity.wrapping_sub(1),
|
||||
@@ -203,12 +201,7 @@ impl Table {
|
||||
});
|
||||
}
|
||||
|
||||
fn index_occupied(&mut self,
|
||||
header: Header,
|
||||
hash: HashValue,
|
||||
mut index: usize)
|
||||
-> Index
|
||||
{
|
||||
fn index_occupied(&mut self, header: Header, hash: HashValue, mut index: usize) -> Index {
|
||||
debug_assert!(self.assert_valid_state("top"));
|
||||
|
||||
// There already is a match for the given header name. Check if a value
|
||||
@@ -256,14 +249,14 @@ impl Table {
|
||||
}
|
||||
}
|
||||
|
||||
fn index_vacant(&mut self,
|
||||
header: Header,
|
||||
hash: HashValue,
|
||||
mut dist: usize,
|
||||
mut probe: usize,
|
||||
statik: Option<(usize, bool)>)
|
||||
-> Index
|
||||
{
|
||||
fn index_vacant(
|
||||
&mut self,
|
||||
header: Header,
|
||||
hash: HashValue,
|
||||
mut dist: usize,
|
||||
mut probe: usize,
|
||||
statik: Option<(usize, bool)>,
|
||||
) -> Index {
|
||||
if header.is_sensitive() {
|
||||
return Index::new(statik, header);
|
||||
}
|
||||
@@ -299,10 +292,11 @@ impl Table {
|
||||
|
||||
let pos_idx = 0usize.wrapping_sub(self.inserted);
|
||||
|
||||
let prev = mem::replace(&mut self.indices[probe], Some(Pos {
|
||||
index: pos_idx,
|
||||
hash: hash,
|
||||
}));
|
||||
let prev = mem::replace(&mut self.indices[probe],
|
||||
Some(Pos {
|
||||
index: pos_idx,
|
||||
hash: hash,
|
||||
}));
|
||||
|
||||
if let Some(mut prev) = prev {
|
||||
// Shift forward
|
||||
@@ -331,10 +325,10 @@ impl Table {
|
||||
self.inserted = self.inserted.wrapping_add(1);
|
||||
|
||||
self.slots.push_front(Slot {
|
||||
hash: hash,
|
||||
header: header,
|
||||
next: None,
|
||||
});
|
||||
hash: hash,
|
||||
header: header,
|
||||
next: None,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn resize(&mut self, size: usize) {
|
||||
@@ -383,11 +377,12 @@ impl Table {
|
||||
// Update the size
|
||||
self.size -= slot.header.len();
|
||||
|
||||
debug_assert_eq!(
|
||||
self.indices.iter().filter_map(|p| *p)
|
||||
.filter(|p| p.index == pos_idx)
|
||||
.count(),
|
||||
1);
|
||||
debug_assert_eq!(self.indices
|
||||
.iter()
|
||||
.filter_map(|p| *p)
|
||||
.filter(|p| p.index == pos_idx)
|
||||
.count(),
|
||||
1);
|
||||
|
||||
// Find the associated position
|
||||
probe_loop!(probe < self.indices.len(), {
|
||||
@@ -500,12 +495,12 @@ impl Table {
|
||||
}
|
||||
|
||||
debug_assert!({
|
||||
let them = self.indices[probe].unwrap();
|
||||
let their_distance = probe_distance(self.mask, them.hash, probe);
|
||||
let our_distance = probe_distance(self.mask, pos.hash, probe);
|
||||
let them = self.indices[probe].unwrap();
|
||||
let their_distance = probe_distance(self.mask, them.hash, probe);
|
||||
let our_distance = probe_distance(self.mask, pos.hash, probe);
|
||||
|
||||
their_distance >= our_distance
|
||||
});
|
||||
their_distance >= our_distance
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -584,8 +579,10 @@ impl Table {
|
||||
}
|
||||
|
||||
assert!(dist <= their_dist,
|
||||
"could not find entry; actual={}; desired={}; probe={}, dist={}; their_dist={}; index={}; msg={}",
|
||||
actual, desired, probe, dist, their_dist, index.wrapping_sub(self.inserted), msg);
|
||||
"could not find entry; actual={}; desired={};" +
|
||||
"probe={}, dist={}; their_dist={}; index={}; msg={}",
|
||||
actual, desired, probe, dist, their_dist,
|
||||
index.wrapping_sub(self.inserted), msg);
|
||||
|
||||
dist += 1;
|
||||
});
|
||||
@@ -661,7 +658,10 @@ fn hash_header(header: &Header) -> HashValue {
|
||||
/// boolean representing if the value matched as well.
|
||||
fn index_static(header: &Header) -> Option<(usize, bool)> {
|
||||
match *header {
|
||||
Header::Field { ref name, ref value } => {
|
||||
Header::Field {
|
||||
ref name,
|
||||
ref value,
|
||||
} => {
|
||||
match *name {
|
||||
header::ACCEPT_CHARSET => Some((15, false)),
|
||||
header::ACCEPT_ENCODING => {
|
||||
|
||||
@@ -2,15 +2,15 @@ extern crate bytes;
|
||||
extern crate hex;
|
||||
extern crate serde_json;
|
||||
|
||||
use hpack::{Header, Decoder, Encoder};
|
||||
use hpack::{Decoder, Encoder, Header};
|
||||
|
||||
use self::bytes::BytesMut;
|
||||
use self::hex::FromHex;
|
||||
use self::serde_json::Value;
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::io::Cursor;
|
||||
use std::io::prelude::*;
|
||||
use std::path::Path;
|
||||
use std::str;
|
||||
|
||||
@@ -27,7 +27,10 @@ fn test_story(story: Value) {
|
||||
let story = story.as_object().unwrap();
|
||||
|
||||
if let Some(cases) = story.get("cases") {
|
||||
let mut cases: Vec<_> = cases.as_array().unwrap().iter()
|
||||
let mut cases: Vec<_> = cases
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|case| {
|
||||
let case = case.as_object().unwrap();
|
||||
|
||||
@@ -37,8 +40,11 @@ fn test_story(story: Value) {
|
||||
let wire = case.get("wire").unwrap().as_str().unwrap();
|
||||
let wire: Vec<u8> = FromHex::from_hex(wire.as_bytes()).unwrap();
|
||||
|
||||
let expect: Vec<_> = case.get("headers").unwrap()
|
||||
.as_array().unwrap().iter()
|
||||
let expect: Vec<_> = case.get("headers")
|
||||
.unwrap()
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|h| {
|
||||
let h = h.as_object().unwrap();
|
||||
let (name, val) = h.iter().next().unwrap();
|
||||
@@ -67,11 +73,13 @@ fn test_story(story: Value) {
|
||||
decoder.queue_size_update(size);
|
||||
}
|
||||
|
||||
decoder.decode(&mut Cursor::new(case.wire.clone().into()), |e| {
|
||||
let (name, value) = expect.remove(0);
|
||||
assert_eq!(name, key_str(&e));
|
||||
assert_eq!(value, value_str(&e));
|
||||
}).unwrap();
|
||||
decoder
|
||||
.decode(&mut Cursor::new(case.wire.clone().into()), |e| {
|
||||
let (name, value) = expect.remove(0);
|
||||
assert_eq!(name, key_str(&e));
|
||||
assert_eq!(value, value_str(&e));
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(0, expect.len());
|
||||
}
|
||||
@@ -88,15 +96,22 @@ fn test_story(story: Value) {
|
||||
decoder.queue_size_update(size);
|
||||
}
|
||||
|
||||
let mut input: Vec<_> = case.expect.iter().map(|&(ref name, ref value)| {
|
||||
Header::new(name.clone().into(), value.clone().into()).unwrap().into()
|
||||
}).collect();
|
||||
let mut input: Vec<_> = case.expect
|
||||
.iter()
|
||||
.map(|&(ref name, ref value)| {
|
||||
Header::new(name.clone().into(), value.clone().into())
|
||||
.unwrap()
|
||||
.into()
|
||||
})
|
||||
.collect();
|
||||
|
||||
encoder.encode(None, &mut input.clone().into_iter(), &mut buf);
|
||||
|
||||
decoder.decode(&mut Cursor::new(buf.into()), |e| {
|
||||
assert_eq!(e, input.remove(0).reify().unwrap());
|
||||
}).unwrap();
|
||||
decoder
|
||||
.decode(&mut Cursor::new(buf.into()), |e| {
|
||||
assert_eq!(e, input.remove(0).reify().unwrap());
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(0, input.len());
|
||||
}
|
||||
@@ -112,7 +127,9 @@ struct Case {
|
||||
|
||||
fn key_str(e: &Header) -> &str {
|
||||
match *e {
|
||||
Header::Field { ref name, .. } => name.as_str(),
|
||||
Header::Field {
|
||||
ref name, ..
|
||||
} => name.as_str(),
|
||||
Header::Authority(..) => ":authority",
|
||||
Header::Method(..) => ":method",
|
||||
Header::Scheme(..) => ":scheme",
|
||||
@@ -123,7 +140,9 @@ fn key_str(e: &Header) -> &str {
|
||||
|
||||
fn value_str(e: &Header) -> &str {
|
||||
match *e {
|
||||
Header::Field { ref value, .. } => value.to_str().unwrap(),
|
||||
Header::Field {
|
||||
ref value, ..
|
||||
} => value.to_str().unwrap(),
|
||||
Header::Authority(ref v) => &**v,
|
||||
Header::Method(ref m) => m.as_str(),
|
||||
Header::Scheme(ref v) => &**v,
|
||||
|
||||
@@ -2,13 +2,13 @@ extern crate bytes;
|
||||
extern crate quickcheck;
|
||||
extern crate rand;
|
||||
|
||||
use hpack::{Header, Decoder, Encoder, Encode};
|
||||
use hpack::{Decoder, Encode, Encoder, Header};
|
||||
|
||||
use http::header::{HeaderName, HeaderValue};
|
||||
|
||||
use self::bytes::{BytesMut, Bytes};
|
||||
use self::quickcheck::{QuickCheck, Arbitrary, Gen, TestResult};
|
||||
use self::rand::{StdRng, Rng, SeedableRng};
|
||||
use self::bytes::{Bytes, BytesMut};
|
||||
use self::quickcheck::{Arbitrary, Gen, QuickCheck, TestResult};
|
||||
use self::rand::{Rng, SeedableRng, StdRng};
|
||||
|
||||
use std::io::Cursor;
|
||||
|
||||
@@ -130,8 +130,7 @@ impl FuzzHpack {
|
||||
let mut index = None;
|
||||
let mut input = frame.headers.into_iter();
|
||||
|
||||
let mut buf = BytesMut::with_capacity(
|
||||
chunks.pop().unwrap_or(MAX_CHUNK));
|
||||
let mut buf = BytesMut::with_capacity(chunks.pop().unwrap_or(MAX_CHUNK));
|
||||
|
||||
if let Some(max) = frame.resizes.iter().max() {
|
||||
decoder.queue_size_update(*max);
|
||||
@@ -149,20 +148,23 @@ impl FuzzHpack {
|
||||
index = Some(i);
|
||||
|
||||
// Decode the chunk!
|
||||
decoder.decode(&mut Cursor::new(buf.into()), |e| {
|
||||
assert_eq!(e, expect.remove(0).reify().unwrap());
|
||||
}).unwrap();
|
||||
decoder
|
||||
.decode(&mut Cursor::new(buf.into()), |e| {
|
||||
assert_eq!(e, expect.remove(0).reify().unwrap());
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
buf = BytesMut::with_capacity(
|
||||
chunks.pop().unwrap_or(MAX_CHUNK));
|
||||
buf = BytesMut::with_capacity(chunks.pop().unwrap_or(MAX_CHUNK));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Decode the chunk!
|
||||
decoder.decode(&mut Cursor::new(buf.into()), |e| {
|
||||
assert_eq!(e, expect.remove(0).reify().unwrap());
|
||||
}).unwrap();
|
||||
decoder
|
||||
.decode(&mut Cursor::new(buf.into()), |e| {
|
||||
assert_eq!(e, expect.remove(0).reify().unwrap());
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
assert_eq!(0, expect.len());
|
||||
@@ -193,9 +195,9 @@ fn gen_header(g: &mut StdRng) -> Header<Option<HeaderName>> {
|
||||
4 => Method::DELETE,
|
||||
5 => {
|
||||
let n: usize = g.gen_range(3, 7);
|
||||
let bytes: Vec<u8> = (0..n).map(|_| {
|
||||
g.choose(b"ABCDEFGHIJKLMNOPQRSTUVWXYZ").unwrap().clone()
|
||||
}).collect();
|
||||
let bytes: Vec<u8> = (0..n)
|
||||
.map(|_| g.choose(b"ABCDEFGHIJKLMNOPQRSTUVWXYZ").unwrap().clone())
|
||||
.collect();
|
||||
|
||||
Method::from_bytes(&bytes).unwrap()
|
||||
}
|
||||
@@ -237,7 +239,10 @@ fn gen_header(g: &mut StdRng) -> Header<Option<HeaderName>> {
|
||||
value.set_sensitive(true);
|
||||
}
|
||||
|
||||
Header::Field { name: Some(name), value: value }
|
||||
Header::Field {
|
||||
name: Some(name),
|
||||
value: value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,7 +325,8 @@ fn gen_header_name(g: &mut StdRng) -> HeaderName {
|
||||
header::X_DNS_PREFETCH_CONTROL,
|
||||
header::X_FRAME_OPTIONS,
|
||||
header::X_XSS_PROTECTION,
|
||||
]).unwrap().clone()
|
||||
]).unwrap()
|
||||
.clone()
|
||||
} else {
|
||||
let value = gen_string(g, 1, 25);
|
||||
HeaderName::from_bytes(value.as_bytes()).unwrap()
|
||||
@@ -333,10 +339,14 @@ fn gen_header_value(g: &mut StdRng) -> HeaderValue {
|
||||
}
|
||||
|
||||
fn gen_string(g: &mut StdRng, min: usize, max: usize) -> String {
|
||||
let bytes: Vec<_> = (min..max).map(|_| {
|
||||
// Chars to pick from
|
||||
g.choose(b"ABCDEFGHIJKLMNOPQRSTUVabcdefghilpqrstuvwxyz----").unwrap().clone()
|
||||
}).collect();
|
||||
let bytes: Vec<_> = (min..max)
|
||||
.map(|_| {
|
||||
// Chars to pick from
|
||||
g.choose(b"ABCDEFGHIJKLMNOPQRSTUVabcdefghilpqrstuvwxyz----")
|
||||
.unwrap()
|
||||
.clone()
|
||||
})
|
||||
.collect();
|
||||
|
||||
String::from_utf8(bytes).unwrap()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user