1use std::fmt;
2
3use ntex_bytes::{BufMut, Bytes, BytesMut};
4
5use crate::frame::{self, FrameError, Head, Kind, Reason, StreamId};
6
7#[derive(Clone, Eq, PartialEq)]
8pub struct GoAway {
9 last_stream_id: StreamId,
10 error_code: Reason,
11 data: Bytes,
12}
13
14impl GoAway {
15 pub fn new(reason: Reason) -> Self {
16 GoAway {
17 last_stream_id: 0.into(),
18 data: Bytes::new(),
19 error_code: reason,
20 }
21 }
22
23 #[must_use]
24 pub fn set_last_stream_id(mut self, id: StreamId) -> Self {
25 self.last_stream_id = id;
26 self
27 }
28
29 #[must_use]
30 pub fn set_data<T>(mut self, data: T) -> Self
31 where
32 Bytes: From<T>,
33 {
34 self.data = data.into();
35 self
36 }
37
38 #[must_use]
39 pub fn set_reason(mut self, error_code: Reason) -> Self {
40 self.error_code = error_code;
41 self
42 }
43
44 pub fn last_stream_id(&self) -> StreamId {
45 self.last_stream_id
46 }
47
48 pub fn reason(&self) -> Reason {
49 self.error_code
50 }
51
52 pub fn data(&self) -> &Bytes {
53 &self.data
54 }
55
56 pub fn load(payload: &[u8]) -> Result<GoAway, FrameError> {
57 if payload.len() < 8 {
58 return Err(FrameError::BadFrameSize);
59 }
60
61 let (last_stream_id, _) = StreamId::parse(&payload[..4]);
62 let error_code = unpack_octets_4!(payload, 4, u32);
63 let data = Bytes::copy_from_slice(&payload[8..]);
64
65 Ok(GoAway {
66 last_stream_id,
67 data,
68 error_code: error_code.into(),
69 })
70 }
71
72 pub fn encode(&self, dst: &mut BytesMut) {
73 log::trace!("encoding GO_AWAY; code={:?}", self.error_code);
74 let head = Head::new(Kind::GoAway, 0, StreamId::zero());
75 head.encode(8 + self.data.len(), dst);
76 dst.put_u32(self.last_stream_id.into());
77 dst.put_u32(self.error_code.into());
78 dst.extend_from_slice(&self.data);
79 }
80}
81
82impl From<GoAway> for frame::Frame {
83 fn from(src: GoAway) -> Self {
84 frame::Frame::GoAway(src)
85 }
86}
87
88impl fmt::Debug for GoAway {
89 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90 let mut builder = f.debug_struct("GoAway");
91 builder.field("error_code", &self.error_code);
92 builder.field("last_stream_id", &self.last_stream_id);
93
94 if !self.data.is_empty() {
95 builder.field("data", &self.data);
96 }
97
98 builder.finish()
99 }
100}