# std.http.Server: requests that take the process down two behaviours of a server built on `std.http.Server` and `IpAddress.listen` that no test of the handlers will show. both hold on 0.16.0 and 0.17.0. ## a body method with no framing panics on respond `curl -X POST http://host/any-path` sends `POST` with neither `Content-Length` nor `Transfer-Encoding`. if the handler answers without reading the body, the process panics with `reached unreachable code` inside `request.respond`. the mechanism: before a keep-alive response, the server discards whatever body the client sent so the connection can carry the next request. for a method that may have a body it asserts the request said how long that body is: ```zig // std/http/Server.zig, discardBody if (request.head.method.requestHasBody()) { assert(request.head.transfer_encoding != .none or request.head.content_length != null); ``` an `assert` is `unreachable` when false, so a ReleaseSafe build panics and a ReleaseFast build has undefined behaviour. the request is legal on the wire and needs no authentication, so any route on a public listener is enough, including a 404. a server whose handlers never read a body cannot rely on them to notice. reject the request right after `receiveHead`, before routing: ```zig fn rejectUnframedBody(request: *http.Server.Request) bool { const head = &request.head; if (!head.method.requestHasBody()) return false; if (head.transfer_encoding != .none or head.content_length != null) return false; request.respond("", .{ .status = .length_required, .keep_alive = false }) catch {}; return true; } ``` `.keep_alive = false` is what makes the 411 safe: the discard step is skipped when the connection will not be reused. the caller then closes the connection. the guard is testable without a socket, because `http.Server` takes any `Io.Reader` and `Io.Writer`: ```zig var in: std.Io.Reader = .fixed("POST /search HTTP/1.1\r\nHost: x\r\n\r\n"); var out_buf: [512]u8 = undefined; var out: std.Io.Writer = .fixed(&out_buf); var server = http.Server.init(&in, &out); var request = try server.receiveHead(); try std.testing.expect(rejectUnframedBody(&request)); try std.testing.expect(std.mem.startsWith(u8, out.buffered(), "HTTP/1.1 411 ")); ``` a proxy in front of the server may add `Content-Length: 0` to such a request and hide the problem; that was not measured here, so do not count on it. ## `reuse_address` lets a second process share the port `listen(io, .{ .reuse_address = true })` sets `SO_REUSEPORT` as well as `SO_REUSEADDR` wherever the platform defines it. a second copy of the server started on the same port does not fail with `AddressInUse`: both bind, and the kernel spreads incoming connections across them. the place this bites is testing. a server left running from an earlier attempt keeps answering a share of the requests, so results flip between old and new behaviour from one request to the next. before trusting a local comparison, confirm one listener per port (`ss -ltnp`, `lsof -i :PORT`). ## sources - `lib/std/http/Server.zig` (`discardBody`) and `lib/std/Io/Threaded.zig` (listen socket options) in 0.16.0 and 0.17.0 - pub-search, typeahead — panic reproduced on 0.16.0 and 0.17.0 builds