package paf

  1. Overview
  2. Docs
HTTP/AF and MirageOS

Install

Dune Dependency

Authors

Maintainers

Sources

paf-0.0.1.tbz
sha256=7a794c21ce458bda302553b0f5ac128c067579fbb3b7b8fba9b410446c43e790
sha512=979da8b57de9eb81d11dbc6df343aa9cb6d454aa8f33e14bf28ebfcd75232aeae49defc975250ae772fd4d174ac9d8737bd018fd72dd2460c8dae5c5252a2bc1

Description

A compatible layer for HTTP/AF and MirageOS.

Published: 27 Jan 2021

README

Paf le chien - A MirageOS compatible layer for HTTP/AF

This library wants to provide an easy way to use HTTP/AF into a unikernel. It implements the global /loop/ with a protocol implementation.

The protocol implementation is given by Mimic and should be the mirage-tcpip implementation - however, it can be something else.

It does the composition between the TLS encryption layer and the StackV4V6 implementation to provide a way to initiate a TLS server.

module Make (Time : Mirage_time.S) (Stack : Mirage_stack.V4V6) = struct
  module Paf = Paf.make(Time)(Stack)

  let start stack =
    let* service = Paf.init ~port:80 stack in
    let `Initialized t = Paf.http ~request_handler ~error_handler in
    t
end

(* For UNIX with mirage-time-unix & tcpip.stack-socket *)

include Make (Time) (Tcpip_stack_socket.V4V6)

let stack () =
  let open Tcpip_stack_socket.V4V6 in
  UDP.connect ~ipv4_only:false ~ipv6_only:false Ipaddr.V4.Prefix.global None >>= fun udp ->
  TCP.connect ~ipv4_only:false ~ipv6_only:false Ipaddr.V4.Prefix.global None >>= fun tcp ->
  connect udp tcp

let () = Lwt_main.run (stack >>= start)

It provides a client-side with the logic of Mimic and let the user to implement the resolution process to determine if the connection needs the TLS encryption layer or not.

Mimic

Paf wants to provide an agnostic implementation of HTTP with the ability to launch a server or a client from an user-defined context: a Mimic.ctx. It does not exist one and unique way to use Paf because the context can be:

  • a MirageOS

  • a simple executable

  • something else like a JavaScript script (with js_of_ocaml)

Mimic ensures the ability to gives a Mirage_flow.S to Paf (client side). The underlying implementation of this /flow/ depends on what the user wants. It can be:

All of these choices is not done by Paf but must be define by the user. Then, the CoHTTP layer trusts on mirage-tcpip and ocaml-tls to easily communicate with a peer from a given Uri.t. Even if it seems to be the easy way to do HTTP requests (over TLS or not), the user is able to choose some others possibilities/paths.

For example, the user is able to start a connection with an Unix domain socket:

module Unix_domain_socket : Mimic.Mirage_protocol.S
  with type flow = Unix.file_descr
   and type endpoint = Fpath.t

let unix_domain_socket = Mimic.register ~name:"unix-domain-socket" (module Unix_domain_socket)

let ctx =
  Mimic.add unix_domain_socket 
    (Fpath.v "/var/my_domain.sock") Mimic.empty
    
let run =
  Paf.request ~ctx ... req

CoHTTP layer

Paf comes with a not-fully-implemented compatible layer with CoHTTP. From this sub-package and the letsencrypt package, Paf provides a process to download a Let's encrypt TLS certificate ready to launch an HTTPS server.

let cfg =
  { LE.email= Result.to_option (Emile.of_string "romain@x25519.net")
  ; LE.seed= None
  ; LE.certificate_seed= None
  ; LE.hostname= Domain_name.(host_exn (of_string_exn "x25519.net")) }

let ctx = ... (* see [mimic] *)

let get_tls_certificate () =
  Lwt_switch.with_switch @@ fun stop ->
  let* service = Paf.init ~port:80 stack in
  let `Initialized th = Paf.http ~stop ~request_handler:LE.request_handler ~error_handler service in
  let fiber =
    LE.provision_certificate ~production:false cfg ctx >>= fun res ->
    Lwt_switch.turn_off stop >>= fun () -> Lwt.return res in
  Lwt.both (th, fiber) >>= fun (_, tls) -> Lwt.return tls

Tests & Benchmark

The distribution comes with a tool which launch several clients to communicate with a server. We record the time spent for each request and show as the result the histogram of them. It's not really a benchmark as is but it a good stress-test and we check that we don't have failure from the server.

Dependencies (11)

  1. ke >= "0.4"
  2. emile >= "1.0"
  3. letsencrypt < "0.3.0"
  4. cohttp-lwt < "6.0.0~"
  5. mimic
  6. tls-mirage < "0.13.0"
  7. httpaf >= "0.6.0"
  8. mirage-time
  9. mirage-stack >= "2.2.0"
  10. dune >= "2.0.0"
  11. ocaml >= "4.08.0"

Dev Dependencies (10)

  1. alcotest-lwt with-test
  2. uri with-test
  3. ptime with-test
  4. mirage-time-unix with-test
  5. tcpip with-test & >= "6.0.0"
  6. mirage-crypto-rng with-test
  7. fmt with-test
  8. logs with-test
  9. base-unix with-test
  10. lwt with-test

Used by

None

Conflicts

None