Case study 19 / 26
Spindrift
An HTTP/1.1 server with its own RFC 9112 protocol stack, a pipeline language instead of a config file, and reloads that never drop a request.
- Status
- Research
- Period
- 2026
- Domain
- web · cloud
- Language
- Go
- Last push
- 05 SEP 2026
- License
- MIT
- Source of claims
- README.md, docs/CONFIG.md, ARCHITECTURE.md
Requests are parsed by Spindrift's own strict HTTP/1.1 implementation — not net/http — then flow through a small declarative pipeline: middleware, routing, static files, reverse proxy, SSE streaming, rate limits, conditions and templates. Go standard library only.
01/The problem
Most servers are configured, and hide the request pipeline behind a large configuration surface and a larger codebase. Frameworks expose a pipeline but tie it to a runtime and a rebuild per change.
02/The system
Requests are parsed by Spindrift's own strict HTTP/1.1 implementation — not net/http — then flow through a small declarative pipeline: middleware, routing, static files, reverse proxy, SSE streaming, rate limits, conditions and templates. Go standard library only.
03/Implementation
- 01Request-line and header parsing with byte budgets, Content-Length and chunked bodies with trailers, pipelining, keep-alive and 100-continue.
- 02Strict rejection of bare LF, obs-fold, conflicting lengths and other malformed framing with the right status.
- 03A pipeline language: route and middleware rules, path params, conditions over request and environment, and templates.
- 04Handlers for respond, redirect, traversal-safe static files, streaming reverse proxy and chunked SSE; middleware for headers, auth gates, per-client token-bucket rate limits and CORS.
- 05Prometheus metrics, JSON access logs, atomic hot reload on SIGHUP and graceful drain on SIGINT/SIGTERM.
04/Engineering
Reloads keep in-flight requests on the old pipeline
The new pipeline is swapped atomically for the next request on every connection, and rate-limit buckets survive reloads for unchanged rules.
Drain that actually drains
Idle keep-alive connections close immediately; active responses — even long streams — finish before exit. Tested with a stream in flight.
Secrets stay out of the config
Conditions can read the environment, so an auth gate is one line and the token never lives in the file.
05/Interface
No product screenshots are published for this project. The visual above is a code-driven representation of how it behaves, built from the repository source — not a screenshot.
06/Tech stack
- Go
- Standard library only
- RFC 9112
- Prometheus metrics
- Docker
07/Result
Verified outcomes
- 30 protocol tests plus a load test (32 keep-alive clients × 200 requests) asserting zero failures and connection reuse; race detector clean.
- Reported in the README (one run, loopback): ~75k requests/s with p99 ≈ 3.6 ms.
Known limitations
- HTTP/1.1 only: no TLS termination, HTTP/2 or WebSocket upgrade; rate limiting is per process.
08/Links
Next case study
Emberline →