Http_readHTTP response parsing using Eio.Buf_read combinators
This module provides efficient HTTP/1.1 response parsing using Eio's buffered read API with parser combinators for clean, composable parsing.
Example:
let buf_read = Http_read.of_flow ~max_size:max_int flow in
let (status, headers, body) = Http_read.response ~limits buf_readThis module uses Response_limits.t for size limit configuration.
type limits = Response_limits.tAlias for Response_limits.t. See Response_limits for documentation.
Per Recommendation #26: Expose HTTP version used for the response.
HTTP protocol version. Useful for debugging protocol negotiation and monitoring HTTP/2 adoption (when supported).
val http_version_to_string : http_version -> stringhttp_version_to_string v returns "HTTP/1.0" or "HTTP/1.1".
val http_version : Eio.Buf_read.t -> stringhttp_version r parses HTTP version string (e.g., "HTTP/1.1").
val status_code : Eio.Buf_read.t -> intstatus_code r parses a 3-digit HTTP status code.
val status_line : Eio.Buf_read.t -> http_version * intstatus_line r parses a complete HTTP status line and returns the HTTP version and status code as a tuple. Validates that the HTTP version is 1.0 or 1.1.
val header_line : Eio.Buf_read.t -> string * stringheader_line r parses a single header line. Returns (name, value) where name is lowercase. Returns ("", "") for the empty line that terminates headers.
val headers : limits:limits -> Eio.Buf_read.t -> Headers.theaders ~limits r parses all headers until the terminating blank line. Enforces header count and size limits.
val fixed_body : limits:limits -> length:int64 -> Eio.Buf_read.t -> stringfixed_body ~limits ~length r reads exactly length bytes as the body.
val chunked_body : limits:limits -> Eio.Buf_read.t -> stringchunked_body ~limits r reads a chunked transfer-encoded body. Handles chunk sizes, extensions, and trailers.
parse_transfer_encoding header parses Transfer-Encoding header value into a list of codings (all lowercase, in order).
validate_transfer_encoding codings validates Transfer-Encoding per RFC 9112 Section 6.1. Returns `Chunked if chunked encoding should be used, `None if no body, or `Unsupported codings for unsupported encodings without chunked.
val validate_no_transfer_encoding :
method_:Method.t option ->
status:int ->
string option ->
boolvalidate_no_transfer_encoding ~method_ ~status te validates that Transfer-Encoding is not present in responses that MUST NOT have it. Per RFC 9112 Section 6.1, these include responses to HEAD, 1xx, 204, and 304. If present, this logs a warning about the RFC violation.
Headers that MUST NOT appear in trailers per RFC 9110 Section 6.5.1. Includes: transfer-encoding, content-length, host, content-encoding, content-type, content-range, trailer.
val parse_trailers : limits:limits -> Eio.Buf_read.t -> Headers.tparse_trailers ~limits r parses trailer headers after final chunk. Forbidden headers are logged and ignored.
val fixed_body_stream :
limits:limits ->
length:int64 ->
Eio.Buf_read.t ->
Eio.Flow.source_ty Eio.Resource.tfixed_body_stream ~limits ~length r creates a flow source that reads length bytes from r. Useful for large bodies to avoid loading everything into memory at once.
val chunked_body_stream :
limits:limits ->
Eio.Buf_read.t ->
Eio.Flow.source_ty Eio.Resource.tchunked_body_stream ~limits r creates a flow source that reads chunked transfer-encoded data from r. Decodes chunks on-the-fly.
val response :
limits:limits ->
?method_:Method.t ->
Eio.Buf_read.t ->
http_version * int * Headers.t * stringresponse ~limits ?method_ r parses a complete HTTP response including:
Returns (http_version, status, headers, body).
This reads the entire body into memory. For large responses, use response_stream instead.
type stream_response = {http_version : http_version;HTTP protocol version
*)status : int;headers : Headers.t;body : [ `String of string
| `Stream of Eio.Flow.source_ty Eio.Resource.t
| `None ];}A parsed response with optional streaming body. Per Recommendation #26: Includes HTTP version for debugging/monitoring.
val response_stream :
limits:limits ->
?method_:Method.t ->
Eio.Buf_read.t ->
stream_responseresponse_stream ~limits ?method_ r parses status line and headers, then returns a streaming body source instead of reading the body into memory. Use this for large responses.
val of_flow :
?initial_size:int ->
max_size:int ->
_ Eio.Flow.source ->
Eio.Buf_read.tof_flow ~max_size flow creates a buffered reader from flow. This is a thin wrapper around Eio.Buf_read.of_flow.