# flare.http3.response_reader

> A module of flare_mlake's API.

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:

```mojo
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`

```mojo
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`

```mojo
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`

```mojo
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__`

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

#### `new`

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

#### `feed`

```mojo
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`

```mojo
def signal_fin(mut self)
```

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

#### `is_complete`

```mojo
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`

```mojo
def has_error(self) -> Bool
```

#### `head_ready`

```mojo
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`

```mojo
def status_code(self) -> Int
```

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

#### `headers_copy`

```mojo
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`

```mojo
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`

```mojo
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

### `H3_RESPONSE_STATE_INIT`

```mojo
comptime H3_RESPONSE_STATE_INIT = Int(0)
```

Awaiting the first HEADERS frame (the response head).

### `H3_RESPONSE_STATE_BODY`

```mojo
comptime H3_RESPONSE_STATE_BODY = Int(1)
```

HEADERS received; reading DATA + optional trailers.

### `H3_RESPONSE_STATE_TRAILERS`

```mojo
comptime H3_RESPONSE_STATE_TRAILERS = Int(2)
```

Trailers received; no further frames are legal.

### `H3_RESPONSE_STATE_DONE`

```mojo
comptime H3_RESPONSE_STATE_DONE = Int(3)
```

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