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 debug_data(&self) -> &Bytes32 pub fn debug_data(&self) -> &Bytes { 33 &self.debug_data 34 } 35 load(payload: &[u8]) -> Result<GoAway, Error>36 pub fn load(payload: &[u8]) -> Result<GoAway, Error> { 37 if payload.len() < 8 { 38 return Err(Error::BadFrameSize); 39 } 40 41 let (last_stream_id, _) = StreamId::parse(&payload[..4]); 42 let error_code = unpack_octets_4!(payload, 4, u32); 43 let debug_data = Bytes::copy_from_slice(&payload[8..]); 44 45 Ok(GoAway { 46 last_stream_id, 47 error_code: error_code.into(), 48 debug_data, 49 }) 50 } 51 encode<B: BufMut>(&self, dst: &mut B)52 pub fn encode<B: BufMut>(&self, dst: &mut B) { 53 tracing::trace!("encoding GO_AWAY; code={:?}", self.error_code); 54 let head = Head::new(Kind::GoAway, 0, StreamId::zero()); 55 head.encode(8, dst); 56 dst.put_u32(self.last_stream_id.into()); 57 dst.put_u32(self.error_code.into()); 58 } 59 } 60 61 impl<B> From<GoAway> for frame::Frame<B> { from(src: GoAway) -> Self62 fn from(src: GoAway) -> Self { 63 frame::Frame::GoAway(src) 64 } 65 } 66 67 impl fmt::Debug for GoAway { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 69 let mut builder = f.debug_struct("GoAway"); 70 builder.field("error_code", &self.error_code); 71 builder.field("last_stream_id", &self.last_stream_id); 72 73 if !self.debug_data.is_empty() { 74 builder.field("debug_data", &self.debug_data); 75 } 76 77 builder.finish() 78 } 79 } 80