Documentation Index
Fetch the complete documentation index at: https://mintlify.com/avsm/httpz/llms.txt
Use this file to discover all available pages before exploring further.
The Chunk module provides zero-allocation parsing for HTTP/1.1 chunked transfer encoding per RFC 7230 Section 4.1. It supports parsing chunk data and optional trailer headers.
Types
Chunk Record
Unboxed chunk record containing parsed chunk information.Offset of chunk data in buffer
Length of chunk data in bytes
Offset where next chunk starts (used for sequential parsing)
Parse Status
Result status from chunk parsing operations.Chunk parsed successfully - use next_off to parse the next chunk
Need more data to complete parsing
Final chunk (zero-length) encountered - parsing complete
Invalid chunk format detected
Chunk size exceeds configured limit (only with parse_with_limit)
Trailer Status
Result status from trailer header parsing.Trailers parsed successfully
Need more data to complete trailer parsing
Invalid trailer format detected
Constants
Maximum number of hex digits allowed for chunk size (16 = 64-bit max).
Default maximum chunk size: 16MB (16,777,216 bytes).
Parsing Functions
parse
val parse : Base_bigstring.t -> off:int16# -> len:int16# -> #(status * t)
Parse a single chunk starting at the specified offset without size limit checking.
Buffer containing chunk data
Offset in buffer where chunk starts
Total number of bytes available in buffer
Returns: Unboxed tuple #(status * t) containing parse status and chunk information.
Usage:
- For
Complete status, use next_off field to parse the next chunk
- For
Done status, parsing is complete (zero-length chunk found)
- For
Partial status, buffer more data and retry
- For
Malformed status, the chunk format is invalid
Example:
let rec parse_chunks buf ~off ~len acc =
let #(status, chunk) = Chunk.parse buf ~off ~len in
match status with
| Chunk.Complete ->
(* Extract chunk data *)
let data = Base_bigstring.To_string.sub buf
~pos:(to_int chunk.#data_off)
~len:(to_int chunk.#data_len) in
parse_chunks buf ~off:chunk.#next_off ~len (data :: acc)
| Chunk.Done ->
(* Final chunk - check for trailers *)
(List.rev acc, chunk.#next_off)
| Chunk.Partial ->
(* Need more data *)
(List.rev acc, off)
| Chunk.Malformed ->
failwith "Invalid chunk encoding"
| Chunk.Chunk_too_large ->
(* Never returned by parse (no limit) *)
assert false
parse_with_limit
val parse_with_limit : Base_bigstring.t -> off:int16# -> len:int16# -> max_chunk_size:int -> #(status * t)
Parse a single chunk with configurable size limit. Returns Chunk_too_large if the chunk size exceeds the limit.
Buffer containing chunk data
Offset in buffer where chunk starts
Total number of bytes available in buffer
Maximum allowed chunk size in bytes (use default_max_chunk_size or custom limit)
Returns: Unboxed tuple #(status * t) containing parse status and chunk information.
Example:
let #(status, chunk) = Chunk.parse_with_limit buf ~off ~len
~max_chunk_size:Chunk.default_max_chunk_size in
match status with
| Chunk.Chunk_too_large ->
(* Reject request with 413 Payload Too Large *)
send_error 413
| Chunk.Complete ->
(* Process chunk *)
process_chunk chunk
| _ -> (* handle other cases *)
Per RFC 7230 Section 4.1.2, trailer headers may follow the final chunk in chunked transfer encoding.
parse_trailers
val parse_trailers
: Base_bigstring.t
-> off:int16#
-> len:int16#
-> max_header_count:int16#
-> #(trailer_status * int16# * Header.t list) @ local
Parse trailer headers after the final chunk. Call this after parse returns Done status.
Buffer containing trailer data
Offset where trailers start (use next_off from final chunk)
Total number of bytes available in buffer
Maximum number of trailer headers to parse
Returns: Local unboxed tuple containing:
trailer_status: Parse result status
int16#: New offset after trailers (for further processing)
Header.t list: List of parsed trailer headers (forbidden headers are filtered out)
Forbidden Trailers:
The following headers are forbidden in trailers per RFC 7230 and are silently ignored:
- Message framing:
Transfer-Encoding, Content-Length
- Routing:
Host
- Control:
Cache-Control, Expect, Range
- Content negotiation:
Content-Encoding, Content-Type, Content-Range
- Authentication:
WWW-Authenticate, Authorization
Example:
(* After receiving final chunk *)
let #(chunk_status, chunk) = Chunk.parse buf ~off ~len in
match chunk_status with
| Chunk.Done ->
(* Parse trailers starting at next_off *)
let #(trailer_status, new_off, trailers) =
Chunk.parse_trailers buf
~off:chunk.#next_off
~len
~max_header_count:(i16 32) in
(match trailer_status with
| Chunk.Trailer_complete ->
(* Process trailers *)
List.iter (fun hdr ->
Printf.printf "Trailer: %s\n" (Header_name.to_string hdr.Header.name)
) trailers
| Chunk.Trailer_partial ->
(* Need more data *)
buffer_more_data ()
| Chunk.Trailer_malformed ->
failwith "Invalid trailer headers")
| _ -> (* handle other chunk statuses *)
is_forbidden_trailer
val is_forbidden_trailer : Header_name.t -> bool
Check if a header name is forbidden in trailers per RFC 7230 Section 4.1.2.
Returns: true if the header is forbidden in trailers, false otherwise.
Example:
if Chunk.is_forbidden_trailer Header_name.Content_length then
(* Skip this header in trailers *)
()
else
(* Safe to include in trailers *)
add_trailer header
Utility Functions
status_to_string
val status_to_string : status -> string
Convert status to string representation for debugging.
trailer_status_to_string
val trailer_status_to_string : trailer_status -> string
Convert trailer status to string representation for debugging.
pp_status
val pp_status : Stdlib.Format.formatter -> status -> unit
Pretty-print chunk parse status.
pp_trailer_status
val pp_trailer_status : Stdlib.Format.formatter -> trailer_status -> unit
Pretty-print trailer parse status.
val pp : Stdlib.Format.formatter -> t -> unit
Pretty-print chunk record fields.
Complete Example
(* Parse chunked request body with trailers *)
let parse_chunked_body buf =
let rec parse_loop ~off ~len chunks =
let #(status, chunk) = Chunk.parse_with_limit buf ~off ~len
~max_chunk_size:Chunk.default_max_chunk_size in
match status with
| Chunk.Complete ->
(* Extract chunk data *)
let data = Base_bigstring.To_string.sub buf
~pos:(to_int chunk.#data_off)
~len:(to_int chunk.#data_len) in
parse_loop ~off:chunk.#next_off ~len (data :: chunks)
| Chunk.Done ->
(* Final chunk - parse trailers *)
let #(tr_status, _new_off, trailers) =
Chunk.parse_trailers buf
~off:chunk.#next_off
~len
~max_header_count:(i16 32) in
(match tr_status with
| Chunk.Trailer_complete ->
{ body = String.concat "" (List.rev chunks)
; trailers = trailers }
| Chunk.Trailer_partial ->
failwith "Incomplete trailers"
| Chunk.Trailer_malformed ->
failwith "Invalid trailer headers")
| Chunk.Partial ->
failwith "Incomplete chunk"
| Chunk.Malformed ->
failwith "Invalid chunk encoding"
| Chunk.Chunk_too_large ->
failwith "Chunk exceeds size limit"
in
parse_loop ~off:(i16 0) ~len:(i16 (Base_bigstring.length buf)) []