Skip to main content

zincio_http/h3/
frame.rs

1//! HTTP/3 frame codec (RFC 9114 Section 7).
2//!
3//! Frames on HTTP/3 streams have the layout `Type (i), Length (i), Frame
4//! Payload (..)` where `Type` and `Length` are QUIC variable-length
5//! integers (RFC 9000 Section 16). This module provides:
6//!
7//! - [`FrameDecoder`]: an incremental, buffer-owning decoder. The driver
8//!   feeds received bytes in and pulls completed [`Frame`]s out; `Ok(None)`
9//!   means more input is needed. Unknown and reserved (grease) frame types
10//!   are skipped without surfacing, per RFC 9114 Section 7.2.8.
11//! - [`Frame::encode`]: the corresponding serializer.
12//!
13//! Parse-level validation follows RFC 9114 Section 7.1: a frame payload
14//! must contain exactly the fields identified for its type — extra bytes
15//! and truncated fields are `H3_FRAME_ERROR`, as are redundant
16//! (non-minimal) variable-length integer encodings (Section 10.8, RFC 9000
17//! Section 16). HTTP/2 frame types without an HTTP/3 equivalent
18//! (PRIORITY, PING, WINDOW_UPDATE, CONTINUATION) are `H3_FRAME_UNEXPECTED`
19//! (Section 7.2.8).
20//!
21//! What this module deliberately does *not* enforce — it is the driver's
22//! (connection-state) job:
23//!
24//! - stream-type rules (which frame types are legal on which stream, and
25//!   that SETTINGS is first on the control stream),
26//! - `SETTINGS_MAX_FIELD_SECTION_SIZE` limits on HEADERS/PUSH_PROMISE
27//!   payloads,
28//! - push ID / stream ID semantics (`H3_ID_ERROR`).
29//!
30//! A clean end of stream (FIN) with `buffered() != 0` means the last frame
31//! was truncated; RFC 9114 Section 7.1 requires that be treated as
32//! `H3_FRAME_ERROR` by the driver.
33
34use std::collections::VecDeque;
35
36use bytes::{BufMut, Bytes, BytesMut};
37
38/// The largest value a QUIC variable-length integer can carry.
39pub const MAX_VARINT: u64 = (1 << 62) - 1;
40
41/// `DATA` frame type (RFC 9114 Section 7.2.1).
42pub const FRAME_DATA: u64 = 0x0;
43/// `HEADERS` frame type (RFC 9114 Section 7.2.2).
44pub const FRAME_HEADERS: u64 = 0x1;
45/// `CANCEL_PUSH` frame type (RFC 9114 Section 7.2.3).
46pub const FRAME_CANCEL_PUSH: u64 = 0x3;
47/// `SETTINGS` frame type (RFC 9114 Section 7.2.4).
48pub const FRAME_SETTINGS: u64 = 0x4;
49/// `PUSH_PROMISE` frame type (RFC 9114 Section 7.2.5).
50pub const FRAME_PUSH_PROMISE: u64 = 0x5;
51/// `GOAWAY` frame type (RFC 9114 Section 7.2.6).
52pub const FRAME_GOAWAY: u64 = 0x7;
53/// `MAX_PUSH_ID` frame type (RFC 9114 Section 7.2.7).
54pub const FRAME_MAX_PUSH_ID: u64 = 0xd;
55
56/// `SETTINGS_QPACK_MAX_TABLE_CAPACITY` (RFC 9204 Section 5).
57///
58/// Consumed by the control-stream driver when interpreting peer SETTINGS.
59#[allow(dead_code)]
60pub const SETTINGS_QPACK_MAX_TABLE_CAPACITY: u64 = 0x1;
61/// `SETTINGS_MAX_FIELD_SECTION_SIZE` (RFC 9114 Section 7.2.4.1).
62///
63/// Consumed by the control-stream driver when interpreting peer SETTINGS.
64#[allow(dead_code)]
65pub const SETTINGS_MAX_FIELD_SECTION_SIZE: u64 = 0x6;
66/// `SETTINGS_QPACK_BLOCKED_STREAMS` (RFC 9204 Section 5).
67///
68/// Consumed by the control-stream driver when interpreting peer SETTINGS.
69#[allow(dead_code)]
70pub const SETTINGS_QPACK_BLOCKED_STREAMS: u64 = 0x7;
71/// `SETTINGS_ENABLE_CONNECT_PROTOCOL` (RFC 9114 Section 7.2.4.1).
72///
73/// Consumed by the control-stream driver when interpreting peer SETTINGS.
74#[allow(dead_code)]
75pub const SETTINGS_ENABLE_CONNECT_PROTOCOL: u64 = 0x8;
76/// `SETTINGS_H3_DATAGRAM` (RFC 9297 Section 3.1).
77///
78/// Consumed by the control-stream driver when interpreting peer SETTINGS.
79#[allow(dead_code)]
80pub const SETTINGS_H3_DATAGRAM: u64 = 0x33;
81
82/// A single SETTINGS parameter: `(identifier, value)`.
83pub type Setting = (u64, u64);
84
85/// A parsed `SETTINGS` frame payload (RFC 9114 Section 7.2.4).
86///
87/// Settings are kept in wire order. Reserved (grease) identifiers are
88/// dropped on decode and may be added for encoding; unknown identifiers
89/// are preserved and ignored by the driver.
90#[derive(Debug, Clone, Default, PartialEq, Eq)]
91pub struct Settings {
92    entries: Vec<Setting>,
93}
94
95impl Settings {
96    /// An empty SETTINGS payload.
97    #[inline]
98    pub fn new() -> Self {
99        Self::default()
100    }
101
102    /// Appends a `(identifier, value)` parameter in wire order.
103    #[inline]
104    pub fn insert(&mut self, id: u64, value: u64) {
105        self.entries.push((id, value));
106    }
107
108    /// The value of the first parameter with `id`, if any.
109    #[inline]
110    pub fn get(&self, id: u64) -> Option<u64> {
111        self.entries
112            .iter()
113            .find_map(|(i, v)| (*i == id).then_some(*v))
114    }
115
116    /// The parameters in wire order.
117    #[inline]
118    pub fn iter(&self) -> impl Iterator<Item = Setting> + '_ {
119        self.entries.iter().copied()
120    }
121}
122
123/// An HTTP/3 frame (RFC 9114 Section 7.2).
124///
125/// `Data` and `Headers` payloads are opaque byte ranges. `Data` is the
126/// streamed body chunk (the driver may hand it to the body reader
127/// without copying); `Headers` and `PushPromise` field sections are
128/// QPACK-encoded and decoded by the driver.
129#[derive(Debug, Clone, PartialEq, Eq)]
130pub enum Frame {
131    /// `DATA`: a chunk of the request or response body.
132    Data(Bytes),
133    /// `HEADERS`: the QPACK-encoded field section.
134    Headers(Bytes),
135    /// `SETTINGS`: connection parameters (first frame of a control
136    /// stream).
137    Settings(Settings),
138    /// `CANCEL_PUSH`: push ID whose push the peer should abandon.
139    CancelPush(u64),
140    /// `PUSH_PROMISE`: push ID plus the promised request's QPACK-encoded
141    /// field section.
142    PushPromise { push_id: u64, field_section: Bytes },
143    /// `GOAWAY`: the highest stream ID (server) or push ID (client) the
144    /// sender will process.
145    Goaway(u64),
146    /// `MAX_PUSH_ID`: the highest push ID the server may use.
147    MaxPushId(u64),
148}
149
150impl Frame {
151    /// Whether this is one of the known HTTP/3 frame types (RFC 9114
152    /// Section 7.2).
153    ///
154    /// The decoder never surfaces unknown or reserved (grease) frame types
155    /// — they are consumed and skipped (Section 7.2.8) — so every frame it
156    /// returns is by construction a known type. This method documents the
157    /// request-stream rule (Section 4.1) that after the trailers only
158    /// unknown frames may still appear.
159    #[inline]
160    pub fn is_known(&self) -> bool {
161        matches!(
162            self,
163            Frame::Data(_)
164                | Frame::Headers(_)
165                | Frame::Settings(_)
166                | Frame::CancelPush(_)
167                | Frame::PushPromise { .. }
168                | Frame::Goaway(_)
169                | Frame::MaxPushId(_)
170        )
171    }
172
173    /// Serializes this frame (type, length, payload) into `dst`.
174    #[inline]
175    pub fn encode(&self, dst: &mut BytesMut) {
176        match self {
177            Frame::Data(payload) => {
178                write_varint(FRAME_DATA, dst);
179                write_varint(payload.len() as u64, dst);
180                dst.extend_from_slice(payload);
181            }
182            Frame::Headers(payload) => {
183                write_varint(FRAME_HEADERS, dst);
184                write_varint(payload.len() as u64, dst);
185                dst.extend_from_slice(payload);
186            }
187            Frame::Settings(settings) => {
188                write_varint(FRAME_SETTINGS, dst);
189                let len: usize = settings
190                    .entries
191                    .iter()
192                    .map(|(id, value)| varint_size(*id) + varint_size(*value))
193                    .sum();
194                write_varint(len as u64, dst);
195                for (id, value) in &settings.entries {
196                    write_varint(*id, dst);
197                    write_varint(*value, dst);
198                }
199            }
200            Frame::CancelPush(push_id) => {
201                write_varint(FRAME_CANCEL_PUSH, dst);
202                write_varint(varint_size(*push_id) as u64, dst);
203                write_varint(*push_id, dst);
204            }
205            Frame::PushPromise {
206                push_id,
207                field_section,
208            } => {
209                write_varint(FRAME_PUSH_PROMISE, dst);
210                write_varint((varint_size(*push_id) + field_section.len()) as u64, dst);
211                write_varint(*push_id, dst);
212                dst.extend_from_slice(field_section);
213            }
214            Frame::Goaway(stream_id) => {
215                write_varint(FRAME_GOAWAY, dst);
216                write_varint(varint_size(*stream_id) as u64, dst);
217                write_varint(*stream_id, dst);
218            }
219            Frame::MaxPushId(push_id) => {
220                write_varint(FRAME_MAX_PUSH_ID, dst);
221                write_varint(varint_size(*push_id) as u64, dst);
222                write_varint(*push_id, dst);
223            }
224        }
225    }
226}
227
228/// Errors raised by [`FrameDecoder::next_frame`].
229///
230/// Each variant corresponds to a distinct RFC 9114 connection error code
231/// (see [`FrameError::h3_code`]).
232#[derive(Debug, Clone, Copy, PartialEq, Eq)]
233pub enum FrameError {
234    /// `H3_FRAME_ERROR` (0x0106): the frame payload does not exactly match
235    /// the fields identified for its type, or a variable-length integer is
236    /// encoded non-minimally (RFC 9114 Sections 7.1 and 10.8).
237    Frame,
238    /// `H3_FRAME_UNEXPECTED` (0x0105): an HTTP/2 frame type with no
239    /// HTTP/3 equivalent (PRIORITY, PING, WINDOW_UPDATE, CONTINUATION;
240    /// RFC 9114 Section 7.2.8).
241    Unexpected(u64),
242    /// `H3_SETTINGS_ERROR` (0x0109): a reserved setting identifier
243    /// (0x02-0x05) or a duplicate identifier in one SETTINGS frame
244    /// (RFC 9114 Section 7.2.4).
245    Settings,
246}
247
248impl FrameError {
249    /// The RFC 9114 connection error code for this error.
250    pub const fn h3_code(self) -> u64 {
251        use crate::h3::H3Error;
252        match self {
253            FrameError::Frame => H3Error::FrameError.code(),
254            FrameError::Unexpected(_) => H3Error::FrameUnexpected.code(),
255            FrameError::Settings => H3Error::Settings.code(),
256        }
257    }
258}
259
260/// Incremental HTTP/3 frame decoder.
261///
262/// The decoder owns its buffer: the driver calls [`FrameDecoder::extend`]
263/// with every received chunk and [`FrameDecoder::next_frame`] once per
264/// event-loop turn, draining as many complete frames as are buffered.
265///
266/// The buffer is a `VecDeque<Bytes>` that keeps each QUIC chunk intact.
267/// `extend` is zero-copy (push), and `DATA` payloads are returned as
268/// refcounted slices when they lie in a single chunk, avoiding the
269/// `BytesMut` coalesce on every fragment.
270#[derive(Debug, Default)]
271pub struct FrameDecoder {
272    bufs: VecDeque<Bytes>,
273    len: usize,
274}
275
276impl FrameDecoder {
277    /// A decoder with an empty buffer.
278    #[inline]
279    pub fn new() -> Self {
280        Self::default()
281    }
282
283    /// Appends received bytes to the input buffer.
284    #[inline]
285    pub fn extend(&mut self, data: Bytes) {
286        if data.is_empty() {
287            return;
288        }
289        self.len += data.len();
290        self.bufs.push_back(data);
291    }
292
293    /// Bytes buffered but not yet consumed by a frame.
294    #[inline]
295    pub fn buffered(&self) -> usize {
296        self.len
297    }
298
299    /// Pops the next complete frame, if any.
300    ///
301    /// Returns `Ok(None)` when the buffer does not yet hold a complete
302    /// frame; callers must extend the buffer and poll again. Unknown and
303    /// reserved frame types are consumed and skipped (RFC 9114 Section
304    /// 7.2.8) — a known frame behind them is still returned.
305    #[inline]
306    pub fn next_frame(&mut self) -> Result<Option<Frame>, FrameError> {
307        loop {
308            let Some((ty, type_len)) = self.parse_varint_at(0)? else {
309                return Ok(None);
310            };
311            if matches!(ty, 0x02 | 0x06 | 0x08 | 0x09) {
312                return Err(FrameError::Unexpected(ty));
313            }
314            let Some((len, len_len)) = self.parse_varint_at(type_len)? else {
315                return Ok(None);
316            };
317            let header_len = type_len + len_len;
318            let Some(total) = header_len.checked_add(len as usize) else {
319                return Err(FrameError::Frame);
320            };
321            if total > self.len {
322                return Ok(None);
323            }
324            if !is_known_frame_type(ty) {
325                self.advance(total);
326                continue;
327            }
328            self.advance(header_len);
329            let payload = self.take_bytes(len as usize);
330            let frame = match ty {
331                FRAME_DATA => Frame::Data(payload),
332                FRAME_HEADERS => Frame::Headers(payload),
333                FRAME_CANCEL_PUSH => Frame::CancelPush(take_varint(&payload)?),
334                FRAME_SETTINGS => Frame::Settings(parse_settings(&payload)?),
335                FRAME_PUSH_PROMISE => {
336                    let Some((push_id, id_len)) = parse_varint(&payload)? else {
337                        return Err(FrameError::Frame);
338                    };
339                    Frame::PushPromise {
340                        push_id,
341                        field_section: payload.slice(id_len..),
342                    }
343                }
344                FRAME_GOAWAY => Frame::Goaway(take_varint(&payload)?),
345                FRAME_MAX_PUSH_ID => Frame::MaxPushId(take_varint(&payload)?),
346                _ => unreachable!("unknown types are skipped above"),
347            };
348            return Ok(Some(frame));
349        }
350    }
351
352    /// Returns the type of the next frame without consuming it, or `None`
353    /// when the type varint is incomplete. Used to pre-reject control-plane
354    /// frames on request streams (RFC 9114 Sections 7.2.3-7.2.7) before the
355    /// decoder parses (and would otherwise accept or mismatch) them.
356    #[inline]
357    pub fn peek_frame_type(&self) -> Option<u64> {
358        match self.parse_varint_at(0) {
359            Ok(Some((ty, _))) => Some(ty),
360            _ => None,
361        }
362    }
363
364    #[inline]
365    fn byte_at(&self, offset: usize) -> Option<u8> {
366        let mut remaining = offset;
367        for buf in &self.bufs {
368            if remaining < buf.len() {
369                return Some(buf[remaining]);
370            }
371            remaining -= buf.len();
372        }
373        None
374    }
375
376    #[inline]
377    fn parse_varint_at(&self, offset: usize) -> Result<Option<(u64, usize)>, FrameError> {
378        if offset >= self.len {
379            return Ok(None);
380        }
381        let first = self.byte_at(offset).expect("offset < len");
382        let len = 1usize << (first >> 6);
383        if self.len < offset + len {
384            return Ok(None);
385        }
386        let mut value = u64::from(first & 0x3f);
387        for i in 1..len {
388            let b = self.byte_at(offset + i).expect("offset + offest_len < len");
389            value = (value << 8) | u64::from(b);
390        }
391        if len > 1 && value < MIN_VARINT[usize::from(first >> 6)] {
392            return Err(FrameError::Frame);
393        }
394        Ok(Some((value, len)))
395    }
396
397    #[inline]
398    fn advance(&mut self, n: usize) {
399        debug_assert!(n <= self.len);
400        let mut remaining = n;
401        while remaining > 0 {
402            let front_len = self.bufs.front().expect("advance within len").len();
403            if front_len <= remaining {
404                self.bufs.pop_front();
405                remaining -= front_len;
406            } else {
407                let mut front = self.bufs.pop_front().expect("advance within len");
408                front = front.slice(remaining..);
409                self.bufs.push_front(front);
410                remaining = 0;
411            }
412        }
413        self.len -= n;
414    }
415
416    #[inline]
417    fn take_bytes(&mut self, n: usize) -> Bytes {
418        if n == 0 {
419            return Bytes::new();
420        }
421        debug_assert!(n <= self.len);
422        if let Some(bytes) = self.bufs.pop_front_if(|front| front.len() == n) {
423            self.len -= n;
424            return bytes;
425        }
426        if let Some(mut first) = self.bufs.pop_front_if(|front| front.len() > n) {
427            let payload = first.split_to(n);
428            if !first.is_empty() {
429                self.bufs.push_front(first);
430            }
431            self.len -= n;
432            return payload;
433        }
434        // Fragmented across multiple chunks: coalesce.
435        let mut out = BytesMut::with_capacity(n);
436        let mut remaining = n;
437        while remaining > 0 {
438            let mut front = self.bufs.pop_front().expect("take_bytes within len");
439            if front.len() <= remaining {
440                out.extend_from_slice(&front);
441                remaining -= front.len();
442            } else {
443                let part = front.split_to(remaining);
444                out.extend_from_slice(&part);
445                self.bufs.push_front(front);
446                remaining = 0;
447            }
448        }
449        self.len -= n;
450        out.freeze()
451    }
452}
453
454#[inline]
455fn is_known_frame_type(ty: u64) -> bool {
456    matches!(
457        ty,
458        FRAME_DATA
459            | FRAME_HEADERS
460            | FRAME_CANCEL_PUSH
461            | FRAME_SETTINGS
462            | FRAME_PUSH_PROMISE
463            | FRAME_GOAWAY
464            | FRAME_MAX_PUSH_ID
465    )
466}
467
468/// Reserved grease identifiers: `0x1f * N + 0x21` (RFC 9114 Sections 7.2.8
469/// and 7.2.4.1) — must be ignored, never interpreted.
470#[inline]
471fn is_grease(v: u64) -> bool {
472    v >= 0x21 && (v - 0x21).is_multiple_of(0x1f)
473}
474
475#[inline]
476fn is_reserved_setting(id: u64) -> bool {
477    (0x02..=0x05).contains(&id)
478}
479
480#[inline]
481fn parse_settings(payload: &[u8]) -> Result<Settings, FrameError> {
482    let mut settings = Settings::new();
483    let mut rest = payload;
484    while !rest.is_empty() {
485        let Some((id, id_len)) = parse_varint(rest)? else {
486            return Err(FrameError::Frame);
487        };
488        rest = &rest[id_len..];
489        let Some((value, value_len)) = parse_varint(rest)? else {
490            return Err(FrameError::Frame);
491        };
492        rest = &rest[value_len..];
493        if is_reserved_setting(id) {
494            return Err(FrameError::Settings);
495        }
496        if settings.get(id).is_some() {
497            return Err(FrameError::Settings);
498        }
499        if !is_grease(id) {
500            settings.insert(id, value);
501        }
502    }
503    Ok(settings)
504}
505
506/// Parses the single variable-length integer that must fill `buf` exactly
507/// (used for CANCEL_PUSH, GOAWAY, MAX_PUSH_ID, and the PUSH_PROMISE push
508/// ID). A truncated or non-minimal integer, or trailing bytes, is
509/// `H3_FRAME_ERROR` (RFC 9114 Sections 7.1 and 10.8).
510#[inline]
511fn take_varint(buf: &[u8]) -> Result<u64, FrameError> {
512    let Some((value, n)) = parse_varint(buf)? else {
513        return Err(FrameError::Frame);
514    };
515    if n != buf.len() {
516        return Err(FrameError::Frame);
517    }
518    Ok(value)
519}
520
521/// The minimum value each variable-length integer encoding width can carry
522/// (indexed by the prefix bits `first >> 6`). A value below it in that width
523/// is a non-minimal encoding (RFC 9000 Section 16).
524const MIN_VARINT: [u64; 4] = [0, 1 << 6, 1 << 14, 1 << 30];
525
526/// Parses a QUIC variable-length integer (RFC 9000 Section 16) from the
527/// front of `buf`.
528///
529/// Returns `Ok(None)` when `buf` is shorter than the encoding; `Err` when
530/// the encoding is non-minimal (a protocol violation, per RFC 9000 Section
531/// 16, surfaced as `H3_FRAME_ERROR`).
532///
533/// The control plane uses this to read uni stream type varints before a
534/// stream is assigned its role.
535#[inline]
536pub(crate) fn parse_varint(buf: &[u8]) -> Result<Option<(u64, usize)>, FrameError> {
537    let Some(&first) = buf.first() else {
538        return Ok(None);
539    };
540    let len = 1usize << (first >> 6);
541    if buf.len() < len {
542        return Ok(None);
543    }
544    let mut value = u64::from(first & 0x3f);
545    for &byte in &buf[1..len] {
546        value = (value << 8) | u64::from(byte);
547    }
548    // Minimal encoding: the value must not fit in the next-smaller
549    // encoding. 2-byte values must be >= 2^6, 4-byte >= 2^14, 8-byte >=
550    // 2^30 (RFC 9000 Section 16).
551    if len > 1 && value < MIN_VARINT[usize::from(first >> 6)] {
552        return Err(FrameError::Frame);
553    }
554    Ok(Some((value, len)))
555}
556
557/// The encoded length of `value` as a QUIC variable-length integer.
558#[inline]
559pub fn varint_size(value: u64) -> usize {
560    if value < (1 << 6) {
561        1
562    } else if value < (1 << 14) {
563        2
564    } else if value < (1 << 30) {
565        4
566    } else {
567        8
568    }
569}
570
571/// Encodes `value` as a QUIC variable-length integer (RFC 9000 Section
572/// 16). Panics in debug builds if `value` does not fit.
573#[inline]
574pub fn write_varint(value: u64, dst: &mut BytesMut) {
575    debug_assert!(value <= MAX_VARINT, "varint out of range: {value:#x}");
576    if value < (1 << 6) {
577        dst.put_u8(value as u8);
578    } else if value < (1 << 14) {
579        dst.put_u16((0b01 << 14) | value as u16);
580    } else if value < (1 << 30) {
581        dst.put_u32((0b10 << 30) | value as u32);
582    } else {
583        dst.put_u64((0b11 << 62) | value);
584    }
585}
586
587#[cfg(test)]
588mod tests {
589    use super::*;
590
591    #[inline]
592    fn decode_all(decoder: &mut FrameDecoder) -> Result<Vec<Frame>, FrameError> {
593        let mut frames = Vec::new();
594        while let Some(frame) = decoder.next_frame()? {
595            frames.push(frame);
596        }
597        Ok(frames)
598    }
599
600    #[inline]
601    fn encode_frames(frames: &[Frame]) -> Bytes {
602        let mut buf = BytesMut::new();
603        for frame in frames {
604            frame.encode(&mut buf);
605        }
606        buf.freeze()
607    }
608
609    #[test]
610    fn round_trip_all_frame_types() {
611        let mut settings = Settings::new();
612        settings.insert(SETTINGS_QPACK_MAX_TABLE_CAPACITY, 4096);
613        settings.insert(SETTINGS_MAX_FIELD_SECTION_SIZE, 100);
614        settings.insert(SETTINGS_QPACK_BLOCKED_STREAMS, 2);
615        settings.insert(0x21, 7); // grease: preserved on encode, ignored on decode
616
617        let frames = [
618            Frame::Data(Bytes::from_static(b"hello world")),
619            Frame::Headers(Bytes::from_static(b"\x3f\xbd\x01")),
620            Frame::Settings(settings),
621            Frame::CancelPush(7),
622            Frame::PushPromise {
623                push_id: 1,
624                field_section: Bytes::from_static(b"\x05\x00\x80"),
625            },
626            Frame::Goaway(2),
627            Frame::MaxPushId(0),
628            Frame::Data(Bytes::new()),
629            Frame::Headers(Bytes::new()),
630        ];
631        let mut decoder = FrameDecoder::new();
632        decoder.extend(encode_frames(&frames));
633        let got = decode_all(&mut decoder).expect("all frames parse");
634
635        // Reserved grease setting is dropped, everything else round-trips.
636        let mut expected = frames.to_vec();
637        expected[2] = Frame::Settings(settings_without_grease());
638        assert_eq!(got, expected);
639    }
640
641    #[inline]
642    fn settings_without_grease() -> Settings {
643        let mut s = Settings::new();
644        s.insert(SETTINGS_QPACK_MAX_TABLE_CAPACITY, 4096);
645        s.insert(SETTINGS_MAX_FIELD_SECTION_SIZE, 100);
646        s.insert(SETTINGS_QPACK_BLOCKED_STREAMS, 2);
647        s
648    }
649
650    #[test]
651    fn incremental_byte_at_a_time() {
652        let wire = encode_frames(&[
653            Frame::Headers(Bytes::from_static(b"abc")),
654            Frame::Data(Bytes::from_static(b"xy")),
655        ]);
656        let mut decoder = FrameDecoder::new();
657        let mut got = Vec::new();
658        for (i, &byte) in wire.iter().enumerate() {
659            decoder.extend(Bytes::copy_from_slice(&[byte]));
660            while let Some(frame) = decoder.next_frame().unwrap() {
661                got.push(frame);
662            }
663            if i < 4 {
664                assert!(got.is_empty(), "frame appeared early at byte {i}");
665            }
666            if i == 4 {
667                // The full HEADERS frame appears exactly when its last
668                // byte lands.
669                assert_eq!(got, vec![Frame::Headers(Bytes::from_static(b"abc"))]);
670            }
671        }
672        assert_eq!(
673            got,
674            vec![
675                Frame::Headers(Bytes::from_static(b"abc")),
676                Frame::Data(Bytes::from_static(b"xy")),
677            ]
678        );
679        assert_eq!(decoder.buffered(), 0);
680    }
681
682    #[test]
683    fn truncated_prefixes_are_incomplete() {
684        // Type byte only.
685        let mut decoder = FrameDecoder::new();
686        decoder.extend(Bytes::from_static(&[0x00]));
687        assert_eq!(decoder.next_frame().unwrap(), None);
688        // Type + length, no payload yet.
689        decoder.extend(Bytes::from_static(&[0x05]));
690        assert_eq!(decoder.next_frame().unwrap(), None);
691        // Partial payload.
692        decoder.extend(Bytes::from_static(b"he"));
693        assert_eq!(decoder.next_frame().unwrap(), None);
694        // Rest of the payload completes the frame.
695        decoder.extend(Bytes::from_static(b"llo"));
696        assert_eq!(
697            decode_all(&mut decoder).unwrap(),
698            vec![Frame::Data(Bytes::from_static(b"hello"))]
699        );
700
701        // A frame declaring the maximum varint length stays incomplete
702        // without erroring or allocating.
703        let mut decoder = FrameDecoder::new();
704        decoder.extend(Bytes::from_static(&[
705            0x01, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
706        ]));
707        assert_eq!(decoder.next_frame().unwrap(), None);
708        assert_eq!(decoder.buffered(), 10);
709    }
710
711    #[test]
712    fn forbidden_http2_frames() {
713        for ty in [0x02u8, 0x06, 0x08, 0x09] {
714            let mut decoder = FrameDecoder::new();
715            decoder.extend(Bytes::copy_from_slice(&[ty, 0x01, 0x00]));
716            let err = decoder.next_frame().unwrap_err();
717            assert_eq!(err, FrameError::Unexpected(u64::from(ty)));
718            assert_eq!(err.h3_code(), 0x0105);
719        }
720    }
721
722    #[test]
723    fn unknown_and_grease_frames_are_skipped() {
724        // Unknown type 0x42 with payload, grease 0x21/0x40/0x5f with
725        // arbitrary payload, between two known frames.
726        let mut wire = BytesMut::new();
727        Frame::Headers(Bytes::from_static(b"first")).encode(&mut wire);
728        write_varint(0x42, &mut wire);
729        write_varint(3, &mut wire);
730        wire.extend_from_slice(b"xyz");
731        write_varint(0x21, &mut wire);
732        write_varint(2, &mut wire);
733        wire.extend_from_slice(&[0xde, 0xad]);
734        Frame::Data(Bytes::from_static(b"last")).encode(&mut wire);
735
736        let mut decoder = FrameDecoder::new();
737        decoder.extend(wire.freeze());
738        let frames = decode_all(&mut decoder).unwrap();
739        assert_eq!(
740            frames,
741            vec![
742                Frame::Headers(Bytes::from_static(b"first")),
743                Frame::Data(Bytes::from_static(b"last")),
744            ]
745        );
746        assert_eq!(decoder.buffered(), 0);
747    }
748
749    #[test]
750    fn settings_payload_validation() {
751        // Empty SETTINGS is legal.
752        let mut decoder = FrameDecoder::new();
753        decoder.extend(Bytes::from_static(&[0x04, 0x00]));
754        assert_eq!(
755            decode_all(&mut decoder).unwrap(),
756            vec![Frame::Settings(Settings::new())]
757        );
758
759        // Duplicate identifier -> H3_SETTINGS_ERROR.
760        let mut wire = BytesMut::new();
761        Frame::Settings({
762            let mut s = Settings::new();
763            s.insert(0x06, 1);
764            s.insert(0x06, 2);
765            s
766        })
767        .encode(&mut wire);
768        let mut decoder = FrameDecoder::new();
769        decoder.extend(wire.freeze());
770        let err = decoder.next_frame().unwrap_err();
771        assert_eq!(err, FrameError::Settings);
772        assert_eq!(err.h3_code(), 0x0109);
773
774        // Reserved identifiers 0x02-0x05 -> H3_SETTINGS_ERROR.
775        for id in 0x02..=0x05 {
776            let mut wire = BytesMut::new();
777            Frame::Settings({
778                let mut s = Settings::new();
779                s.insert(id, 0);
780                s
781            })
782            .encode(&mut wire);
783            let mut decoder = FrameDecoder::new();
784            decoder.extend(wire.freeze());
785            assert_eq!(decoder.next_frame().unwrap_err(), FrameError::Settings);
786        }
787
788        // Unknown identifier is preserved (the driver ignores it), known
789        // ones surface.
790        let mut s = Settings::new();
791        s.insert(0x0100, 5);
792        s.insert(SETTINGS_ENABLE_CONNECT_PROTOCOL, 1);
793        let mut wire = BytesMut::new();
794        Frame::Settings(s.clone()).encode(&mut wire);
795        let mut decoder = FrameDecoder::new();
796        decoder.extend(wire.freeze());
797        match decode_all(&mut decoder).unwrap()[0].clone() {
798            Frame::Settings(got) => {
799                assert_eq!(got.get(0x0100), Some(5));
800                assert_eq!(got.get(SETTINGS_ENABLE_CONNECT_PROTOCOL), Some(1));
801            }
802            other => panic!("expected Settings, got {other:?}"),
803        }
804
805        // Odd-length payload (a lone identifier) -> H3_FRAME_ERROR.
806        let mut decoder = FrameDecoder::new();
807        decoder.extend(Bytes::from_static(&[0x04, 0x01, 0x06]));
808        assert_eq!(decoder.next_frame().unwrap_err(), FrameError::Frame);
809    }
810
811    #[test]
812    fn fixed_value_frames_reject_bad_payloads() {
813        // CANCEL_PUSH with no payload -> H3_FRAME_ERROR.
814        let mut decoder = FrameDecoder::new();
815        decoder.extend(Bytes::from_static(&[0x03, 0x00]));
816        assert_eq!(decoder.next_frame().unwrap_err(), FrameError::Frame);
817
818        // CANCEL_PUSH with trailing bytes -> H3_FRAME_ERROR.
819        let mut decoder = FrameDecoder::new();
820        decoder.extend(Bytes::from_static(&[0x03, 0x02, 0x01, 0x00]));
821        assert_eq!(decoder.next_frame().unwrap_err(), FrameError::Frame);
822
823        // CANCEL_PUSH with a redundant 2-byte encoding of 5 -> H3_FRAME_ERROR.
824        let mut decoder = FrameDecoder::new();
825        decoder.extend(Bytes::from_static(&[0x03, 0x02, 0x40, 0x05]));
826        assert_eq!(decoder.next_frame().unwrap_err(), FrameError::Frame);
827
828        // GOAWAY with a minimal 1-byte value parses.
829        let mut decoder = FrameDecoder::new();
830        decoder.extend(Bytes::from_static(&[0x07, 0x01, 0x05]));
831        assert_eq!(decode_all(&mut decoder).unwrap(), vec![Frame::Goaway(5)]);
832
833        // Non-minimal type encoding (0 encoded in 2 bytes) -> error.
834        let mut decoder = FrameDecoder::new();
835        decoder.extend(Bytes::from_static(&[0x40, 0x00, 0x00]));
836        assert_eq!(decoder.next_frame().unwrap_err(), FrameError::Frame);
837
838        // Non-minimal length encoding -> error.
839        let mut decoder = FrameDecoder::new();
840        decoder.extend(Bytes::from_static(&[0x00, 0x40, 0x00]));
841        assert_eq!(decoder.next_frame().unwrap_err(), FrameError::Frame);
842    }
843
844    #[test]
845    fn push_promise_shapes() {
846        // push ID plus field section.
847        let mut decoder = FrameDecoder::new();
848        decoder.extend(Bytes::from_static(&[0x05, 0x04, 0x01, b'a', b'b', b'c']));
849        assert_eq!(
850            decode_all(&mut decoder).unwrap(),
851            vec![Frame::PushPromise {
852                push_id: 1,
853                field_section: Bytes::from_static(b"abc"),
854            }]
855        );
856
857        // Empty field section.
858        let mut decoder = FrameDecoder::new();
859        decoder.extend(Bytes::from_static(&[0x05, 0x01, 0x01]));
860        assert_eq!(
861            decode_all(&mut decoder).unwrap(),
862            vec![Frame::PushPromise {
863                push_id: 1,
864                field_section: Bytes::new(),
865            }]
866        );
867
868        // Missing push ID -> H3_FRAME_ERROR.
869        let mut decoder = FrameDecoder::new();
870        decoder.extend(Bytes::from_static(&[0x05, 0x00]));
871        assert_eq!(decoder.next_frame().unwrap_err(), FrameError::Frame);
872    }
873
874    #[test]
875    fn varint_edge_encodings() {
876        // Boundaries: 2^6-1 (1 byte), 2^6 (2 bytes), 2^14-1, 2^14, 2^30-1,
877        // 2^30, 2^62-1 (max).
878        for value in [
879            (1 << 6) - 1,
880            1 << 6,
881            (1 << 14) - 1,
882            1 << 14,
883            (1 << 30) - 1,
884            1 << 30,
885            MAX_VARINT,
886        ] {
887            let mut wire = BytesMut::new();
888            write_varint(value, &mut wire);
889            assert_eq!(wire.len(), varint_size(value));
890            let (got, n) = parse_varint(&wire).unwrap().unwrap();
891            assert_eq!(got, value);
892            assert_eq!(n, wire.len());
893        }
894
895        // Non-minimal encodings are rejected.
896        assert_eq!(parse_varint(&[0x40, 0x00]), Err(FrameError::Frame)); // 0 in 2 bytes
897        assert_eq!(
898            parse_varint(&[0x80, 0x00, 0x00, 0x40]),
899            Err(FrameError::Frame)
900        ); // 64 in 4 bytes
901        assert_eq!(parse_varint(&[0x40, 0x40]), Ok(Some((64, 2))));
902        // Truncated.
903        assert_eq!(parse_varint(&[0x40]), Ok(None));
904        assert_eq!(parse_varint(&[]), Ok(None));
905    }
906
907    #[test]
908    fn clean_eof_with_truncated_frame_is_detectable() {
909        let mut decoder = FrameDecoder::new();
910        decoder.extend(Bytes::from_static(&[0x01, 0x05, b'a', b'b']));
911        assert_eq!(decoder.next_frame().unwrap(), None);
912        // Driver's clean-FIN check: buffered() != 0 -> H3_FRAME_ERROR.
913        assert_eq!(decoder.buffered(), 4);
914    }
915}