From 23b2ef49cc2db885acb71cd89841f866b5a1c9e5 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Thu, 10 Aug 2017 23:17:21 -0700 Subject: [PATCH] Stub out priority --- src/frame/headers.rs | 30 +++----------- src/frame/mod.rs | 10 +++++ src/frame/priority.rs | 83 +++++++++++++++++++++++++++++++++++++++ src/proto/connection.rs | 4 ++ src/proto/framed_read.rs | 3 +- src/proto/framed_write.rs | 6 +++ 6 files changed, 110 insertions(+), 26 deletions(-) create mode 100644 src/frame/priority.rs diff --git a/src/frame/headers.rs b/src/frame/headers.rs index ed8d85b..fdf5a67 100644 --- a/src/frame/headers.rs +++ b/src/frame/headers.rs @@ -1,4 +1,4 @@ -use super::StreamId; +use super::{StreamId, StreamDependency}; use hpack; use frame::{self, Frame, Head, Kind, Error}; use HeaderMap; @@ -66,20 +66,6 @@ pub struct Continuation { headers: Iter, } -#[derive(Debug)] -pub struct StreamDependency { - /// The ID of the stream dependency target - stream_id: StreamId, - - /// The weight for the stream. The value exposed (and set) here is always in - /// the range [0, 255], instead of [1, 256] (as defined in section 5.3.2.) - /// so that the value fits into a `u8`. - weight: u8, - - /// True if the stream dependency is exclusive. - is_exclusive: bool, -} - #[derive(Debug, Default)] pub struct Pseudo { // Request @@ -145,20 +131,16 @@ impl Headers { // Read the stream dependency let stream_dep = if flags.is_priority() { - // Parse the stream ID and exclusive flag - let (stream_id, is_exclusive) = StreamId::parse(&src[..4]); + let stream_dep = StreamDependency::load(&src[..5])?; - // Read the weight - let weight = src[4]; + if stream_dep.dependency_id() == head.stream_id() { + return Err(Error::InvalidDependencyId); + } // Drop the next 5 bytes let _ = src.split_to(5); - Some(StreamDependency { - stream_id, - weight, - is_exclusive, - }) + Some(stream_dep) } else { None }; diff --git a/src/frame/mod.rs b/src/frame/mod.rs index 3698b48..683ec13 100644 --- a/src/frame/mod.rs +++ b/src/frame/mod.rs @@ -32,6 +32,7 @@ mod go_away; mod head; mod headers; mod ping; +mod priority; mod reset; mod settings; mod stream_id; @@ -43,6 +44,7 @@ pub use self::go_away::GoAway; pub use self::head::{Head, Kind}; pub use self::headers::{Headers, PushPromise, Continuation, Pseudo}; pub use self::ping::Ping; +pub use self::priority::{Priority, StreamDependency}; pub use self::reset::Reset; pub use self::settings::{Settings, SettingSet}; pub use self::stream_id::StreamId; @@ -59,6 +61,7 @@ pub const HEADER_LEN: usize = 9; pub enum Frame { Data(Data), Headers(Headers), + Priority(Priority), PushPromise(PushPromise), Settings(Settings), Ping(Ping), @@ -98,6 +101,7 @@ impl fmt::Debug for Frame { match *self { Data(..) => write!(fmt, "Frame::Data(..)"), Headers(ref frame) => write!(fmt, "Frame::Headers({:?})", frame), + Priority(ref frame) => write!(fmt, "Frame::Priority({:?})", frame), PushPromise(ref frame) => write!(fmt, "Frame::PushPromise({:?})", frame), Settings(ref frame) => write!(fmt, "Frame::Settings({:?})", frame), Ping(ref frame) => write!(fmt, "Frame::Ping({:?})", frame), @@ -153,6 +157,12 @@ pub enum Error { /// identifier other than zero. InvalidStreamId, + /// An invalid stream dependency ID was provided + /// + /// This is returend if a HEADERS or PRIORITY frame is received with an + /// invalid stream identifier. + InvalidDependencyId, + /// Failed to perform HPACK decoding Hpack(hpack::DecoderError), } diff --git a/src/frame/priority.rs b/src/frame/priority.rs new file mode 100644 index 0000000..2947901 --- /dev/null +++ b/src/frame/priority.rs @@ -0,0 +1,83 @@ +use frame::*; + +#[derive(Debug)] +pub struct Priority { + stream_id: StreamId, + dependency: StreamDependency, +} + +#[derive(Debug)] +pub struct StreamDependency { + /// The ID of the stream dependency target + dependency_id: StreamId, + + /// The weight for the stream. The value exposed (and set) here is always in + /// the range [0, 255], instead of [1, 256] (as defined in section 5.3.2.) + /// so that the value fits into a `u8`. + weight: u8, + + /// True if the stream dependency is exclusive. + is_exclusive: bool, +} + +impl Priority { + pub fn load(head: Head, payload: &[u8]) -> Result { + let dependency = StreamDependency::load(payload)?; + + if dependency.dependency_id() == head.stream_id() { + return Err(Error::InvalidDependencyId); + } + + Ok(Priority { + stream_id: head.stream_id(), + dependency: dependency, + }) + } +} + +impl From for Frame { + fn from(src: Priority) -> Self { + Frame::Priority(src) + } +} + +// ===== impl StreamDependency ===== + +impl StreamDependency { + pub fn new(dependency_id: StreamId, weight: u8, is_exclusive: bool) -> Self { + StreamDependency { + dependency_id, + weight, + is_exclusive, + } + } + + pub fn load(src: &[u8]) -> Result { + if src.len() != 5 { + return Err(Error::InvalidPayloadLength); + } + + // Parse the stream ID and exclusive flag + let (dependency_id, is_exclusive) = StreamId::parse(&src[..4]); + + // Read the weight + let weight = src[4]; + + Ok(StreamDependency::new( + dependency_id, + weight, + is_exclusive)) + } + + pub fn dependency_id(&self) -> StreamId { + self.dependency_id + } + + pub fn weight(&self) -> u8 { + self.weight + } + + pub fn is_exclusive(&self) -> bool { + self.is_exclusive + } +} diff --git a/src/proto/connection.rs b/src/proto/connection.rs index 378b5be..36cd65e 100644 --- a/src/proto/connection.rs +++ b/src/proto/connection.rs @@ -142,6 +142,10 @@ impl Connection trace!("recv WINDOW_UPDATE; frame={:?}", frame); self.streams.recv_window_update(frame)?; } + Some(Priority(frame)) => { + trace!("recv PRIORITY; frame={:?}", frame); + // TODO: handle + } None => { // TODO: Is this correct? trace!("codec closed"); diff --git a/src/proto/framed_read.rs b/src/proto/framed_read.rs index 3fbc509..9dd89c5 100644 --- a/src/proto/framed_read.rs +++ b/src/proto/framed_read.rs @@ -108,8 +108,7 @@ impl FramedRead { frame::PushPromise::load(head, &bytes[frame::HEADER_LEN..])?.into() } Kind::Priority => { - // TODO: implement - return Ok(None); + frame::Priority::load(head, &bytes[frame::HEADER_LEN..])?.into() } Kind::Continuation => { // TODO: Un-hack this diff --git a/src/proto/framed_write.rs b/src/proto/framed_write.rs index d9f24b1..9f2fa6f 100644 --- a/src/proto/framed_write.rs +++ b/src/proto/framed_write.rs @@ -153,6 +153,12 @@ impl Sink for FramedWrite v.encode(self.buf.get_mut()); trace!("encoded window_update; rem={:?}", self.buf.remaining()); } + + Frame::Priority(v) => { + // v.encode(self.buf.get_mut()); + trace!("encoded priority; rem={:?}", self.buf.remaining()); + unimplemented!(); + } Frame::Reset(v) => { v.encode(self.buf.get_mut()); trace!("encoded reset; rem={:?}", self.buf.remaining());