Skip to main content

http2/frame/
go_away.rs

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