๐HTTP parser
proto/http.nim is an incremental, zero-copy HTTP/1.1 request parser. It materializes strings lazily from byte offsets โ nothing is copied until you ask for it โ and it drives streaming bodies, chunked transfer encoding and multipart.
Most users never touch the parser directly: the HTTP server feeds it for you and hands you an HttpRequest (see requests). This page is for understanding it, or for using it standalone.
๐Creating a parser
var p = newHttpParser(initialBufSize = 4096)Public parser fields: buf, bufLen, maxBodySize, maxStreamBodySize, headerEnd, contentLength, connectionClose, expectContinue, onBodyData (streaming callback), methodCache, phase.
๐Feeding bytes
let phase = p.feed(data) # openArray[byte] or stringThe parser is incremental: feed as many or as few bytes as arrive. It tracks a ParsePhase: PhaseRequestLine, PhaseHeaders, PhaseBody, PhaseComplete, PhaseError.
p.isComplete() # reached PhaseComplete
p.isError() # reached PhaseError
p.error() # the HttpCode that caused the error
p.phase() # current phase
p.setError(Http400) # force an error state (rejects the request)reset clears the parser; resetForNext keeps reusable state for the next request on a keep-alive connection.
๐Zero-copy request fields
Before the request is complete you can peek:
p.peekMethod() # HttpMethod
p.peekPath() # lent string
p.peekContentType() # lent stringOnce complete, materialize a request object:
let req = p.getRequest() # HttpRequest โ see requests.mdgetRemainingData(p) returns bytes beyond the current request (pipelining).
๐Streaming bodies
p.onBodyData = proc(data: openArray[byte]; done: bool) {.closure.} is invoked as body bytes are parsed; done signals the final chunk. Set it beforefeeding body bytes.
p.onBodyData = proc(data: openArray[byte]; done: bool) =
write(f, data) # stream to disk without buffering the whole body๐Limits
Constants enforced by the parser/server:
| Constant | Value |
|---|---|
MaxHeaderSize | 8192 |
MaxRequestLine | 8192 |
MaxHeaders | 100 |
DefaultBodyBuf | 65536 |
MaxStreamBodySize | 512 MB |
See security for how these protect against DoS.
๐Chunked trailers
Chunked bodies may carry trailers โ Name: value lines after the zero-size chunk (RFC 9112 ยง7.1.3). The parser accepts them incrementally, enforces the same strictness as headers (CRLF only, colon required, no obs-fold, MaxHeaderSize per section, MaxHeaders per count; violations are 400/431), and exposes them once complete:
if parser.isComplete():
if parser.hasTrailers():
for (name, value) in parser.getTrailers():
echo name, ": ", value
let crc = req.getTrailer("X-Crc32") # case-insensitive lookup, "" if absent๐Body streaming on requests
For fully parsed requests, the BodyStream API in requests is the higher-level way to consume bodies in chunks.
๐API reference
Full signatures: HTTP parser API. Related: requests, server.