Skip to main content

net_wire/http3/frame/
push.rs

1//! Typed HTTP/3 push frame payload views and builders.
2
3use crate::http3::codepoints::Http3FrameType;
4use crate::http3::ids::Http3PushId;
5use crate::quic::varint::{QuicVarInt, QuicVarIntLen};
6
7use super::envelope::Http3Frame;
8use super::payload::{
9    Http3FramePayloadBuildError, Http3FramePayloadField, Http3FramePayloadParseError, add_payload,
10    encode_varint, envelope, parse_exact_varint, parse_payload_varint, validate_type,
11};
12
13/// A validated borrowed HTTP/3 CANCEL_PUSH frame.
14#[derive(Clone, Copy, Debug, Eq, PartialEq)]
15pub struct Http3CancelPush<'a> {
16    frame: Http3Frame<'a>,
17    push_id: QuicVarInt<'a>,
18}
19
20impl<'a> Http3CancelPush<'a> {
21    /// Assembles a CANCEL_PUSH view from builder-validated components.
22    pub(in crate::http3) fn from_validated(
23        frame: Http3Frame<'a>,
24        push_id: Http3PushId,
25        push_id_length: QuicVarIntLen,
26    ) -> Self {
27        let push_id = QuicVarInt::from_validated(
28            &frame.payload()[..push_id_length.byte_len()],
29            push_id.value(),
30            push_id_length,
31        );
32        Self { frame, push_id }
33    }
34
35    /// Parses the first complete CANCEL_PUSH frame, enforcing the caller-provided payload maximum.
36    pub fn parse(
37        bytes: &'a [u8],
38        maximum_payload: usize,
39    ) -> Result<Self, Http3FramePayloadParseError> {
40        Self::from_frame(
41            Http3Frame::parse(bytes, maximum_payload)
42                .map_err(Http3FramePayloadParseError::Frame)?,
43        )
44    }
45
46    /// Validates a raw CANCEL_PUSH frame's intrinsic layout.
47    pub fn from_frame(frame: Http3Frame<'a>) -> Result<Self, Http3FramePayloadParseError> {
48        validate_type(frame, Http3FrameType::CANCEL_PUSH)?;
49        let push_id = parse_exact_varint(frame.payload(), Http3FramePayloadField::PushId)?;
50        Ok(Self { frame, push_id })
51    }
52
53    /// Returns the validated raw frame.
54    pub const fn frame(&self) -> Http3Frame<'a> {
55        self.frame
56    }
57
58    /// Returns the exact represented frame bytes.
59    pub const fn as_bytes(&self) -> &'a [u8] {
60        self.frame.as_bytes()
61    }
62
63    /// Returns the raw-preserving Push ID.
64    pub const fn push_id(&self) -> Http3PushId {
65        Http3PushId::new(self.push_id.value())
66    }
67
68    /// Returns the exact Push ID variable-length integer.
69    pub const fn push_id_varint(&self) -> QuicVarInt<'a> {
70        self.push_id
71    }
72}
73
74/// A validated borrowed HTTP/3 PUSH_PROMISE frame.
75#[derive(Clone, Copy, Debug, Eq, PartialEq)]
76pub struct Http3PushPromise<'a> {
77    frame: Http3Frame<'a>,
78    push_id: QuicVarInt<'a>,
79}
80
81impl<'a> Http3PushPromise<'a> {
82    /// Assembles a PUSH_PROMISE view from builder-validated components.
83    pub(in crate::http3) fn from_validated(
84        frame: Http3Frame<'a>,
85        push_id: Http3PushId,
86        push_id_length: QuicVarIntLen,
87    ) -> Self {
88        let push_id = QuicVarInt::from_validated(
89            &frame.payload()[..push_id_length.byte_len()],
90            push_id.value(),
91            push_id_length,
92        );
93        Self { frame, push_id }
94    }
95
96    /// Parses the first complete PUSH_PROMISE frame, enforcing the caller-provided payload maximum.
97    pub fn parse(
98        bytes: &'a [u8],
99        maximum_payload: usize,
100    ) -> Result<Self, Http3FramePayloadParseError> {
101        Self::from_frame(
102            Http3Frame::parse(bytes, maximum_payload)
103                .map_err(Http3FramePayloadParseError::Frame)?,
104        )
105    }
106
107    /// Validates a raw PUSH_PROMISE frame's initial Push ID without decoding QPACK.
108    pub fn from_frame(frame: Http3Frame<'a>) -> Result<Self, Http3FramePayloadParseError> {
109        validate_type(frame, Http3FrameType::PUSH_PROMISE)?;
110        let push_id = parse_payload_varint(frame.payload(), Http3FramePayloadField::PushId, 0)?;
111        Ok(Self { frame, push_id })
112    }
113
114    /// Returns the validated raw frame.
115    pub const fn frame(&self) -> Http3Frame<'a> {
116        self.frame
117    }
118
119    /// Returns the exact represented frame bytes.
120    pub const fn as_bytes(&self) -> &'a [u8] {
121        self.frame.as_bytes()
122    }
123
124    /// Returns the raw-preserving Push ID.
125    pub const fn push_id(&self) -> Http3PushId {
126        Http3PushId::new(self.push_id.value())
127    }
128
129    /// Returns the exact Push ID variable-length integer.
130    pub const fn push_id_varint(&self) -> QuicVarInt<'a> {
131        self.push_id
132    }
133
134    /// Returns the remaining opaque QPACK-encoded field section.
135    pub fn encoded_field_section(&self) -> &'a [u8] {
136        &self.frame.payload()[self.push_id.byte_len()..]
137    }
138}
139
140/// A validated borrowed HTTP/3 MAX_PUSH_ID frame.
141#[derive(Clone, Copy, Debug, Eq, PartialEq)]
142pub struct Http3MaxPushId<'a> {
143    frame: Http3Frame<'a>,
144    push_id: QuicVarInt<'a>,
145}
146
147impl<'a> Http3MaxPushId<'a> {
148    /// Assembles a MAX_PUSH_ID view from builder-validated components.
149    pub(in crate::http3) fn from_validated(
150        frame: Http3Frame<'a>,
151        push_id: Http3PushId,
152        push_id_length: QuicVarIntLen,
153    ) -> Self {
154        let push_id = QuicVarInt::from_validated(
155            &frame.payload()[..push_id_length.byte_len()],
156            push_id.value(),
157            push_id_length,
158        );
159        Self { frame, push_id }
160    }
161
162    /// Parses the first complete MAX_PUSH_ID frame, enforcing the caller-provided payload maximum.
163    pub fn parse(
164        bytes: &'a [u8],
165        maximum_payload: usize,
166    ) -> Result<Self, Http3FramePayloadParseError> {
167        Self::from_frame(
168            Http3Frame::parse(bytes, maximum_payload)
169                .map_err(Http3FramePayloadParseError::Frame)?,
170        )
171    }
172
173    /// Validates a raw MAX_PUSH_ID frame's intrinsic layout.
174    pub fn from_frame(frame: Http3Frame<'a>) -> Result<Self, Http3FramePayloadParseError> {
175        validate_type(frame, Http3FrameType::MAX_PUSH_ID)?;
176        let push_id = parse_exact_varint(frame.payload(), Http3FramePayloadField::PushId)?;
177        Ok(Self { frame, push_id })
178    }
179
180    /// Returns the validated raw frame.
181    pub const fn frame(&self) -> Http3Frame<'a> {
182        self.frame
183    }
184
185    /// Returns the exact represented frame bytes.
186    pub const fn as_bytes(&self) -> &'a [u8] {
187        self.frame.as_bytes()
188    }
189
190    /// Returns the raw-preserving Push ID.
191    pub const fn push_id(&self) -> Http3PushId {
192        Http3PushId::new(self.push_id.value())
193    }
194
195    /// Returns the exact Push ID variable-length integer.
196    pub const fn push_id_varint(&self) -> QuicVarInt<'a> {
197        self.push_id
198    }
199}
200
201/// Builds a typed HTTP/3 CANCEL_PUSH frame in caller-owned storage.
202pub struct Http3CancelPushBuilder<'output> {
203    destination: &'output mut [u8],
204    push_id: Http3PushId,
205}
206
207impl<'output> Http3CancelPushBuilder<'output> {
208    /// Creates a CANCEL_PUSH builder for a raw Push ID.
209    pub fn new(destination: &'output mut [u8], push_id: Http3PushId) -> Self {
210        Self {
211            destination,
212            push_id,
213        }
214    }
215
216    /// Canonically encodes and atomically writes the CANCEL_PUSH frame.
217    pub fn build(self) -> Result<Http3CancelPush<'output>, Http3FramePayloadBuildError> {
218        let push_id = encode_varint(self.push_id.value()).map_err(|error| {
219            Http3FramePayloadBuildError::PayloadVarInt {
220                field: Http3FramePayloadField::PushId,
221                error,
222            }
223        })?;
224        let plan = envelope(
225            Http3FrameType::CANCEL_PUSH,
226            push_id.byte_len(),
227            self.destination,
228        )?;
229        let header_length = plan.header_length();
230        let required = plan.required();
231        let bytes = &mut self.destination[..required];
232        plan.write_header(bytes);
233        bytes[header_length..].copy_from_slice(push_id.bytes());
234        let frame = plan.finish(bytes);
235        Ok(Http3CancelPush::from_validated(
236            frame,
237            self.push_id,
238            push_id.len,
239        ))
240    }
241}
242
243/// Builds a typed HTTP/3 PUSH_PROMISE frame in caller-owned storage.
244pub struct Http3PushPromiseBuilder<'output, 'section> {
245    destination: &'output mut [u8],
246    push_id: Http3PushId,
247    encoded_field_section: &'section [u8],
248}
249
250impl<'output, 'section> Http3PushPromiseBuilder<'output, 'section> {
251    /// Creates a PUSH_PROMISE builder for a raw Push ID and opaque QPACK field section.
252    pub fn new(
253        destination: &'output mut [u8],
254        push_id: Http3PushId,
255        encoded_field_section: &'section [u8],
256    ) -> Self {
257        Self {
258            destination,
259            push_id,
260            encoded_field_section,
261        }
262    }
263
264    /// Canonically encodes and atomically writes the PUSH_PROMISE frame.
265    pub fn build(self) -> Result<Http3PushPromise<'output>, Http3FramePayloadBuildError> {
266        let push_id = encode_varint(self.push_id.value()).map_err(|error| {
267            Http3FramePayloadBuildError::PayloadVarInt {
268                field: Http3FramePayloadField::PushId,
269                error,
270            }
271        })?;
272        let payload_length = add_payload(push_id.byte_len(), self.encoded_field_section.len())
273            .ok_or(Http3FramePayloadBuildError::PayloadLengthOverflow {
274                current: push_id.byte_len(),
275                addition: self.encoded_field_section.len(),
276            })?;
277        let plan = envelope(
278            Http3FrameType::PUSH_PROMISE,
279            payload_length,
280            self.destination,
281        )?;
282        let header_length = plan.header_length();
283        let required = plan.required();
284        let bytes = &mut self.destination[..required];
285        plan.write_header(bytes);
286        let payload = &mut bytes[header_length..];
287        let push_id_length = push_id.byte_len();
288        payload[..push_id_length].copy_from_slice(push_id.bytes());
289        payload[push_id_length..].copy_from_slice(self.encoded_field_section);
290        let frame = plan.finish(bytes);
291        Ok(Http3PushPromise::from_validated(
292            frame,
293            self.push_id,
294            push_id.len,
295        ))
296    }
297}
298
299/// Builds a typed HTTP/3 MAX_PUSH_ID frame in caller-owned storage.
300pub struct Http3MaxPushIdBuilder<'output> {
301    destination: &'output mut [u8],
302    push_id: Http3PushId,
303}
304
305impl<'output> Http3MaxPushIdBuilder<'output> {
306    /// Creates a MAX_PUSH_ID builder for a raw Push ID.
307    pub fn new(destination: &'output mut [u8], push_id: Http3PushId) -> Self {
308        Self {
309            destination,
310            push_id,
311        }
312    }
313
314    /// Canonically encodes and atomically writes the MAX_PUSH_ID frame.
315    pub fn build(self) -> Result<Http3MaxPushId<'output>, Http3FramePayloadBuildError> {
316        let push_id = encode_varint(self.push_id.value()).map_err(|error| {
317            Http3FramePayloadBuildError::PayloadVarInt {
318                field: Http3FramePayloadField::PushId,
319                error,
320            }
321        })?;
322        let plan = envelope(
323            Http3FrameType::MAX_PUSH_ID,
324            push_id.byte_len(),
325            self.destination,
326        )?;
327        let header_length = plan.header_length();
328        let required = plan.required();
329        let bytes = &mut self.destination[..required];
330        plan.write_header(bytes);
331        bytes[header_length..].copy_from_slice(push_id.bytes());
332        let frame = plan.finish(bytes);
333        Ok(Http3MaxPushId::from_validated(
334            frame,
335            self.push_id,
336            push_id.len,
337        ))
338    }
339}