Module Http.Request

HTTP requests.

The service request and client request conventions may help understanding how connectors construct and use these values.

Requests

type t

The type for HTTP requests.

val make : ?headers:Headers.t -> ?path:Path.t -> ?query:string option -> ?service_path:Path.t -> version:Version.t -> Method.t -> raw_path:string -> Body.t -> t

make method' ~raw_path body is a request with given method', raw_path and body and:

Usually you should rather use for_service_connector or of_url. This ensures that derived data like path and query are computed correctly.

val for_service_connector : service_path:Path.t -> version:Version.t -> Method.t -> raw_path:string -> headers:Headers.t -> Body.t -> (t, Response.t) Stdlib.result

for_service_connector ~service_path ~version method' ~raw_path ~headers body is a request that satisfies the service requests conventions.

In case the response cannot satisfy them an error response is returned according to the connector responses conventions.

val of_url : ?body:Body.t -> ?headers:Headers.t -> ?version:Version.t -> Method.t -> url:string -> (Scheme.t * t, string) Stdlib.result

of_url method' ~url body is a scheme and method' request on url ensuring that the request satsifies the client request conventions.

headers defaults to Headers.empty and a suitable Headers.host is added to it. body defaults to Body.empty, version defaults to Version.v11.

An error is returned if the scheme is neither http or https or if a decoding error occurs. Both path and query are derived with a service_path of Path.root.

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

pp formats responses for inspection. Guarantees not to consume the body.

Properties

val body : t -> Body.t

body request is the body of request.

val headers : t -> Headers.t

headers request are the HTTP headers of request. Should always at least includes at the Http.Headers.host header.

val method' : t -> Method.t

method' request is the HTTP method of request.

val path : t -> Path.t

path request is the absolute path of the raw_path of request stripped by the service_path of request. This is the path you want your service to handle.

val query : t -> string option

query request is the the query part (without the ?) of the raw_path of request. None is returned if there is no ? at all. Some "" is returned if there is a ? followed by emptyness. To decode the query and possibly handle those that are POSTed aswell, see to_query.

val raw_path : t -> string

raw_path request is the request target (HTTP/1.1) or :path pseudo-header (HTTP/2, HTTP/3) of request. Usually one rather wants to use the convenience path and query which are derived from this value as this makes the service insensitive to where it is attached, see service_path.

val service_path : t -> Path.t

service_path r is service path of r.

  • For service connectors this is the path on which the root of the service is attached. This is usually defined by the service connector. The path value of r is the path mentioned in raw_path stripped by this path.
  • For client connectors this is irrelevant and set to Path.root
val version : t -> Version.t

version r is the HTTP version of the request.

  • For service connectors this should be the HTTP version of the request made on the connector. Note that if the service connector interfaces with a gateway this may be different from the actual version used by the gateway with the client.
  • For client connectors this is mostly irrelevant: the connectors decides how they want to talk to the client. But it can be used as hint for which HTTP version to use.

Echo

val echo : ?status:Status.t -> t -> Response.t

echo request is a response with status status (defaults to 404) and a text/plain body that has all the properties of request, including the request body, which is consumed by the function with Body.to_string.

Note. In general using echo violates numerous HTTP musts.

Deconstructing and responding

Request deconstruction and response helpers. When they error these functions directly do with responses that have the right statuses and, unless otherwise noted, empty bodies.

Redirection

val redirect_to_path : ?body:Body.t -> ?explain:string -> ?headers:Headers.t -> ?reason:string -> t -> Status.t -> Path.t -> Response.t

redirect_to_path request status path redirects to path in the service of request. This is Response.redirect status loc with loc the result of encoding the path:

Path.concat (service_path request) path

Header decoding

val decode_header : Headers.Name.t -> (string -> ('a, string) Stdlib.result) -> t -> ('a option, Response.t) Stdlib.result

decode_header h dec r decodes header h (if any) in r. Errors with Http.Status.bad_request_400 in case of decoding errors and transfers the error message to Response.reason.

Method constraints

val allow : 'a Method.constraint' list -> t -> ('a, Response.t) Stdlib.result

allow ms r is:

Cookies

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 ?

Queries

val to_query : t -> (Query.t, Response.t) Stdlib.result

to_query r extracts a query from r. This is

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

Path cleaning

val clean_path : t -> (unit, Response.t) Stdlib.result

clean_path r is:

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

Note. 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 (I no longer understand this comment).

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.t -> file_root:Path.fpath -> t -> (Path.fpath, Response.t) Stdlib.result

absolute_filepath ~strip ~file_root request is:

Etags

val eval_if_none_match : t -> Etag.t -> headers:Headers.t -> (Headers.t, Response.t) Stdlib.result

eval_if_none_match request etag ~headers is

Design note. This slightly abuses the idea of the result design idea which was rather to carry error responses in the Error _ case. But… it's convenient.