A bunch of work
This commit is contained in:
@@ -17,7 +17,10 @@ pub enum Encode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct EncodeState(Index);
|
pub struct EncodeState {
|
||||||
|
index: Index,
|
||||||
|
value: Option<HeaderValue>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub enum EncoderError {
|
pub enum EncoderError {
|
||||||
@@ -74,7 +77,7 @@ impl Encoder {
|
|||||||
/// Encode a set of headers into the provide buffer
|
/// Encode a set of headers into the provide buffer
|
||||||
pub fn encode<I>(&mut self, resume: Option<EncodeState>, headers: &mut I, dst: &mut BytesMut)
|
pub fn encode<I>(&mut self, resume: Option<EncodeState>, headers: &mut I, dst: &mut BytesMut)
|
||||||
-> Result<Encode, EncoderError>
|
-> Result<Encode, EncoderError>
|
||||||
where I: Iterator<Item=Header>,
|
where I: Iterator<Item=Header<Option<HeaderName>>>,
|
||||||
{
|
{
|
||||||
let len = dst.len();
|
let len = dst.len();
|
||||||
|
|
||||||
@@ -89,28 +92,62 @@ impl Encoder {
|
|||||||
if let Some(resume) = resume {
|
if let Some(resume) = resume {
|
||||||
let len = dst.len();
|
let len = dst.len();
|
||||||
|
|
||||||
match self.encode_header(&resume.0, dst) {
|
if let Some(ref value) = resume.value {
|
||||||
Err(EncoderError::BufferOverflow) => {
|
unimplemented!();
|
||||||
dst.truncate(len);
|
} else {
|
||||||
return Ok(Encode::Partial(resume));
|
// Encode the header
|
||||||
|
match self.encode_header(&resume.index, dst) {
|
||||||
|
Err(EncoderError::BufferOverflow) => {
|
||||||
|
dst.truncate(len);
|
||||||
|
return Ok(Encode::Partial(resume));
|
||||||
|
}
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
Ok(_) => {}
|
||||||
}
|
}
|
||||||
Err(e) => return Err(e),
|
|
||||||
Ok(_) => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut last_index = None;
|
||||||
|
|
||||||
for header in headers {
|
for header in headers {
|
||||||
let len = dst.len();
|
let len = dst.len();
|
||||||
let index = self.table.index(header);
|
|
||||||
|
|
||||||
match self.encode_header(&index, dst) {
|
match header.reify() {
|
||||||
Err(EncoderError::BufferOverflow) => {
|
// The header has an associated name. In which case, try to
|
||||||
dst.truncate(len);
|
// index it in the table.
|
||||||
return Ok(Encode::Partial(EncodeState(index)));
|
Ok(header) => {
|
||||||
|
let index = self.table.index(header);
|
||||||
|
let res = self.encode_header(&index, dst);
|
||||||
|
|
||||||
|
if try!(is_buffer_overflow(res)) {
|
||||||
|
dst.truncate(len);
|
||||||
|
return Ok(Encode::Partial(EncodeState {
|
||||||
|
index: index,
|
||||||
|
value: None,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
last_index = Some(index);
|
||||||
}
|
}
|
||||||
Err(e) => return Err(e),
|
// The header does not have an associated name. This means that
|
||||||
Ok(_) => {}
|
// the name is the same as the previously yielded header. In
|
||||||
}
|
// 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);
|
||||||
|
|
||||||
|
if try!(is_buffer_overflow(res)) {
|
||||||
|
dst.truncate(len);
|
||||||
|
return Ok(Encode::Partial(EncodeState {
|
||||||
|
index: last_index.unwrap(),
|
||||||
|
value: Some(value),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Encode::Full)
|
Ok(Encode::Full)
|
||||||
@@ -145,13 +182,11 @@ impl Encoder {
|
|||||||
Index::Name(idx, _) => {
|
Index::Name(idx, _) => {
|
||||||
let header = self.table.resolve(&index);
|
let header = self.table.resolve(&index);
|
||||||
|
|
||||||
if header.is_sensitive() {
|
try!(encode_not_indexed(
|
||||||
try!(encode_int(idx, 4, 0b10000, dst));
|
idx,
|
||||||
} else {
|
header.value_slice(),
|
||||||
try!(encode_int(idx, 4, 0, dst));
|
header.is_sensitive(),
|
||||||
}
|
dst));
|
||||||
|
|
||||||
try!(encode_str(header.value_slice(), dst));
|
|
||||||
}
|
}
|
||||||
Index::Inserted(idx) => {
|
Index::Inserted(idx) => {
|
||||||
let header = self.table.resolve(&index);
|
let header = self.table.resolve(&index);
|
||||||
@@ -178,18 +213,41 @@ impl Encoder {
|
|||||||
Index::NotIndexed(_) => {
|
Index::NotIndexed(_) => {
|
||||||
let header = self.table.resolve(&index);
|
let header = self.table.resolve(&index);
|
||||||
|
|
||||||
if !dst.has_remaining_mut() {
|
try!(encode_not_indexed2(
|
||||||
return Err(EncoderError::BufferOverflow);
|
header.name().as_slice(),
|
||||||
}
|
header.value_slice(),
|
||||||
|
header.is_sensitive(),
|
||||||
|
dst));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if header.is_sensitive() {
|
Ok(())
|
||||||
dst.put_u8(0b10000);
|
}
|
||||||
} else {
|
|
||||||
dst.put_u8(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
try!(encode_str(header.name().as_slice(), dst));
|
fn encode_header_without_name(&mut self, last: &Index,
|
||||||
try!(encode_str(header.value_slice(), dst));
|
value: &HeaderValue, dst: &mut BytesMut)
|
||||||
|
-> Result<(), EncoderError>
|
||||||
|
{
|
||||||
|
match *last {
|
||||||
|
Index::Indexed(idx, ..) |
|
||||||
|
Index::Name(idx, ..) |
|
||||||
|
Index::Inserted(idx) |
|
||||||
|
Index::InsertedValue(idx, ..) =>
|
||||||
|
{
|
||||||
|
try!(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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,6 +261,43 @@ impl Default for Encoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn encode_size_update<B: BufMut>(val: usize, dst: &mut B) -> Result<(), EncoderError> {
|
||||||
|
encode_int(val, 5, 0b00100000, dst)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encode_not_indexed(name: usize, value: &[u8],
|
||||||
|
sensitive: bool, dst: &mut BytesMut)
|
||||||
|
-> Result<(), EncoderError>
|
||||||
|
{
|
||||||
|
if sensitive {
|
||||||
|
try!(encode_int(name, 4, 0b10000, dst));
|
||||||
|
} else {
|
||||||
|
try!(encode_int(name, 4, 0, dst));
|
||||||
|
}
|
||||||
|
|
||||||
|
try!(encode_str(value, dst));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encode_not_indexed2(name: &[u8], value: &[u8],
|
||||||
|
sensitive: bool, dst: &mut BytesMut)
|
||||||
|
-> Result<(), EncoderError>
|
||||||
|
{
|
||||||
|
if !dst.has_remaining_mut() {
|
||||||
|
return Err(EncoderError::BufferOverflow);
|
||||||
|
}
|
||||||
|
|
||||||
|
if sensitive {
|
||||||
|
dst.put_u8(0b10000);
|
||||||
|
} else {
|
||||||
|
dst.put_u8(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
try!(encode_str(name, dst));
|
||||||
|
try!(encode_str(value, dst));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn encode_str(val: &[u8], dst: &mut BytesMut) -> Result<(), EncoderError> {
|
fn encode_str(val: &[u8], dst: &mut BytesMut) -> Result<(), EncoderError> {
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
@@ -261,10 +356,6 @@ fn encode_str(val: &[u8], dst: &mut BytesMut) -> Result<(), EncoderError> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode_size_update<B: BufMut>(val: usize, dst: &mut B) -> Result<(), EncoderError> {
|
|
||||||
encode_int(val, 5, 0b00100000, dst)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Encode an integer into the given destination buffer
|
/// Encode an integer into the given destination buffer
|
||||||
fn encode_int<B: BufMut>(
|
fn encode_int<B: BufMut>(
|
||||||
mut value: usize, // The integer to encode
|
mut value: usize, // The integer to encode
|
||||||
@@ -321,6 +412,14 @@ fn encode_int_one_byte(value: usize, prefix_bits: usize) -> bool {
|
|||||||
value < (1 << prefix_bits) - 1
|
value < (1 << prefix_bits) - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_buffer_overflow(res: Result<(), EncoderError>) -> Result<bool, EncoderError> {
|
||||||
|
match res {
|
||||||
|
Err(EncoderError::BufferOverflow) => Ok(true),
|
||||||
|
Err(e) => Err(e),
|
||||||
|
Ok(_) => Ok(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -452,7 +551,7 @@ mod test {
|
|||||||
let mut value = HeaderValue::try_from_bytes(b"12345").unwrap();
|
let mut value = HeaderValue::try_from_bytes(b"12345").unwrap();
|
||||||
value.set_sensitive(true);
|
value.set_sensitive(true);
|
||||||
|
|
||||||
let header = Header::Field { name: name, value: value };
|
let header = Header::Field { name: Some(name), value: value };
|
||||||
|
|
||||||
// Now, try to encode the sensitive header
|
// Now, try to encode the sensitive header
|
||||||
|
|
||||||
@@ -469,7 +568,7 @@ mod test {
|
|||||||
let mut value = HeaderValue::try_from_bytes(b"12345").unwrap();
|
let mut value = HeaderValue::try_from_bytes(b"12345").unwrap();
|
||||||
value.set_sensitive(true);
|
value.set_sensitive(true);
|
||||||
|
|
||||||
let header = Header::Field { name: name, value: value };
|
let header = Header::Field { name: Some(name), value: value };
|
||||||
|
|
||||||
let mut encoder = Encoder::default();
|
let mut encoder = Encoder::default();
|
||||||
let res = encode(&mut encoder, vec![header]);
|
let res = encode(&mut encoder, vec![header]);
|
||||||
@@ -487,7 +586,7 @@ mod test {
|
|||||||
let mut value = HeaderValue::try_from_bytes(b"12345").unwrap();
|
let mut value = HeaderValue::try_from_bytes(b"12345").unwrap();
|
||||||
value.set_sensitive(true);
|
value.set_sensitive(true);
|
||||||
|
|
||||||
let header = Header::Field { name: name, value: value };
|
let header = Header::Field { name: Some(name), value: value };
|
||||||
let res = encode(&mut encoder, vec![header]);
|
let res = encode(&mut encoder, vec![header]);
|
||||||
|
|
||||||
assert_eq!(&[0b11111, 47], &res[..2]);
|
assert_eq!(&[0b11111, 47], &res[..2]);
|
||||||
@@ -649,23 +748,23 @@ mod test {
|
|||||||
// Not sure what the best way to do this is.
|
// Not sure what the best way to do this is.
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode(e: &mut Encoder, hdrs: Vec<Header>) -> BytesMut {
|
fn encode(e: &mut Encoder, hdrs: Vec<Header<Option<HeaderName>>>) -> BytesMut {
|
||||||
let mut dst = BytesMut::with_capacity(1024);
|
let mut dst = BytesMut::with_capacity(1024);
|
||||||
e.encode(None, &mut hdrs.into_iter(), &mut dst);
|
e.encode(None, &mut hdrs.into_iter(), &mut dst);
|
||||||
dst
|
dst
|
||||||
}
|
}
|
||||||
|
|
||||||
fn method(s: &str) -> Header {
|
fn method(s: &str) -> Header<Option<HeaderName>> {
|
||||||
Header::Method(Method::from_bytes(s.as_bytes()).unwrap())
|
Header::Method(Method::from_bytes(s.as_bytes()).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn header(name: &str, val: &str) -> Header {
|
fn header(name: &str, val: &str) -> Header<Option<HeaderName>> {
|
||||||
use http::header::{HeaderName, HeaderValue};
|
use http::header::{HeaderName, HeaderValue};
|
||||||
|
|
||||||
let name = HeaderName::from_bytes(name.as_bytes()).unwrap();
|
let name = HeaderName::from_bytes(name.as_bytes()).unwrap();
|
||||||
let value = HeaderValue::try_from_bytes(val.as_bytes()).unwrap();
|
let value = HeaderValue::try_from_bytes(val.as_bytes()).unwrap();
|
||||||
|
|
||||||
Header::Field { name: name, value: value }
|
Header::Field { name: Some(name), value: value }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn huff_decode(src: &[u8]) -> BytesMut {
|
fn huff_decode(src: &[u8]) -> BytesMut {
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ use bytes::Bytes;
|
|||||||
|
|
||||||
/// HTTP/2.0 Header
|
/// HTTP/2.0 Header
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub enum Header {
|
pub enum Header<T = HeaderName> {
|
||||||
Field {
|
Field {
|
||||||
name: HeaderName,
|
name: T,
|
||||||
value: HeaderValue,
|
value: HeaderValue,
|
||||||
},
|
},
|
||||||
Authority(ByteStr),
|
Authority(ByteStr),
|
||||||
@@ -35,6 +35,22 @@ pub fn len(name: &HeaderName, value: &HeaderValue) -> usize {
|
|||||||
32 + n.len() + value.len()
|
32 + n.len() + value.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Header<Option<HeaderName>> {
|
||||||
|
pub fn reify(self) -> Result<Header, HeaderValue> {
|
||||||
|
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),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Header {
|
impl Header {
|
||||||
pub fn new(name: Bytes, value: Bytes) -> Result<Header, DecoderError> {
|
pub fn new(name: Bytes, value: Bytes) -> Result<Header, DecoderError> {
|
||||||
if name[0] == b':' {
|
if name[0] == b':' {
|
||||||
@@ -191,6 +207,20 @@ impl Header {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mostly for tests
|
||||||
|
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::Authority(v) => Header::Authority(v),
|
||||||
|
Header::Method(v) => Header::Method(v),
|
||||||
|
Header::Scheme(v) => Header::Scheme(v),
|
||||||
|
Header::Path(v) => Header::Path(v),
|
||||||
|
Header::Status(v) => Header::Status(v),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> Name<'a> {
|
impl<'a> Name<'a> {
|
||||||
pub fn into_entry(self, value: Bytes) -> Result<Header, DecoderError> {
|
pub fn into_entry(self, value: Bytes) -> Result<Header, DecoderError> {
|
||||||
match self {
|
match self {
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ struct FuzzHpack {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct HeaderFrame {
|
struct HeaderFrame {
|
||||||
resizes: Vec<usize>,
|
resizes: Vec<usize>,
|
||||||
headers: Vec<Header>,
|
headers: Vec<Header<Option<HeaderName>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FuzzHpack {
|
impl FuzzHpack {
|
||||||
@@ -124,7 +124,7 @@ impl FuzzHpack {
|
|||||||
let mut rng = StdRng::from_seed(&seed);
|
let mut rng = StdRng::from_seed(&seed);
|
||||||
|
|
||||||
// Generates a bunch of source headers
|
// Generates a bunch of source headers
|
||||||
let mut source: Vec<Header> = vec![];
|
let mut source: Vec<Header<Option<HeaderName>>> = vec![];
|
||||||
|
|
||||||
for _ in 0..2000 {
|
for _ in 0..2000 {
|
||||||
source.push(gen_header(&mut rng));
|
source.push(gen_header(&mut rng));
|
||||||
@@ -221,7 +221,7 @@ impl FuzzHpack {
|
|||||||
|
|
||||||
// Decode the chunk!
|
// Decode the chunk!
|
||||||
decoder.decode(&buf.into(), |e| {
|
decoder.decode(&buf.into(), |e| {
|
||||||
assert_eq!(e, expect.remove(0));
|
assert_eq!(e, expect.remove(0).reify().unwrap());
|
||||||
}).unwrap();
|
}).unwrap();
|
||||||
|
|
||||||
buf = BytesMut::with_capacity(
|
buf = BytesMut::with_capacity(
|
||||||
@@ -232,7 +232,7 @@ impl FuzzHpack {
|
|||||||
|
|
||||||
// Decode the chunk!
|
// Decode the chunk!
|
||||||
decoder.decode(&buf.into(), |e| {
|
decoder.decode(&buf.into(), |e| {
|
||||||
assert_eq!(e, expect.remove(0));
|
assert_eq!(e, expect.remove(0).reify().unwrap());
|
||||||
}).unwrap();
|
}).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,7 +246,7 @@ impl Arbitrary for FuzzHpack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_header(g: &mut StdRng) -> Header {
|
fn gen_header(g: &mut StdRng) -> Header<Option<HeaderName>> {
|
||||||
use http::StatusCode;
|
use http::StatusCode;
|
||||||
use http::method::{self, Method};
|
use http::method::{self, Method};
|
||||||
|
|
||||||
@@ -309,7 +309,7 @@ fn gen_header(g: &mut StdRng) -> Header {
|
|||||||
value.set_sensitive(true);
|
value.set_sensitive(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Header::Field { name: name, value: value }
|
Header::Field { name: Some(name), value: value }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -528,13 +528,13 @@ fn test_story(story: Value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut input: Vec<_> = case.expect.iter().map(|&(ref name, ref value)| {
|
let mut input: Vec<_> = case.expect.iter().map(|&(ref name, ref value)| {
|
||||||
Header::new(name.clone().into(), value.clone().into()).unwrap()
|
Header::new(name.clone().into(), value.clone().into()).unwrap().into()
|
||||||
}).collect();
|
}).collect();
|
||||||
|
|
||||||
encoder.encode(None, &mut input.clone().into_iter(), &mut buf).unwrap();
|
encoder.encode(None, &mut input.clone().into_iter(), &mut buf).unwrap();
|
||||||
|
|
||||||
decoder.decode(&buf.into(), |e| {
|
decoder.decode(&buf.into(), |e| {
|
||||||
assert_eq!(e, input.remove(0));
|
assert_eq!(e, input.remove(0).reify().unwrap());
|
||||||
}).unwrap();
|
}).unwrap();
|
||||||
|
|
||||||
assert_eq!(0, input.len());
|
assert_eq!(0, input.len());
|
||||||
|
|||||||
Reference in New Issue
Block a user