Repository navigation
Commit c601aa7
committed
fix(http): bound the request-head read — one packet no longer DoSes the server
Smell-audited: depth 1: the fix is scoped narrower than the debt row's
severity language invites, and the narrowing is the honest part. SO_RCVTIMEO
turns an UNBOUNDED wedge into a bounded one; it does not make a serial server
concurrent. N held connections still cost N x timeout of throughput. Closing
that needs per-connection threading, and a Ring handler runs Clojure — so its
thread must be a registered GC worker under the ADR-0175 safepoint discipline.
That is a concurrency design change, not a line in this function, and pulling
it in here would be exactly the scope-creep the smell sensor watches for. It
stays with the D-257 threading follow-on that server.zig's module doc already
names, and D-339 is marked PARTIAL rather than discharged.
D-339 (SE-3), raised 2026-06-09 and untouched for two months: `run-server`'s
accept loop is serial and blocking with no read deadline anywhere, so a client
that opened a connection and never finished sending the request head held the
whole server — which binds 0.0.0.0 and is internet-facing in a container —
for as long as it cared to. The 8 MB body cap guards volume, not time.
The test earned its keep by being wrong first. Written as "hold a half-open
connection, then assert a normal request still succeeds", it PASSED against
the unfixed server: the stalled client's subshell exits after 12s, and the
server served the next request the moment the attacker gave up. A body-only
assertion cannot tell "the server recovered" from "the attacker left", so the
elapsed bound IS the assertion: 12s before, 1s after, fail over 5s.
- `armReceiveDeadline` sets SO_RCVTIMEO on each accepted connection before the
first read. Best-effort — a platform that rejects the option leaves the
socket blocking rather than failing the request; nothing else depends on it.
- `:header-timeout-ms` in the opts map, default 10000 (the order of nginx's
client_header_timeout and Go's documented ReadHeaderTimeout examples),
0 disables. Non-integer is rejected at the boundary with a named message.
- The e2e fixture sets 1500 so the case runs fast; legitimate requests
complete in milliseconds, so the other 12 cases are unaffected.
Smoke green (phase16_http_server, 283s).1 parent 92d7926 commit c601aa7
4 files changed
Lines changed: 104 additions & 9 deletions
File tree
- .dev
- src/runtime/cljw/http
- test/e2e
- fixtures
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
978 | 978 | | |
979 | 979 | | |
980 | 980 | | |
981 | | - | |
| 981 | + | |
982 | 982 | | |
983 | 983 | | |
984 | 984 | | |
| |||
989 | 989 | | |
990 | 990 | | |
991 | 991 | | |
992 | | - | |
| 992 | + | |
993 | 993 | | |
994 | 994 | | |
995 | 995 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
61 | 61 | | |
62 | 62 | | |
63 | 63 | | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
64 | 101 | | |
65 | | - | |
66 | | - | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
67 | 112 | | |
68 | 113 | | |
69 | 114 | | |
| |||
82 | 127 | | |
83 | 128 | | |
84 | 129 | | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
85 | 134 | | |
86 | 135 | | |
87 | 136 | | |
| |||
226 | 275 | | |
227 | 276 | | |
228 | 277 | | |
229 | | - | |
230 | | - | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
231 | 282 | | |
232 | 283 | | |
233 | 284 | | |
| |||
242 | 293 | | |
243 | 294 | | |
244 | 295 | | |
245 | | - | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
246 | 306 | | |
247 | 307 | | |
248 | 308 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
26 | | - | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
81 | 81 | | |
82 | 82 | | |
83 | 83 | | |
84 | | - | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
0 commit comments