h2/frame/
go_away.rs

1use std::fmt;
2
3use bytes::{BufMut, Bytes};
4
5use crate::frame::{self, Error, Head, Kind, Reason, StreamId};
6
7#[derive(Clone, Eq, PartialEq)]
8pub struct GoAway {
9    last_stream_id: StreamId,
10    error_code: Reason,
11    debug_data: Bytes,
12}
13
14impl GoAway {
15    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
23    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
31    pub fn last_stream_id(&self) -> StreamId {
32        self.last_stream_id
33    }
34
35    pub fn reason(&self) -> Reason {
36        self.error_code
37    }
38
39    pub fn debug_data(&self) -> &Bytes {
40        &self.debug_data
41    }
42
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
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
69impl<B> From<GoAway> for frame::Frame<B> {
70    fn from(src: GoAway) -> Self {
71        frame::Frame::GoAway(src)
72    }
73}
74
75impl fmt::Debug for GoAway {
76    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}