Skip to content

httpjet v0.0.5

Latest

Choose a tag to compare

@faratech faratech released this 12 Oct 20:38

httpjet 0.0.5 — whole-codebase audit remediation

This release fixes the 15 findings of a whole-codebase bug sweep (2026-10-12: four parallel reviewers across the transport, page-cache, LSAPI/rewrite, and proxy/ACL/TLS surfaces, every finding hand-verified in source and the worst one reproduced dynamically). Every fix ships with a regression test. Dependencies are refreshed to their latest releases; the toolchain stays at Rust 1.99.

Availability (high)

  • Rewrite [S=n] infinite loop. A rule such as RewriteRule ^x$ - [S=18446744073709551615] wrapped the evaluator's rule index back onto itself in release builds, pinning a worker core forever per matching request. Skip advance now saturates past the end of the ruleset.
  • Unbounded HTTP/2 upstream handshake in the proxy. The h2:///h2s:// handshake could stall indefinitely at the IO layer, pinning a permit from the process-wide dial budget (64) plus an upstream maxConns slot. It now runs under the connect budget, mirroring the health-check probe.
  • HTTP/2 reset without teardown. After the server sent RST_STREAM for a body-pending stream (zero WINDOW_UPDATE increment, self-referential PRIORITY), a later DATA … END_STREAM still completed and dispatched the already-reset request. The reset path now tears down the receiving stream and returns its buffered-body accounting.

Proxy correctness

  • WebSocket targets enforce maxConns. Default (non-load-balanced) WebSocket upstreams acquired no concurrency permit at all; the long-lived relay was bounded only by global client limits. A permit is now acquired and held for the relay's lifetime.
  • Failover survives config reloads. Retained upstreams kept writing dial failures to the previous generation's cooldown counter, so after a reload the new pool never saw the primary as bad and fast-failed instead of failing over. Cooldowns are carried into the retained generation and handles are rebound on selection.

Request handling and PHP trust boundary

  • Forwarding-header synonyms. The blocklist for proxy-asserted identity headers was an exact-name list; X-Client-IP, X-Forwarded-Protocol, Proxy-Client-IP, and similar synonyms from untrusted clients reached PHP as spoofable $_SERVER values. Matching is now class-based (the *-client-ip, x-forwarded-*, and *-real-ip families, dash/underscore-folded) and fails closed.
  • CGI env overrides. [E=…] could replace server-computed REQUEST_METHOD, REQUEST_URI, PATH_INFO, CONTENT_*, GATEWAY_INTERFACE, and REQUEST_TIME*; all are now on the override deny-list.
  • WAF fail-open no longer corrupts requests. A sidecar timeout mid-body-collection used to forward an emptied body downstream; the body is now collected and restored before the timed inspection exchange.

HTTP/3, page cache, and LSAPI lifecycle

  • H3 request targets. A network-path :path (//evil.example/x) minted a URI authority diverging from the routed Host; rejected. QPACK field sections with a nonzero Required Insert Count or Delta Base are rejected (the dynamic table is advertised at capacity 0).
  • Purge completeness. /__hj_cache_purge honors every X-LiteSpeed-Purge header line instead of only the first, and the tag-purge version sweep can no longer unlink a live re-stored page's body file. enablePostCache now warns (config lint + startup log) instead of being silently inert.
  • LSAPI lifecycle. Restart backoff is cancellable on shutdown, registry drain has a wall-clock bound so a mid-start pool cannot be orphaned, and a jail chroot configured without credentials is a hard spawn error rather than a silent skip.

Dependencies

Cargo.lock refreshed to the latest semver-compatible releases (aws-lc-rs 1.18.2, zstd 0.14.2, serde_json 1.0.154, tokio-util 0.7.20, OpenTelemetry 0.33.1, proptest 1.12, and more); all manifests already required the latest majors. cargo audit is clean and the full test suite (2,028 tests) passes.

Production deployments should follow the usual path: scripts/build-pgo.sh, then scripts/deploy-lscache.sh and the cache gate scripts.