GET /health HTTP/1.1\r\n
Host: localhost\r\n
\r\n
The server accumulates reads until the first CRLF-CRLF. Exactly 8192 bytes,
including that delimiter, are allowed; larger headers return 400. An empty
disconnect has no response. Nonempty EOF before the delimiter returns 400.
The pure parser reports Empty, Incomplete, Malformed, TooLarge, or Ok.
The request line requires one SP between method, target and literal HTTP/1.1.
Methods must be nonempty HTTP token characters. A syntactically valid method
other than GET/HEAD returns 405 with Allow: GET, HEAD; invalid syntax is 400.
Targets must start with /, contain printable ASCII without spaces, and have
no fragment (#). Targets are compared literally: no percent decoding or
normalization is performed. This is a restricted origin-form subset.
Header names are case-insensitive tokens with no whitespace before the colon. Values reject control bytes other than HTAB. Folded headers are unsupported. Exactly one nonempty Host is required; spaces, tabs, commas and slashes are rejected in its value. This is basic validation, not a complete authority parser. Unknown well-formed headers are ignored. Content-Length is optional, must occur at most once and contain only zero digits. Any Transfer-Encoding is rejected. Request bodies are unsupported. Bytes after the first header block are discarded; there is no second request on the connection and no keep-alive or pipelining.
| Path | GET representation | Validation |
|---|---|---|
/, /health |
ok\n |
Query ignored |
/compute?n=N |
Decimal checksum plus newline | Exactly n=, unsigned decimal 0..1000000 |
/sleep?ms=N |
slept N ms\n after delay |
Exactly ms=, unsigned decimal 0..1000 |
/metrics |
Named counters, one per line | Query ignored |
Compute starts at zero and performs value = (value * 33 + i) % 1000000007
for i in [0, n), giving 35 for n=3. The bound limits CPU work and the
64-bit intermediate avoids overflow. Sleep simulates occupied workers, can
overshoot due to scheduling, and checks cancellation. Missing, signed, duplicate,
extra, overflowing, or nonnumeric compute/sleep parameters return 400.
HEAD follows the same routing/validation and computes the representation length but sends no body, including error routes. It also executes compute/sleep work. Metrics returns counters, gauges, lifetime throughput and a latency histogram; see observability.md for exact names and definitions. The metrics request itself is included in active/request counts, but not its own completion/latency statistics. GET and HEAD snapshots can differ because uptime and concurrent activity change; Content-Length always matches that response's own representation.
All responses use HTTP/1.1, Content-Type: text/plain, byte-based Content-Length,
and Connection: close. GET sends the body; HEAD omits it while retaining its
would-be length. Status codes: 200, 400 (syntax/size/query), 404 (unknown path),
405 (unsupported method), and 500 (unexpected application failure).
The default response is the controlled 500 fallback; there is no public crash
or error-injection endpoint. Allocation exhaustion cannot guarantee a response.
Full queue/baseline-cap rejection closes TCP without an HTTP response. Transport failure, read/write deadline expiry and shutdown may also close without completing a response. Rejecting an oversized request can finish with TCP reset because bytes remain unread; clients should retain any HTTP response bytes received before the reset.
TLS, request bodies, keep-alive, static files, full URI/authority validation, chunking, HTTP/2, and HTTP/3 are not implemented. Read and write deadlines are configurable; no whole-connection deadline covering queue wait is implemented.