Artifact 21ca6c42ba1da1eee45a2b96e16cc2a3749e8d7987e396809f50850853a756ec:
- File
src/serve.zig
-
2026-07-20 04:34:32
— part of check-in
[e87fb840d1]
on branch h11-serve-socket
— serve: bound each connection so a stalled client cannot wedge the server
zit serve accepts one connection to completion before the next (single-threaded, serve.zig), and receiveHead plus the body read blocked with no deadline. A loopback peer that dribbles a request head, half-sends a body, or connects idle and holds could pin the accept loop forever -- the socket read path the exchange fuzzers never reach, covered before only by happy-path interop.
Add a whole-connection deadline: the request work runs on its own unit of concurrency raced against a timed sleep, and draining the loser cancels the blocked read, freeing the loop. A per-read SO_RCVTIMEO is unusable here (the Io backend treats a socket-timeout EAGAIN as a bug). serve binds 127.0.0.1 only, so a legitimate same-host request finishes in milliseconds even at the 512 MiB body ceiling; the 5 s bound never fires on a real client and only sheds a stalled one.
Four end-to-end scenarios abuse a live server over loopback -- dribbled head, half-sent body, mid-response disconnect, idle-connection burst -- and assert with bounded waits that a fresh request is still answered and a clone still converges (sync 3.7). (user: dmestas, size: 34882) [annotate] [blame] [check-ins using]
-
2026-07-20 04:40:31
— part of check-in
[56c17d0675]
on branch trunk
— Merge h11-serve-socket: a stalled client can no longer wedge the server
zit serve accepts one connection at a time and read its request head and body with no deadline, so a single peer that opened a connection and then dribbled or withheld its request pinned the accept loop and starved every other client -- a real availability gap the in-memory fuzzers could not see, since they never touch the socket. The connection now runs under a whole-connection deadline: the request work races a timed sleep, and a peer that misses the deadline is dropped so the loop moves on. The bind is loopback only and the deadline is generous, so a legitimate request -- even at the reply ceiling -- always finishes far inside it; only a stalled peer is shed. Four end-to-end abuses -- a slow-loris head, a half-sent body, a mid-response disconnect, an idle-connection burst -- each prove the server still answers a fresh request and a real clone still converges, and the fix is shown to be load-bearing by wedging with it removed. A per-read idle timeout and a configurable value are left for later. (user: dmestas, size: 34882) [annotate] [blame] [check-ins using]
-
2026-07-20 04:34:32
— part of check-in
[e87fb840d1]
on branch h11-serve-socket
— serve: bound each connection so a stalled client cannot wedge the server