Request hardening

Limits, smuggling defences, slow clients and path normalisation.

Updated 2 min read

The request line, header block, header count and body size are all bounded, and exceeding one is answered rather than allocated for.

LimitDefaultResponse
Request line8 KB414
Header block32 KB431
Header count100431
Bodyserver.max_body_bytes, 1 MB413
Connection buffer256 KB

Request smuggling

A request carrying both Content-Length and Transfer-Encoding is rejected. A duplicate Content-Length, Host or Transfer-Encoding is rejected, because a front-end proxy may read one copy and the origin the other — which is the whole trick. Obsolete line folding (obs-fold) is rejected. Any Transfer-Encoding other than chunked is 501. Chunked trailers are consumed and discarded, never merged into the request headers.

Framing

A POST, PUT or PATCH with no framing header is 411, before routing. HTTP/1.1 without Host is 400.

Slow clients

header_timeout_ms bounds a single recv, which is not enough on its own because every byte received restarts it. request_timeout_ms is an absolute budget for the whole request, armed when the first byte arrives; a client dripping one byte per interval is disconnected at that deadline.

Header syntax

Field names are restricted to alphanumerics, -, _ and .. Anything else is 400.

Paths

The target is percent-decoded, then normalised: . and .. are resolved against a virtual root and any residual escape yields 400.

Normalisation runs on the decoded path, so %2e%2e%2f cannot slip past a check for ../. Control bytes, spaces and NUL in a decoded segment are rejected — a NUL would truncate the path at any later C boundary.

The static file layer re-checks independently before touching disk: any .., backslash, NUL, or segment beginning with . is refused, and a directory path is never served. Two independent guards, either sufficient alone.

Cross-origin requests

A POST, PUT, PATCH or DELETE carrying an Origin that matches neither the request Host nor security.allowed_origins is answered 403 before any handler runs.

A request with no Origin is allowed through: this defends against browser-driven cross-site requests, and is not a substitute for authentication.