ThwipHome

Overview / Roadmap

Feature roadmap

These items describe the direction we want to take with thwip, not currently available behavior.

TLS

Thwip currently serves plaintext HTTP and connects to plaintext http:// upstreams. TLS needs to cover two distinct roles: terminating HTTPS from clients and establishing HTTPS connections to upstream services.

Client TLS termination

A server will need certificate and private-key configuration, protocol and cipher policy, and a way to select certificates during SNI. The listener still owns the accepted socket, while each connection owns its TLS session and handshake state. HTTP parsing begins only after the handshake has produced decrypted application bytes.

Runtime integration

Epoll and kqueue will drive nonblocking handshakes whenever the TLS engine requests more readable or writable socket progress. io_uring will submit network receives and sends around the same runtime-neutral TLS session; cryptographic state remains connection-owned rather than ring-owned. This keeps certificates, routing, and HTTP behavior consistent across drivers.

HTTPS upstreams

Upstream TLS also requires hostname verification, trust-store configuration, SNI, handshake deadlines, and clear separation between DNS, TCP-connect, TLS-handshake, request-write, and response-read failures. Connection pooling should follow TLS so established secure sessions can be reused safely.

Likely configuration areas include certificate/key paths per server, minimum TLS version, trust roots for upstreams, verification controls, and a dedicated handshake timeout. Secure defaults should be mandatory; disabling verification should be explicit and difficult to do accidentally.

Benchmarking

Benchmarking is a primary roadmap stepping stone because Thwip’s platform-specific runtimes exist to pursue practical performance. We are really looking forward to see how our tech does in comparison to other alternatives and how different runtimes affect our performance benchmarks

Core workloads

Measurements

Every published run should report throughput, median and tail latency, CPU time, context switches, memory high-water mark, open connections, errors, and runtime-specific pressure such as submission occupancy or event-batch saturation. Warm-up, run duration, concurrency, response sizes, worker count, kernel, hardware, compiler profile, and configuration must be recorded alongside results.

Fair comparisons

Runtime comparisons need the same machine, client generator, worker count, socket settings, request mix, and output validation. The load generator should run on separate capacity when possible so it does not compete with Thwip. Multiple runs and variance are required; a single best result is not representative.

The intended deliverable is a reproducible benchmark suite plus checked-in configurations and published result snapshots. Optional io_uring operations should be adopted only when those measurements show a meaningful improvement without weakening correctness or portability.

OpenBenchmark benchmarks

Is a benchmark we are looking forward to prepare for, once we achieve a benchmark ready state with sufficient features, we will be conducting this benchmark in the hardware we currently have at our disposal and publish a findings report to this documentation page.

Documenting different user alternatives for benchmarking

Is what our end goal is to observe adoption and adoption success.

Hot reload & thwip_ctl (systemctl/services support)

After TLS, the primary operational feature is a local control plane that can apply configuration changes without dropping active traffic. A dedicated thwip_ctl terminal application will communicate with the master process over a permission-restricted Unix domain socket.

Transactional hot reload

The master should read and fully validate a candidate configuration before changing live state. It then starts a new worker generation with the new listeners, routes, certificates, and upstream definitions. Only after the new generation reports readiness does the master stop sending work to the old generation and ask it to drain within the configured deadline.

If parsing, binding, certificate loading, capability probing, or worker startup fails, the candidate generation is discarded and the existing workers continue serving the previous configuration. Reload must therefore be atomic from an operator’s perspective: either the complete configuration becomes ready or none of it is activated.

thwip_ctl commands

thwip_ctl validate /etc/thwip/thwip.toml
thwip_ctl reload
thwip_ctl status
thwip_ctl workers
thwip_ctl metrics
thwip_ctl drain
thwip_ctl stop
Command Purpose
validate Parse and validate a file without changing the running server.
reload Request a transactional worker-generation replacement.
status Show master identity, uptime, active generation, selected runtimes, and reload state.
workers List worker PIDs, generation, health, restart count, and drain state.
metrics Read a concise snapshot of per-worker and aggregate counters.
drain Stop accepting new traffic and gracefully finish active work.
stop Request graceful server shutdown through the master.

Control safety

The control socket should default to a runtime directory with restrictive filesystem permissions. Requests need a versioned protocol, bounded message sizes, explicit timeouts, structured error responses, and no ability for workers to mutate master state directly. Signals can remain as an emergency compatibility path, while thwip_ctl becomes the observable and scriptable interface.

HTTP lifecycle

Regex routing

Thwip will add an explicit regular-expression matcher for routes that cannot be expressed as an exact path or a stable prefix. Exact and prefix matching will remain the default because they are easier to understand, faster to evaluate, and sufficient for most proxy layouts.

Regex routes should be opt-in and evaluated only after exact and prefix matches. Configuration will need an obvious matcher type, a documented ordering rule for multiple matching expressions, and compile-time validation so an invalid pattern prevents startup rather than failing during a request.

Regular expressions can be expensive or surprising when used broadly. The implementation should enforce practical pattern and evaluation limits, avoid unbounded backtracking behavior, and keep captures or rewrite-style transformations out of the first version.

Secondary protocols

WebSockets

WebSocket support begins as an HTTP/1.1 upgrade. Thwip must validate the upgrade handshake, switch the connection out of HTTP request/response mode, and relay frames bidirectionally with bounded buffers, backpressure, idle timeouts, close-frame handling, and half-close/error propagation. The initial goal should be transparent WebSocket proxying rather than interpreting application messages.

UDP proxying

UDP is connectionless and should use a separate datagram listener and action model instead of being forced through the TCP connection abstraction. Workers will need flow tracking keyed by client and destination addresses, bounded per-flow state, idle expiry, datagram-size limits, and a clear policy for upstream selection and response association.

QUIC and HTTP/3

QUIC runs over UDP but adds encrypted connections, streams, congestion control, and transport-level state. HTTP/3 should therefore be treated as a later protocol implementation built on a QUIC library—not as a side effect of adding raw UDP forwarding. Its TLS requirements and lifecycle are substantially different from TCP HTTP.

Likely configuration should separate http, stream, and datagram services so protocol-specific limits and routing remain explicit.

Proxy resilience

Pooling, retries, and health checks must remain compatible with streaming and backpressure; they should not require buffering entire requests or responses.

Runtime control and observability

Configuration hardening

Optional io_uring acceleration

After baseline behavior is stable, Thwip can capability-probe optional operations such as recvmsg, zero-copy sends, fixed files, and splice. None should become a baseline requirement: unsupported kernels must retain the current paths, and auto mode must continue to choose a dependable runtime.

Adoption should be driven by measured CPU, latency, throughput, queue pressure, and memory behavior rather than the availability of an opcode alone.