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 Parser module provides zero-allocation parser combinators for HTTP/1.1 parsing. Position is threaded explicitly through all combinators to avoid allocation. All combinators raise Parse_error on failure.
Types
pstate
type pstate = #{ buf : Base_bigstring.t; len : int16# }
Parser state - unboxed record holding buffer and length. Position is threaded explicitly through functions as a separate parameter.
The buffer containing data to parse
Length of valid data in the buffer
Parse_error
exception Parse_error of Buf_read.status
Parse error exception with detailed status. Alias for Err.Parse_error.
Core Functions
make
val make : Base_bigstring.t -> len:int16# -> pstate
Create parser state from buffer and length.
Number of valid bytes in buffer
Example:
let pst = Parser.make buf ~len:(i16 1024) in
(* Now use combinators *)
remaining
val remaining : pstate -> pos:int16# -> int16#
Get number of remaining bytes at current position.
Number of bytes from pos to end of buffer
at_end
val at_end : pstate -> pos:int16# -> bool
Check if at end of buffer (no remaining bytes).
Basic Combinators
All combinators take ~pos parameter and return new position.
peek_char
val peek_char : pstate -> pos:int16# -> char#
Peek current character without advancing position. Raises Parse_error with Partial status if at end.
Example:
let c = Parser.peek_char pst ~pos in
if c =. '\r' then (* handle CR *)
peek_at
val peek_at : pstate -> pos:int16# -> int16# -> char#
Peek character at offset from current position. Raises Parse_error with Partial if out of bounds.
Offset from current position
char
val char : char# -> pstate -> pos:int16# -> int16#
Match single character, return new position. Raises Parse_error with Partial if at end or Malformed if character doesn’t match.
Example:
let pos = Parser.char ' ' pst ~pos in (* Match space *)
string
val string : string -> pstate -> pos:int16# -> int16#
Match literal string, return new position. Raises Parse_error with Partial or Malformed.
Example:
let pos = Parser.string "HTTP/" pst ~pos in
take_while
val take_while :
(char# -> bool) ->
pstate ->
pos:int16# ->
#(Span.t * int16#)
Take characters while predicate holds, return span and new position. Returns empty span if predicate fails immediately.
Predicate function to test each character
Span covering matched characters
New position after matched characters
Example:
let #(digits, pos) = Parser.take_while is_digit pst ~pos in
let value = Span.parse_int64 pst.#buf digits in
skip_while
val skip_while : (char# -> bool) -> pstate -> pos:int16# -> int16#
Skip characters while predicate holds, return new position.
take
val take : int16# -> pstate -> pos:int16# -> #(Span.t * int16#)
Take exactly n characters as span, return span and new position. Raises Parse_error with Partial if not enough bytes.
Number of characters to take
skip
val skip : int16# -> pstate -> pos:int16# -> int16#
Skip exactly n characters, return new position. Raises Parse_error with Partial if not enough bytes.
satisfy
val satisfy :
(char# -> bool) ->
pstate ->
pos:int16# ->
#(char# * int16#)
Match character satisfying predicate, return character and new position. Raises Parse_error if predicate fails or at end.
Example:
let #(digit, pos) = Parser.satisfy is_digit pst ~pos in
optional
val optional :
(pstate -> pos:int16# -> #('a * int16#)) ->
pstate ->
pos:int16# ->
#('a or_null * int16#)
Try parser, return Null and original position on failure. Returns #('a) (unboxed option) on success.
parser
pstate -> pos:int16# -> #('a * int16#)
Parser to try
Example:
let #(version_opt, pos) = Parser.optional Parser.http_version pst ~pos in
match version_opt with
| Null -> (* No version found *)
| #(version) -> (* Use version *)
HTTP-Specific Combinators
crlf
val crlf : pstate -> pos:int16# -> int16#
Match CRLF sequence (\r\n), return new position. Raises Parse_error if not found.
Example:
let pos = Parser.crlf pst ~pos in (* Consume line ending *)
val sp : pstate -> pos:int16# -> int16#
Match single space character (SP), return new position.
token
val token : pstate -> pos:int16# -> #(Span.t * int16#)
Take HTTP token characters (for method, header names), return span and new position. Must be non-empty. Raises Malformed if empty.
Token characters are: alphanumeric and !#$%&'*+-.^_|~`
Example:
let #(method_span, pos) = Parser.token pst ~pos in
ows
val ows : pstate -> pos:int16# -> int16#
Skip optional whitespace (OWS = SP / HTAB), return new position. OWS stands for “optional whitespace” in HTTP grammar.
http_version
val http_version : pstate -> pos:int16# -> #(Version.t * int16#)
Parse HTTP version (HTTP/1.0 or HTTP/1.1), return version and new position. Raises Parse_error with Invalid_version if malformed.
Example:
let #(version, pos) = Parser.http_version pst ~pos in
match version with
| Version.Http_1_0 -> (* HTTP/1.0 *)
| Version.Http_1_1 -> (* HTTP/1.1 *)
parse_method
val parse_method : pstate -> pos:int16# -> #(Method.t * int16#)
Parse HTTP method from token, return method enum and new position. Raises Parse_error with Invalid_method if unknown method.
Parsed method: Get, Head, Post, Put, Delete, Connect, Options, Trace, or Patch
Example:
let #(meth, pos) = Parser.parse_method pst ~pos in
parse_target
val parse_target : pstate -> pos:int16# -> #(Span.t * int16#)
Parse request target, return span and new position. Raises Parse_error with Invalid_target if empty.
request_line
val request_line :
pstate ->
pos:int16# ->
#(Method.t * Span.t * Version.t * int16#)
Parse complete request line: METHOD SP target SP version CRLF.
Position after request line
Example:
let pst = Parser.make buf ~len in
let #(meth, target, version, pos) = Parser.request_line pst ~pos:(i16 0) in
let target_str = Span.to_string pst.#buf target in
val parse_header :
pstate ->
pos:int16# ->
#(Header_name.t * Span.t * Span.t * int16#)
Parse a single header line: name: value CRLF.
Parsed header name enum (or Other for unknown headers)
Span of header name (meaningful when header_name is Other)
Span of header value (leading/trailing OWS trimmed)
Position after header line
Example:
let #(name, name_span, value_span, pos) = Parser.parse_header pst ~pos in
match name with
| Header_name.Content_length ->
let len = Span.parse_int64 pst.#buf value_span in
(* ... *)
| Header_name.Other ->
if Span.equal_caseless pst.#buf name_span "x-custom" then
let value = Span.to_string pst.#buf value_span in
(* Handle custom header *)
| _ -> ()
val is_headers_end : pstate -> pos:int16# -> bool
Check if at end of headers (CRLF at current position, indicating empty line).
Example:
if Parser.is_headers_end pst ~pos then
let pos = Parser.end_headers pst ~pos in
(* pos now points to body *)
val end_headers : pstate -> pos:int16# -> int16#
Skip the empty line at end of headers (consume final CRLF), return new position pointing to body.
Usage Pattern
The typical pattern for using parser combinators:
open Httpz
let parse_request buf ~len ~limits =
try
let pst = Parser.make buf ~len in
(* Parse request line *)
let #(meth, target, version, pos) =
Parser.request_line pst ~pos:(i16 0)
in
(* Parse headers in a loop *)
let rec parse_headers pos acc =
if Parser.is_headers_end pst ~pos then
let body_off = Parser.end_headers pst ~pos in
#(body_off, List.rev acc)
else
let #(name, name_span, value_span, pos) =
Parser.parse_header pst ~pos
in
let hdr = { Header.name; name_span; value = value_span } in
parse_headers pos (hdr :: acc)
in
let #(body_off, headers) = parse_headers pos [] in
(* Build request *)
Ok #(meth, target, version, body_off, headers)
with Parser.Parse_error status ->
Error status
Error Handling
All combinators raise Parse_error exception with specific status:
- Partial - Need more data (at end of buffer)
- Malformed - Invalid syntax
- Invalid_method - Unknown HTTP method
- Invalid_target - Empty or invalid target
- Invalid_version - Malformed HTTP version
- Invalid_header - Malformed header line
Handle errors using try/catch:
try
let #(result, pos) = Parser.some_combinator pst ~pos in
(* Success *)
with Parser.Parse_error status ->
match status with
| Partial -> need_more_data ()
| Malformed -> send_400 ()
| _ -> send_error ()
- Zero allocation - Position threading avoids closure allocation
- Unboxed types - Uses
char#, int16#, and unboxed tuples
- Explicit position - No hidden state, enables optimization
- Single-pass - Parse data in one forward pass
- Stack results - All results returned with
@ local annotation