Handle padding & stream priority when parsing headers frame
This commit is contained in:
		| @@ -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 { | ||||
|   | ||||
| @@ -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, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -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() | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user