Skip to main content

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(head: Head, payload: &[u8]) -> Result<GoAway, Error> {
44        debug_assert_eq!(head.kind(), crate::frame::Kind::GoAway);
45
46        // The GOAWAY frame applies to the connection, not a specific stream.
47        // An endpoint MUST treat a GOAWAY frame with a stream identifier
48        // other than 0x00 as a connection error (Section 5.4.1) of type
49        // PROTOCOL_ERROR.
50        if !head.stream_id().is_zero() {
51            return Err(Error::InvalidStreamId);
52        }
53
54        if payload.len() < 8 {
55            return Err(Error::BadFrameSize);
56        }
57
58        let (last_stream_id, _) = StreamId::parse(&payload[..4]);
59        let error_code = unpack_octets_4!(payload, 4, u32);
60        let debug_data = Bytes::copy_from_slice(&payload[8..]);
61
62        Ok(GoAway {
63            last_stream_id,
64            error_code: error_code.into(),
65            debug_data,
66        })
67    }
68
69    pub fn encode<B: BufMut>(&self, dst: &mut B) {
70        tracing::trace!("encoding GO_AWAY; code={:?}", self.error_code);
71        let head = Head::new(Kind::GoAway, 0, StreamId::zero());
72        head.encode(8 + self.debug_data.len(), dst);
73        dst.put_u32(self.last_stream_id.into());
74        dst.put_u32(self.error_code.into());
75        dst.put(self.debug_data.slice(..));
76    }
77}
78
79impl<B> From<GoAway> for frame::Frame<B> {
80    fn from(src: GoAway) -> Self {
81        frame::Frame::GoAway(src)
82    }
83}
84
85impl fmt::Debug for GoAway {
86    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87        let mut builder = f.debug_struct("GoAway");
88        builder.field("error_code", &self.error_code);
89        builder.field("last_stream_id", &self.last_stream_id);
90
91        if !self.debug_data.is_empty() {
92            builder.field("debug_data", &self.debug_data);
93        }
94
95        builder.finish()
96    }
97}