Skip to main content

webtrans_proto/
frame.rs

1//! HTTP/3 frame type utilities used by WebTransport.
2
3use bytes::{Buf, BufMut};
4
5use crate::grease::is_grease_value;
6use crate::{VarInt, VarIntUnexpectedEnd};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9/// HTTP/3 frame type identifier.
10pub struct Frame(pub VarInt);
11
12impl Frame {
13    /// Decode a frame type varint from the buffer.
14    pub fn decode<B: Buf>(buf: &mut B) -> Result<Self, VarIntUnexpectedEnd> {
15        let typ = VarInt::decode(buf)?;
16        Ok(Frame(typ))
17    }
18
19    /// Encode this frame type varint to the buffer.
20    pub fn encode<B: BufMut>(&self, buf: &mut B) {
21        self.0.encode(buf)
22    }
23
24    /// Return `true` when this frame type uses RFC 9114 GREASE spacing.
25    pub fn is_grease(&self) -> bool {
26        is_grease_value(self.0.into_inner())
27    }
28
29    /// Read one full frame header and return its type plus a limited payload view.
30    pub fn read<B: Buf>(
31        buf: &mut B,
32    ) -> Result<(Frame, bytes::buf::Take<&mut B>), VarIntUnexpectedEnd> {
33        let typ = Frame::decode(buf)?;
34        let size = VarInt::decode(buf)?;
35
36        let mut limit = Buf::take(buf, size.into_inner() as usize);
37        if limit.remaining() < limit.limit() {
38            return Err(VarIntUnexpectedEnd);
39        }
40
41        // Retry if this is a GREASE frame that must be ignored.
42        if typ.is_grease() {
43            limit.advance(limit.limit());
44            return Self::read(limit.into_inner());
45        }
46
47        Ok((typ, limit))
48    }
49
50    /// Build a frame type from a known `u32` value.
51    pub const fn from_u32(value: u32) -> Self {
52        Self(VarInt::from_u32(value))
53    }
54
55    // Frames sent at the start of a bidirectional stream.
56    /// DATA frame type (`0x00`).
57    pub const DATA: Frame = Frame::from_u32(0x00);
58    /// HEADERS frame type (`0x01`).
59    pub const HEADERS: Frame = Frame::from_u32(0x01);
60    /// SETTINGS frame type (`0x04`).
61    pub const SETTINGS: Frame = Frame::from_u32(0x04);
62    /// WEBTRANSPORT stream frame type (`0x41`).
63    pub const WEBTRANSPORT: Frame = Frame::from_u32(0x41);
64}