Skip to main content

net_wire/quic/frame/
stream.rs

1//! RFC 9000 STREAM frame parsing.
2
3use super::super::varint::QuicVarInt;
4use super::parse::{QuicFrameField, QuicFrameParseError};
5
6const MAX_STREAM_RANGE_END: u64 = (1 << 62) - 1;
7
8/// A checked borrowed RFC 9000 STREAM frame view.
9#[derive(Clone, Copy, Debug, Eq, PartialEq)]
10pub struct QuicStreamFrame<'a> {
11    bytes: &'a [u8],
12    frame_type: QuicVarInt<'a>,
13    stream_id: QuicVarInt<'a>,
14    offset: Option<QuicVarInt<'a>>,
15    length: Option<QuicVarInt<'a>>,
16    stream_data: &'a [u8],
17}
18
19impl<'a> QuicStreamFrame<'a> {
20    /// Returns the exact encoded frame bytes.
21    pub const fn as_bytes(self) -> &'a [u8] {
22        self.bytes
23    }
24
25    /// Returns the exact encoded frame-type variable integer.
26    pub const fn frame_type(self) -> QuicVarInt<'a> {
27        self.frame_type
28    }
29
30    /// Returns the exact encoded stream-ID variable integer.
31    pub const fn stream_id(self) -> QuicVarInt<'a> {
32        self.stream_id
33    }
34
35    /// Returns the exact encoded offset when the OFF bit is present.
36    ///
37    /// `None` means the effective stream offset is zero.
38    pub const fn offset(self) -> Option<QuicVarInt<'a>> {
39        self.offset
40    }
41
42    /// Returns the exact encoded data length when the LEN bit is present.
43    ///
44    /// `None` means stream data consumes the remaining supplied frame-sequence bytes.
45    pub const fn length(self) -> Option<QuicVarInt<'a>> {
46        self.length
47    }
48
49    /// Returns the exact borrowed STREAM data bytes, which may be empty.
50    pub const fn stream_data(self) -> &'a [u8] {
51        self.stream_data
52    }
53
54    /// Returns whether the FIN bit is set in the frame type.
55    pub const fn fin(self) -> bool {
56        self.frame_type.value() & 0x01 != 0
57    }
58}
59
60pub(super) fn parse_stream<'a>(
61    bytes: &'a [u8],
62    frame_type: QuicVarInt<'a>,
63    offset: usize,
64) -> Result<(QuicStreamFrame<'a>, &'a [u8]), QuicFrameParseError> {
65    let flags = frame_type.value();
66    let has_offset = flags & 0x04 != 0;
67    let has_length = flags & 0x02 != 0;
68
69    let stream_id_start = frame_type.byte_len();
70    let stream_id_offset = offset + stream_id_start;
71    let stream_id = QuicVarInt::parse(&bytes[stream_id_start..]).map_err(|error| {
72        QuicFrameParseError::Field {
73            field: QuicFrameField::StreamId,
74            offset: stream_id_offset,
75            error,
76        }
77    })?;
78
79    let mut data_start = stream_id_start + stream_id.byte_len();
80    // For an implicit offset, this is the first byte after Stream ID, where zero applies.
81    let range_offset = offset + data_start;
82    let stream_offset = if has_offset {
83        let field_offset = offset + data_start;
84        let value = QuicVarInt::parse(&bytes[data_start..]).map_err(|error| {
85            QuicFrameParseError::Field {
86                field: QuicFrameField::StreamOffset,
87                offset: field_offset,
88                error,
89            }
90        })?;
91        data_start += value.byte_len();
92        Some(value)
93    } else {
94        None
95    };
96
97    let length = if has_length {
98        let field_offset = offset + data_start;
99        let value = QuicVarInt::parse(&bytes[data_start..]).map_err(|error| {
100            QuicFrameParseError::Field {
101                field: QuicFrameField::StreamLength,
102                offset: field_offset,
103                error,
104            }
105        })?;
106        data_start += value.byte_len();
107        Some((value, field_offset))
108    } else {
109        None
110    };
111
112    let start = stream_offset.map_or(0, QuicVarInt::value);
113    let data_offset = offset + data_start;
114    let (length_varint, data_end) = match length {
115        Some((length, length_offset)) => {
116            let data_length = length.value();
117            validate_range(start, data_length, range_offset)?;
118            let length_usize = usize::try_from(data_length).map_err(|_| {
119                QuicFrameParseError::LengthNotRepresentable {
120                    field: QuicFrameField::StreamLength,
121                    offset: length_offset,
122                    value: data_length,
123                }
124            })?;
125            let data_end = data_start.checked_add(length_usize).ok_or(
126                QuicFrameParseError::LengthOverflow {
127                    field: QuicFrameField::StreamData,
128                    offset: data_offset,
129                    length: length_usize,
130                },
131            )?;
132            let available = bytes.len() - data_start;
133            if available < length_usize {
134                return Err(QuicFrameParseError::IncompleteBytes {
135                    field: QuicFrameField::StreamData,
136                    offset: data_offset,
137                    required: length_usize,
138                    available,
139                });
140            }
141            (Some(length), data_end)
142        }
143        None => {
144            let data_end = bytes.len();
145            // Rust supports no target where usize is wider than u64; preserve the
146            // conversion site so that this cannot silently become truncating there.
147            let data_length = match u64::try_from(data_end - data_start) {
148                Ok(value) => value,
149                Err(_) => {
150                    return Err(QuicFrameParseError::ImplicitLengthNotRepresentable {
151                        field: QuicFrameField::StreamData,
152                        offset: data_offset,
153                        length: data_end - data_start,
154                    });
155                }
156            };
157            validate_range(start, data_length, range_offset)?;
158            (None, data_end)
159        }
160    };
161
162    Ok((
163        QuicStreamFrame {
164            bytes: &bytes[..data_end],
165            frame_type,
166            stream_id,
167            offset: stream_offset,
168            length: length_varint,
169            stream_data: &bytes[data_start..data_end],
170        },
171        &bytes[data_end..],
172    ))
173}
174
175fn validate_range(start: u64, length: u64, offset: usize) -> Result<(), QuicFrameParseError> {
176    if start
177        .checked_add(length)
178        .is_none_or(|end| end > MAX_STREAM_RANGE_END)
179    {
180        return Err(QuicFrameParseError::FieldRangeOutOfRange {
181            field: QuicFrameField::StreamOffset,
182            offset,
183            start,
184            length,
185            maximum: MAX_STREAM_RANGE_END,
186        });
187    }
188    Ok(())
189}