Picos_io_cohttp
Minimalistic Cohttp implementation using Picos_io
for Picos
.
⚠️ This library is currently minimalistic and experimental and is highly likely to change. Feedback from potential users is welcome!
module Client : sig ... end
Convenience functions for constructing requests and processing responses.
module Server : sig ... end
Convenience functions for processing requests and constructing responses.
First we open some modules for convenience:
open Cohttp
open Picos_io
open Picos_io_cohttp
open Picos_std_finally
open Picos_std_structured
Let's build a simple hello server. We first define a function that creates and configures a socket for the server:
let server_create ?(max_pending_reqs = 8) addr =
let socket = Unix.socket ~cloexec:true PF_INET SOCK_STREAM 0 in
match
Unix.set_nonblock socket;
Unix.bind socket addr;
Unix.listen socket max_pending_reqs
with
| () -> socket
| exception exn ->
Unix.close socket;
raise exn
The reason for doing it like this, as we'll see later, is that we want the OS to decide the port for our server. Also note that we explicitly set the socket to non-blocking mode, which is what we should do with Picos_io
whenever possible.
Then we'll define a function that runs a server given a socket:
let server_run socket =
let callback _conn _req body =
let body = Printf.sprintf "Hello, %s!" (Body.to_string body) in
Server.respond_string ~status:`OK ~body ()
in
Server.run (Server.make ~callback ()) socket
The idea is that the body of the request is the name to be greeted in the body of the response.
A client then posts to the specified uri and returns the response body:
let client uri name =
let resp, body = Client.post ~body:(`String name) uri in
if Response.status resp != `OK then failwith "Not OK";
Body.to_string body
Now we are ready to put everything together:
# Picos_mux_random.run_on ~n_domains:2 @@ fun () ->
let@ server_socket =
finally Unix.close @@ fun () ->
server_create
Unix.(ADDR_INET (inet_addr_loopback, 0))
in
let server_port =
match Unix.getsockname server_socket with
| ADDR_UNIX _ -> failwith "impossible"
| ADDR_INET (_, port) -> port
in
let server_uri =
Uri.make
~scheme:"http"
~host:"127.0.0.1"
~port:server_port
()
in
Flock.join_after ~on_return:`Terminate @@ fun () ->
Flock.fork begin fun () ->
server_run server_socket
end;
client server_uri "World"
- : string = "Hello, World!"
We first create the server_socket
and obtain the server_port
and ultimately the server_uri
from it — typically one can avoid this complexity and use a fixed port. We then create a flock for running the server as a concurrent fiber, which we arrange to terminate at the end of the scope. Finally we act as the client to get a greeting from the server.