sec_http3/
ext.rs

1//! Extensions for the HTTP/3 protocol.
2
3use std::convert::TryFrom;
4use std::str::FromStr;
5
6use bytes::{Buf, Bytes};
7
8use crate::{
9    error::Code,
10    proto::{stream::StreamId, varint::VarInt},
11    Error,
12};
13
14/// Describes the `:protocol` pseudo-header for extended connect
15///
16/// See: <https://www.rfc-editor.org/rfc/rfc8441#section-4>
17#[derive(Copy, PartialEq, Debug, Clone)]
18pub struct Protocol(ProtocolInner);
19
20impl Protocol {
21    /// WebTransport protocol
22    pub const WEB_TRANSPORT: Protocol = Protocol(ProtocolInner::WebTransport);
23}
24
25#[derive(Copy, PartialEq, Debug, Clone)]
26enum ProtocolInner {
27    WebTransport,
28}
29
30/// Error when parsing the protocol
31pub struct InvalidProtocol;
32
33impl FromStr for Protocol {
34    type Err = InvalidProtocol;
35
36    fn from_str(s: &str) -> Result<Self, Self::Err> {
37        match s {
38            "webtransport" => Ok(Self(ProtocolInner::WebTransport)),
39            _ => Err(InvalidProtocol),
40        }
41    }
42}
43
44/// HTTP datagram frames
45/// See: <https://www.rfc-editor.org/rfc/rfc9297#section-2.1>
46pub struct Datagram<B = Bytes> {
47    /// Stream id divided by 4
48    stream_id: StreamId,
49    /// The data contained in the datagram
50    payload: B,
51}
52
53impl<B> Datagram<B>
54where
55    B: Buf,
56{
57    /// Creates a new datagram frame
58    pub fn new(stream_id: StreamId, payload: B) -> Self {
59        assert!(
60            stream_id.into_inner() % 4 == 0,
61            "StreamId is not divisible by 4"
62        );
63        Self { stream_id, payload }
64    }
65
66    /// Decodes a datagram frame from the QUIC datagram
67    pub fn decode(mut buf: B) -> Result<Self, Error> {
68        let q_stream_id = VarInt::decode(&mut buf)
69            .map_err(|_| Code::H3_DATAGRAM_ERROR.with_cause("Malformed datagram frame"))?;
70
71        //= https://www.rfc-editor.org/rfc/rfc9297#section-2.1
72        // Quarter Stream ID: A variable-length integer that contains the value of the client-initiated bidirectional
73        // stream that this datagram is associated with divided by four (the division by four stems
74        // from the fact that HTTP requests are sent on client-initiated bidirectional streams,
75        // which have stream IDs that are divisible by four). The largest legal QUIC stream ID
76        // value is 262-1, so the largest legal value of the Quarter Stream ID field is 260-1.
77        // Receipt of an HTTP/3 Datagram that includes a larger value MUST be treated as an HTTP/3
78        // connection error of type H3_DATAGRAM_ERROR (0x33).
79        let stream_id = StreamId::try_from(u64::from(q_stream_id) * 4)
80            .map_err(|_| Code::H3_DATAGRAM_ERROR.with_cause("Invalid stream id"))?;
81
82        let payload = buf;
83
84        Ok(Self { stream_id, payload })
85    }
86
87    #[inline]
88    /// Returns the associated stream id of the datagram
89    pub fn stream_id(&self) -> StreamId {
90        self.stream_id
91    }
92
93    #[inline]
94    /// Returns the datagram payload
95    pub fn payload(&self) -> &B {
96        &self.payload
97    }
98
99    /// Encode the datagram to wire format
100    pub fn encode<D: bytes::BufMut>(self, buf: &mut D) {
101        (VarInt::from(self.stream_id) / 4).encode(buf);
102        buf.put(self.payload);
103    }
104
105    /// Returns the datagram payload
106    pub fn into_payload(self) -> B {
107        self.payload
108    }
109}