Skip to main content

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

t
unboxed record
Unboxed chunk record containing parsed chunk information.
data_off
int16#
Offset of chunk data in buffer
data_len
int16#
Length of chunk data in bytes
next_off
int16#
Offset where next chunk starts (used for sequential parsing)

Parse Status

status
variant
Result status from chunk parsing operations.
Complete
Chunk parsed successfully - use next_off to parse the next chunk
Partial
Need more data to complete parsing
Done
Final chunk (zero-length) encountered - parsing complete
Malformed
Invalid chunk format detected
Chunk_too_large
Chunk size exceeds configured limit (only with parse_with_limit)

Trailer Status

trailer_status
variant
Result status from trailer header parsing.
Trailer_complete
Trailers parsed successfully
Trailer_partial
Need more data to complete trailer parsing
Trailer_malformed
Invalid trailer format detected

Constants

max_hex_digits
int16#
default:"16"
Maximum number of hex digits allowed for chunk size (16 = 64-bit max).
default_max_chunk_size
int
default:"16777216"
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.
buf
Base_bigstring.t
required
Buffer containing chunk data
off
int16#
required
Offset in buffer where chunk starts
len
int16#
required
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.
buf
Base_bigstring.t
required
Buffer containing chunk data
off
int16#
required
Offset in buffer where chunk starts
len
int16#
required
Total number of bytes available in buffer
max_chunk_size
int
required
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 *)

Trailer Headers

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.
buf
Base_bigstring.t
required
Buffer containing trailer data
off
int16#
required
Offset where trailers start (use next_off from final chunk)
len
int16#
required
Total number of bytes available in buffer
max_header_count
int16#
required
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.
name
Header_name.t
required
Header name to check
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.

pp

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)) []

Build docs developers (and LLMs) love