package tiny_httpd
Install
Dune Dependency
Authors
Maintainers
Sources
sha256=67c636f1bbaf93da0cb0a12cb44803299892caf51e637815c753f0af6f4e7b7e
sha512=c254415a69df5a1bec255a223dbc2d10370b2f533da0b14ff458545da7aa5e4a634972272e7eef64425b6360494d6b3446761c03b49fd7558765cbfefae2178b
doc/tiny_httpd/Tiny_httpd/index.html
Module Tiny_httpd
Source
Tiny Http Server
This library implements a very simple, basic HTTP/1.1 server using blocking IOs and threads. Basic routing based is provided for convenience, so that several handlers can be registered.
It is possible to use a thread pool, see create
's argument new_thread
.
The echo
example (see src/examples/echo.ml
) demonstrates some of the features by declaring a few endpoints, including one for uploading files:
module S = Tiny_httpd
let () =
let server = S.create () in
(* say hello *)
S.add_route_handler ~meth:`GET server
S.Route.(exact "hello" @/ string @/ return)
(fun name _req -> S.Response.make_string (Ok ("hello " ^name ^"!\n")));
(* echo request *)
S.add_route_handler server
S.Route.(exact "echo" @/ return)
(fun req -> S.Response.make_string
(Ok (Format.asprintf "echo:@ %a@." S.Request.pp req)));
(* file upload *)
S.add_route_handler ~meth:`PUT server
S.Route.(exact "upload" @/ string_urlencoded @/ return)
(fun path req ->
try
let oc = open_out @@ "/tmp/" ^ path in
output_string oc req.S.Request.body;
flush oc;
S.Response.make_string (Ok "uploaded file")
with e ->
S.Response.fail ~code:500 "couldn't upload file: %s"
(Printexc.to_string e)
);
(* run the server *)
Printf.printf "listening on http://%s:%d\n%!" (S.addr server) (S.port server);
match S.run server with
| Ok () -> ()
| Error e -> raise e
It is then possible to query it using curl:
$ dune exec src/examples/echo.exe &
listening on http://127.0.0.1:8080
# the path "hello/name" greets you.
$ curl -X GET http://localhost:8080/hello/quadrarotaphile
hello quadrarotaphile!
# the path "echo" just prints the request.
$ curl -X GET http://localhost:8080/echo --data "howdy y'all"
echo:
{meth=GET;
headers=Host: localhost:8080
User-Agent: curl/7.66.0
Accept: */*
Content-Length: 10
Content-Type: application/x-www-form-urlencoded;
path="/echo"; body="howdy y'all"}
Tiny buffer implementation
These buffers are used to avoid allocating too many byte arrays when processing streams and parsing requests.
IO Abstraction
Logging
Utils
Resource pool
Static directory serving
HTML combinators
Alias to Tiny_httpd_html
Main server types
Exception raised to exit request handlers with a code+error message
Middlewares
A middleware can be inserted in a handler to modify or observe its behavior.
A middleware that only considers the request's head+headers.
Main Server type
A HTTP server. See create
for more details.
A 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 ->
t
Create a new webserver using provided backend.
The server will not do anything until run
is called on it. Before starting the server, one can use add_path_handler
and set_top_handler
to specify how to handle incoming requests.
is_ipv6 server
returns true
iff the address of the server is an IPv6 address.
Port 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 add_decode_request_cb :
t ->
(unit Tiny_httpd_core.Request.t ->
(unit Tiny_httpd_core.Request.t
* (Tiny_httpd_core.IO.Input.t ->
Tiny_httpd_core.IO.Input.t))
option) ->
unit
Add 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-Encoding
header and returning a stream transformer that decompresses on the fly.
val add_encode_response_cb :
t ->
(unit Tiny_httpd_core.Request.t ->
Tiny_httpd_core.Response.t ->
Tiny_httpd_core.Response.t option) ->
unit
Add a callback for every request/response pair. Similarly to add_encode_response_cb
the 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.
Add a middleware to every request/response pair.
Request handlers
val set_top_handler :
t ->
(Tiny_httpd_core.IO.Input.t Tiny_httpd_core.Request.t ->
Tiny_httpd_core.Response.t) ->
unit
Setup 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 a 404
not found
This used to take a string Request.t
but it now takes a byte_stream Request.t
since 0.14 . Use Request.read_body_full
to read the body into a string if needed.
val add_route_handler :
?accept:
(unit Tiny_httpd_core.Request.t ->
(unit, Tiny_httpd_core.Response_code.t * string) result) ->
?middlewares:Middleware.t list ->
?meth:Tiny_httpd_core.Meth.t ->
t ->
('a, string Tiny_httpd_core.Request.t -> Tiny_httpd_core.Response.t)
Tiny_httpd_core.Route.t ->
'a ->
unit
add_route_handler server Route.(exact "path" @/ string @/ int @/ return) f
calls f "foo" 42 request
when a request
with 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.
val add_route_handler_stream :
?accept:
(unit Tiny_httpd_core.Request.t ->
(unit, Tiny_httpd_core.Response_code.t * string) result) ->
?middlewares:Middleware.t list ->
?meth:Tiny_httpd_core.Meth.t ->
t ->
('a,
Tiny_httpd_core.IO.Input.t Tiny_httpd_core.Request.t ->
Tiny_httpd_core.Response.t)
Tiny_httpd_core.Route.t ->
'a ->
unit
Similar 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 as Jsonm
) or into a file.
Server-sent events
EXPERIMENTAL: this API is not stable yet.
A server-side function to generate of Server-sent events.
Server-sent event generator. This generates events that are forwarded to the client (e.g. the browser).
val add_route_server_sent_handler :
?accept:
(unit Tiny_httpd_core.Request.t ->
(unit, Tiny_httpd_core.Response_code.t * string) result) ->
?middlewares:Head_middleware.t list ->
t ->
('a, string Tiny_httpd_core.Request.t -> server_sent_generator -> unit)
Tiny_httpd_core.Route.t ->
'a ->
unit
Add 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. See server_sent_generator
for more details.
This handler stays on the original thread (it is synchronous).
Upgrade handlers
These handlers upgrade the connection to another protocol.
Handler that upgrades to another protocol.
val add_upgrade_handler :
?accept:
(unit Tiny_httpd_core.Request.t ->
(unit, Tiny_httpd_core.Response_code.t * string) result) ->
?middlewares:Head_middleware.t list ->
t ->
('a, upgrade_handler) Tiny_httpd_core.Route.t ->
'a ->
unit
Run the server
Ask the server to stop. This might not have an immediate effect as run
might currently be waiting on IO.
Run the main loop of the server, listening on a socket described at the server's creation time, using new_thread
to start a thread for each new client.
This returns Ok ()
if the server exits gracefully, or Error e
if it exits with an error.
run_exn s
is like run s
but re-raises an exception if the server exits with an error.
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 ->
t
Create a new webserver using UNIX abstractions.
The server will not do anything until run
is called on it. Before starting the server, one can use add_path_handler
and set_top_handler
to specify how to handle incoming requests.