Module Header_parsing

HTTP Header Value Parsing

This module provides parsing and generation functions for complex HTTP header values that go beyond simple strings.

Supported Headers

Content-Range (RFC 9110 Section 14.4)

The Content-Range header indicates which part of a representation is enclosed when a 206 (Partial Content) response is returned.

type content_range = {
  1. unit : string;
    (*

    The range unit, typically "bytes"

    *)
  2. range : (int64 * int64) option;
    (*

    The byte range (start, end) inclusive, or None for unsatisfied range

    *)
  3. complete_length : int64 option;
    (*

    The complete representation length, or None if unknown

    *)
}
val content_range_to_string : content_range -> string

content_range_to_string cr formats a content range as a header value.

Example: "bytes 0-499/1234"

val parse_content_range : string -> content_range option

parse_content_range s parses a Content-Range header value.

Returns None if the value cannot be parsed.

Examples:

  • "bytes 0-499/1234" -> Some \{unit="bytes"; range=Some(0,499); complete_length=Some 1234\}
  • "bytes */1234" -> Some \{unit="bytes"; range=None; complete_length=Some 1234\}
val make_content_range : start:int64 -> end_:int64 -> complete_length:int64 -> content_range

make_content_range ~start ~end_ ~complete_length creates a Content-Range value for a byte range response.

  • parameter start

    The first byte position (0-indexed)

  • parameter end_

    The last byte position (inclusive)

  • parameter complete_length

    The total size of the representation

val make_unsatisfied_range : complete_length:int64 -> content_range

make_unsatisfied_range ~complete_length creates a Content-Range value for an unsatisfied range (416 response).

If-Range (RFC 9110 Section 13.1.5)

The If-Range header makes a Range request conditional. It can contain either an ETag or a Last-Modified date.

type if_range =
  1. | If_range_etag of string
    (*

    An entity tag (strong or weak)

    *)
  2. | If_range_date of string
    (*

    A Last-Modified date in HTTP-date format

    *)
val if_range_to_string : if_range -> string

if_range_to_string ir converts an If-Range value to a string.

val parse_if_range : string -> if_range option

parse_if_range s parses an If-Range header value.

Distinguishes between ETags (contain quotes or start with W/) and HTTP-date values (start with a weekday abbreviation).

val if_range_of_etag : string -> if_range

if_range_of_etag etag creates an If-Range value from an ETag.

val if_range_of_date : string -> if_range

if_range_of_date date creates an If-Range value from a date string.

val if_range_is_etag : if_range -> bool

if_range_is_etag ir returns true if ir is an ETag.

val if_range_is_date : if_range -> bool

if_range_is_date ir returns true if ir is a date.

Allow (RFC 9110 Section 10.2.1)

The Allow header lists the set of methods supported by the target resource.

val parse_allow : string -> Method.t list

parse_allow s parses an Allow header value into a list of methods.

