diff --git a/src/frame/go_away.rs b/src/frame/go_away.rs index f7fc8df..13a6b70 100644 --- a/src/frame/go_away.rs +++ b/src/frame/go_away.rs @@ -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 { diff --git a/src/frame/head.rs b/src/frame/head.rs index 899dd18..28caad0 100644 --- a/src/frame/head.rs +++ b/src/frame/head.rs @@ -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, } } diff --git a/src/frame/headers.rs b/src/frame/headers.rs index a181e18..94e2495 100644 --- a/src/frame/headers.rs +++ b/src/frame/headers.rs @@ -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 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() + } +} diff --git a/src/frame/stream_id.rs b/src/frame/stream_id.rs index 29652ef..4f9b9fe 100644 --- a/src/frame/stream_id.rs +++ b/src/frame/stream_id.rs @@ -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 {