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