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