Skip to content
ehsanmokPublic

About

Full Networking Stack for Mojo🔥

Topics

Resources

Security policy

Stars

67 stars

Watchers

2 watching

Forks

Latest commit

 

History

1,289 Commits

Folders and files

Repository files navigation

flare

flare

CI Fuzz Docs License: MIT

Full networking stack for Mojo 🔥 HTTP/1.1, HTTP/2, and HTTP/3 server and client (HTTP/3 over QUIC), WebSocket, TLS, TCP, UDP, Unix sockets, DNS, all in one library on top of one non-blocking reactor. Drop to raw sockets when HTTP isn't the right shape. The codecs and protocol state machines are proved against the RFCs in Lean 4.

from flare.prelude import *

def hello(req: Request) -> Response:
    return ok("hello")

def main() raises:
    var r = Router()
    r.get("/", hello)
    var srv = HttpServer.bind(SocketAddr.localhost(8080))
    srv.serve(r^, num_workers=2)

And a version-aware client (negotiates HTTP/2 via ALPN, opt into HTTP/3):

from flare.prelude import *

def main() raises:
    with HttpClient("https://example.com", prefer_http3=True) as c:
        var r = c.get("/")
        print(r.status, r.text())

Why flare

  • Batteries included: HTTP/1.1, HTTP/2 and HTTP/3 (server and client), WebSocket (also over HTTP/2 and HTTP/3), gRPC, TLS and mTLS with SNI certificates, streaming, sessions, compression, CORS, static files, SSE, templates, caching and an OpenAPI emitter. Full inventory in docs/features.md.
  • Composable by types, not callbacks: Handler is a trait; Router, middleware and typed extractors compose by nesting structs, monomorphised into one direct call sequence per request type.
  • Hard to misuse under load: per-request Cancel tokens, graceful drain, sanitized 4xx/5xx, TLS cert hot reload, structured logging, Prometheus metrics and an in-process TestClient[H].
  • Fast, with a tight tail: thread-per-core reactor (kqueue / epoll, opt-in io_uring). At 4 workers the handler path reaches 0.96-1.00x of actix_web and the static path 1.08-1.16x, with p99 about 3 ms at the peak; see Performance.
  • Fuzzed and formally modelled: 63 fuzz harnesses (9M+ runs, zero known crashes) and Lean 4 models of the codecs, state machines and scheduler, proved against the RFCs; see Formal verification.

Install

[workspace]
channels = ["https://conda.modular.com/max", "conda-forge"]
preview = ["pixi-build"]

[dependencies]
flare = { git = "https://github.com/ehsanmok/flare.git", tag = "<latest-release>" }
pixi install

Requires pixi (pulls Mojo automatically). Pin to a released tag for reproducible builds.

To track unreleased work (breaking changes possible between tags):

[dependencies]
flare = { git = "https://github.com/ehsanmok/flare.git", branch = "main" }

Quick start

Simplest

from flare.prelude import *

def home(req: Request) -> Response:
    return ok("flare is up")

def health(req: Request) -> Response:
    return ok_json('{"status":"ok"}')

def greet(req: Request) raises -> Response:        # raises: req.param() can
    return ok("hello, " + req.param("name"))

def main() raises:
    var r = Router()
    r.get("/", home)
    r.get("/hi/:name", greet)
    r.get("/health", health)
    var srv = HttpServer.bind(SocketAddr.localhost(8080))
    srv.serve(r^)

Intermediate: typed extractors

Handler fields are the inputs; a bad value becomes a sanitized 400 before your code runs.

from flare.prelude import *

@fieldwise_init
struct GetUser(Copyable, Defaultable, Handler):
    var id: PathInt["id"]

    def __init__(out self):
        self.id = PathInt["id"]()

    def serve(self, req: Request) raises -> Response:
        return ok("user=" + String(self.id.value))

def main() raises:
    var r = Router()
    r.get("/users/:id", Extracted[GetUser]())
    var srv = HttpServer.bind(SocketAddr.localhost(8080))
    srv.serve(r^, num_workers=4)

Advanced

Cancel-aware handlers get a token the reactor flips on peer FIN, deadline or drain:

@fieldwise_init
struct SlowHandler(CancelHandler, Copyable):
    def serve(self, req: Request, cancel: Cancel) raises -> Response:
        for i in range(100):
            if cancel.cancelled():
                return ok("partial: " + String(i))
            # ...one expensive step...
        return ok("done")

