fix(http): advertise keep-alive on HTTP/1.0 responses we keep open
1.0 defaults to close: honoring 'Connection: Keep-Alive' without echoing it back left spec-following clients waiting for an EOF that never came (ab -k deadlocked to its poll timeout on response 1). As agreed: - serialise_response echoes 'connection: keep-alive' when keep_alive is on AND version is 1.0. 1.1 keep-alive stays implicit. - Error statuses (>=400) on 1.0 force keep_alive off in the conn actor (joins the existing 1.0-stream force-close): we don't advertise reuse on a 4xx/5xx to a protocol generation where reuse is opt-in. - HEAD needs nothing: the echo is framing-neutral. - Parse-error responses already carried 'connection: close'. Tests: unit pair (1.0 echo / 1.1 implicit) + integration pair (socket actually reused on 1.0; 404 forces close + EOF). Validated against the original repro: ab -k -n 5000 -c 50 GET /users -> 5000/5000 keep-alive, 0 failed, ~63k rps (~18.9k without keep-alive).
This commit is contained in:
+13
-15
@@ -229,21 +229,19 @@ PubSub underneath.
|
||||
|
||||
## Known bugs
|
||||
|
||||
- **HTTP/1.0 keep-alive: server honors but never advertises** (found
|
||||
2026-06-12 via `ab -k`). A 1.0 request with `Connection: Keep-Alive`
|
||||
IS kept alive (second pipelined request on the same socket gets
|
||||
answered), but the response carries no `Connection: Keep-Alive`
|
||||
header. Per 1.0 convention the client may only reuse when the server
|
||||
explicitly opts in; absent the header, clients assume the server will
|
||||
close and wait for EOF — which never comes. `ab -k` therefore
|
||||
deadlocks until its poll timeout (`apr_pollset_poll: timeout 70007`)
|
||||
on the FIRST response; no keep-alive bench numbers obtainable.
|
||||
Fix direction: when the conn stays alive on a 1.0 exchange, echo
|
||||
`Connection: Keep-Alive` in serialise_response — or don't keep 1.0
|
||||
alive at all. Decide scope (error responses, HEAD) with user first.
|
||||
Baseline for reference: GET /users (crud example, release, loopback,
|
||||
stdout logging silenced), no keep-alive, c=50: ~18.9k req/s, 0
|
||||
failed, p50 3ms / p99 5ms. HTTP/1.1 path responds normally.
|
||||
- ~~**HTTP/1.0 keep-alive: server honors but never advertises**~~ FIXED
|
||||
(2026-06-12, same session it was found). As-landed decisions:
|
||||
serialise_response now echoes `connection: keep-alive` on a kept-alive
|
||||
1.0 response (1.1 keep-alive stays implicit); error statuses (>=400)
|
||||
on 1.0 force close — no keep-alive advertised on a 4xx/5xx where reuse
|
||||
is opt-in (conn_actor, alongside the existing 1.0-stream force-close);
|
||||
HEAD needs nothing special (header echo only, framing untouched);
|
||||
parse-error responses already carried `connection: close`. Validated
|
||||
against the original repro: `ab -k -n 5000 -c 50` on GET /users now
|
||||
reports 5000/5000 keep-alive requests, 0 failed, ~63k req/s
|
||||
(vs ~18.9k no-keep-alive baseline, same box). Watch out benching:
|
||||
ab counts a response toward "Non-2xx" silently — a 404'd route still
|
||||
shows "Failed requests: 0" with great rps; check the route first.
|
||||
|
||||
## Later / icebox
|
||||
|
||||
|
||||
Reference in New Issue
Block a user