Handle padding & stream priority when parsing headers frame

This commit is contained in:
Carl Lerche
2017-08-10 13:55:36 -07:00
parent e7c07b0b12
commit 50e0ad2f2a
4 changed files with 54 additions and 9 deletions

View File

@@ -14,7 +14,7 @@ impl GoAway {
unimplemented!();
}
let last_stream_id = StreamId::parse(&payload[..4]);
let (last_stream_id, _) = StreamId::parse(&payload[..4]);
let error_code = unpack_octets_4!(payload, 4, u32);
Ok(GoAway {

View File

@@ -38,10 +38,12 @@ impl Head {
/// Parse an HTTP/2.0 frame header
pub fn parse(header: &[u8]) -> Head {
let (stream_id, _) = StreamId::parse(&header[5..]);
Head {
kind: Kind::new(header[3]),
flag: header[4],
stream_id: StreamId::parse(&header[5..]),
stream_id,
}
}

View File

@@ -7,10 +7,11 @@ use http::{self, request, response, version, uri, Method, StatusCode, Uri};
use http::{Request, Response};
use http::header::{self, HeaderName, HeaderValue};
use bytes::{BytesMut, Bytes};
use bytes::{BytesMut, Bytes, Buf};
use byteorder::{BigEndian, ByteOrder};
use string::String;
use std::fmt;
use std::io::Cursor;
/// Header frame
@@ -35,7 +36,7 @@ pub struct Headers {
flags: HeadersFlag,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct HeadersFlag(u8);
#[derive(Debug)]
@@ -127,7 +128,36 @@ impl Headers {
{
let flags = HeadersFlag(head.flag());
assert!(!flags.is_priority(), "unimplemented stream priority");
// Read the padding length
if flags.is_padded() {
let pad = src.get_u8() as usize;
// Truncate the last `pad` bytes.
let len = src.get_ref().len() - pad;
src.get_mut().truncate(len);
}
// Read the stream dependency
let stream_dep = if flags.is_priority() {
let mut buf = [0u8; 4];
// Read the next 4 bytes
src.copy_to_slice(&mut buf);
// Parse the stream ID and exclusive flag
let (stream_id, is_exclusive) = StreamId::parse(&buf);
// Read the weight
let weight = src.get_u8();
Some(StreamDependency {
stream_id,
weight,
is_exclusive,
})
} else {
None
};
let mut pseudo = Pseudo::default();
let mut fields = HeaderMap::new();
@@ -169,7 +199,7 @@ impl Headers {
Ok(Headers {
stream_id: head.stream_id(),
stream_dep: None,
stream_dep: stream_dep,
fields: fields,
pseudo: pseudo,
flags: flags,
@@ -312,7 +342,7 @@ impl PushPromise {
// TODO: Handle padding
let promised_id = StreamId::parse(&payload[..4]);
let (promised_id, _) = StreamId::parse(&payload[..4]);
Ok(PushPromise {
stream_id: head.stream_id(),
@@ -476,3 +506,14 @@ impl From<HeadersFlag> for u8 {
src.0
}
}
impl fmt::Debug for HeadersFlag {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("HeadersFlag")
.field("end_stream", &self.is_end_stream())
.field("end_headers", &self.is_end_headers())
.field("padded", &self.is_padded())
.field("priority", &self.is_priority())
.finish()
}
}

View File

@@ -9,11 +9,13 @@ const STREAM_ID_MASK: u32 = 1 << 31;
impl StreamId {
/// Parse the stream ID
#[inline]
pub fn parse(buf: &[u8]) -> StreamId {
pub fn parse(buf: &[u8]) -> (StreamId, bool) {
let unpacked = BigEndian::read_u32(buf);
let flag = unpacked & STREAM_ID_MASK == STREAM_ID_MASK;
// Now clear the most significant bit, as that is reserved and MUST be
// ignored when received.
StreamId(unpacked & !STREAM_ID_MASK)
(StreamId(unpacked & !STREAM_ID_MASK), flag)
}
pub fn is_client_initiated(&self) -> bool {