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 Err module provides zero-cost abstractions for raising parse errors with various status codes. All functions are inlined for performance, making error handling both ergonomic and efficient.

Status Type

status
variant
Parse status enumeration (re-exported from Buf_read.status).
Complete
variant
Parsing completed successfully
Partial
variant
Need more input data to continue parsing
Invalid_method
variant
HTTP method is invalid or unsupported
Invalid_target
variant
Request target (URI) is malformed
Invalid_version
variant
HTTP version is invalid or unsupported
Invalid_header
variant
Header name or value is malformed
Headers_too_large
variant
Headers exceed maximum allowed size
Malformed
variant
General protocol format violation
Content_length_overflow
variant
Content-Length value exceeds maximum allowed
Ambiguous_framing
variant
Both Content-Length and Transfer-Encoding present
Bare_cr_detected
variant
Bare CR found (security violation)
Missing_host_header
variant
Required Host header is missing (HTTP/1.1)
Unsupported_transfer_encoding
variant
Transfer-Encoding other than chunked is not supported

Exception

Parse_error

exception Parse_error of status
Parse error exception with detailed status information. Example:
try
  parse_request buffer
with
| Err.Parse_error status ->
  match status with
  | Invalid_method -> respond_with 400 "Bad Request"
  | Headers_too_large -> respond_with 431 "Request Header Fields Too Large"
  | Content_length_overflow -> respond_with 413 "Payload Too Large"
  | _ -> respond_with 400 "Bad Request"

Direct Fail Combinators

These functions immediately raise a Parse_error with the specified status.

fail

val fail : status -> 'a
Raise Parse_error with the given status.
status
status
required
The error status to raise
Example:
if not (is_valid_method method_str) then
  Err.fail Invalid_method

partial

val partial : unit -> 'a
Raise Parse_error Partial. Use when more input is needed. Example:
if pos + 4 > buffer_length then
  Err.partial ()

malformed

val malformed : unit -> 'a
Raise Parse_error Malformed. Use for format violations. Example:
if byte <> '\r' then
  Err.malformed ()

Conditional Raises (when condition is TRUE)

These functions raise errors when the condition is true.

when_

val when_ : bool -> status -> unit
Raise Parse_error status if condition is true.
cond
bool
required
Condition to check
status
status
required
The error status to raise if condition is true
Example:
Err.when_ (header_count > max_headers) Headers_too_large

partial_when

val partial_when : bool -> unit
Raise Parse_error Partial if condition is true.
cond
bool
required
Condition to check
Example:
Err.partial_when (pos + needed > available)

malformed_when

val malformed_when : bool -> unit
Raise Parse_error Malformed if condition is true.
cond
bool
required
Condition to check
Example:
Err.malformed_when (byte = '\r' && next_byte <> '\n')

Guard Combinators (raise when condition is FALSE)

These functions raise errors when the condition is false (i.e., they “guard” that the condition must be true).

guard

val guard : bool -> status -> unit
Raise Parse_error status if condition is false.
cond
bool
required
Condition that must be true
status
status
required
The error status to raise if condition is false
Example:
Err.guard (version = "HTTP/1.1" || version = "HTTP/1.0") Invalid_version

partial_unless

val partial_unless : bool -> unit
Raise Parse_error Partial if condition is false. Use for buffer boundary checks where you require more data.
cond
bool
required
Condition that must be true (enough data available)
Example:
Err.partial_unless (pos + 2 <= buffer_length)

malformed_unless

val malformed_unless : bool -> unit
Raise Parse_error Malformed if condition is false. Use for validation checks where you require a condition to hold.
cond
bool
required
Condition that must be true (valid format)
Example:
Err.malformed_unless (byte >= '0' && byte <= '9')

Recovery Combinator

optional

val optional : save:(unit -> 'pos) -> restore:('pos -> unit) -> (unit -> 'a) -> 'a or_null
Try to run a parser function. On success, returns the result wrapped with Or_null.some. On Parse_error, restores state using restore (save ()) and returns Or_null.none.
save
unit -> 'pos
required
Function to save current parser position/state
restore
'pos -> unit
required
Function to restore parser position/state
f
unit -> 'a
required
Parser function to attempt
Example:
let optional_content_length =
  Err.optional 
    ~save:(fun () -> !pos)
    ~restore:(fun p -> pos := p)
    (fun () -> parse_content_length ())
in
match Or_null.to_option optional_content_length with
| Some length -> (* Content-Length found *)
  ...
| None -> (* No Content-Length, continue *)
  ...

Usage Patterns

Input Validation

let parse_request_line buffer pos =
  (* Ensure we have enough data *)
  Err.partial_unless (pos + 14 <= buffer_length);
  
  (* Parse method *)
  let method_end = find_space buffer pos in
  Err.malformed_unless (method_end > pos);
  
  (* Validate HTTP version *)
  let version = substring buffer version_start 8 in
  Err.guard (version = "HTTP/1.1" || version = "HTTP/1.0") Invalid_version;
  
  ...

Security Checks

let parse_content_length buffer span =
  let max_allowed = Int64.of_int 10_000_000 in
  let #(length, overflow) = 
    Span.parse_int64_limited buffer span ~max_value:max_allowed in
  
  (* Reject if overflow or too large *)
  Err.when_ overflow Content_length_overflow;
  
  (* Reject if invalid *)
  Err.malformed_when (Int64.compare length (Int64.of_int (-1)) = 0);
  
  length

Optional Header Parsing

let find_optional_header buffer headers name =
  Err.optional
    ~save:(fun () -> 0) (* No state to save *)
    ~restore:(fun _ -> ()) (* No state to restore *)
    (fun () ->
      match find_header headers name with
      | Some h -> h
      | None -> Err.fail Partial (* Trigger recovery *)
    )

Build docs developers (and LLMs) love