The Handler trait is already a perfectly good middleware abstraction: a middleware is a handler that wraps another handler. This module bundles the middlewares every flare app eventually needs:

  • Logger[Inner] — log method / url / status / latency.
  • RequestId[Inner] — attach an opaque request id (read on inbound, echo on outbound).
  • Compress[Inner] — content-encoding negotiation (Accept-Encoding q-values per RFC 9110 paragraph 12.5.3), encoding the response body in gzip or brotli.
  • CatchPanic[Inner] — turn any raise from the inner handler into a sanitised 500 response so the connection is not torn down (the HttpServer already does this; CatchPanic is for inner-only middleware stacks where the server isn't reached).

Each middleware is generic over its inner Handler so the chain stays monomorphised — no virtual dispatch, no allocation per request.

Functions

fn negotiate_encoding Pick the best ``Content-Encoding`` for an ``Accept-Encoding``.

Structs

struct Logger Log method, url, status, and latency around the inner handler.
struct RequestId Echo the inbound ``X-Request-Id`` header back on the response.
struct Compress Negotiate ``Content-Encoding`` per RFC 9110 paragraph 12.5.3.
struct CatchPanic Convert any ``raise`` from the inner handler into a 500.
Detail Documentation

Functions

fn negotiate_encoding §

negotiate_encoding(accept: String, brotli_ok: Bool) -> _AcceptEncodingPick

Pick the best ``Content-Encoding`` for an ``Accept-Encoding``.

Walks every comma-separated entry, parses ;q=<weight> per RFC 9110 paragraph 12.5.3, and returns the highest-q entry from {br, gzip, identity} that the client accepts. Ties break on brotli > gzip > identity (matches nginx default).

Args

accept String

Raw Accept-Encoding header value.

brotli_ok Bool

Whether brotli is linkable on this build.

Returns

_AcceptEncodingPick

_AcceptEncodingPick with the chosen encoding (defaults to identity / q=1000 when the header is absent).

Structs

struct Logger §

struct Logger[Inner: Handler & Copyable & Defaultable]

Log method, url, status, and latency around the inner handler.

Output goes to stdout via print. The format is intentionally machine-grep-friendly so you can pipe it through jq / awk without a structured-logging dep.

Fields

inner Inner The wrapped handler.
prefix String Prefix prepended to every log line; defaults to ``"[flare]"``.

Methods

fn __init__
fn serve

fn __init__ static §

__init__(out self)
Args
self out Self
Returns
Self

fn __init__ static §

__init__(out self, var inner: Inner, prefix: String = "[flare]")
Args
inner var Inner
prefix String Default: "[flare]"
self out Self
Returns
Self

fn serve §

serve(self, req: Request) -> Response
Args
self Self
req Request
Returns
Response
Raises

May raise an exception.

struct RequestId §

struct RequestId[Inner: Handler & Copyable & Defaultable]

Echo the inbound ``X-Request-Id`` header back on the response.

If absent on the inbound side, a deterministic id derived from perf_counter_ns is generated. Useful for request tracing when paired with the upstream gateway / load balancer.

Fields

inner Inner

Methods

fn __init__
fn serve

fn __init__ static §

__init__(out self)
Args
self out Self
Returns
Self

fn __init__ static §

__init__(out self, var inner: Inner)
Args
inner var Inner
self out Self
Returns
Self

fn serve §

serve(self, req: Request) -> Response
Args
self Self
req Request
Returns
Response
Raises

May raise an exception.

struct Compress §

struct Compress[Inner: Handler & Copyable & Defaultable]

Negotiate ``Content-Encoding`` per RFC 9110 paragraph 12.5.3.

Inspects the inbound Accept-Encoding header, picks the highest-q entry from {br, gzip, identity}, and encodes the inner response body accordingly. Sets Content-Encoding and Vary: Accept-Encoding on the response.

Bodies smaller than min_size_bytes (default 1024) are passed through untouched — the per-request encoder overhead beats the transfer-time savings on small bodies.

Fields

inner Inner
min_size_bytes Int
brotli_quality Int
gzip_level Int

Methods

fn __init__
fn serve

fn __init__ static §

__init__(out self)
Args
self out Self
Returns
Self

fn __init__ static §

__init__(out self, var inner: Inner, min_size_bytes: Int = 1024, brotli_quality: Int = 5, gzip_level: Int = 6)
Args
inner var Inner
min_size_bytes Int Default: 1024
brotli_quality Int Default: 5
gzip_level Int Default: 6
self out Self
Returns
Self

fn serve §

serve(self, req: Request) -> Response
Args
self Self
req Request
Returns
Response
Raises

May raise an exception.

struct CatchPanic §

struct CatchPanic[Inner: Handler & Copyable & Defaultable]

Convert any ``raise`` from the inner handler into a 500.

Useful when stacking middleware below the server's own error-sanitisation layer (e.g. inside a router branch). The server's HttpServer.serve path already wraps the top-level handler this way; this is for inner stacks.

Fields

inner Inner
body String

Methods

fn __init__
fn serve

fn __init__ static §

__init__(out self)
Args
self out Self
Returns
Self

fn __init__ static §

__init__(out self, var inner: Inner, body: String = "Internal Server Error")
Args
inner var Inner
body String Default: "Internal Server Error"
self out Self
Returns
Self

fn serve §

serve(self, req: Request) -> Response
Args
self Self
req Request
Returns
Response
Raises

May raise an exception.