Module Http.Req

HTTP requests.

Request bodies

type body = unit -> (bytes * int * int) option

The type for request bodies.

Bodies are blocking functions pulled by services to yield byte chunks of data of the request body as Some (bytes, first, len) values. The bytes value must not be modified and is readable from first to first+len until the next call to the function. The function returns None at the end of stream.

val empty_body : body

empty_body is an empty body.

val body_to_string : body -> string

body_to_string b accumulates the body to a string.


type t = req

The type for HTTP requests.

val v : ?init:req -> ?body:body -> ?body_length:int option -> ?headers:headers -> ?meth:meth -> ?path:path -> ?query:string option -> ?request_target:string -> ?service_path:path -> ?version:version -> unit -> req

v ~init () is an HTTP request with given attributes and for those that are unspecified the ones of init (defaults to default).

Important. This is not checked by the module but clients of this function, at least connectors, should maintain these invariant:

  • request_target is the raw request target, still percent encoded.
  • Path.concat service_path path should represent the path of request_target.
  • query (if any) should correspond to the query of request_target.

Routing function may tweak paths but it's a good idea to keep request_target unchanged.

val default : req

default is a request whose

val body : req -> body

body r is r's body.

val body_length : req -> int option

body_length r is r's request body length (if known).

val headers : req -> headers

headers r is r's HTTP headers. Includes at least the header.

val meth : req -> meth

meth r is r's HTTP method.

val path : req -> path

path r should be the absolute path of request_target, stripped by service_path (see v).

val query : req -> string option

query r should be the query (without the '?') of request_target (see v). Note that query string may be the empty string which is different from None (no '?' in the request target). To decode the query (and handle those that are POSTed) see to_query.

val request_target : req -> string

request_target is r's request target. This should be the raw request, still percent encoded (see v). Note that you usually rather want to use the convenience path and query which should be derived from this value.

val service_path : req -> path

service_path r is the path on which the root of the service is served. This is usually set by the connector. The path value of r is should be the path mentioned in request_target stripped by this path (see v).

val version : req -> version

version r is r's HTTP version.

val pp : Stdlib.Format.formatter -> req -> unit

pp ppf req prints and unspecified representation of req on ppf but guarantees not to consume the body.

Request deconstruction and responses

Request deconstruction helpers. These functions directly error with responses that have the right statuses and empty bodies.


val echo : ?status:status -> req -> resp

echo r returns r as a 404 text/plain document (and by doing so violates numerous HTTP's musts). This includes the request body, which is consumed by the service.

Header decoding

val decode_header : name -> (string -> ('a, string) Stdlib.result) -> req -> ('a optionresp) Stdlib.result

decode_header h dec r decodes header h (if any) in r. Errors with Http.bad_request_400 in case of decoding errors.

Method constraints

val allow : 'a Meth.constraint' list -> req -> ('aresp) Stdlib.result

allow ms r is:


find_cookie ~name r is the value of cookie name or None if undefined in r. Errors on header or cookie decoding errors.

FIXME. Why is this a string error ?

Service forwarding


val service_redirect : ?explain:string -> int -> path -> req -> resp

service_redirect status p r redirects r to the service path p (this means r's service_path is prefixed to p) with status status. See also Resp.redirect.

val forward_service : strip:path -> req -> (reqresp) Stdlib.result

forward_service ~strip r is:

FIXME. Because of the new behaviour of Http.Path.strip_prefix on root. This may introduce empty path segments that did not exist originally in the request when one concatenates the service root and the path. Would that be an argument to let also represent the root path ?


Warning. Http.query values are untrusted, you need to properly validate their data.

val to_query : req -> (queryresp) Stdlib.result

to_query r extracts a query from r. This is

Path cleaning

There's more than one way to handle empty segments and trailing slashes in request paths. The scheme proposed here simply always redirects to paths in which all empty segments, and thus trailing slashes, are removed; except on the root path. The advantage of this scheme is that no elaborate file extension logic on the final segment is needed to route file serving.

val clean_path : req -> (reqresp) Stdlib.result

clean_path r is:

  • Ok r if r's path is [], [""] or if it has no empty segment.
  • Error _ with a Http.moved_permanently_301 to r's path without empty segments or the root if that results in the empty path.

Warning. This cleaning does not touch dot segments or percent-encoded directory separators that may be present in the path. You should still use that function or to_absolute_filepath for mapping paths to file paths.

Absolute file paths

val to_absolute_filepath : ?strip:path -> root:fpath -> req -> (fpathresp) Stdlib.result

absolute_filepath ~strip ~root r determines an absolute file path strictly rooted in root by stripping strip (defaults to [""]) from r's path, converting the result to an absolute filepath and prefixing it with root.

Errors with Http.not_found_404 if stripping strip results in None and Http.bad_request_400 if the absolute path conversion fails.