Module Tiny_httpd_server
HTTP server.
This module implements a very simple, basic HTTP/1.1 server using blocking IOs and threads.
It is possible to use a thread pool, see create's argument new_thread.
- since
- 0.13
type buf= Tiny_httpd_buf.ttype byte_stream= Tiny_httpd_stream.t
HTTP Methods
module Meth : sig ... endHeaders
Headers are metadata associated with a request or response.
module Headers : sig ... endRequests
Requests are sent by a client, e.g. a web browser or cURL. From the point of view of the server, they're inputs.
module Request : sig ... endResponse Codes
module Response_code : sig ... endResponses
Responses are what a http server, such as Tiny_httpd, send back to the client to answer a Request.t
module Response : sig ... endRouting
Basic type-safe routing of handlers based on URL paths. This is optional, it is possible to only define the root handler with something like Routes.
- since
- 0.6
module Route : sig ... endMiddlewares
A middleware can be inserted in a handler to modify or observe its behavior.
- since
- 0.11
module Middleware : sig ... endMain Server type
type tA HTTP server. See
createfor more details.
val create : ?masksigpipe:bool -> ?max_connections:int -> ?timeout:float -> ?buf_size:int -> ?get_time_s:(unit -> float) -> ?new_thread:((unit -> unit) -> unit) -> ?addr:string -> ?port:int -> ?sock:Unix.file_descr -> ?middlewares:([ `Encoding | `Stage of int ] * Middleware.t) list -> unit -> tCreate a new webserver using UNIX abstractions.
The server will not do anything until
runis called on it. Before starting the server, one can useadd_path_handlerandset_top_handlerto specify how to handle incoming requests.- parameter masksigpipe
if true, block the signal
Sys.sigpipe which otherwise tends to kill client threads when they try to write on broken sockets. Default:true.
- parameter buf_size
size for buffers (since 0.11)
- parameter new_thread
a function used to spawn a new thread to handle a new client connection. By default it is
Thread.create but one could use a thread pool instead. See for example this use of moonpool.
- parameter middlewares
see
add_middlewarefor more details.
- parameter max_connections
maximum number of simultaneous connections.
- parameter timeout
connection is closed if the socket does not do read or write for the amount of second. Default: 0.0 which means no timeout. timeout is not recommended when using proxy.
- parameter addr
address (IPv4 or IPv6) to listen on. Default
"127.0.0.1".
- parameter port
to listen on. Default
8080.
- parameter sock
an existing socket given to the server to listen on, e.g. by systemd on Linux (or launchd on macOS). If passed in, this socket will be used instead of the
addrandport. If not passed in, those will be used. This parameter exists since 0.10.
- parameter get_time_s
obtain the current timestamp in seconds. This parameter exists since 0.11.
module type IO_BACKEND = sig ... endA backend that provides IO operations, network operations, etc.
val create_from : ?buf_size:int -> ?middlewares:([ `Encoding | `Stage of int ] * Middleware.t) list -> backend:(module IO_BACKEND) -> unit -> tCreate a new webserver using provided backend.
The server will not do anything until
runis called on it. Before starting the server, one can useadd_path_handlerandset_top_handlerto specify how to handle incoming requests.- parameter buf_size
size for buffers (since 0.11)
- parameter middlewares
see
add_middlewarefor more details.
- since
- 0.14
val addr : t -> stringAddress on which the server listens.
val is_ipv6 : t -> boolis_ipv6 serverreturnstrueiff the address of the server is an IPv6 address.- since
- 0.3
val port : t -> intPort on which the server listens. Note that this might be different than the port initially given if the port was
0(meaning that the OS picks a port for us).
val active_connections : t -> intNumber of currently active connections.
val add_decode_request_cb : t -> (unit Request.t -> (unit Request.t * (byte_stream -> byte_stream)) option) -> unitAdd a callback for every request. The callback can provide a stream transformer and a new request (with modified headers, typically). A possible use is to handle decompression by looking for a
Transfer-Encodingheader and returning a stream transformer that decompresses on the fly.- deprecated
use
add_middlewareinstead
val add_encode_response_cb : t -> (unit Request.t -> Response.t -> Response.t option) -> unitAdd a callback for every request/response pair. Similarly to
add_encode_response_cbthe callback can return a new response, for example to compress it. The callback is given the query with only its headers, as well as the current response.- deprecated
use
add_middlewareinstead
val add_middleware : stage:[ `Encoding | `Stage of int ] -> t -> Middleware.t -> unitAdd a middleware to every request/response pair.
- parameter stage
specify when middleware applies. Encoding comes first (outermost layer), then stages in increasing order.
- raises Invalid_argument
if stage is
`Stage nwheren < 1
- since
- 0.11
Request handlers
val set_top_handler : t -> (byte_stream Request.t -> Response.t) -> unitSetup a handler called by default.
This handler is called with any request not accepted by any handler installed via
add_path_handler. If no top handler is installed, unhandled paths will return a404not foundThis used to take a
string Request.tbut it now takes abyte_stream Request.tsince 0.14 . UseRequest.read_body_fullto read the body into a string if needed.
val add_route_handler : ?accept:(unit Request.t -> (unit, Response_code.t * string) Stdlib.result) -> ?middlewares:Middleware.t list -> ?meth:Meth.t -> t -> ('a, string Request.t -> Response.t) Route.t -> 'a -> unitadd_route_handler server Route.(exact "path" @/ string @/ int @/ return) fcallsf "foo" 42 requestwhen arequestwith path "path/foo/42/" is received.Note that the handlers are called in the reverse order of their addition, so the last registered handler can override previously registered ones.
- parameter meth
if provided, only accept requests with the given method. Typically one could react to
`GETor`PUT.
- parameter accept
should return
Ok()if the given request (before its body is read) should be accepted,Error (code,message)if it's to be rejected (e.g. because its content is too big, or for some permission error). See thehttp_of_dirprogram for an example of how to useacceptto filter uploads that are too large before the upload even starts. The default always returnsOk(), i.e. it accepts all requests.
- since
- 0.6
val add_route_handler_stream : ?accept:(unit Request.t -> (unit, Response_code.t * string) Stdlib.result) -> ?middlewares:Middleware.t list -> ?meth:Meth.t -> t -> ('a, byte_stream Request.t -> Response.t) Route.t -> 'a -> unitSimilar to
add_route_handler, but where the body of the request is a stream of bytes that has not been read yet. This is useful when one wants to stream the body directly into a parser, json decoder (such asJsonm) or into a file.- since
- 0.6
Server-sent events
EXPERIMENTAL: this API is not stable yet.
module type SERVER_SENT_GENERATOR = sig ... endA server-side function to generate of Server-sent events.
type server_sent_generator= (module SERVER_SENT_GENERATOR)Server-sent event generator. This generates events that are forwarded to the client (e.g. the browser).
- since
- 0.9
val add_route_server_sent_handler : ?accept:(unit Request.t -> (unit, Response_code.t * string) Stdlib.result) -> t -> ('a, string Request.t -> server_sent_generator -> unit) Route.t -> 'a -> unitAdd a handler on an endpoint, that serves server-sent events.
The callback is given a generator that can be used to send events as it pleases. The connection is always closed by the client, and the accepted method is always
GET. This will set the header "content-type" to "text/event-stream" automatically and reply with a 200 immediately. Seeserver_sent_generatorfor more details.This handler stays on the original thread (it is synchronous).
- since
- 0.9
Run the server
val running : t -> boolIs the server running?
- since
- 0.14
val stop : t -> unitAsk the server to stop. This might not have an immediate effect as
runmight currently be waiting on IO.
val run : ?after_init:(unit -> unit) -> t -> (unit, exn) Stdlib.resultRun the main loop of the server, listening on a socket described at the server's creation time, using
new_threadto start a thread for each new client.This returns
Ok ()if the server exits gracefully, orError eif it exits with an error.- parameter after_init
is called after the server starts listening. since 0.13 .
val run_exn : ?after_init:(unit -> unit) -> t -> unitrun_exn sis likerun sbut re-raises an exception if the server exits with an error.- since
- 0.14