flare_mlake · API · quic

flare.quic.frame

QUIC v1 transport-frame codec (RFC 9000 §19).

This module is the canonical sans-I/O codec for the 22 transport frame types QUIC v1 carries inside (deprotected) packet payloads. The parser walks one frame at a time and dispatches each decoded payload through a typed callback on a caller-supplied :trait:FrameHandler; the QUIC connection state machine implements the handler and advances per-frame state without ever materialising an intermediate carrier value.

Frame types covered (RFC 9000 §19, all 22):

  • §19.1 PADDING (0x00)
  • §19.2 PING (0x01)
  • §19.3 ACK (0x02), ACK with ECN (0x03)
  • §19.4 RESET_STREAM (0x04)
  • §19.5 STOP_SENDING (0x05)
  • §19.6 CRYPTO (0x06)
  • §19.7 NEW_TOKEN (0x07)
  • §19.8 STREAM (0x08..0x0f -- 8 sub-shapes via OFF/LEN/FIN bits)
  • §19.9 MAX_DATA (0x10)
  • §19.10 MAX_STREAM_DATA (0x11)
  • §19.11 MAX_STREAMS (bidirectional 0x12, unidirectional 0x13)
  • §19.12 DATA_BLOCKED (0x14)
  • §19.13 STREAM_DATA_BLOCKED (0x15)
  • §19.14 STREAMS_BLOCKED (bidirectional 0x16, unidirectional 0x17)
  • §19.15 NEW_CONNECTION_ID (0x18)
  • §19.16 RETIRE_CONNECTION_ID (0x19)
  • §19.17 PATH_CHALLENGE (0x1a)
  • §19.18 PATH_RESPONSE (0x1b)
  • §19.19 CONNECTION_CLOSE (transport 0x1c, application 0x1d)
  • §19.20 HANDSHAKE_DONE (0x1e)
Dispatch contract

:func:parse_frame_into reads exactly one frame at the start of the supplied :class:Span[UInt8, _], fires the matching typed callback on the caller's handler, and returns the number of wire bytes consumed. The caller advances its cursor and re-invokes the dispatcher on the remainder until the buffer drains or a parse error fires.

Every typed payload struct is Copyable (which implies Movable) so the handler can stash the dispatched value (or move it into a queue) without lifetime gymnastics.

Sans-I/O contract

This file holds zero I/O imports. It is registered in tests/tools/check_sans_io.sh so the contract is lint-enforced.

References
  • RFC 9000 §19 "Frame Types and Formats".
  • RFC 9000 §16 "Variable-Length Integer Encoding" (varint).

Traits

FrameHandler

Per-type callback contract :func:parse_frame_into fires.

The dispatcher reads one wire frame at the start of the input buffer and invokes the matching callback. Implementors carry out the per-frame state-machine work (or stash the dispatched payload for later use) without an intermediate carrier allocation: each callback receives the already-typed payload by value.

The 20 callbacks below cover every RFC 9000 §19 frame type. The ACK / ACK-ECN split is collapsed into :meth:on_ack (the handler reads len(ack.ecn) to discriminate); the MAX_STREAMS / STREAMS_BLOCKED bidi/uni splits are collapsed via the unidirectional flag on the typed payload; the CONNECTION_CLOSE transport/application split is collapsed via the application flag.

A frame type outside the v1 master table never reaches a callback: :func:parse_frame_into raises a FRAME_ENCODING_ERROR for it (RFC 9000 §12.4).

Implements Movable

on_padding

def on_padding(mut self, count: Int)

PADDING run consumed (§19.1).

count is the number of consecutive 0x00 bytes the parser collapsed into one callback (≥ 1).

on_ping

def on_ping(mut self)

PING frame (§19.2).

on_ack

def on_ack(mut self, ack: AckFrame)

ACK / ACK-ECN frame (§19.3). When len(ack.ecn) == 1 the wire type was 0x03 (ACK with ECN counts); otherwise 0x02.

on_reset_stream

def on_reset_stream(mut self, rs: ResetStreamFrame)

RESET_STREAM (§19.4).

on_stop_sending

def on_stop_sending(mut self, ss: StopSendingFrame)

STOP_SENDING (§19.5).

on_crypto

def on_crypto(mut self, c: CryptoFrame)

CRYPTO (§19.6).

on_new_token

def on_new_token(mut self, t: NewTokenFrame)

NEW_TOKEN (§19.7).

on_stream

def on_stream(mut self, sf: StreamFrame)

STREAM (§19.8). The wire-type flag bits are surfaced via sf.offset (set / zero), the explicit data length (read when LEN was set) and sf.fin.

on_max_data

def on_max_data(mut self, m: MaxDataFrame)

MAX_DATA (§19.9).

on_max_stream_data

def on_max_stream_data(mut self, m: MaxStreamDataFrame)

MAX_STREAM_DATA (§19.10).

on_max_streams

def on_max_streams(mut self, m: MaxStreamsFrame)

MAX_STREAMS (§19.11). The bidi (0x12) vs uni (0x13) wire split is surfaced via m.unidirectional.

on_data_blocked

def on_data_blocked(mut self, db: DataBlockedFrame)

DATA_BLOCKED (§19.12).

on_stream_data_blocked

def on_stream_data_blocked(mut self, sdb: StreamDataBlockedFrame)

STREAM_DATA_BLOCKED (§19.13).

on_streams_blocked

def on_streams_blocked(mut self, sb: StreamsBlockedFrame)

STREAMS_BLOCKED (§19.14). The bidi (0x16) vs uni (0x17) wire split is surfaced via sb.unidirectional.

