1 use std::fmt; 2 3 use bytes::{BufMut, Bytes}; 4 5 use crate::frame::{self, Error, Head, Kind, Reason, StreamId}; 6 7 #[derive(Clone, Eq, PartialEq)] 8 pub struct GoAway { 9 last_stream_id: StreamId, 10 error_code: Reason, 11 #[allow(unused)] 12 debug_data: Bytes, 13 } 14 15 impl GoAway { new(last_stream_id: StreamId, reason: Reason) -> Self16 pub fn new(last_stream_id: StreamId, reason: Reason) -> Self { 17 GoAway { 18 last_stream_id, 19 error_code: reason, 20 debug_data: Bytes::new(), 21 } 22 } 23 last_stream_id(&self) -> StreamId24 pub fn last_stream_id(&self) -> StreamId { 25 self.last_stream_id 26 } 27 reason(&self) -> Reason28 pub fn reason(&self) -> Reason { 29 self.error_code 30 } 31 32 #[cfg(feature = "unstable")] debug_data(&self) -> &[u8]33 pub fn debug_data(&self) -> &[u8] { 34 &self.debug_data 35 } 36 load(payload: &[u8]) -> Result<GoAway, Error>37 pub fn load(payload: &[u8]) -> Result<GoAway, Error> { 38 if payload.len() < 8 { 39 return Err(Error::BadFrameSize); 40 } 41 42 let (last_stream_id, _) = StreamId::parse(&payload[..4]); 43 let error_code = unpack_octets_4!(payload, 4, u32); 44 let debug_data = Bytes::copy_from_slice(&payload[8..]); 45 46 Ok(GoAway { 47 last_stream_id, 48 error_code: error_code.into(), 49 debug_data, 50 }) 51 } 52 encode<B: BufMut>(&self, dst: &mut B)53 pub fn encode<B: BufMut>(&self, dst: &mut B) { 54 tracing::trace!("encoding GO_AWAY; code={:?}", self.error_code); 55 let head = Head::new(Kind::GoAway, 0, StreamId::zero()); 56 head.encode(8, dst); 57 dst.put_u32(self.last_stream_id.into()); 58 dst.put_u32(self.error_code.into()); 59 } 60 } 61 62 impl<B> From<GoAway> for frame::Frame<B> { from(src: GoAway) -> Self63 fn from(src: GoAway) -> Self { 64 frame::Frame::GoAway(src) 65 } 66 } 67 68 impl fmt::Debug for GoAway { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 70 let mut builder = f.debug_struct("GoAway"); 71 builder.field("error_code", &self.error_code); 72 builder.field("last_stream_id", &self.last_stream_id); 73 74 if !self.debug_data.is_empty() { 75 builder.field("debug_data", &self.debug_data); 76 } 77 78 builder.finish() 79 } 80 } 81