Repository navigation
CWIST v3.3
CWIST v3.3 — gRPC streaming, deferred async handlers, and stability hardening
Major changes compared to v3.2 (including subsequent patch updates in this tag):
-
Full gRPC Streaming Support (d3222d6)
- Connect incremental decoders/output sinks directly to HTTP/2 DATA frames via per-connection stream hooks.
- Send grpc-status and grpc-message as actual trailer HEADERS frames.
- Parse grpc-timeout, enforce DEADLINE_EXCEEDED, and propagate RST_STREAM cancellations.
- Metadata normalization (case-insensitivity, *-bin base64 encoding), gzip request compression negotiation.
- cwist proto extensions: repeated fields (packed/unpacked), recursive encode/decode/free for nested messages, proto3 open enum support.
- New tests: test_grpc_stream (wire-level h2c) and test_proto_gen (roundtrip).
-
Deferred Async Handlers & Packaging (2352d0f)
- cwist_async_defer/respond/abort: delegate response completion to worker job threads with 504 timeout enforcement.
- Per-reactor wake fd (eventfd/pipe) and lock-free MPSC completion routing.
- make install support for cwist.pc (pkg-config), make dist tarball, and Homebrew/vcpkg drafts.
-
RFC 9218 HTTP/3 Priority Compliance (52b023b, e7d8297)
- Removed PRIORITY_UPDATE frame transmission on request streams (resolving H3_FRAME_UNEXPECTED on strict stacks).
- Preserved set_stream_priority ABI with deprecation warnings.
-
HTTP Connection Stability (e719cf6, 1ab0e9f)
- Enhanced graceful close, added error-checking helpers, and enabled sanitizer CI.
- Implemented grace-period serving after HTTP/2 idle GOAWAY.
-
- Added the-benchmarker/web-frameworks contract app; fixed v3.3 tag build.
- Fixed the-benchmarker/web-frameworks main.c build command missing vendored include paths (sqlite3, libttak, BoringSSL, ...), causing a clean-container build to fail with 'sqlite3.h: No such file or directory' (the-benchmarker/web-frameworks#9745).
--- Patch Updates ---
-
Status Code & Header Consistency
- Expanded cwist_http_status_t to cover the full standard 1xx–5xx range (RFC 9110 + WebDAV) while retaining legacy aliases.
- Added cwist_http_status_reason() to automatically apply standard reason phrases to error responses and status line fallbacks.
- Cleaned up duplicate app.h declarations and resolved header guard collisions: unified top-level <cwist/app.h> and <cwist/sys/app/app.h> under an umbrella header to eliminate differing cwist_app struct layouts across translation units.
- Standardized build baseline to -std=c17 (aligned with documentation) and updated CLI scaffolding templates.
-
Concurrency & Memory Safety
- io_queue: Fixed node reclamation race (UAF/ABA) in Michael-Scott queue by guarding push/pop in ttak EBR critical sections and retiring unlinked nodes via 2-stage retirement (new -> old -> ttak_epoch_retire) past epoch boundaries (100x clean TSAN, clean ASan/UBSan).
- execute_chain(): Fixed static files returning 500 on apps with 0 middleware due to lost handler_data.
- rdbms_auto_mount: Fixed uninitialized host pointer free (ASAN BUS) by replacing it with zeroed allocation.
- http2: Fixed sequenced DATA message leak on flow-control wait abort paths.
- Added cwist_error_dispose() and eliminated cJSON error payload leaks in sstring/nuke-db (resolving prior ASan CI failures).
- test_static_and_range: Fixed test hanging on keep-alive responses waiting for EOF by checking Content-Length instead.
- http2: Fixed HPACK dynamic table desync on stream errors — a header block that failed pseudo-header validation (e.g. duplicated :method) was abandoned mid-decode, skipping later incremental-indexing inserts and corrupting the shared compression context for subsequent requests on the same connection.
-
Hardening & Interop CI
- Linux: Enabled -fstack-protector-strong, _FORTIFY_SOURCE=2, PIE, and full RELRO by default.
- Added WERROR=1 build toggle (excluding vendored objects) and integrated it into ASan/UBSan workflows.
- Introduced interop workflow: h2spec h2c compliance checks with baseline diff against known failures (fails build on unexpected regressions).
- tests/lsan.supp: Documented known lsquic teardown leaks and h3 header-set teardown gaps (ROADMAP known issues).
-
Tooling & Documentation
- make install now installs the cwist CLI into $(PREFIX)/bin; uninstall cleans it up.
- README: Added CLI project workflows (new/watcher/openapi/proto/describe) and stability/conformance sections.
- NOTICE.md: Added summary of vendored dependency licenses.
-
Async v2 Writer, P2C TLS Shepherd & Idle Reaper (428df58)
- cwist_async_complete: removed synchronous SO_SNDTIMEO blocking; speculative non-blocking send pipeline with zero added latency on the hot path.
- TLS shepherd: SSL_accept crypto offload out of the accept loop, Power-of-Two-Choices shard load balancing, SO_REUSEPORT ingress distribution.
-
HTTP/2 DoS Mitigations — Rapid Reset & Control-Frame Floods (f89fb78)
- CVE-2023-44487 (Rapid Reset): token-bucket RST_STREAM budget per connection (burst 100, refill 100/s; CWIST_HTTP2_MAX_RST_BURST / CWIST_HTTP2_MAX_RST_RATE); excess triggers GOAWAY(ENHANCE_YOUR_CALM) and connection teardown, enforced on both blocking and non-blocking send loops.
- RFC 7540 §5.1: RST_STREAM on idle streams (stream_id > last_processed_stream_id) is now a PROTOCOL_ERROR connection error.
- CVE-2024-27983 (CONTINUATION flood): 64KB header-block cap (CWIST_HTTP2_MAX_HEADER_BLOCK_SIZE), 32-frame CONTINUATION limit (CWIST_HTTP2_MAX_CONTINUATIONS), 256 headers/request cap, and SETTINGS_MAX_HEADER_LIST_SIZE=65536 advertised in the handshake.
- CVE-2019-9512 (PING flood): token-bucket rate limit on non-ACK PING frames with ENHANCE_YOUR_CALM enforcement.
-
Async HTTPS over TLS (f9d447c)
- Deferred handlers on TLS connections now respond via SSL_write through the connection wrapper (cwist_https_send_response/_head) instead of writing plaintext to the socket; keep-alive connections re-arm through https_pool_submit_conn.
- Thread-local arena: _Thread_local fast-path TLS lookup (no pthread_getspecific call on the hot path), owner_tid tagging so cross-thread destroys bypass foreign caches, and arena struct + buffer recycled together.
- HTTP/2 responses are created inside the request arena — one arena block per request-response cycle.
-
HTTP/2 Async Defer — MPSC Queue + eventfd (0183305)
- Deferred handlers no longer block the HTTP/2 connection loop: completed (stream_id, req, res) nodes are pushed onto a per-connection MPSC queue and the connection thread is woken via eventfd; HPACK encoding and flow control stay single-threaded (no cross-thread frame injection, no output mutex).
- RST_STREAM on a deferred stream removes it from the stream table; late completions for cancelled streams are dropped at drain time. Refcounted queue survives teardown races.
-
HTTP/3 UDP GSO Fix (485ce64)
- Capped GSO super-packet runs at 65535 bytes (max UDP payload); an exactly-64KiB batch previously failed sendmsg with EMSGSIZE and permanently disabled GSO.
-
POLLOUT-Resumable Async Writer (6eef7a7)
- Deferred async completions on the reactor path no longer poll-wait in the completion thread on slow clients: unsent bytes are deep-copied into an owned buffer, parked in a one-shot POLLOUT slot (new cwist_reactor_add_out; io_uring POLL_ADD / epoll EPOLLOUT|ONESHOT / kqueue EVFILT_WRITE|EV_ONESHOT), and resumed on write-readiness.
- Parked writers are bounded by a deadline (keep-alive timeout, refreshed on progress); file-stream bodies and the classic pool path keep the existing bounded poll loop.
- Removes the last case where a slow client could occupy a reactor thread for the SO_SNDTIMEO budget (ROADMAP "Async v2" item closed).
-
HTTP/3 Header-Set Leak Fix (151f61c)
- lsquic never calls hsi_discard_header_set for streams still open on abortive engine destroy, leaking cwist_h3_hset_t objects.
- Header sets are now tracked in an intrusive list on cwist_http3_context and swept after lsquic_engine_destroy; hsi_discard untracks before freeing so the sweep only touches true orphans.
- The leak:cwist_h3_hsi_create entry is removed from tests/lsan.supp — LSan now passes on the HTTP/3 suite without that suppression.
-
gRPC WINDOW_UPDATE Backpressure (097c4cb)
- Handler-thread gRPC sends no longer fail with UNAVAILABLE on zero flow-control credit: cwist_http2_stream_send_data now flushes pending DATA, parks the handler on a per-connection condvar (h2_fc_wait_credit) signalled by the dispatcher on WINDOW_UPDATE/SETTINGS credit, and resumes chunk-by-chunk without holding the output mutex.
- RST_STREAM (Rapid Reset), stream removal, connection teardown, and stall timeout still fail fast.
- With this, every HTTP-layer item under ROADMAP "Known limits" that is controllable in-tree is closed; remaining limits are upstream-bound (e.g. WebTransport pending lsquic PR #629).