# flare.http.frontend

> A module of flare_mlake's API.

HTTP frontends for the multicore :class:`flare.runtime.Scheduler`.

A :trait:`flare.runtime.Frontend` impl is the *only* coupling
point between the runtime's multicore lifecycle and a serving
protocol's accept-and-serve loop. This module ships every HTTP-
flavoured frontend flare needs:

- :class:`HttpFrontend[H]` — the dynamic-handler frontend. Wraps
  a user :trait:`Handler` plus a :class:`ServerConfig` and an
  optional :class:`flare.http2.Http2Config`. Selects between the
  HTTP/1.1-only loop, the unified HTTP/1.1 + HTTP/2 preface-peek
  loop, and the io_uring buffer-ring loop based on its config
  flags + the runtime backend probe.
- :class:`StaticHttpFrontend` — the pre-encoded
  :class:`StaticResponse` frontend. Dedicated fast path for
  workloads whose every response is identical (the TFB plaintext
  gate; production health-check / fixed-response endpoints).
  Replaces the prior ``StaticScheduler`` type which baked the
  same dispatch into the runtime layer.

The runtime no longer imports anything from :mod:`flare.http`;
both frontends here import the reactor entry points and serve as
the inversion boundary. See :mod:`flare.runtime.frontend` for the
trait contract.

## Structs

### `HttpFrontend`

```mojo
struct HttpFrontend[H: Handler & Copyable]
```

Dynamic-handler HTTP frontend for the multicore scheduler.

Carries the per-worker HTTP state (handler, request config,
HTTP/2 settings, auto-protocol toggle) and dispatches into
one of three reactor entry points per accepted connection:

1. **io_uring buffer-ring path** (Linux + ``use_bufring``):
   :func:`run_uring_bufring_reactor_loop_shared`. Signalled
   to the scheduler via :meth:`requires_per_worker_listener`
   so each worker gets its own SO_REUSEPORT listener.
2. **Unified HTTP/1.1 + HTTP/2** (``auto_protocol``):
   :func:`run_unified_reactor_loop_shared`. Per-connection
   preface peek selects the protocol.
3. **HTTP/1.1 only** (default):
   :func:`run_reactor_loop_shared`.

The frontend is :class:`Copyable` so the scheduler can clone
it once per worker before pthread spawn; expensive shared
state inside the user handler should be wrapped behind an
:class:`Pointer` so per-worker copies stay cheap.

Implements: `Copyable`, `Frontend`, `Movable`

Fields:

- `handler: H`
- `config: ServerConfig`
- `h2_config: Http2Config`
- `auto_protocol: Bool`
- `tls_ctx_addr: Int`: Address of the server's shared ``SSL_CTX``, or 0 for cleartext.
- `ws_hooks: Optional[WsH2Hooks]`: The server's WebSocket-over-h2 sidecar; each worker serves a copy of it (:meth:`WsH2Hooks.clone`).

#### `__init__`

```mojo
def __init__(out self, var handler: H, var config: ServerConfig, var h2_config: Http2Config = Http2Config(), auto_protocol: Bool = False, tls_ctx_addr: Int = Int(0), ws_hooks: Optional[WsH2Hooks] = None)
```

Build a frontend with the given handler + config combo.

Args:

- `handler`: User request handler; cloned per worker.
- `config`: Server configuration; cloned per worker.
- `h2_config`: HTTP/2 SETTINGS used by the unified path.
    Ignored when ``auto_protocol`` is ``False``.
- `auto_protocol`: When ``True``, every accepted
    connection auto-dispatches to the right per-conn
    state machine via the RFC 9113 §3.4 preface peek.
    When ``False`` (default), the worker speaks
    HTTP/1.1 exclusively.
- `tls_ctx_addr`: Address of the shared server ``SSL_CTX``;
    0 (default) serves cleartext. When set, each accepted
    connection starts as a TLS handshake and its protocol
    is chosen by ALPN.
- `ws_hooks`: Optional WS-over-h2 sidecar handler (RFC 8441).
    ``None`` disables the WS carrier path.

#### `requires_per_worker_listener`

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

The io_uring buffer-ring path needs per-worker listeners.

See the trait docstring for the full rationale: the
kernel-side accept fan-out happens at multishot accept
arming time, and a shared listener with EPOLLEXCLUSIVE
would funnel every accept event through one entry. For
every other backend the scheduler is free to pick its
listener strategy from the ``FLARE_REUSEPORT_WORKERS``
env knob (which still applies to the epoll handler /
unified paths).

#### `run_worker`

```mojo
def run_worker(mut self, listener_fd: Int, mut stopping: Bool, stats_addr: Int, extra_fds: List[Int] = List())
```

Pick the reactor entry point and run it until ``stopping`` flips.

### `StreamFrontend`

```mojo
struct StreamFrontend[H: StreamHandler & Copyable]
```

Typed-streaming frontend for the multicore scheduler.

The :trait:`StreamHandler` twin of :class:`HttpFrontend`: carries a
per-worker streaming handler + admission-control knobs and drives
:func:`run_stream_reactor_loop_shared` on each worker's listener fd.
Copied once per worker before pthread spawn (the ``H: Copyable``
bound); expensive shared state should sit behind an
:class:`Pointer` so the per-worker copy stays cheap.

Implements: `Copyable`, `Frontend`, `Movable`

Fields:

- `handler: H`
- `max_in_flight: Int`
- `retry_after_s: Int`

#### `__init__`

```mojo
def __init__(out self, var handler: H, max_in_flight: Int = Int(0), retry_after_s: Int = Int(1))
```

#### `requires_per_worker_listener`

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

Streaming is fine with either listener strategy (honours the ``FLARE_REUSEPORT_WORKERS`` knob via the scheduler).

#### `run_worker`

```mojo
def run_worker(mut self, listener_fd: Int, mut stopping: Bool, stats_addr: Int, extra_fds: List[Int] = List())
```

Drive the shared streaming reactor loop.

``extra_fds`` is refused rather than ignored: the streaming
reactor registers a single listener, so accepting the list
silently would leave an address the caller bound with nothing
listening on it. ``HttpServer.serve_streaming`` refuses
multi-address binds up front for the same reason.

### `StaticHttpFrontend`

```mojo
struct StaticHttpFrontend
```

Pre-encoded :class:`StaticResponse` frontend.

Replaces the prior runtime-side ``StaticScheduler`` type. The
serving loop is the static fast-path
:func:`run_reactor_loop_static_shared`; every accepted
connection emits the same canned bytes, sized once at startup.

Used by :meth:`HttpServer.serve_static` for the TFB plaintext
gate and any production endpoint that returns a fixed body.

Implements: `Copyable`, `Frontend`, `Movable`

Fields:

- `config: ServerConfig`
- `resp: StaticResponse`

#### `__init__`

```mojo
def __init__(out self, var config: ServerConfig, var resp: StaticResponse)
```

Build a static-response frontend.

Args:

- `config`: Server configuration; cloned per worker.
- `resp`: Pre-encoded response bytes; cloned per worker.

#### `requires_per_worker_listener`

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

The static path is fine with either listener strategy.

It honours the ``FLARE_REUSEPORT_WORKERS`` env knob
directly (per-worker SO_REUSEPORT by default; shared
EPOLLEXCLUSIVE listener when the knob is ``0``).

#### `run_worker`

```mojo
def run_worker(mut self, listener_fd: Int, mut stopping: Bool, stats_addr: Int, extra_fds: List[Int] = List())
```

Drive the static-response fast path.

``extra_fds`` is refused rather than ignored -- see
:meth:`StreamFrontend.run_worker` for why. ``serve_static``
binds one address.
