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 debug_data: Bytes, 12 } 13 14 impl GoAway { new(last_stream_id: StreamId, reason: Reason) -> Self15 pub fn new(last_stream_id: StreamId, reason: Reason) -> Self { 16 GoAway { 17 last_stream_id, 18 error_code: reason, 19 debug_data: Bytes::new(), 20 } 21 } 22 with_debug_data(last_stream_id: StreamId, reason: Reason, debug_data: Bytes) -> Self23 pub fn with_debug_data(last_stream_id: StreamId, reason: Reason, debug_data: Bytes) -> Self { 24 Self { 25 last_stream_id, 26 error_code: reason, 27 debug_data, 28 } 29 } 30 last_stream_id(&self) -> StreamId31 pub fn last_stream_id(&self) -> StreamId { 32 self.last_stream_id 33 } 34 reason(&self) -> Reason35 pub fn reason(&self) -> Reason { 36 self.error_code 37 } 38 debug_data(&self) -> &Bytes39 pub fn debug_data(&self) -> &Bytes { 40 &self.debug_data 41 } 42 load(payload: &[u8]) -> Result<GoAway, Error>43 pub fn load(payload: &[u8]) -> Result<GoAway, Error> { 44 if payload.len() < 8 { 45 return Err(Error::BadFrameSize); 46 } 47 48 let (last_stream_id, _) = StreamId::parse(&payload[..4]); 49 let error_code = unpack_octets_4!(payload, 4, u32); 50 let debug_data = Bytes::copy_from_slice(&payload[8..]); 51 52 Ok(GoAway { 53 last_stream_id, 54 error_code: error_code.into(), 55 debug_data, 56 }) 57 } 58 encode<B: BufMut>(&self, dst: &mut B)59 pub fn encode<B: BufMut>(&self, dst: &mut B) { 60 tracing::trace!("encoding GO_AWAY; code={:?}", self.error_code); 61 let head = Head::new(Kind::GoAway, 0, StreamId::zero()); 62 head.encode(8 + self.debug_data.len(), dst); 63 dst.put_u32(self.last_stream_id.into()); 64 dst.put_u32(self.error_code.into()); 65 dst.put(self.debug_data.slice(..)); 66 } 67 } 68 69 impl<B> From<GoAway> for frame::Frame<B> { from(src: GoAway) -> Self70 fn from(src: GoAway) -> Self { 71 frame::Frame::GoAway(src) 72 } 73 } 74 75 impl fmt::Debug for GoAway { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result76 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 77 let mut builder = f.debug_struct("GoAway"); 78 builder.field("error_code", &self.error_code); 79 builder.field("last_stream_id", &self.last_stream_id); 80 81 if !self.debug_data.is_empty() { 82 builder.field("debug_data", &self.debug_data); 83 } 84 85 builder.finish() 86 } 87 } 88