🚀 drip v0.8.0 — 4× faster, in-house mux, HTTP/3, and large-transfer fixes
This release rebuilds drip's data plane. On the same hardware it delivers roughly 4× the throughput, ~6× lower p99 latency, and 35–45% less memory — plus HTTP/3 on the public edge and bulk transfers that survive real speedtests.
📊 Benchmarks
Same machine, same wrk script, before vs. after.
High concurrency (12 threads / 400 connections)
| Metric | Before | After | Delta |
|---|---|---|---|
| Requests/sec | 5,498 | 21,170 | 3.85× |
| p50 latency | 68.67 ms | 18.87 ms | 3.6× lower |
| p99 latency | 144.66 ms | 24.40 ms | 5.9× lower |
All tiers
| Tier | Before | After | Delta |
|---|---|---|---|
| Quick (50 conns) | 5,542 req/s | 20,782 req/s | 3.75× |
| Standard (100 conns) | 5,375 req/s | 21,805 req/s | 4.06× |
| High (400 conns) | 5,498 req/s | 21,170 req/s | 3.85× |
The three tiers now converge at ~21k req/s: the system is CPU-bound at a much higher ceiling instead of queueing.
Memory under the 400-connection load
| Process | Before | After | Delta |
|---|---|---|---|
drip-server RSS |
366 MB | 239 MB | -35% |
drip-client RSS |
243 MB | 134 MB | -45% |
🧠 What changed
In-house mux replaces yamux
- New
internal/shared/mux/dmux: 12-byte frame header, optimistic stream open (zero RTT), per-stream window flow control, batchedwritevsends, and no per-stream goroutines. - Stream open/close: ~4.5× faster with far fewer allocations.
- 32 KB writes: ~1.45× faster (2.9 GB/s vs 1.9 GB/s).
- Concurrent streams: ~1.9× faster.
hashicorp/yamuxis gone.
Per-request path
- HTTP response headers are coalesced into one tunnel write (previously up to 46 writes per response, each a separate mux frame).
- Removed a goroutine and a 3-second timer per request.
- Lock-free activity tracking, amortized write deadlines, no per-chunk channel allocations, right-sized buffers.
- Removed the 2 ms frame-batching ticker (500 wakeups/s per tunnel while idle).
- Removed
goccy/go-json; stdlib JSON on cold control-plane paths only.
HTTP/3 on the public edge
- QUIC on the same public port, sharing the HTTP handler, with
Alt-Svcon h1/h2, graceful shutdown, and WebSocket upgrades cleanly rejected over h3. - Enable or disable with
--http3,DRIP_HTTP3, orhttp3:in config. - Loopback: h1 20.2k, h2 20.3k, h3 9.4k req/s — h3's win is lossy/high-RTT networks.
Bulk transfers that don't get cut
- Removed the server's total
ReadTimeout/WriteTimeout, which aborted slow large transfers. - Request bodies are now unlimited by default (
max_request_body_bytes: 0); set a positive value to cap. - Real Chrome + LibreSpeed through the tunnel: 60.0 Mbps down / 90.5 Mbps up, matching direct LAN.
- 1 GiB HTTP download/upload: SHA-256 match at ~230 MB/s.
- 100 MiB at 1 MB/s for 100 s: completes without interruption.
- 4 × 256 MiB concurrent: all SHA-256 match.
- 512 MiB TCP tunnel: SHA-256 match at ~268 MB/s.
- 60 s soak, 8 workers, ~50 GB: 0 failures, stable RSS.
Security
- Trusted-proxy client IP handling: forwarding headers are honored only from configured proxies.
- Strict auth, ACL, and lifecycle hardening carried over.
Toolchain
- Go 1.27.3, staticcheck v0.8.2, gosec v2.30.0, govulncheck v1.9.0.
- GitHub Actions upgraded (checkout v7, setup-go v7, goreleaser v7, Docker actions v4–v7).
- Docker:
golang:1.27.3-alpine3.24,alpine:3.24.3. - Native
net/http.HTTP2Configreplaces the deprecatedx/net/http2setup.
⚠️ Upgrade note
The wire protocol changed (dmux replaces yamux). Upgrade the client and
server together. The new default is unlimited request bodies; operators who
need a cap can set max_request_body_bytes.
Changelog
- [b73a2c] Merge pull request [#31] from Gouryella/feat/security-hardening
- [150cd1] Merge remote-tracking branch 'origin/main' into feat/security-hardening
- [96759a] chore(deps): upgrade Go, CI tooling and dependencies
- [32308e] fix(mux): remove dead code flagged by staticcheck
- [806311] perf: cut per-request CPU, add in-house mux and HTTP/3
- [beac23] feat(security): trusted proxy client IP handling
- [ae927a] Create FUNDING.yml
- [8d87a3] Create SECURITY.md
- [afdecd] test(e2e): query metrics via the management host
- [bbc17d] feat(deploy): container hardening and example config alignment
- [692d4f] feat(install): verify checksums and pin versions in install scripts
- [ea5d96] test(server/tcp): end-to-end tunnel integration tests
- [736e16] feat(client): reconnect backoff, clean shutdown, server security flags
- [fbab1f] feat(client): pass daemon secrets via file instead of argv
- [1b5335] feat(client/tcp): dialer normalization, pool lifecycle, session retirement
- [0eb7be] feat(server/tcp): listener admission, ALPN pass-through, port handoff
- [e8c6ea] feat(server/tcp): strict auth, connection group quotas, lifecycle fixes
- [3c3619] feat(server): harden proxy auth, forwarding, and management endpoints
- [b39a01] feat(config): strict YAML, sensitive file permissions, atomic writes
- [0f5f1f] fix(server): tunnel lifecycle races and strict IP access rules
- [f768e2] fix(shared): pipe half-close handling and write deadlines
- [93967a] feat(shared): trusted proxy set and spoof-proof client IP extraction
- [411962] feat(shared): wrap yamux streams with net.Conn close semantics
- [166351] feat(shared): container-aware memory limits and runtime env respect
- [c00cb7] fix(shared): make rate-limited IO interruptible by deadlines
- [d07d73] fix(shared): wsutil write deadlines and non-blocking close
- [64b877] fix(shared): strip every Connection header value and Upgrade
- [9df782] fix(shared): validate frame types and harden FrameWriter lifecycle
- [9d1e49] fix(shared): pool buffer sizing, bufio retention, worker pool race
- [a19bd5] feat(shared): log redaction, constant-time compare, error classification
- [ae9cd7] chore: bump Go to 1.26.8 and pin CI tooling