Get HPACK decoder working

This commit is contained in:
Carl Lerche
2017-05-31 14:44:38 -07:00
parent b9da06a576
commit f45a4b4cd7

View File

@@ -4,6 +4,7 @@ use util::byte_str::FromUtf8Error;
use http::{method, header, status, StatusCode, Method}; use http::{method, header, status, StatusCode, Method};
use bytes::{Buf, Bytes}; use bytes::{Buf, Bytes};
use std::cmp;
use std::io::Cursor; use std::io::Cursor;
use std::collections::VecDeque; use std::collections::VecDeque;
@@ -139,6 +140,16 @@ impl Decoder {
} }
} }
/// Queues a potential size update
pub fn queue_size_update(&mut self, size: usize) {
let size = match self.max_size_update {
Some(v) => cmp::min(v, size),
None => size,
};
self.max_size_update = Some(size);
}
/// 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(Entry)
@@ -180,7 +191,7 @@ impl Decoder {
f(entry); f(entry);
} }
SizeUpdate => { SizeUpdate => {
let max = match self.max_size_update { let max = match self.max_size_update.take() {
Some(max) if can_resize => max, Some(max) if can_resize => max,
_ => { _ => {
// Resize is too big or other frames have been read // Resize is too big or other frames have been read
@@ -238,13 +249,13 @@ impl Decoder {
if table_idx == 0 { if table_idx == 0 {
// Read the name as a literal // Read the name as a literal
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) Entry::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.key().into_entry(value)
} }
} }
@@ -264,17 +275,20 @@ impl Representation {
const LITERAL_WITH_INDEXING: u8 = 0b01000000; const LITERAL_WITH_INDEXING: u8 = 0b01000000;
const LITERAL_WITHOUT_INDEXING: u8 = 0b11110000; const LITERAL_WITHOUT_INDEXING: u8 = 0b11110000;
const LITERAL_NEVER_INDEXED: u8 = 0b00010000; const LITERAL_NEVER_INDEXED: u8 = 0b00010000;
const SIZE_UPDATE_MASK: u8 = 0b11100000;
const SIZE_UPDATE: u8 = 0b00100000; const SIZE_UPDATE: u8 = 0b00100000;
// TODO: What did I even write here?
if byte & INDEXED == INDEXED { if byte & INDEXED == INDEXED {
Ok(Representation::Indexed) Ok(Representation::Indexed)
} else if byte & LITERAL_WITH_INDEXING == LITERAL_WITH_INDEXING { } else if byte & LITERAL_WITH_INDEXING == LITERAL_WITH_INDEXING {
Ok(Representation::LiteralWithIndexing) Ok(Representation::LiteralWithIndexing)
} else if byte & LITERAL_WITHOUT_INDEXING == 0 { } else if byte & LITERAL_WITHOUT_INDEXING == 0 {
Ok(Representation::LiteralWithoutIndexing) Ok(Representation::LiteralWithoutIndexing)
} else if byte & LITERAL_NEVER_INDEXED == LITERAL_NEVER_INDEXED { } else if byte & LITERAL_WITHOUT_INDEXING == LITERAL_NEVER_INDEXED {
Ok(Representation::LiteralNeverIndexed) Ok(Representation::LiteralNeverIndexed)
} else if byte & SIZE_UPDATE == SIZE_UPDATE { } else if byte & SIZE_UPDATE_MASK == SIZE_UPDATE {
Ok(Representation::SizeUpdate) Ok(Representation::SizeUpdate)
} else { } else {
Err(DecoderError::InvalidRepresentation) Err(DecoderError::InvalidRepresentation)
@@ -328,7 +342,7 @@ fn decode_int<B: Buf>(buf: &mut B, prefix_size: u8) -> Result<usize, DecoderErro
ret += ((b & VARINT_MASK) as usize) << shift; ret += ((b & VARINT_MASK) as usize) << shift;
shift += 7; shift += 7;
if b & VARINT_FLAG == VARINT_FLAG { if b & VARINT_FLAG == 0 {
return Ok(ret); return Ok(ret);
} }
@@ -344,25 +358,27 @@ fn decode_int<B: Buf>(buf: &mut B, prefix_size: u8) -> Result<usize, DecoderErro
fn decode_string(buf: &mut Cursor<&Bytes>) -> Result<Bytes, DecoderError> { fn decode_string(buf: &mut Cursor<&Bytes>) -> Result<Bytes, DecoderError> {
const HUFF_FLAG: u8 = 0b10000000; const HUFF_FLAG: u8 = 0b10000000;
// The first bit in the first byte contains the huffman encoded flag.
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 = try!(decode_int(buf, 7));
if len > buf.remaining() { if len > buf.remaining() {
return Err(DecoderError::StringUnderflow); return Err(DecoderError::StringUnderflow);
} }
{ if huff {
if peek_u8(buf) & HUFF_FLAG == HUFF_FLAG { let ret = {
let ret = { let raw = &buf.bytes()[..len];
let raw = &buf.bytes()[..len]; huffman::decode(raw).map(Into::into)
huffman::decode(raw).map(Into::into) };
};
buf.advance(len); buf.advance(len);
return ret; return ret;
} } else {
Ok(take(buf, len))
} }
Ok(take(buf, len))
} }
fn peek_u8<B: Buf>(buf: &mut B) -> u8 { fn peek_u8<B: Buf>(buf: &mut B) -> u8 {