diff --git a/src/frame/go_away.rs b/src/frame/go_away.rs index 13a6b70..444e3d6 100644 --- a/src/frame/go_away.rs +++ b/src/frame/go_away.rs @@ -1,4 +1,7 @@ -use frame::{Error, StreamId}; +use error::Reason; +use frame::{self, Head, Error, Kind, StreamId}; + +use bytes::{BufMut, BigEndian}; #[derive(Debug)] pub struct GoAway { @@ -7,6 +10,10 @@ pub struct GoAway { } impl GoAway { + pub fn reason(&self) -> Reason { + self.error_code.into() + } + pub fn load(payload: &[u8]) -> Result { if payload.len() < 8 { // Invalid payload len @@ -22,4 +29,18 @@ impl GoAway { error_code: error_code, }) } + + pub fn encode(&self, dst: &mut B) { + trace!("encoding GO_AWAY; code={}", self.error_code); + let head = Head::new(Kind::GoAway, 0, StreamId::zero()); + head.encode(8, dst); + dst.put_u32::(self.last_stream_id.into()); + dst.put_u32::(self.error_code); + } +} + +impl From for frame::Frame { + fn from(src: GoAway) -> Self { + frame::Frame::GoAway(src) + } } diff --git a/src/frame/mod.rs b/src/frame/mod.rs index c0a5270..3698b48 100644 --- a/src/frame/mod.rs +++ b/src/frame/mod.rs @@ -62,6 +62,7 @@ pub enum Frame { PushPromise(PushPromise), Settings(Settings), Ping(Ping), + GoAway(GoAway), WindowUpdate(WindowUpdate), Reset(Reset) } @@ -100,6 +101,7 @@ impl fmt::Debug for 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), + GoAway(ref frame) => write!(fmt, "Frame::GoAway({:?})", frame), WindowUpdate(ref frame) => write!(fmt, "Frame::WindowUpdate({:?})", frame), Reset(ref frame) => write!(fmt, "Frame::Reset({:?})", frame), } diff --git a/src/frame/window_update.rs b/src/frame/window_update.rs index 785051d..29f8c2a 100644 --- a/src/frame/window_update.rs +++ b/src/frame/window_update.rs @@ -48,7 +48,7 @@ impl WindowUpdate { pub fn encode(&self, dst: &mut B) { trace!("encoding WINDOW_UPDATE; id={:?}", self.stream_id); - let head = Head::new(Kind::Ping, 0, self.stream_id); + let head = Head::new(Kind::WindowUpdate, 0, self.stream_id); head.encode(4, dst); dst.put_u32::(self.size_increment); } diff --git a/src/proto/connection.rs b/src/proto/connection.rs index 1d119fe..378b5be 100644 --- a/src/proto/connection.rs +++ b/src/proto/connection.rs @@ -128,6 +128,12 @@ impl Connection // TODO: ACK must be sent THEN settings applied. } + Some(GoAway(frame)) => { + // TODO: handle the last_stream_id. Also, should this be + // handled as an error? + let e = ConnectionError::Proto(frame.reason()); + return Ok(().into()); + } Some(Ping(frame)) => { trace!("recv PING; frame={:?}", frame); self.ping_pong.recv_ping(frame); diff --git a/src/proto/framed_read.rs b/src/proto/framed_read.rs index 4c31d0e..1b2d3b5 100644 --- a/src/proto/framed_read.rs +++ b/src/proto/framed_read.rs @@ -64,7 +64,6 @@ impl FramedRead { let _ = bytes.split_to(frame::HEADER_LEN); frame::Data::load(head, bytes)?.into() } - Kind::Headers => { let mut buf = Cursor::new(bytes); buf.set_position(frame::HEADER_LEN as u64); @@ -80,16 +79,11 @@ impl FramedRead { frame.into() } - Kind::Reset => { frame::Reset::load(head, &bytes[frame::HEADER_LEN..])?.into() } - - // TODO - Kind::GoAway => { - let _todo = try!(frame::GoAway::load(&bytes[frame::HEADER_LEN..])); - unimplemented!(); + frame::GoAway::load(&bytes[frame::HEADER_LEN..])?.into() } Kind::PushPromise => { frame::PushPromise::load(head, &bytes[frame::HEADER_LEN..])?.into() diff --git a/src/proto/framed_write.rs b/src/proto/framed_write.rs index 4dbedbe..d9f24b1 100644 --- a/src/proto/framed_write.rs +++ b/src/proto/framed_write.rs @@ -141,6 +141,10 @@ impl Sink for FramedWrite v.encode(self.buf.get_mut()); trace!("encoded settings; rem={:?}", self.buf.remaining()); } + Frame::GoAway(v) => { + v.encode(self.buf.get_mut()); + trace!("encoded go_away; rem={:?}", self.buf.remaining()); + } Frame::Ping(v) => { v.encode(self.buf.get_mut()); trace!("encoded ping; rem={:?}", self.buf.remaining());