Skip to main content

net_wire/http2/builder/
raw.rs

1//! Atomic caller-buffer construction of raw HTTP/2 frames.
2
3use super::super::error::Http2BuildError;
4use super::super::frame::Http2FrameMut;
5use super::super::types::{Http2FrameType, Http2StreamId};
6
7pub(super) const FRAME_HEADER_LENGTH: usize = 9;
8pub(super) const MAXIMUM_PAYLOAD: usize = 0x00ff_ffff;
9
10pub(super) fn write_frame_envelope(
11    buffer: &mut [u8],
12    payload_length: usize,
13    frame_type: Http2FrameType,
14    flags: u8,
15    stream_id: Http2StreamId,
16    maximum_payload: usize,
17) -> Result<&mut [u8], Http2BuildError> {
18    let maximum_payload = maximum_payload.min(MAXIMUM_PAYLOAD);
19    if payload_length > maximum_payload {
20        return Err(Http2BuildError::PayloadTooLarge {
21            maximum: maximum_payload,
22            actual: payload_length,
23        });
24    }
25    let required = FRAME_HEADER_LENGTH.checked_add(payload_length).ok_or(
26        Http2BuildError::PayloadTooLarge {
27            maximum: maximum_payload,
28            actual: payload_length,
29        },
30    )?;
31    if buffer.len() < required {
32        return Err(Http2BuildError::BufferTooShort {
33            required,
34            available: buffer.len(),
35        });
36    }
37
38    let bytes = &mut buffer[..required];
39    let payload_length = payload_length as u32;
40    bytes[0] = (payload_length >> 16) as u8;
41    bytes[1] = (payload_length >> 8) as u8;
42    bytes[2] = payload_length as u8;
43    bytes[3] = frame_type.raw();
44    bytes[4] = flags;
45    bytes[5..FRAME_HEADER_LENGTH].copy_from_slice(&stream_id.raw().to_be_bytes());
46    Ok(bytes)
47}
48
49/// Builds a raw HTTP/2 frame in caller-owned storage.
50pub struct Http2FrameBuilder<'a, 'b> {
51    buffer: &'a mut [u8],
52    frame_type: Http2FrameType,
53    flags: u8,
54    stream_id: Http2StreamId,
55    payload: &'b [u8],
56}
57
58impl<'a, 'b> Http2FrameBuilder<'a, 'b> {
59    /// Creates a builder that copies the supplied raw payload.
60    pub fn new(
61        buffer: &'a mut [u8],
62        frame_type: Http2FrameType,
63        flags: u8,
64        stream_id: Http2StreamId,
65        payload: &'b [u8],
66    ) -> Self {
67        Self {
68            buffer,
69            frame_type,
70            flags,
71            stream_id,
72            payload,
73        }
74    }
75
76    /// Validates HTTP/2's representable payload length and capacity before writing the frame.
77    pub fn build(self) -> Result<Http2FrameMut<'a>, Http2BuildError> {
78        self.build_with_maximum(MAXIMUM_PAYLOAD)
79    }
80
81    /// Validates the caller-provided payload maximum and capacity before writing the frame.
82    pub fn build_with_maximum(
83        self,
84        maximum_payload: usize,
85    ) -> Result<Http2FrameMut<'a>, Http2BuildError> {
86        if self.stream_id.has_reserved_bit() {
87            return Err(Http2BuildError::ReservedStreamId);
88        }
89        let bytes = write_frame_envelope(
90            self.buffer,
91            self.payload.len(),
92            self.frame_type,
93            self.flags,
94            self.stream_id,
95            maximum_payload,
96        )?;
97        bytes[FRAME_HEADER_LENGTH..].copy_from_slice(self.payload);
98        Ok(Http2FrameMut::from_validated(bytes))
99    }
100}