Skip to main content

net_wire/http2/
frame.rs

1//! Exact HTTP/2 client-preface and frame views.
2
3use super::error::Http2ParseError;
4use super::types::{Http2FrameType, Http2StreamId};
5
6/// The exact HTTP/2 client connection preface.
7pub const HTTP2_CLIENT_PREFACE: &[u8; 24] = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
8
9/// A validated borrowed HTTP/2 client connection preface.
10#[derive(Clone, Copy, Debug, Eq, PartialEq)]
11pub struct Http2ClientPreface<'a> {
12    bytes: &'a [u8],
13}
14
15impl<'a> Http2ClientPreface<'a> {
16    /// Parses the exact client preface at the start of `bytes` and excludes any suffix.
17    pub fn parse(bytes: &'a [u8]) -> Result<Self, Http2ParseError> {
18        if bytes.len() < HTTP2_CLIENT_PREFACE.len() {
19            return Err(Http2ParseError::Incomplete {
20                required: HTTP2_CLIENT_PREFACE.len(),
21                available: bytes.len(),
22            });
23        }
24        for (offset, (&actual, &expected)) in
25            bytes.iter().zip(HTTP2_CLIENT_PREFACE.iter()).enumerate()
26        {
27            if actual != expected {
28                return Err(Http2ParseError::ClientPrefaceMismatch {
29                    offset,
30                    expected,
31                    actual,
32                });
33            }
34        }
35        Ok(Self {
36            bytes: &bytes[..HTTP2_CLIENT_PREFACE.len()],
37        })
38    }
39
40    /// Returns the exact represented preface bytes.
41    pub fn as_bytes(&self) -> &'a [u8] {
42        self.bytes
43    }
44}
45
46/// A structurally bounded raw HTTP/2 frame preserving all header fields.
47#[derive(Clone, Copy, Debug, Eq, PartialEq)]
48pub struct Http2Frame<'a> {
49    bytes: &'a [u8],
50}
51
52impl<'a> Http2Frame<'a> {
53    pub(super) fn from_validated(bytes: &'a [u8]) -> Self {
54        Self { bytes }
55    }
56
57    /// Parses the first complete frame, enforcing the caller-provided payload maximum.
58    pub fn parse(bytes: &'a [u8], maximum_payload: usize) -> Result<Self, Http2ParseError> {
59        let length = frame_length(bytes, maximum_payload)?;
60        Ok(Self {
61            bytes: &bytes[..length],
62        })
63    }
64
65    /// Returns the declared payload length.
66    pub fn payload_length(&self) -> usize {
67        usize::from(self.bytes[0]) << 16
68            | usize::from(self.bytes[1]) << 8
69            | usize::from(self.bytes[2])
70    }
71
72    /// Returns the raw frame type.
73    pub fn frame_type(&self) -> Http2FrameType {
74        Http2FrameType::new(self.bytes[3])
75    }
76
77    /// Returns the unmodified flags byte.
78    pub fn flags(&self) -> u8 {
79        self.bytes[4]
80    }
81
82    /// Returns the raw stream identifier, including its reserved bit.
83    pub fn stream_id(&self) -> Http2StreamId {
84        Http2StreamId::new(u32::from_be_bytes([
85            self.bytes[5],
86            self.bytes[6],
87            self.bytes[7],
88            self.bytes[8],
89        ]))
90    }
91
92    /// Returns the exact payload bytes.
93    pub fn payload(&self) -> &'a [u8] {
94        &self.bytes[9..]
95    }
96
97    /// Returns the exact represented frame bytes.
98    pub fn as_bytes(&self) -> &'a [u8] {
99        self.bytes
100    }
101}
102
103/// A mutable structurally bounded raw HTTP/2 frame preserving all header fields.
104#[derive(Debug, Eq, PartialEq)]
105pub struct Http2FrameMut<'a> {
106    bytes: &'a mut [u8],
107}
108
109impl<'a> Http2FrameMut<'a> {
110    /// Parses the first complete frame, enforcing the caller-provided payload maximum.
111    pub fn parse(bytes: &'a mut [u8], maximum_payload: usize) -> Result<Self, Http2ParseError> {
112        let length = frame_length(bytes, maximum_payload)?;
113        Ok(Self {
114            bytes: &mut bytes[..length],
115        })
116    }
117
118    pub(crate) fn from_validated(bytes: &'a mut [u8]) -> Self {
119        Self { bytes }
120    }
121
122    /// Returns the declared payload length.
123    pub fn payload_length(&self) -> usize {
124        usize::from(self.bytes[0]) << 16
125            | usize::from(self.bytes[1]) << 8
126            | usize::from(self.bytes[2])
127    }
128
129    /// Returns the raw frame type.
130    pub fn frame_type(&self) -> Http2FrameType {
131        Http2FrameType::new(self.bytes[3])
132    }
133
134    /// Returns the unmodified flags byte.
135    pub fn flags(&self) -> u8 {
136        self.bytes[4]
137    }
138
139    /// Returns the raw stream identifier, including its reserved bit.
140    pub fn stream_id(&self) -> Http2StreamId {
141        Http2StreamId::new(u32::from_be_bytes([
142            self.bytes[5],
143            self.bytes[6],
144            self.bytes[7],
145            self.bytes[8],
146        ]))
147    }
148
149    /// Returns the exact payload bytes.
150    pub fn payload(&self) -> &[u8] {
151        &self.bytes[9..]
152    }
153
154    /// Returns the exact payload bytes mutably without changing their encoded length.
155    pub fn payload_mut(&mut self) -> &mut [u8] {
156        &mut self.bytes[9..]
157    }
158
159    /// Returns the exact represented frame bytes.
160    pub fn as_bytes(&self) -> &[u8] {
161        self.bytes
162    }
163}
164
165fn frame_length(bytes: &[u8], maximum_payload: usize) -> Result<usize, Http2ParseError> {
166    const HEADER_LENGTH: usize = 9;
167
168    if bytes.len() < HEADER_LENGTH {
169        return Err(Http2ParseError::Incomplete {
170            required: HEADER_LENGTH,
171            available: bytes.len(),
172        });
173    }
174    let payload_length =
175        usize::from(bytes[0]) << 16 | usize::from(bytes[1]) << 8 | usize::from(bytes[2]);
176    if payload_length > maximum_payload {
177        return Err(Http2ParseError::PayloadTooLarge {
178            maximum: maximum_payload,
179            actual: payload_length,
180        });
181    }
182    let required =
183        HEADER_LENGTH
184            .checked_add(payload_length)
185            .ok_or(Http2ParseError::PayloadTooLarge {
186                maximum: maximum_payload,
187                actual: payload_length,
188            })?;
189    if bytes.len() < required {
190        return Err(Http2ParseError::Incomplete {
191            required,
192            available: bytes.len(),
193        });
194    }
195    Ok(required)
196}