HeadersHTTP header field handling per RFC 9110 Section 5
This module provides an efficient implementation of HTTP headers with case-insensitive field names per RFC 9110 Section 5.1. Headers can have multiple values for the same field name (e.g., Set-Cookie).
Header names use the Header_name.t type, providing compile-time safety for standard headers while allowing custom headers via `Other:
let headers = Headers.empty
|> Headers.set `Content_type "application/json"
|> Headers.set `Authorization "Bearer token"
|> Headers.set (`Other "X-Custom") "value"Header names and values are validated to prevent HTTP header injection attacks. CR and LF characters are rejected per RFC 9110 Section 5.5.
val src : Logs.Src.tLog source for header operations
Abstract header collection type. Headers are stored with case-insensitive keys and maintain insertion order.
val empty : tempty creates an empty header collection.
val of_list : (string * string) list -> tof_list pairs creates headers from an association list of string pairs. This is useful when parsing headers from the wire format. Later entries override earlier ones for the same key.
val to_list : t -> (string * string) listto_list headers converts headers to an association list. The order of headers is preserved.
Raised when a header name or value contains invalid characters (CR/LF) that could enable HTTP request smuggling attacks.
Raised when Basic auth credentials contain invalid characters. Per RFC 7617 Section 2:
These functions use Header_name.t for compile-time type safety.
val add : Header_name.t -> string -> t -> tadd name value headers adds a header value. Multiple values for the same header name are allowed (e.g., for Set-Cookie).
val set : Header_name.t -> string -> t -> tset name value headers sets a header value, replacing any existing values for that header name.
val get : Header_name.t -> t -> string optionget name headers returns the first value for a header name, or None if the header doesn't exist.
val get_all : Header_name.t -> t -> string listget_all name headers returns all values for a header name. Returns an empty list if the header doesn't exist.
val remove : Header_name.t -> t -> tremove name headers removes all values for a header name.
val mem : Header_name.t -> t -> boolmem name headers checks if a header name exists.
These functions accept string header names for wire format compatibility. Use these when parsing HTTP messages where header names arrive as strings.
add_string name value headers adds a header using a string name. Use this when parsing headers from the wire.
set_string name value headers sets a header using a string name.
val get_string : string -> t -> string optionget_string name headers gets a header using a string name.
val get_all_string : string -> t -> string listget_all_string name headers gets all values for a string header name.
remove_string name headers removes a header using a string name.
val mem_string : string -> t -> boolmem_string name headers checks if a header exists using a string name.
merge base override merges two header collections. Headers from override replace those in base.
Convenience functions for setting common HTTP headers.
accept_language lang headers sets the Accept-Language header. Per RFC 9110 Section 12.5.4.
Examples:
headers |> Headers.accept_language "en-US"
headers |> Headers.accept_language "en-US, en;q=0.9, de;q=0.8"
headers |> Headers.accept_language "*"authorization value headers sets the Authorization header with a raw value.
bearer token headers sets the Authorization header with a Bearer token. Example: bearer "abc123" sets "Authorization: Bearer abc123"
basic ~username ~password headers sets the Authorization header with HTTP Basic authentication (base64-encoded username:password).
cookie name value headers adds a cookie to the Cookie header. Multiple cookies can be added by calling this function multiple times.
range ~start ?end_ () headers sets the Range header for partial content. Example: range ~start:0L ~end_:999L () requests the first 1000 bytes.
Per Recommendation #7: Expect: 100-continue protocol for large uploads. RFC 9110 Section 10.1.1 (Expect)
expect value headers sets the Expect header. Example: expect "100-continue" for large request bodies.
expect_100_continue headers sets Expect: 100-continue. Use this for large uploads to allow the server to reject the request before the body is sent, saving bandwidth.
Per RFC 9110 Section 10.1.4: The TE header indicates what transfer codings the client is willing to accept in the response, and whether the client is willing to accept trailer fields in a chunked transfer coding.
te value headers sets the TE header to indicate accepted transfer codings. Example: te "trailers, deflate"
te_trailers headers sets TE: trailers to indicate the client accepts trailer fields in chunked transfer coding. Per RFC 9110 Section 10.1.4, a client MUST send this if it wishes to receive trailers.
Per Recommendation #17 and #19: Response caching and conditional requests. RFC 9111 (HTTP Caching), RFC 9110 Section 8.8.2-8.8.3 (Last-Modified, ETag)
if_none_match etag headers sets the If-None-Match header for conditional requests. The request succeeds only if the resource's ETag does NOT match. Used with GET/HEAD to implement efficient caching (returns 304 Not Modified if matches).
if_match etag headers sets the If-Match header for conditional requests. The request succeeds only if the resource's ETag matches. Used with PUT/DELETE for optimistic concurrency (prevents lost updates).
if_modified_since date headers sets the If-Modified-Since header. The date should be in HTTP-date format (RFC 9110 Section 5.6.7). Example: "Sun, 06 Nov 1994 08:49:37 GMT"
if_unmodified_since date headers sets the If-Unmodified-Since header. The request succeeds only if the resource has NOT been modified since the date.
val http_date_of_ptime : Ptime.t -> stringhttp_date_of_ptime time formats a Ptime.t as an HTTP-date. Format: "Sun, 06 Nov 1994 08:49:37 GMT" (RFC 9110 Section 5.6.7)
if_modified_since_ptime time headers sets If-Modified-Since using a Ptime.t value.
if_unmodified_since_ptime time headers sets If-Unmodified-Since using a Ptime.t value.
cache_control directives headers sets the Cache-Control header with a raw directive string. Example: cache_control "no-cache, max-age=3600"
val cache_control_directives :
?max_age:int ->
?max_stale:int option option ->
?min_fresh:int ->
?no_cache:bool ->
?no_store:bool ->
?no_transform:bool ->
?only_if_cached:bool ->
unit ->
t ->
tcache_control_directives ?max_age ?max_stale ?min_fresh ~no_cache ~no_store ~no_transform ~only_if_cached () headers builds a Cache-Control header from individual directives (RFC 9111 request directives).
max_age: Maximum age in seconds the client is willing to acceptmax_stale: Accept stale responses:None: omit max_stale entirelySome None: "max-stale" (accept any staleness)Some (Some n): "max-stale=N" (accept n seconds staleness)min_fresh: Response must be fresh for at least n more secondsno_cache: Force revalidation with origin serverno_store: Response must not be stored in cacheno_transform: Intermediaries must not transform the responseonly_if_cached: Only return cached response, 504 if not availableetag value headers sets the ETag header (for responses). Example: etag "\"abc123\""
last_modified date headers sets the Last-Modified header (for responses). The date should be in HTTP-date format.
last_modified_ptime time headers sets Last-Modified using a Ptime.t value.
Per RFC 9110 Section 7.6.1: The Connection header field lists hop-by-hop header fields that MUST be removed before forwarding the message.
val parse_connection_header : t -> Header_name.t listparse_connection_header headers parses the Connection header value into a list of header names.
val get_hop_by_hop_headers : t -> Header_name.t listget_hop_by_hop_headers headers returns all hop-by-hop headers. This is the union of Header_name.hop_by_hop_headers and any headers listed in the Connection header.
remove_hop_by_hop headers removes all hop-by-hop headers. This should be called before caching or forwarding a response. Per RFC 9110 Section 7.6.1.
val connection_close : t -> boolconnection_close headers returns true if Connection: close is present. This indicates the connection should be closed after the current message.
val connection_keep_alive : t -> boolconnection_keep_alive headers returns true if Connection: keep-alive is present. This is primarily used with HTTP/1.0 to request a persistent connection.
val get_multi : Header_name.t -> t -> string listget_multi is an alias for get_all.
val pp : Format.formatter -> t -> unitPretty printer for headers
val pp_brief : Format.formatter -> t -> unitBrief pretty printer showing count only
HTTP/2 uses pseudo-header fields to convey information that was previously carried in the request line (HTTP/1.1) or status line. Pseudo-headers start with a colon character (:).
Per RFC 9113 Section 8.3:
:method - HTTP method (required):scheme - URI scheme (required for non-CONNECT):authority - Authority portion of URI (host:port):path - Path and query (required for non-CONNECT):status - HTTP status code (required)is_pseudo_header name returns true if the header name starts with :. Per RFC 9113 Section 8.3, pseudo-headers are identified by a colon prefix.
val get_pseudo : string -> t -> string optionget_pseudo name headers retrieves a pseudo-header value. The name should NOT include the colon prefix. Example: get_pseudo "method" headers retrieves :method.
set_pseudo name value headers sets a pseudo-header value. The name should NOT include the colon prefix. Pseudo-headers are stored with the colon prefix internally. Example: set_pseudo "method" "GET" headers sets :method: GET.
remove_pseudo name headers removes a pseudo-header. The name should NOT include the colon prefix.
val mem_pseudo : string -> t -> boolmem_pseudo name headers returns true if the pseudo-header exists. The name should NOT include the colon prefix.
val has_pseudo_headers : t -> boolhas_pseudo_headers headers returns true if any pseudo-headers are present.
val pseudo_headers : t -> (string * string) listpseudo_headers headers returns all pseudo-headers as (name, value) pairs. Names are returned WITHOUT the colon prefix.
val regular_headers : t -> (string * string) listregular_headers headers returns all non-pseudo headers as (name, value) pairs.
val to_list_ordered : t -> (string * string) listto_list_ordered headers returns all headers with pseudo-headers first, followed by regular headers, as required by RFC 9113 Section 8.3.
h2_request ~meth ~scheme ?authority ~path headers sets the required HTTP/2 request pseudo-headers.
Per RFC 9113 Section 8.3.1:
:method is required:scheme is required (except for CONNECT):path is required (except for CONNECT, OPTIONS with empty path):authority is optional but recommendedExample:
Headers.empty
|> Headers.h2_request ~meth:"GET" ~scheme:"https"
~authority:"example.com" ~path:"/"
|> Headers.set `Accept "application/json"Per RFC 9113 Section 8.2.
type h2_validation_error = | Missing_pseudo of stringRequired pseudo-header is missing
*)| Invalid_pseudo of stringUnknown or misplaced pseudo-header
*)| Pseudo_after_regularPseudo-header appeared after regular header
*)| Invalid_header_name of stringHeader name contains invalid characters
*)| Uppercase_header_name of stringHeader name contains uppercase (forbidden in HTTP/2)
*)| Connection_header_forbiddenConnection-specific headers are forbidden in HTTP/2
*)| Te_header_invalidTE header with value other than "trailers"
*)val pp_h2_validation_error : Format.formatter -> h2_validation_error -> unitPretty printer for validation errors.
val validate_h2_request : t -> (unit, h2_validation_error) resultvalidate_h2_request headers validates headers for HTTP/2 request constraints.
Per RFC 9113 Section 8.3.1, validates:
:method, :scheme, :path)val validate_h2_response : t -> (unit, h2_validation_error) resultvalidate_h2_response headers validates headers for HTTP/2 response constraints.
Per RFC 9113 Section 8.3.2, validates:
:status pseudo-header is presentval validate_h2_user_headers : t -> (unit, h2_validation_error) resultvalidate_h2_user_headers headers validates user-provided headers for HTTP/2.
Unlike validate_h2_request, this validates headers before pseudo-headers are added by the HTTP/2 layer. Use this in the HTTP adapter.
Per RFC 9113 Section 8.2.2 and 8.3, validates:
Per RFC 9113 Section 8.2.2, certain headers are connection-specific and MUST NOT appear in HTTP/2.
val h2_forbidden_headers : Header_name.t listHeaders that MUST NOT appear in HTTP/2 messages: