Handle padding & stream priority when parsing headers frame
This commit is contained in:
@@ -14,7 +14,7 @@ impl GoAway {
|
|||||||
unimplemented!();
|
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);
|
let error_code = unpack_octets_4!(payload, 4, u32);
|
||||||
|
|
||||||
Ok(GoAway {
|
Ok(GoAway {
|
||||||
|
|||||||
@@ -38,10 +38,12 @@ impl Head {
|
|||||||
|
|
||||||
/// Parse an HTTP/2.0 frame header
|
/// Parse an HTTP/2.0 frame header
|
||||||
pub fn parse(header: &[u8]) -> Head {
|
pub fn parse(header: &[u8]) -> Head {
|
||||||
|
let (stream_id, _) = StreamId::parse(&header[5..]);
|
||||||
|
|
||||||
Head {
|
Head {
|
||||||
kind: Kind::new(header[3]),
|
kind: Kind::new(header[3]),
|
||||||
flag: header[4],
|
flag: header[4],
|
||||||
stream_id: StreamId::parse(&header[5..]),
|
stream_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,10 +7,11 @@ use http::{self, request, response, version, uri, Method, StatusCode, Uri};
|
|||||||
use http::{Request, Response};
|
use http::{Request, Response};
|
||||||
use http::header::{self, HeaderName, HeaderValue};
|
use http::header::{self, HeaderName, HeaderValue};
|
||||||
|
|
||||||
use bytes::{BytesMut, Bytes};
|
use bytes::{BytesMut, Bytes, Buf};
|
||||||
use byteorder::{BigEndian, ByteOrder};
|
use byteorder::{BigEndian, ByteOrder};
|
||||||
use string::String;
|
use string::String;
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
/// Header frame
|
/// Header frame
|
||||||
@@ -35,7 +36,7 @@ pub struct Headers {
|
|||||||
flags: HeadersFlag,
|
flags: HeadersFlag,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||||
pub struct HeadersFlag(u8);
|
pub struct HeadersFlag(u8);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -127,7 +128,36 @@ impl Headers {
|
|||||||
{
|
{
|
||||||
let flags = HeadersFlag(head.flag());
|
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 pseudo = Pseudo::default();
|
||||||
let mut fields = HeaderMap::new();
|
let mut fields = HeaderMap::new();
|
||||||
@@ -169,7 +199,7 @@ impl Headers {
|
|||||||
|
|
||||||
Ok(Headers {
|
Ok(Headers {
|
||||||
stream_id: head.stream_id(),
|
stream_id: head.stream_id(),
|
||||||
stream_dep: None,
|
stream_dep: stream_dep,
|
||||||
fields: fields,
|
fields: fields,
|
||||||
pseudo: pseudo,
|
pseudo: pseudo,
|
||||||
flags: flags,
|
flags: flags,
|
||||||
@@ -312,7 +342,7 @@ impl PushPromise {
|
|||||||
|
|
||||||
// TODO: Handle padding
|
// TODO: Handle padding
|
||||||
|
|
||||||
let promised_id = StreamId::parse(&payload[..4]);
|
let (promised_id, _) = StreamId::parse(&payload[..4]);
|
||||||
|
|
||||||
Ok(PushPromise {
|
Ok(PushPromise {
|
||||||
stream_id: head.stream_id(),
|
stream_id: head.stream_id(),
|
||||||
@@ -476,3 +506,14 @@ impl From<HeadersFlag> for u8 {
|
|||||||
src.0
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,11 +9,13 @@ const STREAM_ID_MASK: u32 = 1 << 31;
|
|||||||
impl StreamId {
|
impl StreamId {
|
||||||
/// Parse the stream ID
|
/// Parse the stream ID
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn parse(buf: &[u8]) -> StreamId {
|
pub fn parse(buf: &[u8]) -> (StreamId, bool) {
|
||||||
let unpacked = BigEndian::read_u32(buf);
|
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
|
// Now clear the most significant bit, as that is reserved and MUST be
|
||||||
// ignored when received.
|
// ignored when received.
|
||||||
StreamId(unpacked & !STREAM_ID_MASK)
|
(StreamId(unpacked & !STREAM_ID_MASK), flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_client_initiated(&self) -> bool {
|
pub fn is_client_initiated(&self) -> bool {
|
||||||
|
|||||||
Reference in New Issue
Block a user