Targeted stress testing under this branch's HTTP/2 work surfaced four independent
production bugs, each verified with a before/after load test and a regression test:
- Http2Limits.MAX_STREAMS_CREATED_PER_INTERVAL (400/10s) rejected legitimate
high-concurrency HTTP/2 clients as if they were CVE-2023-44487 rapid-reset abuse —
h2load's default pattern alone triggered 40-92% request failure. Raised to 100,000,
matching MAX_STREAMS_PER_CONNECTION's existing lifetime budget; the RST_STREAM-rate
counter remains the precise defence against the actual attack signature.
- Flash had no connection-admission control anywhere: AcceptLoop accepted every TCP
connection unconditionally, so a connection flood (h2load -c 400) ran the JVM out of
heap and crashed with OutOfMemoryError, killing even unrelated daemon threads.
TransportLimits.defaultMaxConnections() auto-scales a cap from Runtime.maxMemory();
ConnectionRunner.accept() enforces it before any per-connection state (TLS handshake
included) is created. Verified surviving 42x the admission limit under both cleartext
and TLS load with bounded RSS.
- Http1ResponseWriter never closed a handler's streaming response body on a write
failure (e.g. the client disconnecting mid-transfer) — only on a clean EOF. A handler
whose stream releases a held resource (a pooled backend connection, for a reverse
proxy) from close() leaks it under any real amount of client disconnects. Now closed
on every exit path, matching InputStream#close()'s own idempotency contract.
- Http2StreamState.transition() called the enum's values() every state transition;
values() clones a fresh array on every call. Cached once, removing ~10.76% of
allocations measured live under load.
695 -> 698 tests (three new regression tests), all passing.