Compile-time route tables unroll dispatch per route, with no runtime trie walk:

comptime ROUTES: List[ComptimeRoute] = [
    ComptimeRoute(Method.GET, "/",          home),
    ComptimeRoute(Method.GET, "/users/:id", get_user),
    ComptimeRoute(Method.GET, "/files/*",   files),
]

var r = ComptimeRouter[ROUTES]()

Middleware and shared state are structs wrapping a Handler, monomorphised into one call sequence per request type:

@fieldwise_init
struct WithHits[Inner: Handler](Handler):
    var inner: Self.Inner
    var hits: Int

    def serve(self, req: Request) raises -> Response:
        var resp = self.inner.serve(req).lower()
        resp.headers.set("X-Hits", String(self.hits))
        return resp^

srv.serve(WithHits(inner=router^, hits=37))

Every tier has runnable, tested equivalents:

I want to... Go to
Start with routing, JSON, a client, raw TCP/UDP/TLS/WebSocket examples/basic/
Add middleware, state, sessions, forms, SSE, caching, CORS, static files examples/intermediate/
Go to HTTP/2, HTTP/3, gRPC, mTLS, compile-time routing, streaming proxies, the raw reactor examples/advanced/
Find the example for a use case docs/cookbook.md
Browse the API https://ehsanmok.github.io/flare/

Performance

TFB plaintext, wrk2 -t8 -c256 -d30s, 48-vCPU Xeon Platinum 8488C, Linux 6.12, one run for all rows, flare workers pinned, all servers built without debug asserts (mojo build -D ASSERT=none, cargo build --release --locked). Each row is the highest rate that survives the harness's sustainable-peak finder.

Server (4 workers) Req/s p99 (ms)
flare_mc_static (fixed-response path) 705,569 2.82
actix_web 610,408 2.78
flare_mc (handler path) 607,940 3.00
hyper 556,619 2.67
axum 489,422 2.71

On one worker flare does 168k req/s against nginx's 212k and Go net/http's 99k, with the lowest p50 and p99 of the three. Absolute numbers move by about 5 % between runs on this shared box, so compare rows within one run. Methodology, every workload, HTTP/2 and HTTP/3 results, and how to reproduce are in docs/benchmark.md. Production builds use -D ASSERT=none; see docs/build.md.

Low-level API

The primitives the HTTP server is built on are public, for when HTTP isn't the right shape: flare.tcp, flare.tls, flare.udp, flare.uds, flare.ws, flare.dns and the flare.runtime.Reactor. Runnable examples are in examples/basic/ and examples/advanced/reactor.mojo.

Architecture

flare.http / http2 / http3   servers, clients, Router, middleware, extractors
flare.ws  grpc  openapi      WebSocket, gRPC, OpenAPI
flare.quic                   QUIC v1 (sans-I/O codec + live UDP reactor, ECN, PMTU discovery)
flare.tls  crypto            TLS 1.2/1.3 (OpenSSL, rustls for QUIC), HMAC, base64url
flare.tcp  udp  uds  dns     sockets
flare.net  io                addresses, buffered readers
flare.runtime                reactor (kqueue / epoll / io_uring), scheduler, timers

Each layer imports only from layers below it. The per-module inventory, the request lifecycle and the per-connection state machine are in docs/architecture.md.

Formal verification

formal/ holds Lean 4 models of flare, from the byte codecs up through HTTP/1.1, HTTP/2, QUIC and HTTP/3 to the scheduler, each proved against a separate spec written from the RFC (core Lean only, no sorry, no extra axioms). Anchors, a spec lock and differential tests keep the models in sync with the Mojo code, and the 0.12 audit found 138 issues, all fixed. The design is in formal/README.md, the audit in formal/REPORT.md.

Security

Per-layer posture, limits and the sanitized-error policy are in docs/security.md, the threat model in docs/threat-model.md. To report a vulnerability, open a private security advisory on GitHub or email the maintainer.

Develop

git clone https://github.com/ehsanmok/flare.git && cd flare
pixi install
pixi run tests                  # full suite plus every example
pixi run tests-gen              # after adding a test file
pixi run format                 # mojo format (needs `pixi install -e dev`)

Environments, the task list and the structural lints are in docs/development.md; every task is defined in pixi.toml.

License

MIT

About

Full Networking Stack for Mojo🔥

Topics

Resources

Security policy

Stars

67 stars

Watchers

2 watching

Forks

Releases

Used by

Contributors

Languages