Example: "GET, HEAD, PUT" -> \`GET; \`HEAD; \`PUT

val allow_to_string : Method.t list -> string

allow_to_string methods formats a list of methods as an Allow header value.

Example: \`GET; \`HEAD -> "GET, HEAD"

val allow_contains : Method.t -> string -> bool

allow_contains method_ allow_value checks if a method is in an Allow header value.

Authentication-Info (RFC 9110 Section 11.6.3)

The Authentication-Info header is sent by the server after successful authentication. For Digest authentication, it provides:

type authentication_info = {
  1. nextnonce : string option;
    (*

    Next nonce to use for subsequent requests

    *)
  2. qop : string option;
    (*

    Quality of protection that was used

    *)
  3. rspauth : string option;
    (*

    Response authentication (server proves it knows the password)

    *)
  4. cnonce : string option;
    (*

    Client nonce echoed back

    *)
  5. nc : string option;
    (*

    Nonce count echoed back

    *)
}
val parse_authentication_info : string -> authentication_info

parse_authentication_info s parses an Authentication-Info header value.

Example: "nextnonce=\"abc123\", qop=auth, rspauth=\"xyz789\""

val has_nextnonce : authentication_info -> bool

has_nextnonce info returns true if a new nonce is provided.

If present, the client should use this nonce for subsequent requests instead of waiting for a 401 response with a new challenge.

val get_nextnonce : authentication_info -> string option

get_nextnonce info returns the next nonce, if present.

Retry-After (RFC 9110 Section 10.2.3)

The Retry-After header indicates how long to wait before retrying.

type retry_after =
  1. | Retry_after_date of string
    (*

    An HTTP-date when the resource will be available

    *)
  2. | Retry_after_seconds of int
    (*

    Number of seconds to wait before retrying

    *)
val parse_retry_after : string -> retry_after option

parse_retry_after s parses a Retry-After header value.

Examples:

  • "120" -> Some (Retry_after_seconds 120)
  • "Fri, 31 Dec 1999 23:59:59 GMT" -> Some (Retry_after_date "...")
val retry_after_to_seconds : ?now:float -> retry_after -> int option

retry_after_to_seconds ?now retry_after converts to seconds.

For Retry_after_seconds, returns the value directly. For Retry_after_date, parses the HTTP-date per RFC 9110 Section 5.6.7 and computes the difference from now. Returns 0 if the date is in the past. Returns None if the date cannot be parsed or now is not provided.

  • parameter now

    The current time as a Unix timestamp (required for date calculation)

Accept-Ranges (RFC 9110 Section 14.3)

The Accept-Ranges header indicates whether the server supports range requests.

type accept_ranges =
  1. | Accept_ranges_bytes
    (*

    Server supports byte range requests

    *)
  2. | Accept_ranges_none
    (*

    Server does not support range requests

    *)
  3. | Accept_ranges_other of string
    (*

    Server supports some other range unit

    *)
val parse_accept_ranges : string -> accept_ranges

parse_accept_ranges s parses an Accept-Ranges header value.

Examples:

  • "bytes" -> Accept_ranges_bytes
  • "none" -> Accept_ranges_none
val supports_byte_ranges : accept_ranges -> bool

supports_byte_ranges ar returns true if byte range requests are supported.

Cache-Status (RFC 9211)

The Cache-Status header field indicates how caches have handled a request. It is a List structured field (RFC 8941) where each member is a cache identifier with optional parameters.

Example: Cache-Status: "Cloudflare"; hit, ExampleCDN; fwd=uri-miss; stored

type cache_status_fwd =
  1. | Fwd_uri_miss
    (*

    The cache did not contain any matching response

    *)
  2. | Fwd_vary_miss
    (*

    The cache contained a response, but Vary header prevented match

    *)
  3. | Fwd_miss
    (*

    The cache did not find a usable response (generic)

    *)
  4. | Fwd_request
    (*

    The request semantics required forwarding (e.g., no-cache)

    *)
  5. | Fwd_stale
    (*

    The cache had a stale response that needed revalidation

    *)
  6. | Fwd_partial
    (*

    The cache had a partial response that needed completion

    *)
  7. | Fwd_bypass
    (*

    The cache was configured to bypass for this request

    *)
  8. | Fwd_other of string
    (*

    Other forward reason

    *)

Forward/stored response indicator for Cache-Status

type cache_status_entry = {
  1. cache_id : string;
    (*

    Identifier for the cache (e.g., "CDN", "proxy", "Cloudflare")

    *)
  2. hit : bool option;
    (*

    True if served from cache without forwarding

    *)
  3. fwd : cache_status_fwd option;
    (*

    Why the request was forwarded

    *)
  4. fwd_status : int option;
    (*

    Status code from the forwarded response

    *)
  5. stored : bool option;
    (*

    Whether the response was stored in cache

    *)
  6. collapsed : bool option;
    (*

    Whether request was collapsed with others

    *)
  7. ttl : int option;
    (*

    Time-to-live remaining in seconds

    *)
  8. key : string option;
    (*

    Cache key used

    *)
  9. detail : string option;
    (*

    Implementation-specific detail

    *)
}

A single cache status entry from the Cache-Status header

val cache_status_fwd_of_string : string -> cache_status_fwd

cache_status_fwd_of_string s parses a forward reason string.

val cache_status_fwd_to_string : cache_status_fwd -> string

cache_status_fwd_to_string fwd converts a forward reason to string.

val parse_cache_status_entry : string -> cache_status_entry option

parse_cache_status_entry s parses a single cache status entry. Format: cache-id; param1; param2=value

val parse_cache_status : string -> cache_status_entry list

parse_cache_status s parses a complete Cache-Status header value.

Example: "Cloudflare; hit, CDN; fwd=uri-miss" -> list of entries

val cache_status_entry_to_string : cache_status_entry -> string

cache_status_entry_to_string entry formats a single entry.

val cache_status_to_string : cache_status_entry list -> string

cache_status_to_string entries formats entries as a header value.

val cache_status_is_hit : cache_status_entry list -> bool

cache_status_is_hit entries returns true if any cache reported a hit.

val cache_status_is_stored : cache_status_entry list -> bool

cache_status_is_stored entries returns true if any cache stored the response.

val cache_status_get_fwd : cache_status_entry list -> cache_status_fwd option

cache_status_get_fwd entries returns the forward reason from the first cache that forwarded the request, if any.

Content-Digest / Repr-Digest (RFC 9530)

Content-Digest contains a digest of the content (after content coding). Repr-Digest contains a digest of the representation (before content coding).

These headers allow integrity verification of HTTP message bodies.

Example: Content-Digest: sha-256=:base64digest:

type digest_algorithm =
  1. | Sha256
    (*

    SHA-256 (recommended by RFC 9530)

    *)
  2. | Sha512
    (*

    SHA-512

    *)
  3. | Other of string
    (*

    Other algorithm (for forward compatibility)

    *)

Supported digest algorithms

val digest_algorithm_of_string : string -> digest_algorithm

digest_algorithm_of_string s parses an algorithm name. Example: "sha-256" -> Sha256

val digest_algorithm_to_string : digest_algorithm -> string

digest_algorithm_to_string algo converts to standard algorithm name.

type digest_value = {
  1. algorithm : digest_algorithm;
    (*

    The hash algorithm used

    *)
  2. digest : string;
    (*

    The base64-encoded digest value

    *)
}

A single digest value with its algorithm

val parse_digest_header : string -> digest_value list

parse_digest_header s parses a Content-Digest or Repr-Digest header.

Example: "sha-256=:base64data:, sha-512=:base64data:" -> list of values

val digest_value_to_string : digest_value -> string

digest_value_to_string dv formats a single digest value.

val digest_header_to_string : digest_value list -> string

digest_header_to_string digests formats as a header value.

val compute_sha256 : string -> string

compute_sha256 content computes SHA-256 and returns base64-encoded result.

val compute_sha512 : string -> string

compute_sha512 content computes SHA-512 and returns base64-encoded result.

val compute_digest : algorithm:digest_algorithm -> string -> digest_value

compute_digest ~algorithm content computes a digest using the specified algorithm.

val make_content_digest : ?algorithm:digest_algorithm -> string -> digest_value

make_content_digest ?algorithm content creates a Content-Digest value. Defaults to SHA-256 which is recommended by RFC 9530.

val validate_digest : digests:digest_value list -> string -> bool

validate_digest ~digests content validates content against provided digests. Returns true if any of the digests matches.

val get_strongest_digest : digest_value list -> digest_value option

get_strongest_digest digests returns the strongest available digest. Prefers SHA-512 over SHA-256 over others.

Strict-Transport-Security (RFC 6797)

The Strict-Transport-Security (HSTS) header tells browsers to only access the site over HTTPS, protecting against protocol downgrade attacks and cookie hijacking.

Example: Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

type hsts = {
  1. max_age : int64;
    (*

    Required: Time in seconds the browser should remember HTTPS-only

    *)
  2. include_subdomains : bool;
    (*

    If true, policy applies to all subdomains

    *)
  3. preload : bool;
    (*

    If true, site requests inclusion in browser preload lists

    *)
}

HSTS directive values

val parse_hsts : string -> hsts option

parse_hsts s parses a Strict-Transport-Security header value.

Returns None if the required max-age directive is missing.

Example: "max-age=31536000; includeSubDomains" -> Some \{max_age=31536000; include_subdomains=true; preload=false\}

val hsts_to_string : hsts -> string

hsts_to_string hsts formats an HSTS value as a header string.

Example: \{max_age=31536000; include_subdomains=true; preload=false\} -> "max-age=31536000; includeSubDomains"

val make_hsts : ?max_age:int64 -> ?include_subdomains:bool -> ?preload:bool -> unit -> hsts

make_hsts ?max_age ?include_subdomains ?preload () creates an HSTS value.

  • parameter max_age

    Time in seconds (default: 1 year = 31536000)

  • parameter include_subdomains

    Apply to subdomains (default: false)

  • parameter preload

    Request preload list inclusion (default: false)

val hsts_is_enabled : hsts -> bool

hsts_is_enabled hsts returns true if HSTS is effectively enabled (max-age > 0).

Common HSTS Configurations

val hsts_one_year_subdomains : hsts

One year with subdomains - recommended for production

val hsts_preload : hsts

Two years with subdomains and preload - for HSTS preload submission

val hsts_disable : hsts

Disable HSTS by setting max-age to 0