flare_mlake · API · http3

flare.http3.response_reader

HTTP/3 response-stream reader -- sans-I/O stateful decoder.

The client-side mirror of :mod:flare.http3.request_reader. Where the server's request reader fires a callback per frame, this reader keeps the response head and trailers while accepting reassembled bidi-stream bytes. DATA is available immediately, even within an incomplete frame. Drain it incrementally or collect an assembled :class:Http3Response.

A response stream carries, in order (RFC 9114 §4.1):

HEADERS frame (:status pseudo-header + application headers) DATA frame (zero or more, response body) HEADERS frame (optional trailers)

then the QUIC stream FIN. Control-stream frame types (SETTINGS, GOAWAY, ...) are illegal on a request stream and surface a protocol error (RFC 9114 §6.2).

Usage:

var reader = Http3ResponseReader.new()
reader.feed(chunk0)
reader.feed(chunk1)
reader.signal_fin()
if reader.is_complete():
    var resp = reader.take_response()

Sans-I/O contract: the reader holds zero socket / QUIC references; the QUIC client driver feeds it the per-stream reassembled bytes.

References:

  • RFC 9114 §4 (HTTP Message Exchanges) + §7 (Frames).
  • RFC 9204 (QPACK) -- field-section decoder used for HEADERS.

Structs

Http3Response

struct Http3Response

An assembled HTTP/3 response.

status is the :status pseudo-header (RFC 9114 §4.3.2); headers are the application response headers (:status stripped); body is the concatenation of every DATA frame; trailers is the optional trailing field section.

Implements Copyable, Movable

Fields
status: Int
headers: List[HpackHeader]
body: List[UInt8]
trailers: List[HpackHeader]

Http3BodyChunk

struct Http3BodyChunk

One incremental slice of a streaming HTTP/3 response body.

Returned by :meth:flare.http3.client.Http3ClientConnection.poll_body. data is the body bytes that became available on this poll (possibly empty); done is True once the response stream has finished (QUIC FIN), after which no further DATA will arrive and the trailers / final status are retrievable via :meth:take_if_complete.

Implements Copyable, Movable

Fields
data: List[UInt8]
done: Bool

Http3ResponseReader

struct Http3ResponseReader

Per-stream stateful HTTP/3 response decoder.

Feed reassembled request-stream bytes via :meth:feed; the reader drains every complete frame it can and accumulates the response. A partial trailing frame is buffered in :attr:inbox until the next :meth:feed. Mark the QUIC FIN with :meth:signal_fin; once HEADERS are parsed and FIN is seen :meth:is_complete returns True and :meth:take_response yields the assembled :class:Http3Response.

Implements Copyable, Movable

Fields
state: Int
inbox: List[UInt8]
status: Int
headers: List[HpackHeader]
body: List[UInt8]
trailers: List[HpackHeader]
fin_received: Bool
error: String
max_field_section_bytes: UInt64

__init__

def __init__(out self, max_field_section_bytes: UInt64 = UInt64(65536), method: String = "GET")

new

def new(max_field_section_bytes: UInt64 = UInt64(65536)) -> Self

feed

def feed(mut self, chunk: Span[UInt8])

Append chunk to the inbox and drain every complete frame. Stops at the first incomplete frame (buffered) or on a protocol error (state -> DONE, message in :attr:error).

signal_fin

def signal_fin(mut self)

Record that the QUIC layer signalled end-of-stream.

is_complete

def is_complete(self) -> Bool

Whether a full response head has been parsed and the stream has finished (FIN), or the reader is DONE.

has_error

def has_error(self) -> Bool

head_ready

def head_ready(self) -> Bool

Whether the response head (:status + headers) has been parsed. True as soon as the first HEADERS frame is decoded -- before the body or FIN arrive -- so a streaming caller can read :meth:status_code / :meth:headers_copy and begin draining the body with :meth:drain_body while DATA is still in flight. False on a protocol error before the head.

status_code

def status_code(self) -> Int

The parsed :status (0 until :meth:head_ready).

headers_copy

def headers_copy(self) -> List[HpackHeader]

A copy of the application response headers parsed so far (:status already stripped). Valid once :meth:head_ready is True.

drain_body

def drain_body(mut self) -> List[UInt8]

Move out the body bytes accumulated since the last drain, leaving the reader ready to accumulate more DATA. This is the streaming counterpart to :meth:take_response: a caller polls the connection, drains the available body chunk, and repeats until :meth:is_complete, never holding the whole body in memory at once. Trailers (if any) are still available via :meth:take_response after completion.

take_response

def take_response(mut self) -> Http3Response

Move out the assembled response. Raises if a protocol error fired or the response head was never parsed.

Aliases

comptime H3_RESPONSE_STATE_INIT = Int(0)

Awaiting the first HEADERS frame (the response head).

comptime H3_RESPONSE_STATE_BODY = Int(1)

HEADERS received; reading DATA + optional trailers.

comptime H3_RESPONSE_STATE_TRAILERS = Int(2)

Trailers received; no further frames are legal.

comptime H3_RESPONSE_STATE_DONE = Int(3)

Protocol error or shutdown; further feeds are no-ops.