on_new_connection_id

def on_new_connection_id(mut self, ncid: NewConnectionIdFrame)

NEW_CONNECTION_ID (§19.15).

on_retire_connection_id

def on_retire_connection_id(mut self, rcid: RetireConnectionIdFrame)

RETIRE_CONNECTION_ID (§19.16).

on_path_challenge

def on_path_challenge(mut self, pc: PathChallengeFrame)

PATH_CHALLENGE (§19.17).

on_path_response

def on_path_response(mut self, pr: PathResponseFrame)

PATH_RESPONSE (§19.18).

on_connection_close

def on_connection_close(mut self, cc: ConnectionCloseFrame)

CONNECTION_CLOSE (§19.19). The transport (0x1c) vs application (0x1d) wire split is surfaced via cc.application.

on_handshake_done

def on_handshake_done(mut self)

HANDSHAKE_DONE (§19.20).

on_datagram

def on_datagram(mut self, dg: DatagramFrame)

DATAGRAM (RFC 9221 §4) -- an unreliable application datagram. dg.has_length records whether the wire type carried an explicit length (0x31) or ran to the end of the packet (0x30).

on_ack_frequency

def on_ack_frequency(mut self, f: AckFrequencyFrame)

ACK_FREQUENCY (draft-ietf-quic-ack-frequency).

on_immediate_ack

def on_immediate_ack(mut self)

IMMEDIATE_ACK (draft-ietf-quic-ack-frequency): acknowledge now.

Functions

encode_datagram

def encode_datagram(frame: DatagramFrame, mut out: List[UInt8])

Encode a DATAGRAM frame (RFC 9221 §4).

When frame.has_length is set, emit type 0x31 with an explicit length varint so the frame may be followed by others in the packet; otherwise emit type 0x30, which the caller MUST place last in the packet (its payload runs to the end of the QUIC payload).

encode_padding

def encode_padding(length: Int, mut out: List[UInt8])

Encode length PADDING frames (§19.1) as repeated 0x00s.

encode_ping

def encode_ping(mut out: List[UInt8])

Encode a PING frame (§19.2): single 0x01 byte.

encode_ack

def encode_ack(frame: AckFrame, mut out: List[UInt8])

Encode an ACK / ACK-ECN frame (§19.3).

Picks the type byte based on whether frame.ecn is empty (0x02) or carries a single :class:EcnCounts entry (0x03).

encode_reset_stream

def encode_reset_stream(frame: ResetStreamFrame, mut out: List[UInt8])

encode_stop_sending

def encode_stop_sending(frame: StopSendingFrame, mut out: List[UInt8])

encode_crypto

def encode_crypto(frame: CryptoFrame, mut out: List[UInt8])

encode_new_token

def encode_new_token(frame: NewTokenFrame, mut out: List[UInt8])

encode_stream

def encode_stream(frame: StreamFrame, mut out: List[UInt8], emit_length: Bool = True)

Encode a STREAM frame (§19.8).

emit_length controls whether the LEN bit is set: producers that emit a STREAM frame as the last frame of a packet may omit the explicit length and let the frame extend to the packet boundary. Most callers pass emit_length=True for safe self-describing framing.

encode_max_data

def encode_max_data(frame: MaxDataFrame, mut out: List[UInt8])

encode_max_stream_data

def encode_max_stream_data(frame: MaxStreamDataFrame, mut out: List[UInt8])

encode_max_streams

def encode_max_streams(frame: MaxStreamsFrame, mut out: List[UInt8])

encode_data_blocked

def encode_data_blocked(frame: DataBlockedFrame, mut out: List[UInt8])

encode_stream_data_blocked

def encode_stream_data_blocked(frame: StreamDataBlockedFrame, mut out: List[UInt8])

encode_streams_blocked

def encode_streams_blocked(frame: StreamsBlockedFrame, mut out: List[UInt8])

encode_new_connection_id

def encode_new_connection_id(frame: NewConnectionIdFrame, mut out: List[UInt8])

encode_retire_connection_id

def encode_retire_connection_id(frame: RetireConnectionIdFrame, mut out: List[UInt8])

encode_path_challenge

def encode_path_challenge(frame: PathChallengeFrame, mut out: List[UInt8])

encode_path_response

def encode_path_response(frame: PathResponseFrame, mut out: List[UInt8])

encode_connection_close

def encode_connection_close(frame: ConnectionCloseFrame, mut out: List[UInt8])

encode_handshake_done

def encode_handshake_done(mut out: List[UInt8])

encode_ack_frequency

def encode_ack_frequency(f: AckFrequencyFrame, mut out: List[UInt8])

encode_immediate_ack

def encode_immediate_ack(mut out: List[UInt8])

parse_frame_into

def parse_frame_into[H: FrameHandler](buf: Span[UInt8], mut handler: H) -> Int

Parse a single transport frame at the start of buf and fire the matching :trait:FrameHandler callback.

The QUIC frame type is itself varint-encoded (§19); for the 22 codepoints defined in v1 the encoding is single-byte, but the dispatcher reads it as a varint to stay forward-compatible with extension types that may register higher-numbered codepoints. Codepoints outside the v1 master table are a connection error of type FRAME_ENCODING_ERROR (RFC 9000 §12.4): the dispatcher raises, so an unknown frame's body is never re-read as further frames.

Returns the number of wire bytes consumed -- the caller advances its cursor and re-invokes the dispatcher on the remainder. The dispatcher never panics on malformed input; structural errors (truncated payload, malformed varint, range out of bounds) are reported via raised :class:Error.