[
  {
    "path": ".gitattributes",
    "content": "bench/* linguist-vendored\n*.re linguist-language=Reason\n*.rei linguist-language=Reason\n*.ml linguist-language=OCaml\n*.mli linguist-language=OCaml\n"
  },
  {
    "path": ".gitignore",
    "content": "_esy\n_build\n_public\n.merlin\n/lua\n/lua_modules\n*.install\n"
  },
  {
    "path": "3rdparty/dune-project",
    "content": "(lang dune 1.9)\n(name httpaf-lwt-unix)\n"
  },
  {
    "path": "3rdparty/httpaf-lwt-unix/buffer.ml",
    "content": "open Lwt.Infix\n\n(* Based on the Buffer module in httpaf_async.ml. *)\ntype t =\n  { buffer      : Lwt_bytes.t\n  ; mutable off : int\n  ; mutable len : int }\n\nlet create size =\n  let buffer = Lwt_bytes.create size in\n  { buffer; off = 0; len = 0 }\n\nlet compress t =\n  if t.len = 0\n  then begin\n    t.off <- 0;\n    t.len <- 0;\n  end else if t.off > 0\n  then begin\n    Lwt_bytes.blit t.buffer t.off t.buffer 0 t.len;\n    t.off <- 0;\n  end\n\nlet get t ~f =\n  let n = f t.buffer ~off:t.off ~len:t.len in\n  t.off <- t.off + n;\n  t.len <- t.len - n;\n  if t.len = 0\n  then t.off <- 0;\n  n\n\nlet put t ~f =\n  compress t;\n  f t.buffer ~off:(t.off + t.len) ~len:(Lwt_bytes.length t.buffer - t.len)\n  >>= fun n ->\n  t.len <- t.len + n;\n  Lwt.return n\n"
  },
  {
    "path": "3rdparty/httpaf-lwt-unix/buffer.mli",
    "content": "type t\n\nval create : int -> t\n\nval get : t -> f:(Lwt_bytes.t -> off:int -> len:int -> int) -> int\nval put : t -> f:(Lwt_bytes.t -> off:int -> len:int -> int Lwt.t) -> int Lwt.t\n"
  },
  {
    "path": "3rdparty/httpaf-lwt-unix/dune",
    "content": "(library\n (name httpaf_lwt_unix)\n (public_name httpaf-lwt-unix)\n (libraries faraday-lwt-unix httpaf lwt.unix ssl lwt_ssl)\n (modules buffer httpaf_lwt_unix tls_io ssl_io)\n (flags (:standard -safe-string)))\n"
  },
  {
    "path": "3rdparty/httpaf-lwt-unix/httpaf_lwt_unix.ml",
    "content": "(*----------------------------------------------------------------------------\n    Copyright (c) 2018 Inhabited Type LLC.\n    Copyright (c) 2018 Anton Bachin\n\n    All rights reserved.\n\n    Redistribution and use in source and binary forms, with or without\n    modification, are permitted provided that the following conditions\n    are met:\n\n    1. Redistributions of source code must retain the above copyright\n       notice, this list of conditions and the following disclaimer.\n\n    2. Redistributions in binary form must reproduce the above copyright\n       notice, this list of conditions and the following disclaimer in the\n       documentation and/or other materials provided with the distribution.\n\n    3. Neither the name of the author nor the names of his contributors\n       may be used to endorse or promote products derived from this software\n       without specific prior written permission.\n\n    THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS\n    OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n    DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR\n    ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n    OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\n    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n    POSSIBILITY OF SUCH DAMAGE.\n  ----------------------------------------------------------------------------*)\n\nopen Lwt.Infix\n\nlet read fd buffer =\n  Lwt.catch\n    (fun () ->\n      Buffer.put buffer ~f:(fun bigstring ~off ~len ->\n        Lwt_bytes.read fd bigstring off len))\n    (function\n    | Unix.Unix_error (Unix.EBADF, _, _) as exn ->\n      Lwt.fail exn\n    | exn ->\n      Lwt.async (fun () ->\n        Lwt_unix.close fd);\n      Lwt.fail exn)\n\n  >>= fun bytes_read ->\n  if bytes_read = 0 then\n    Lwt.return `Eof\n  else\n    Lwt.return (`Ok bytes_read)\n\n\nlet shutdown socket command =\n  try Lwt_unix.shutdown socket command\n  with Unix.Unix_error (Unix.ENOTCONN, _, _) -> ()\n\nmodule Config = Httpaf.Config\n\nmodule Server = struct\n  module Server_connection = Httpaf.Server_connection\n\n  let start_read_write_loops\n    ?(readf=read)\n    ?(writev=Faraday_lwt_unix.writev_of_fd)\n    ~config\n    ~socket\n    connection =\n    let read_buffer = Buffer.create config.Config.read_buffer_size in\n    let read_loop_exited, notify_read_loop_exited = Lwt.wait () in\n\n    let rec read_loop () =\n      let rec read_loop_step () =\n        match Server_connection.next_read_operation connection with\n        | `Read ->\n          readf socket read_buffer >>= begin function\n          | `Eof ->\n            Buffer.get read_buffer ~f:(fun bigstring ~off ~len ->\n              Server_connection.read_eof connection bigstring ~off ~len)\n            |> ignore;\n            read_loop_step ()\n          | `Ok _ ->\n            Buffer.get read_buffer ~f:(fun bigstring ~off ~len ->\n              Server_connection.read connection bigstring ~off ~len)\n            |> ignore;\n            read_loop_step ()\n          end\n\n        | `Yield ->\n          Server_connection.yield_reader connection read_loop;\n          Lwt.return_unit\n\n        | `Close ->\n          Lwt.wakeup_later notify_read_loop_exited ();\n          if not (Lwt_unix.state socket = Lwt_unix.Closed) then begin\n            shutdown socket Unix.SHUTDOWN_RECEIVE\n          end;\n          Lwt.return_unit\n      in\n\n      Lwt.async (fun () ->\n        Lwt.catch\n          read_loop_step\n          (fun exn ->\n            Server_connection.report_exn connection exn;\n            Lwt.return_unit))\n    in\n\n\n    let writev = writev socket in\n    let write_loop_exited, notify_write_loop_exited = Lwt.wait () in\n\n    let rec write_loop () =\n      let rec write_loop_step () =\n        match Server_connection.next_write_operation connection with\n        | `Write io_vectors ->\n          writev io_vectors >>= fun result ->\n          Server_connection.report_write_result connection result;\n          write_loop_step ()\n\n        | `Yield ->\n          Server_connection.yield_writer connection write_loop;\n          Lwt.return_unit\n\n        | `Close _ ->\n          Lwt.wakeup_later notify_write_loop_exited ();\n          if not (Lwt_unix.state socket = Lwt_unix.Closed) then begin\n            shutdown socket Unix.SHUTDOWN_SEND\n          end;\n          Lwt.return_unit\n      in\n\n      Lwt.async (fun () ->\n        Lwt.catch\n          write_loop_step\n          (fun exn ->\n            Server_connection.report_exn connection exn;\n            Lwt.return_unit))\n    in\n\n\n    read_loop ();\n    write_loop ();\n    Lwt.join [read_loop_exited; write_loop_exited] >>= fun () ->\n\n    if Lwt_unix.state socket <> Lwt_unix.Closed then\n      Lwt.catch\n        (fun () -> Lwt_unix.close socket)\n        (fun _exn -> Lwt.return_unit)\n    else\n      Lwt.return_unit\n\n  let create_connection_handler ?(config=Config.default) ~request_handler ~error_handler =\n    fun client_addr socket ->\n      let connection =\n        Server_connection.create\n          ~config\n          ~error_handler:(error_handler client_addr)\n          (request_handler client_addr)\n      in\n      start_read_write_loops ~config ~socket connection\n\n  module TLS = struct\n    let create_connection_handler\n      ?server\n      ?certfile\n      ?keyfile\n      ?(config=Config.default)\n      ~request_handler\n      ~error_handler =\n      let make_tls_server = Tls_io.make_server ?server ?certfile ?keyfile in\n      fun client_addr socket ->\n        let connection =\n          Server_connection.create\n            ~config\n            ~error_handler:(error_handler client_addr)\n            (request_handler client_addr)\n        in\n        make_tls_server socket >>= fun tls_server ->\n        let readf = Tls_io.readf tls_server in\n        let writev = Tls_io.writev tls_server in\n        start_read_write_loops ~config ~readf ~writev ~socket connection\n        >>= Lwt.return\n  end\n\n  module SSL = struct\n    let create_connection_handler\n      ?server\n      ?certfile\n      ?keyfile\n      ?(config=Config.default)\n      ~request_handler\n      ~error_handler =\n      let make_ssl_server = Ssl_io.make_server ?server ?certfile ?keyfile in\n      fun client_addr socket ->\n        let connection =\n          Server_connection.create\n            ~config\n            ~error_handler:(error_handler client_addr)\n            (request_handler client_addr)\n        in\n        make_ssl_server socket >>= fun tls_server ->\n        let readf = Ssl_io.readf tls_server in\n        let writev = Ssl_io.writev tls_server in\n        start_read_write_loops ~config ~readf ~writev ~socket connection\n        >>= Lwt.return\n  end\nend\n\n\n\nmodule Client = struct\n  module Client_connection = Httpaf.Client_connection\n\n  let start_read_write_loops\n    ?(readf=read)\n    ?(writev=Faraday_lwt_unix.writev_of_fd)\n    ~config\n    ~socket\n    connection =\n    let read_buffer = Buffer.create config.Config.read_buffer_size in\n    let read_loop_exited, notify_read_loop_exited = Lwt.wait () in\n\n    let read_loop () =\n      let rec read_loop_step () =\n        match Client_connection.next_read_operation connection with\n        | `Read ->\n          readf socket read_buffer >>= begin function\n          | `Eof ->\n            Buffer.get read_buffer ~f:(fun bigstring ~off ~len ->\n              Client_connection.read_eof connection bigstring ~off ~len)\n            |> ignore;\n            read_loop_step ()\n          | `Ok _ ->\n            Buffer.get read_buffer ~f:(fun bigstring ~off ~len ->\n              Client_connection.read connection bigstring ~off ~len)\n            |> ignore;\n            read_loop_step ()\n          end\n\n        | `Close ->\n          Lwt.wakeup_later notify_read_loop_exited ();\n          if not (Lwt_unix.state socket = Lwt_unix.Closed) then begin\n            shutdown socket Unix.SHUTDOWN_RECEIVE\n          end;\n          Lwt.return_unit\n      in\n\n      Lwt.async (fun () ->\n        Lwt.catch\n          read_loop_step\n          (fun exn ->\n            Client_connection.report_exn connection exn;\n            Lwt.return_unit))\n    in\n\n\n    let writev = writev socket in\n    let write_loop_exited, notify_write_loop_exited = Lwt.wait () in\n\n    let rec write_loop () =\n      let rec write_loop_step () =\n        match Client_connection.next_write_operation connection with\n        | `Write io_vectors ->\n          writev io_vectors >>= fun result ->\n          Client_connection.report_write_result connection result;\n          write_loop_step ()\n\n        | `Yield ->\n          Client_connection.yield_writer connection write_loop;\n          Lwt.return_unit\n\n        | `Close _ ->\n          Lwt.wakeup_later notify_write_loop_exited ();\n          Lwt.return_unit\n      in\n\n      Lwt.async (fun () ->\n        Lwt.catch\n          write_loop_step\n          (fun exn ->\n            Client_connection.report_exn connection exn;\n            Lwt.return_unit))\n    in\n\n\n    read_loop ();\n    write_loop ();\n\n    Lwt.async (fun () ->\n      Lwt.join [read_loop_exited; write_loop_exited] >>= fun () ->\n\n      if Lwt_unix.state socket <> Lwt_unix.Closed then\n        Lwt.catch\n          (fun () -> Lwt_unix.close socket)\n          (fun _exn -> Lwt.return_unit)\n      else\n        Lwt.return_unit)\n\n  let request ?(config=Config.default) socket request ~error_handler ~response_handler =\n    let request_body, connection =\n      Client_connection.request ~config request ~error_handler ~response_handler\n    in\n\n    start_read_write_loops ~config ~socket connection;\n    request_body\n\n  module TLS = struct\n    let request ?client ?(config=Config.default) socket request ~error_handler ~response_handler =\n      let request_body, connection =\n        Client_connection.request ~config request ~error_handler ~response_handler\n      in\n\n      Lwt.async(fun () ->\n        Tls_io.make_client ?client socket >|= fun tls_client ->\n        let readf = Tls_io.readf tls_client in\n        let writev = Tls_io.writev tls_client in\n\n        start_read_write_loops ~config ~readf ~writev ~socket connection);\n      request_body\n  end\n\n  module SSL = struct\n    let request ?client ?(config=Config.default) socket request ~error_handler ~response_handler =\n      let request_body, connection =\n        Client_connection.request ~config request ~error_handler ~response_handler\n      in\n\n      Lwt.async(fun () ->\n        Ssl_io.make_client ?client socket >|= fun tls_client ->\n        let readf = Ssl_io.readf tls_client in\n        let writev = Ssl_io.writev tls_client in\n\n        start_read_write_loops ~config ~readf ~writev ~socket connection);\n      request_body\n  end\nend\n"
  },
  {
    "path": "3rdparty/httpaf-lwt-unix/httpaf_lwt_unix.mli",
    "content": "open Httpaf\n\n\n(* The function that results from [create_connection_handler] should be passed\n   to [Lwt_io.establish_server_with_client_socket]. For an example, see\n   [examples/lwt_echo_server.ml]. *)\nmodule Server : sig\n  val create_connection_handler\n    :  ?config         : Config.t\n    -> request_handler : (Unix.sockaddr -> Server_connection.request_handler)\n    -> error_handler   : (Unix.sockaddr -> Server_connection.error_handler)\n    -> Unix.sockaddr\n    -> Lwt_unix.file_descr\n    -> unit Lwt.t\n\n  module TLS : sig\n    val create_connection_handler\n      :  ?server         : Tls_io.server\n      -> ?certfile       : string\n      -> ?keyfile        : string\n      -> ?config         : Config.t\n      -> request_handler : (Unix.sockaddr -> Server_connection.request_handler)\n      -> error_handler   : (Unix.sockaddr -> Server_connection.error_handler)\n      -> Unix.sockaddr\n      -> Lwt_unix.file_descr\n      -> unit Lwt.t\n  end\n\n  module SSL : sig\n    val create_connection_handler\n      :  ?server         : Ssl_io.server\n      -> ?certfile       : string\n      -> ?keyfile        : string\n      -> ?config         : Config.t\n      -> request_handler : (Unix.sockaddr -> Server_connection.request_handler)\n      -> error_handler   : (Unix.sockaddr -> Server_connection.error_handler)\n      -> Unix.sockaddr\n      -> Lwt_unix.file_descr\n      -> unit Lwt.t\n  end\nend\n\n(* For an example, see [examples/lwt_get.ml]. *)\nmodule Client : sig\n  val request\n    :  ?config          : Config.t\n    -> Lwt_unix.file_descr\n    -> Request.t\n    -> error_handler    : Client_connection.error_handler\n    -> response_handler : Client_connection.response_handler\n    -> [`write] Body.t\n\n  module TLS : sig\n    val request\n      :  ?client          : Tls_io.client\n      -> ?config          : Config.t\n      -> Lwt_unix.file_descr\n      -> Request.t\n      -> error_handler    : Client_connection.error_handler\n      -> response_handler : Client_connection.response_handler\n      -> [`write] Body.t\n  end\n\n  module SSL : sig\n    val request\n      :  ?client          : Ssl_io.client\n      -> ?config          : Config.t\n      -> Lwt_unix.file_descr\n      -> Request.t\n      -> error_handler    : Client_connection.error_handler\n      -> response_handler : Client_connection.response_handler\n      -> [`write] Body.t\n  end\nend\n"
  },
  {
    "path": "3rdparty/httpaf-lwt-unix/ssl_io.ml",
    "content": "open Lwt.Infix\n\nlet () = Ssl.init ()\n\nlet readf socket =\n  fun _fd buffer ->\n  Lwt.catch\n    (fun () ->\n      Buffer.put buffer ~f:(fun bigstring ~off ~len ->\n        Lwt_unix.blocking (Lwt_ssl.get_fd socket) >>= fun _ ->\n        Lwt_ssl.read_bytes socket bigstring off len))\n    (function\n    | Unix.Unix_error (Unix.EBADF, _, _) as exn ->\n      Lwt.fail exn\n    | exn ->\n      Lwt.async (fun () ->\n        Lwt_ssl.ssl_shutdown socket >>= fun () ->\n        Lwt_ssl.close socket);\n      Lwt.fail exn)\n  >>= fun bytes_read ->\n    if bytes_read = 0 then\n      Lwt.return `Eof\n    else\n      Lwt.return (`Ok bytes_read)\n\nlet writev socket _fd =\n  fun iovecs ->\n  Lwt.catch\n    (fun () ->\n      Lwt_list.fold_left_s (fun acc {Faraday.buffer; off; len} ->\n        Lwt_ssl.write_bytes socket buffer off len\n        >|= fun written -> acc + written) 0 iovecs\n      >|= fun n -> `Ok n)\n    (function\n    | Unix.Unix_error (Unix.EBADF, \"check_descriptor\", _) ->\n      Lwt.return `Closed\n    | exn ->\n      Lwt.fail exn)\n\ntype client = Lwt_ssl.socket\ntype server = Lwt_ssl.socket\n\nlet make_client ?client socket =\n  match client with\n  | Some client -> Lwt.return client\n  | None ->\n    let client_ctx = Ssl.create_context Ssl.SSLv23 Ssl.Client_context in\n    Ssl.disable_protocols client_ctx [Ssl.SSLv23];\n    Ssl.honor_cipher_order client_ctx;\n    Lwt_ssl.ssl_connect socket client_ctx\n\nlet make_server ?server ?certfile ?keyfile socket\n  =\n  match server, certfile, keyfile with\n  | Some server, _, _ -> Lwt.return server\n  | None, Some cert, Some priv_key ->\n    let server_ctx = Ssl.create_context Ssl.SSLv23 Ssl.Server_context in\n    Ssl.disable_protocols server_ctx [Ssl.SSLv23];\n    Ssl.use_certificate server_ctx cert priv_key;\n    Lwt_ssl.ssl_accept socket server_ctx\n  | _ ->\n    Lwt.fail (Invalid_argument \"Certfile and Keyfile required when server isn't provided\")\n"
  },
  {
    "path": "3rdparty/httpaf-lwt-unix/tls_io.ml",
    "content": "let readf _tls =\n  fun _fd _buffer ->\n  Lwt.fail_with \"Tls not available\"\n\nlet writev _tls _fd =\n  fun _iovecs ->\n  Lwt.fail_with \"Tls not available\"\n\ntype client = [ `Tls_not_available ]\ntype server = [ `Tls_not_available ]\n\nlet[@ocaml.warning \"-21\"] make_client ?client:_ =\n  failwith \"TLS not available\";\n  fun _socket -> Lwt.return `Tls_not_available\n\nlet[@ocaml.warning \"-21\"] make_server ?server:_ ?certfile:_ ?keyfile:_ =\n  failwith \"TLS not available\";\n  fun _socket -> Lwt.fail_with \"TLS not available\"\n"
  },
  {
    "path": "3rdparty/httpaf-lwt-unix.opam",
    "content": ""
  },
  {
    "path": "README.md",
    "content": "# ⚡️HttpKit — high-level, high-performance HTTP1.1/2 clients/servers in Reason\n\n> NOTE: under heavy reconstruction. Latest stable version was [`660d1c8`](https://github.com/ostera/httpkit/tree/660d1c8b7438d207be2717495d8590a529bf5a1f)\n\nHttpKit is a high-level library for building and consuming web servers over\nHTTP, HTTPS, and HTTP2.\n\nIt serves as a thin layer over `h2` and `http/af`, and when it can it allows you\nto seamlessly transition from one to the other.\n\n0. [Roadmap](#roadmap)\n1. [Getting Started](#getting-started)\n1. [Running the Examples](#running-the-examples)\n\n## Roadmap\n\n| Feature          | HTTP/1.1 | HTTPS/1.1 | HTTP/2 | HTTPS/2 |\n|------------------|----------|-----------|--------|---------|\n| Listen as Server | Yes      | No        | Yes    | No      |\n| Send Request     | Yes      | Yes       | No     | No      |\n| Server Push      | -        | -         | No     | No      |\n|                  |          |           |        |         |\n\n## Getting Started\n\n#### Usage\n\n`httpkit` can be used both to build servers and to make requests as a client.\n\nDocumentation is still a work-in-progress, but there's examples in the\n`examples` section that can give you a better idea of how to use the libraries.\nIn short:\n\nFor making a request:\n\n```reason\nopen Lwt_result.Infix;\n\nmodule Httpkit = Httpkit_lwt_unix_httpaf;\n\nlet req =\n  Httpkit.Request.create(\n    ~headers=[(\"User-Agent\", \"Reason HttpKit\")],\n    `GET,\n    Uri.of_string(\"http://api.github.com/repos/ostera/httpkit\"),\n  );\n\n/* Send over HTTP */\nreq\n|> Httpkit.Client.Http.send\n>>= Httpkit.Client.Response.body\n|> Lwt_main.run\n\n/* Send over HTTPS */\nreq\n|> Httpkit.Client.Https.send\n>>= Httpkit.Client.Response.body\n|> Lwt_main.run\n```\n\nFor making a server:\n\n```reason\nmodule Httpkit = Httpkit_lwt_unix_httpaf;\n\nlet port = 8080;\n\nlet on_start = (~hoststring) =>\n  Logs.app(m => m(\"Running on %s\", hoststring));\n\nlet handler: Httpkit.Server.handler =\n  (req, reply, kill_server) => {\n    let method = req |> Httpkit.Request.meth |> H2.Method.to_string;\n    let path = req |> Httpkit.Request.path;\n    Logs.app(m => m(\"%s %s\", method, path));\n    reply(200, \"hi\");\n    kill_server();\n  };\n\n/* Start server over HTTP */\nHttpkit.Server.Http.listen(~port, ~address=`Any, ~handler, ~on_start)\n|> Lwt_main.run;\n\n/* Start server over HTTPS */\nHttpkit.Server.Http.listen(~port, ~address=`Any, ~handler, ~on_start)\n|> Lwt_main.run;\n```\n\n#### Installing with esy\n\nYou can install by dropping the following dependencies in your `package.json`:\n\n```json\n{\n  \"dependencies\": {\n    \"@opam/httpkit\": \"*\",\n    \"@opam/httpkit-lwt-unix-httpaf\": \"*\",\n    \"@opam/logs\": \"*\",\n    \"@opam/fmt\": \"*\",\n    // ...\n  },\n  \"resolutions\": {\n    \"@opam/httpkit\": \"ostera/httpkit:httpkit.opam#f738417\",\n    \"@opam/httpkit-lwt-unix-httpaf\": \"ostera/httpkit:httpkit-lwt-unix-httpaf.opam#f738417\",\n  }\n}\n```\n\n> NOTE: For `httpkit` make sure you're using the latest commit hash!\n\n## Running the Examples\n\nAll of the examples are runnable as binaries after compilation, so you can\neither run `esy build` and find them within\n`./_esy/default/build/default/examples/*.exe` or you can ask dune to run them\nfor you:\n\n```sh\nostera/httpkit λ esy dune exec ./examples/Request.exe\n```\n"
  },
  {
    "path": "bench/.gitignore",
    "content": "echo\n"
  },
  {
    "path": "bench/Gemfile",
    "content": "source \"https://rubygems.org\"\n\ngem \"rack\"\n"
  },
  {
    "path": "bench/README.md",
    "content": "# Benchmarking HttpKit ⚡️\n\nIn order to ensure that `httpkit` stays fast, here you'll find a number of small\nservers written in other languages to benchmark against.\n\nThey should all do the same thing:\n\n1. Log down the time, method and path\n2. Reply with the path\n\nThey will all be called with the same command:\n\n```sh\nwrk2 \\\n  --threads=12 \\\n  --connections=400 \\\n  --duration=30s \\\n  --rate 30K\n  https://localhost:8080/bench-it-chewie!\n```\n## Results\n\n| Lang    | Lib                 |   KB/s   | RPS   | Total Req |\n|---------|---------------------|----------|-------|-----------|\n| OCaml   | httpkit+http/af+lwt | 414.17KB | 10874 |   326230  |\n| OCaml   | http/af+lwt         | 414.76KB | 10890 |   326792  |\n| Ruby    | rack                | 149.70KB |   806 |    24349  |\n| Node.js | stdlib http         | 591.80KB |  5179 |   155767  |\n| Golang  | stdlib http         |   0.95MB | 13314 |   399390  |\n| Python  | BaseHTTPServer      |  65.50KB |   519 |    15704  |\n\n## Details\n\n### OCaml/httpkit+httpaf+lwt\n\n```sh\nostera/httpkit λ wrk2 --threads=12 --connections=400 --duration=30s --rate 30K http://localhost:9999/what\nRunning 30s test @ http://localhost:9999/what\n  12 threads and 400 connections\n  Thread calibration: mean lat.: 3092.528ms, rate sampling interval: 11714ms\n  Thread calibration: mean lat.: 3241.606ms, rate sampling interval: 12107ms\n  Thread calibration: mean lat.: 3183.128ms, rate sampling interval: 11763ms\n  Thread calibration: mean lat.: 3235.211ms, rate sampling interval: 12009ms\n  Thread calibration: mean lat.: 3109.703ms, rate sampling interval: 11780ms\n  Thread calibration: mean lat.: 3214.701ms, rate sampling interval: 12017ms\n  Thread calibration: mean lat.: 3174.243ms, rate sampling interval: 11862ms\n  Thread calibration: mean lat.: 3067.300ms, rate sampling interval: 11575ms\n  Thread calibration: mean lat.: 3066.558ms, rate sampling interval: 11755ms\n  Thread calibration: mean lat.: 3101.464ms, rate sampling interval: 11722ms\n  Thread calibration: mean lat.: 3084.410ms, rate sampling interval: 11829ms\n  Thread calibration: mean lat.: 3075.844ms, rate sampling interval: 11444ms\n  Thread Stats   Avg      Stdev     Max   +/- Stdev\n    Latency    12.87s     3.62s   20.76s    58.95%\n    Req/Sec     0.92k    18.58     0.95k    58.33%\n  326230 requests in 30.00s, 12.13MB read\n  Socket errors: connect 0, read 40, write 3, timeout 4\nRequests/sec:  10874.67\nTransfer/sec:    414.17KB\n```\n\n### OCaml/httpaf+lwt\n\n```sh\nostera/httpkit λ wrk2 --threads=12 --connections=400 --duration=30s --rate 30K http://localhost:9999/what\nRunning 30s test @ http://localhost:9999/what\n  12 threads and 400 connections\n  Thread calibration: mean lat.: 3103.933ms, rate sampling interval: 11304ms\n  Thread calibration: mean lat.: 3074.874ms, rate sampling interval: 11141ms\n  Thread calibration: mean lat.: 3190.094ms, rate sampling interval: 11370ms\n  Thread calibration: mean lat.: 2974.283ms, rate sampling interval: 10543ms\n  Thread calibration: mean lat.: 2987.974ms, rate sampling interval: 11091ms\n  Thread calibration: mean lat.: 2895.381ms, rate sampling interval: 10919ms\n  Thread calibration: mean lat.: 2908.596ms, rate sampling interval: 10870ms\n  Thread calibration: mean lat.: 3164.646ms, rate sampling interval: 11526ms\n  Thread calibration: mean lat.: 3000.368ms, rate sampling interval: 11182ms\n  Thread calibration: mean lat.: 3051.481ms, rate sampling interval: 11386ms\n  Thread calibration: mean lat.: 3005.150ms, rate sampling interval: 11165ms\n  Thread calibration: mean lat.: 2956.432ms, rate sampling interval: 10960ms\n  Thread Stats   Avg      Stdev     Max   +/- Stdev\n    Latency    12.55s     3.75s   21.20s    59.01%\n    Req/Sec     0.91k    15.95     0.95k    75.00%\n  326792 requests in 30.01s, 12.15MB read\n  Socket errors: connect 0, read 97, write 4, timeout 11\nRequests/sec:  10890.16\nTransfer/sec:    414.76KB\n```\n\n### Ruby/Rack\n\n```sh\nostera/httpkit λ wrk2 --threads=12 --connections=400 --duration=30s --rate 30K http://localhost:8080/bench-it-chewie!\nRunning 30s test @ http://localhost:8080/bench-it-chewie!\n  12 threads and 400 connections\n  Thread calibration: mean lat.: 4611.970ms, rate sampling interval: 16515ms\n  Thread calibration: mean lat.: 4602.015ms, rate sampling interval: 16154ms\n  Thread calibration: mean lat.: 4654.559ms, rate sampling interval: 16613ms\n  Thread calibration: mean lat.: 4516.088ms, rate sampling interval: 16179ms\n  Thread calibration: mean lat.: 4601.379ms, rate sampling interval: 16269ms\n  Thread calibration: mean lat.: 4900.919ms, rate sampling interval: 16449ms\n  Thread calibration: mean lat.: 4552.994ms, rate sampling interval: 16523ms\n  Thread calibration: mean lat.: 9223372036854776.000ms, rate sampling interval: 10ms\n  Thread calibration: mean lat.: 9223372036854776.000ms, rate sampling interval: 10ms\n  Thread calibration: mean lat.: 9223372036854776.000ms, rate sampling interval: 10ms\n  Thread calibration: mean lat.: 9223372036854776.000ms, rate sampling interval: 10ms\n  Thread calibration: mean lat.: 4669.880ms, rate sampling interval: 16556ms\n  Thread Stats   Avg      Stdev     Max   +/- Stdev\n    Latency    17.89s     5.12s   27.25s    57.47%\n    Req/Sec     0.11      3.31   108.00     99.89%\n  24349 requests in 30.18s, 4.41MB read\n  Socket errors: connect 0, read 0, write 0, timeout 4276\nRequests/sec:    806.78\nTransfer/sec:    149.70KB\n```\n\n### Node/Http\n\n```sh\nostera/httpkit λ wrk2 --threads=12 --connections=400 --duration=30s --rate 30K http://localhost:8080/bench-it-chewie!\nRunning 30s test @ http://localhost:8080/bench-it-chewie!\n  12 threads and 400 connections\n  Thread calibration: mean lat.: 3976.372ms, rate sampling interval: 13983ms\n  Thread calibration: mean lat.: 4418.043ms, rate sampling interval: 15417ms\n  Thread calibration: mean lat.: 4419.606ms, rate sampling interval: 15417ms\n  Thread calibration: mean lat.: 4413.743ms, rate sampling interval: 15409ms\n  Thread calibration: mean lat.: 4421.132ms, rate sampling interval: 15417ms\n  Thread calibration: mean lat.: 4418.656ms, rate sampling interval: 15417ms\n  Thread calibration: mean lat.: 4422.277ms, rate sampling interval: 15417ms\n  Thread calibration: mean lat.: 4420.156ms, rate sampling interval: 15409ms\n  Thread calibration: mean lat.: 4420.646ms, rate sampling interval: 15409ms\n  Thread calibration: mean lat.: 3972.669ms, rate sampling interval: 13885ms\n  Thread calibration: mean lat.: 4421.550ms, rate sampling interval: 15417ms\n  Thread calibration: mean lat.: 3966.959ms, rate sampling interval: 13877ms\n  Thread Stats   Avg      Stdev     Max   +/- Stdev\n    Latency    16.14s     4.73s   24.72s    56.45%\n    Req/Sec   456.33      0.75   458.00    100.00%\n  155767 requests in 30.07s, 17.38MB read\n  Socket errors: connect 0, read 1, write 0, timeout 0\nRequests/sec:   5179.50\nTransfer/sec:    591.80KB\n```\n\n### Golang/Http\n\nThe golang standard library `http` module seems flexible enough for us to build\nan incredibly fast echo server! Closer to 3 times faster than node's, and around\n2000 requests per second more than `httpkit`.\n\nIf the superior type-safety offered by `httpkit` is not what you're looking for,\nhave a look at this:\n\n```sh\nostera/httpkit λ wrk2 --threads=12 --connections=400 --duration=30s --rate 30K http://localhost:8080/bench-it-chewie!\nRunning 30s test @ http://localhost:8080/bench-it-chewie!\n  12 threads and 400 connections\n  Thread calibration: mean lat.: 2694.872ms, rate sampling interval: 9592ms\n  Thread calibration: mean lat.: 2674.729ms, rate sampling interval: 9551ms\n  Thread calibration: mean lat.: 2644.030ms, rate sampling interval: 9437ms\n  Thread calibration: mean lat.: 2680.816ms, rate sampling interval: 9568ms\n  Thread calibration: mean lat.: 2667.644ms, rate sampling interval: 9502ms\n  Thread calibration: mean lat.: 2691.502ms, rate sampling interval: 9560ms\n  Thread calibration: mean lat.: 2490.139ms, rate sampling interval: 8781ms\n  Thread calibration: mean lat.: 2652.057ms, rate sampling interval: 9461ms\n  Thread calibration: mean lat.: 2665.217ms, rate sampling interval: 9519ms\n  Thread calibration: mean lat.: 2687.348ms, rate sampling interval: 9584ms\n  Thread calibration: mean lat.: 2697.834ms, rate sampling interval: 9560ms\n  Thread calibration: mean lat.: 2684.353ms, rate sampling interval: 9519ms\n  Thread Stats   Avg      Stdev     Max   +/- Stdev\n    Latency    11.02s     3.20s   17.10s    58.01%\n    Req/Sec     1.09k    23.03     1.12k    62.50%\n  399390 requests in 30.00s, 28.57MB read\nRequests/sec:  13314.83\nTransfer/sec:      0.95MB\n```\n\n### Python/BaseHTTPServer\n\n```sh\nostera/httpkit λ wrk2 --threads=12 --connections=400 --duration=30s --rate 30K http://localhost:8080/bench-it-chewie!\nRunning 30s test @ http://localhost:8080/bench-it-chewie!\n  12 threads and 400 connections\n  Thread calibration: mean lat.: 4190.046ms, rate sampling interval: 14639ms\n  Thread calibration: mean lat.: 4269.527ms, rate sampling interval: 14483ms\n  Thread calibration: mean lat.: 4213.688ms, rate sampling interval: 15704ms\n  Thread calibration: mean lat.: 3632.081ms, rate sampling interval: 14434ms\n  Thread calibration: mean lat.: 3932.717ms, rate sampling interval: 13344ms\n  Thread calibration: mean lat.: 4980.591ms, rate sampling interval: 15450ms\n  Thread calibration: mean lat.: 3027.887ms, rate sampling interval: 12361ms\n  Thread calibration: mean lat.: 4010.051ms, rate sampling interval: 12828ms\n  Thread calibration: mean lat.: 4807.472ms, rate sampling interval: 18104ms\n  Thread calibration: mean lat.: 4543.476ms, rate sampling interval: 14524ms\n  Thread calibration: mean lat.: 4214.574ms, rate sampling interval: 14008ms\n  Thread calibration: mean lat.: 4466.553ms, rate sampling interval: 16506ms\n  Thread Stats   Avg      Stdev     Max   +/- Stdev\n    Latency    10.99s     2.92s   20.97s    63.93%\n    Req/Sec     6.50      1.89    10.00     91.67%\n  15704 requests in 30.20s, 1.93MB read\n  Socket errors: connect 0, read 1533, write 57, timeout 4489\nRequests/sec:    519.94\nTransfer/sec:     65.50KB\n```\n\n### Lua/http\n### Rust/hyper+tokio\n"
  },
  {
    "path": "bench/echo.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"log\"\n\t\"net/http\"\n)\n\nconst DefaultPort = \"8080\"\n\nfunc EchoHandler(writer http.ResponseWriter, request *http.Request) {\n\tstamp := request.Method + \" \" + request.URL.Path\n\tlog.Println(stamp)\n\tbuf := bytes.NewBufferString(request.URL.Path)\n\trequest.Write(buf)\n}\n\nfunc main() {\n\tlog.Println(\"Listening on port \" + DefaultPort)\n\thttp.HandleFunc(\"/\", EchoHandler)\n\thttp.ListenAndServe(\":\"+DefaultPort, nil)\n}\n"
  },
  {
    "path": "bench/echo.js",
    "content": "const httpServer = require('http');\n\nhttpServer.createServer((req, res) => {\n  console.log(new Date(), req.method, req.url);\n  res.end(req.url);\n})\n.listen(8080, () => console.log(\"Server started...\"));;\n"
  },
  {
    "path": "bench/echo.py",
    "content": "from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer\n\nPORT_NUMBER = 8080\n\nclass handler(BaseHTTPRequestHandler):\n    def do_GET(self):\n        self.send_response(200)\n        self.send_header('Content-Length',len(self.path))\n        self.end_headers()\n        self.wfile.write(self.path)\n        return\n\nserver = HTTPServer(('', PORT_NUMBER), handler)\nprint 'Listening on port ' , PORT_NUMBER\nserver.serve_forever()\n"
  },
  {
    "path": "bench/echo.rb",
    "content": "require 'rack'\n \napp = Proc.new do |env|\n  req = Rack::Request.new(env)\n  meth = req.request_method\n  path = req.path\n  now = Time.now\n  puts \"#{now} - #{meth} #{path}\"\n  ['200', {'Content-Type' => 'text/html'}, [path]]\nend\n \nRack::Handler::WEBrick.run app\n"
  },
  {
    "path": "dune-project",
    "content": "(lang dune 1.5)\n(name httpkit)\n(using fmt 1.0)\n"
  },
  {
    "path": "esy.json",
    "content": "{\n  \"dependencies\": {\n    \"@esy-ocaml/reason\": \"3.4.0\",\n    \"@opam/dune\": \"*\",\n    \"@opam/fmt\": \"*\",\n    \"@opam/h2\": \"0.2.0\",\n    \"@opam/h2-lwt\": \"0.2.0\",\n    \"@opam/h2-lwt-unix\": \"0.2.0\",\n    \"@opam/httpaf\": \"*\",\n    \"@opam/logs\": \"*\",\n    \"@opam/lwt\": \"4.2.1\",\n    \"@opam/lwt_ssl\": \"1.1.2\",\n    \"@opam/merlin\": \"*\",\n    \"@opam/odoc\": \"*\",\n    \"@opam/uri\": \"*\",\n    \"@opam/yojson\": \"*\",\n    \"ocaml\": \"~4.7.0\",\n    \"refmterr\": \"*\"\n  },\n  \"resolutions\": {\n    \"@opam/conf-libev\": \"esy-packages/libev:package.json#86d244e\",\n    \"@opam/conf-autoconf\": \"esy-packages/esy-autoconf:package.json#71a8836\",\n    \"@opam/conf-openssl\": {\n      \"source\": \"no-source:\",\n      \"override\": {\n        \"dependencies\": {\n          \"@opam/conf-pkg-config\": \"*\",\n          \"@esy-packages/esy-openssl\": \"esy-packages/esy-openssl#f6107d6\",\n          \"@opam/conf-autoconf\": \"*\"\n        }\n      }\n    },\n    \"@opam/httpaf\": \"anmonteiro/httpaf:httpaf.opam#6d2c80e3a16ecf85d74df76005ab68136457e111\",\n    \"@opam/ssl\": \"anmonteiro/ocaml-ssl:ssl.opam#b965d15\"\n  }\n}\n"
  },
  {
    "path": "examples/dune",
    "content": "(executable\n  (name request_http)\n  (modules request_http)\n\t(ocamlopt_flags -O3)\n  (libraries httpkit-lwt-unix-httpaf httpkit logs.fmt fmt.tty))\n\n(executable\n  (name request_http2)\n  (modules request_http2)\n\t(ocamlopt_flags -O3)\n  (libraries httpkit-lwt-unix-h2 httpkit logs.fmt fmt.tty))\n\n(executable\n  (name echo_server_http)\n  (modules echo_server_http)\n\t(ocamlopt_flags -O3)\n  (libraries httpkit-lwt-unix-httpaf httpkit logs.fmt fmt.tty))\n\n(executable\n  (name echo_server_http2)\n  (modules echo_server_http2)\n\t(ocamlopt_flags -O3)\n  (libraries httpkit-lwt-unix-h2 httpkit logs.fmt fmt.tty))\n"
  },
  {
    "path": "examples/echo_server_http.re",
    "content": "/** Handle sigpipe internally */\nSys.(set_signal(sigpipe, Signal_ignore));\n\n/** Setup loggers */\nFmt_tty.setup_std_outputs();\nLogs.set_level(Some(Logs.Debug));\nLogs.set_reporter(Logs_fmt.reporter());\n\nmodule Httpkit = Httpkit_lwt_unix_httpaf;\n\nlet port = 8080;\n\nlet on_start = (~hoststring) =>\n  Logs.app(m => m(\"Running on %s\", hoststring));\n\nlet handler: Httpkit.Server.handler =\n  (req, reply, close) => {\n    let method = req |> Httpkit.Request.meth |> H2.Method.to_string;\n    let path = req |> Httpkit.Request.path;\n    Logs.app(m => m(\"%s %s\", method, path));\n    reply(200, \"hi\");\n    close();\n  };\n\nHttpkit.Server.Http.listen(~port, ~address=`Any, ~handler, ~on_start)\n|> Lwt_main.run;\n"
  },
  {
    "path": "examples/echo_server_http2.re",
    "content": "/** Handle sigpipe internally */\nSys.(set_signal(sigpipe, Signal_ignore));\n\n/** Setup loggers */\nFmt_tty.setup_std_outputs();\nLogs.set_level(Some(Logs.Debug));\nLogs.set_reporter(Logs_fmt.reporter());\n\nmodule Httpkit = Httpkit_lwt_unix_h2;\n\nlet port = 8080;\n\nlet on_start = (~hoststring) =>\n  Logs.app(m => m(\"Running on %s\", hoststring));\n\nlet handler: Httpkit.Server.handler =\n  (req, reply, close) => {\n    let method = req |> Httpkit.Request.meth |> H2.Method.to_string;\n    let path = req |> Httpkit.Request.path;\n    Logs.app(m => m(\"%s %s\", method, path));\n    reply(200, \"hi\");\n    close();\n  };\n\nHttpkit.Server.Http.listen(~port, ~address=`Any, ~handler, ~on_start)\n|> Lwt_main.run;\n"
  },
  {
    "path": "examples/request_http.re",
    "content": "open Lwt_result.Infix;\n\n/** Handle sigpipe internally */\nSys.(set_signal(sigpipe, Signal_ignore));\n\n/** Setup loggers */\nFmt_tty.setup_std_outputs();\nLogs.set_level(Some(Logs.Debug));\nLogs.set_reporter(Logs_fmt.reporter());\n\nmodule Httpkit = Httpkit_lwt_unix_httpaf;\n\n/**\n  Sample HTTPS Request using No Authentication :tm:\n*/\n\nlet https_url = Sys.argv[1];\nLogs.app(m => m(\"Requesting: %s\", https_url));\nswitch (\n  Httpkit.Request.create(\n    ~headers=[\n      (\"User-Agent\", \"Reason HttpKit\"),\n      (\"Accept\", \"*/*\"),\n    ],\n    `GET,\n    https_url |> Uri.of_string,\n  )\n  |> Httpkit.Client.Https.send\n  >>= Httpkit.Client.Response.body\n  |> Lwt_main.run\n) {\n| exception e => Logs.err(m => m(\"%s\", Printexc.to_string(e)))\n| Ok(body) => Logs.app(m => m(\"Response: %s\", body))\n| Error(`Connection_error(`Invalid_response_body_length(req))) =>\n  let str = Buffer.create(1024);\n  let fmt = Format.formatter_of_buffer(str);\n  Httpaf.Response.pp_hum(fmt, req);\n  Logs.err(m =>\n    m(\n      \"Connection Error (Invalid response body length): %s\",\n      str |> Buffer.to_bytes |> Bytes.to_string,\n    )\n  );\n| Error(`Connection_error(`Malformed_response(str))) =>\n  Logs.err(m => m(\"Connection Error (Malformed response): %s\", str))\n| Error(`Connection_error(`Exn(ex))) =>\n  Logs.err(m =>\n    m(\"Connection Error (Exception): %s\", ex |> Printexc.to_string)\n  )\n};\n"
  },
  {
    "path": "examples/request_http2.re",
    "content": "open Lwt_result.Infix;\n\n/** Handle sigpipe internally */\nSys.(set_signal(sigpipe, Signal_ignore));\n\n/** Setup loggers */\nFmt_tty.setup_std_outputs();\nLogs.set_level(Some(Logs.Debug));\nLogs.set_reporter(Logs_fmt.reporter());\n\nmodule Httpkit = Httpkit_lwt_unix_h2;\n\n/**\n  Sample HTTPS Request using No Authentication :tm:\n*/\n\nlet https_url = Sys.argv[1];\nLogs.app(m => m(\"Requesting: %s\", https_url));\nswitch (\n  Httpkit.Request.create(`GET, https_url |> Uri.of_string)\n  |> Httpkit.Client.Https.send\n  >>= Httpkit.Client.Response.body\n  |> Lwt_main.run\n) {\n| exception e => Logs.err(m => m(\"%s\", Printexc.to_string(e)))\n| Ok(body) => Logs.app(m => m(\"Response: %s\", body))\n| Error(`Connection_error(`Invalid_response_body_length(req))) =>\n  let str = Buffer.create(1024);\n  let fmt = Format.formatter_of_buffer(str);\n  H2.Response.pp_hum(fmt, req);\n  Logs.err(m =>\n    m(\n      \"Connection Error (Invalid response body length): %s\",\n      str |> Buffer.to_bytes |> Bytes.to_string,\n    )\n  );\n| Error(`Connection_error(`Malformed_response(str))) =>\n  Logs.err(m => m(\"Connection Error (Malformed response): %s\", str))\n| Error(`Connection_error(`Exn(ex))) =>\n  Logs.err(m =>\n    m(\"Connection Error (Exception): %s\", ex |> Printexc.to_string)\n  )\n| Error(`Connection_error(`Protocol_error)) =>\n  Logs.err(m => m(\"Connection Error (Protocol Error)\"))\n};\n"
  },
  {
    "path": "httpkit-lwt-unix-h2.opam",
    "content": "opam-version: \"2.0\"\nname: \"httpkit-lwt-unix-h2\"\nversion: \"0.13\"\nsynopsis: \"High-level, High-performance HTTP(S) Clients/Servers with Lwt\"\nmaintainer: \"Leandro Ostera <leandro@ostera.io>\"\nauthors: \"Leandro Ostera <leandro@ostera.io>\"\nlicense: \"MIT\"\nhomepage: \"https//github.com/ostera/httpkit\"\nbug-reports: \"https//github.com/ostera/httpkit/issues\"\ndepends: [\n  \"httpkit\"\n  \"h2\"\n  \"h2-lwt\"\n  \"h2-lwt-unix\"\n  \"lwt\"\n  \"lwt_ssl\"\n  \"ssl\"\n  \"tls\"\n\n  \"dune\" {build}\n  \"reason\" {build}\n]\nbuild: [\"dune\" \"build\" \"-p\" name]\ninstall: [\"dune\" \"install\" name \"--prefix\" prefix \"--root\" \".\"]\n"
  },
  {
    "path": "httpkit-lwt-unix-httpaf.opam",
    "content": "opam-version: \"2.0\"\nname: \"httpkit-lwt-unix-httpaf\"\nversion: \"0.13\"\nsynopsis: \"High-level, High-performance HTTP(S) Clients/Servers with Lwt\"\nmaintainer: \"Leandro Ostera <leandro@ostera.io>\"\nauthors: \"Leandro Ostera <leandro@ostera.io>\"\nlicense: \"MIT\"\nhomepage: \"https//github.com/ostera/httpkit\"\nbug-reports: \"https//github.com/ostera/httpkit/issues\"\ndepends: [\n  \"httpkit\"\n  \"httpaf\"\n  \"httpaf-lwt-unix\"\n  \"lwt\"\n  \"ssl\"\n  \"tls\"\n\n  \"dune\" {build}\n  \"reason\" {build}\n]\nbuild: [\"dune\" \"build\" \"-p\" name]\ninstall: [\"dune\" \"install\" name \"--prefix\" prefix \"--root\" \".\"]\n"
  },
  {
    "path": "httpkit.opam",
    "content": "opam-version: \"2.0\"\nname: \"httpkit\"\nversion: \"0.13\"\nsynopsis: \"High-level, High-performance HTTP(S) Clients/Servers\"\nmaintainer: \"Leandro Ostera <leandro@ostera.io>\"\nauthors: \"Leandro Ostera <leandro@ostera.io>\"\nlicense: \"MIT\"\nhomepage: \"https//github.com/ostera/httpkit\"\nbug-reports: \"https//github.com/ostera/httpkit/issues\"\ndepends: [\n  \"logs\"\n  \"uri\"\n  \"httpaf\"\n  \"h2\"\n\n  \"dune\" {build}\n  \"reason\" {build}\n]\nbuild: [\"dune\" \"build\" \"-p\" name]\ninstall: [\"dune\" \"install\" name \"--prefix\" prefix \"--root\" \".\"]\n"
  },
  {
    "path": "lwt-unix-h2/client_http.re",
    "content": "open Lwt.Infix;\n\nlet send:\n  (~config: H2.Config.t=?, Httpkit.Request.t) =>\n  Lwt_result.t(\n    (H2.Response.t, H2.Body.t([ | `read])),\n    [> | `Connection_error(H2.Client_connection.error)],\n  ) =\n  (~config=H2.Config.default, req) => {\n    let uri = Httpkit.Request.uri(req);\n\n    let response_handler = (notify_response_received, response, response_body) => {\n      Logs.debug(m => m(\"Handling response...\"));\n      Lwt.wakeup_later(\n        notify_response_received,\n        (response, response_body) |> Lwt_result.return,\n      );\n    };\n\n    let error_handler = (notify_response_received, error) => {\n      Logs.debug(m => m(\"Handling errors...\"));\n      Lwt.wakeup_later(\n        notify_response_received,\n        `Connection_error(error) |> Lwt_result.fail,\n      );\n    };\n\n    let host = Uri.host_with_default(uri);\n    let port =\n      switch (Uri.port(uri)) {\n      | None => \"443\"\n      | Some(number) => string_of_int(number)\n      };\n\n    Lwt_unix.getaddrinfo(host, port, [Unix.(AI_FAMILY(PF_INET))])\n    >>= (\n      addresses => {\n        Logs.debug(m => m(\"Got address...\"));\n        let socket_addr = List.hd(addresses).Unix.ai_addr;\n        let socket = Lwt_unix.socket(Unix.PF_INET, Unix.SOCK_STREAM, 0);\n\n        Lwt_unix.connect(socket, socket_addr)\n        >>= (\n          () => {\n            Logs.debug(m => m(\"Opened socket...\"));\n            let (response_received, notify_response_received) = Lwt.wait();\n            let response_handler = response_handler(notify_response_received);\n            let error_handler = error_handler(notify_response_received);\n\n            let write_body = request_body => {\n              Logs.debug(m => m(\"Writing body...\"));\n              switch (Httpkit.Request.body(req)) {\n              | None => ()\n              | Some(str) => H2.Body.write_string(request_body, str)\n              };\n              H2.Body.close_writer(request_body);\n              Logs.debug(m => m(\"Closed writer...\"));\n              response_received >>= (x => x);\n            };\n\n            let request = Client_request.of_httpkit_request(req);\n\n            H2_lwt_unix.Client.create_connection(\n              ~config,\n              ~error_handler,\n              socket,\n            )\n            >>= (\n              connection => {\n                H2_lwt_unix.Client.request(\n                  connection,\n                  request,\n                  ~error_handler,\n                  ~response_handler,\n                )\n                |> write_body;\n              }\n            );\n          }\n        );\n      }\n    );\n  };\n"
  },
  {
    "path": "lwt-unix-h2/client_https.re",
    "content": "open Lwt.Infix;\n\nSsl_threads.init();\nSsl.init();\nlet default_ssl_context = Ssl.create_context(Ssl.SSLv23, Ssl.Client_context);\nSsl.disable_protocols(default_ssl_context, [Ssl.SSLv23]);\nSsl.set_context_alpn_protos(default_ssl_context, [\"h2\"]);\nSsl.honor_cipher_order(default_ssl_context);\n\nlet send:\n  (~config: H2.Config.t=?, Httpkit.Request.t) =>\n  Lwt_result.t(\n    (H2.Response.t, H2.Body.t([ | `read])),\n    [> | `Connection_error(H2.Client_connection.error)],\n  ) =\n  (~config=H2.Config.default, req) => {\n    let uri = Httpkit.Request.uri(req);\n\n    let response_handler = (notify_response_received, response, response_body) => {\n      Logs.debug(m => m(\"Handling response...\"));\n      Lwt.wakeup_later(\n        notify_response_received,\n        (response, response_body) |> Lwt_result.return,\n      );\n    };\n\n    let error_handler = (notify_response_received, error) => {\n      Logs.debug(m => m(\"Handling errors...\"));\n      Lwt.wakeup_later(\n        notify_response_received,\n        `Connection_error(error) |> Lwt_result.fail,\n      );\n    };\n\n    let host = Uri.host_with_default(uri);\n    let port =\n      switch (Uri.port(uri)) {\n      | None => \"443\"\n      | Some(number) => string_of_int(number)\n      };\n\n    Lwt_unix.getaddrinfo(host, port, [Unix.(AI_FAMILY(PF_INET))])\n    >>= (\n      addresses => {\n        let socket_addr = List.hd(addresses).Unix.ai_addr;\n        let socket = Lwt_unix.socket(Unix.PF_INET, Unix.SOCK_STREAM, 0);\n\n        Lwt_unix.connect(socket, socket_addr)\n        >>= (\n          () => {\n            Lwt_ssl.ssl_connect(socket, default_ssl_context)\n            >>= (\n              ssl_client => {\n                let (response_received, notify_response_received) =\n                  Lwt.wait();\n                let response_handler =\n                  response_handler(notify_response_received);\n                let error_handler = error_handler(notify_response_received);\n\n                let write_body = request_body => {\n                  switch (Httpkit.Request.body(req)) {\n                  | None => ()\n                  | Some(str) => H2.Body.write_string(request_body, str)\n                  };\n                  H2.Body.flush(\n                    request_body,\n                    () => {\n                      H2.Body.close_writer(request_body);\n                      Logs.debug(m => m(\"Closed body writer...\"));\n                    },\n                  );\n                  response_received >>= (x => x);\n                };\n\n                let request = Client_request.of_httpkit_request(req);\n\n                Logs.debug(m => {\n                  let buffer = Buffer.create(1024);\n                  let fmt = Format.formatter_of_buffer(buffer);\n                  H2.Request.pp_hum(fmt, request);\n                  m(\"%s\", buffer |> Buffer.contents);\n                });\n\n                let handle_ssl_connection = connection =>\n                  H2_lwt_unix.Client.SSL.request(\n                    connection,\n                    request,\n                    ~error_handler,\n                    ~response_handler,\n                  )\n                  |> write_body;\n\n                let connect = () =>\n                  H2_lwt_unix.Client.SSL.create_connection(\n                    ~client=ssl_client,\n                    ~config,\n                    ~error_handler,\n                    socket,\n                  );\n\n                connect() >>= handle_ssl_connection;\n              }\n            );\n          }\n        );\n      }\n    );\n  };\n"
  },
  {
    "path": "lwt-unix-h2/client_request.re",
    "content": "let of_httpkit_request = req => {\n  open Httpkit;\n  let host = req |> Request.host;\n  let scheme = req |> Request.scheme;\n  let meth = req |> Request.meth;\n  let path = req |> Request.path;\n\n  let headers =\n    [\n      (\":authority\", host),\n      (\":method\", meth |> Method.to_string),\n      (\":path\", path),\n      (\":scheme\", scheme),\n    ]\n    @ (req |> Request.headers)\n    |> H2.Headers.of_list;\n\n  H2.Request.create(~headers, ~scheme, meth, path);\n};\n\nlet to_httpkit_request = (~body, ~uri, req) => {\n  Httpkit.Request.create(\n    ~headers=req.H2.Request.headers |> H2.Headers.to_list,\n    ~body=\n      switch (body) {\n      | None => \"\"\n      | Some(b) => b\n      },\n    req.meth,\n    uri,\n  );\n};\n"
  },
  {
    "path": "lwt-unix-h2/client_response.re",
    "content": "let body:\n  ((H2.Response.t, H2.Body.t([ | `read]))) => Lwt.t(result(string, 'b)) =\n  ((_response, body)) => {\n    open Lwt.Infix;\n    let buffer = Buffer.create(1024);\n    Logs.debug(m => m(\"Buffering response...\"));\n    let (next, wakeup) = Lwt.wait();\n    Lwt.async(() => {\n      let rec read_response = () =>\n        H2.Body.schedule_read(\n          body,\n          ~on_eof=\n            () => Lwt.wakeup_later(wakeup, Ok(Buffer.contents(buffer))),\n          ~on_read=\n            (response_fragment, ~off, ~len) => {\n              let response_fragment_string = Bytes.create(len);\n              Lwt_bytes.blit_to_bytes(\n                response_fragment,\n                off,\n                response_fragment_string,\n                0,\n                len,\n              );\n              Buffer.add_bytes(buffer, response_fragment_string);\n              read_response();\n            },\n        );\n      read_response() |> Lwt.return;\n    })\n    |> ignore;\n    next >>= Lwt_result.lift;\n  };\n"
  },
  {
    "path": "lwt-unix-h2/dune",
    "content": "(library\n  (name httpkit_lwt_unix_h2)\n  (public_name httpkit-lwt-unix-h2)\n  (libraries httpkit h2 h2-lwt h2-lwt-unix lwt lwt.unix uri logs logs.lwt fpath bigstringaf))\n"
  },
  {
    "path": "lwt-unix-h2/httpkit_lwt_unix_h2.re",
    "content": "module Method = Httpkit.Method;\n\nmodule Status = Httpkit.Status;\n\nmodule Request = Httpkit.Request;\n\nmodule Server = {\n  include Httpkit.Server;\n  module Http = Server_http;\n};\n\nmodule Client = {\n  module Https = Client_https;\n  module Http = Client_http;\n  module Response = Client_response;\n};\n"
  },
  {
    "path": "lwt-unix-h2/server_http.re",
    "content": "open Lwt.Infix;\n\nlet make_request_handler:\n  (\n    ~uri: Uri.t,\n    ~handler: Httpkit.Server.handler,\n    ~closer: unit => unit,\n    Unix.sockaddr\n  ) =>\n  H2.Server_connection.request_handler =\n  (~uri, ~handler, ~closer, _client, reqd) => {\n    let req = reqd |> H2.Reqd.request;\n    Logs.debug(m => m(\"Handling request...\"));\n    let respond = (~headers=?, status, content) => {\n      let headers =\n        (\n          switch (headers) {\n          | None => []\n          | Some(hs) => hs\n          }\n        )\n        @ [(\"content-length\", content |> String.length |> string_of_int)]\n        |> H2.Headers.of_list;\n      let res =\n        H2.Response.create(status |> H2.Status.of_code, ~headers);\n      H2.Reqd.respond_with_string(reqd, res, content);\n    };\n    Server_request.read_body(reqd)\n    >|= (\n      body => {\n        let uri = Uri.with_path(uri, req.target);\n        let req = Client_request.to_httpkit_request(~uri, ~body, req);\n        let () = handler(req, respond, closer);\n        ();\n      }\n    )\n    |> ignore;\n  };\n\nlet error_handler = (_client, ~request as _=?, err, _get) => {\n  Logs.err(m =>\n    m(\n      \"Something went wrong! %s\",\n      switch (err) {\n      | `Bad_gateway => \"Bad gateway\"\n      | `Bad_request => \"Bad request\"\n      | `Internal_server_error => \"Internal_server_error\"\n      | `Exn(exn) => Printexc.to_string(exn)\n      },\n    )\n  );\n  ();\n};\n\nlet listen:\n  (\n    ~address: [ | `Loopback | `Any | `Of_string(string)]=?,\n    ~port: int,\n    ~on_start: (~hoststring: string) => unit,\n    ~handler: Httpkit.Server.handler\n  ) =>\n  Lwt.t(unit) =\n  (~address=`Any, ~port, ~on_start, ~handler) => {\n    let host =\n      switch (address) {\n      | `Loopback => \"127.0.0.1\"\n      | `Any => \"0.0.0.0\"\n      | `Of_string(str) => str\n      };\n    let uri = Uri.make(~scheme=\"http\", ~host, ~port, ());\n\n    let (forever, awaker) = Lwt.wait();\n    let closer = () => Lwt.wakeup_later(awaker, ());\n\n    let address =\n      switch (address) {\n      | `Loopback => Unix.inet_addr_loopback\n      | `Any => Unix.inet_addr_any\n      | `Of_string(str) => Unix.inet_addr_of_string(str)\n      };\n    let listening_address = Unix.(ADDR_INET(address, port));\n\n    let connection_handler =\n      H2_lwt_unix.Server.create_connection_handler(\n        ~config=H2.Config.default,\n        ~request_handler=make_request_handler(~uri, ~handler, ~closer),\n        ~error_handler,\n      );\n\n    Lwt_io.establish_server_with_client_socket(\n      listening_address,\n      connection_handler,\n    )\n    >|= (_ => on_start(~hoststring=Uri.to_string(uri)))\n    |> ignore;\n\n    forever;\n  };\n"
  },
  {
    "path": "lwt-unix-h2/server_request.re",
    "content": "let read_body = reqd => {\n  let (next, awake) = Lwt.wait();\n\n  Lwt.async(() => {\n    let body = reqd |> H2.Reqd.request_body;\n    let body_str = ref(\"\");\n    let on_eof = () => Lwt.wakeup_later(awake, Some(body_str^));\n    let rec on_read = (request_data, ~off, ~len) => {\n      let read = Bigstringaf.substring(~off, ~len, request_data);\n      body_str := body_str^ ++ read;\n      H2.Body.schedule_read(body, ~on_read, ~on_eof);\n    };\n    H2.Body.schedule_read(body, ~on_read, ~on_eof);\n    Lwt.return_unit;\n  });\n\n  next;\n};\n"
  },
  {
    "path": "lwt-unix-httpaf/client_http.re",
    "content": "open Lwt.Infix;\n\nlet send:\n  (~config: Httpaf.Config.t=?, Httpkit.Request.t) =>\n  Lwt_result.t(\n    (Httpaf.Response.t, Httpaf.Body.t([ | `read])),\n    [> | `Connection_error(Httpaf.Client_connection.error)],\n  ) =\n  (~config=Httpaf.Config.default, req) => {\n    let uri = Httpkit.Request.uri(req);\n\n    let response_handler = (notify_response_received, response, response_body) => {\n      Logs.debug(m => m(\"Handling response...\"));\n      Lwt.wakeup_later(\n        notify_response_received,\n        (response, response_body) |> Lwt_result.return,\n      );\n    };\n\n    let error_handler = (notify_response_received, error) => {\n      Logs.debug(m => m(\"Handling errors...\"));\n      Lwt.wakeup_later(\n        notify_response_received,\n        `Connection_error(error) |> Lwt_result.fail,\n      );\n    };\n\n    let host = Uri.host_with_default(uri);\n    let port =\n      switch (Uri.port(uri)) {\n      | None => \"80\"\n      | Some(number) => string_of_int(number)\n      };\n\n    Logs.debug(m => m(\"Getting address for %s:%s\", host, port));\n    Lwt_unix.getaddrinfo(host, port, [Unix.(AI_FAMILY(PF_INET))])\n    >>= (\n      addresses => {\n        let socket_addr = List.hd(addresses).Unix.ai_addr;\n        let socket = Lwt_unix.socket(Unix.PF_INET, Unix.SOCK_STREAM, 0);\n        Logs.debug(m => m(\"Opening socket to %s:%s\", host, port));\n        Lwt_unix.connect(socket, socket_addr)\n        >>= (\n          () => {\n            let (response_received, notify_response_received) = Lwt.wait();\n            let response_handler = response_handler(notify_response_received);\n            let error_handler = error_handler(notify_response_received);\n\n            let write_body = request_body => {\n              switch (Httpkit.Request.body(req)) {\n              | None => ()\n              | Some(str) => Httpaf.Body.write_string(request_body, str)\n              };\n              Httpaf.Body.close_writer(request_body);\n              Logs.debug(m => m(\"Request sent. Awaiting for response...\"));\n              response_received >>= (x => x);\n            };\n\n            let request = Client_request.of_httpkit_request(req);\n\n            Logs.debug(m =>\n              m(\"Sending request: \\n\\n%s\", req |> Httpkit.Request.to_string)\n            );\n            Httpaf_lwt_unix.Client.request(\n              ~config,\n              ~error_handler,\n              ~response_handler,\n              socket,\n              request,\n            )\n            |> write_body;\n          }\n        );\n      }\n    );\n  };\n"
  },
  {
    "path": "lwt-unix-httpaf/client_https.re",
    "content": "open Lwt.Infix;\n\ntype client_security = [\n  | `No_authentication\n];\n\nlet send:\n  (\n    ~config: Httpaf.Config.t=?,\n    ~client: client_security=?,\n    Httpkit.Request.t\n  ) =>\n  Lwt_result.t(\n    (Httpaf.Response.t, Httpaf.Body.t([ | `read])),\n    [> | `Connection_error(Httpaf.Client_connection.error)],\n  ) =\n  (~config=Httpaf.Config.default, ~client as _=`No_authentication, req) => {\n    let uri = Httpkit.Request.uri(req);\n\n    let response_handler = (notify_response_received, response, response_body) => {\n      Logs.debug(m => m(\"Handling response...\"));\n      Lwt.wakeup_later(\n        notify_response_received,\n        (response, response_body) |> Lwt_result.return,\n      );\n    };\n\n    let error_handler = (notify_response_received, error) => {\n      Logs.debug(m => m(\"Handling errors...\"));\n      Lwt.wakeup_later(\n        notify_response_received,\n        `Connection_error(error) |> Lwt_result.fail,\n      );\n    };\n\n    let host = Uri.host_with_default(uri);\n    let port =\n      switch (Uri.port(uri)) {\n      | None => \"443\"\n      | Some(number) => string_of_int(number)\n      };\n\n    Lwt_unix.getaddrinfo(host, port, [Unix.(AI_FAMILY(PF_INET))])\n    >>= (\n      addresses => {\n        Logs.debug(m => m(\"Got address...\"));\n        let socket_addr = List.hd(addresses).Unix.ai_addr;\n        let socket = Lwt_unix.socket(Unix.PF_INET, Unix.SOCK_STREAM, 0);\n\n        Lwt_unix.connect(socket, socket_addr)\n        >>= (\n          () => {\n            Logs.debug(m => m(\"Opened socket...\"));\n            let (response_received, notify_response_received) = Lwt.wait();\n            let response_handler = response_handler(notify_response_received);\n            let error_handler = error_handler(notify_response_received);\n\n            let write_body = request_body => {\n              Logs.debug(m => m(\"Writing body...\"));\n              switch (Httpkit.Request.body(req)) {\n              | None => ()\n              | Some(str) => Httpaf.Body.write_string(request_body, str)\n              };\n              Httpaf.Body.close_writer(request_body);\n              response_received >>= (x => x);\n            };\n\n            let request = Client_request.of_httpkit_request(req);\n\n            Httpaf_lwt_unix.Client.SSL.request(\n              ~config,\n              ~error_handler,\n              ~response_handler,\n              socket,\n              request\n            )\n            |> write_body\n          }\n        );\n      }\n    );\n  };\n"
  },
  {
    "path": "lwt-unix-httpaf/client_request.re",
    "content": "let of_httpkit_request = req => {\n  Httpkit.(\n    Httpaf.Request.create(\n      ~headers=req |> Request.headers |> Httpaf.Headers.of_list,\n      req |> Request.meth,\n      req |> Request.path,\n    )\n  );\n};\n\nlet to_httpkit_request = (~body, ~uri, req) => {\n  Httpkit.Request.create(\n    ~headers=req.Httpaf.Request.headers |> Httpaf.Headers.to_list,\n    ~body=\n      switch (body) {\n      | None => \"\"\n      | Some(b) => b\n      },\n    req.meth,\n    uri,\n  );\n};\n"
  },
  {
    "path": "lwt-unix-httpaf/client_response.re",
    "content": "let body:\n  ((Httpaf.Response.t, Httpaf.Body.t([ | `read]))) => Lwt_result.t(string, 'b) =\n  ((_response, body)) => {\n    open Lwt.Infix;\n    let buffer = Buffer.create(2048);\n    Logs.debug(m => m(\"Prepared buffer for response body...\"));\n    let (next, wakeup) = Lwt.wait();\n    Lwt.async(() => {\n      let rec read_response = () =>\n        Httpaf.Body.schedule_read(\n          body,\n          ~on_eof=\n            () => Lwt.wakeup_later(wakeup, Ok(Buffer.contents(buffer))),\n          ~on_read=\n            (response_fragment, ~off, ~len) => {\n              let response_fragment_string = Bytes.create(len);\n              Lwt_bytes.blit_to_bytes(\n                response_fragment,\n                off,\n                response_fragment_string,\n                0,\n                len,\n              );\n              Buffer.add_bytes(buffer, response_fragment_string);\n              read_response();\n            },\n        );\n      read_response() |> Lwt.return;\n    })\n    |> ignore;\n    next >>= Lwt_result.lift;\n  };\n"
  },
  {
    "path": "lwt-unix-httpaf/dune",
    "content": "(library\n  (name httpkit_lwt_unix_httpaf)\n  (public_name httpkit-lwt-unix-httpaf)\n  (libraries httpkit httpaf httpaf-lwt-unix lwt lwt.unix uri logs logs.lwt bigstringaf))\n"
  },
  {
    "path": "lwt-unix-httpaf/httpkit_lwt_unix_httpaf.re",
    "content": "module Method = Httpkit.Method;\n\nmodule Status = Httpkit.Status;\n\nmodule Request = Httpkit.Request;\n\nmodule Server = {\n  include Httpkit.Server;\n  module Http = Server_http;\n};\n\nmodule Client = {\n  module Https = Client_https;\n  module Http = Client_http;\n  module Response = Client_response;\n};\n"
  },
  {
    "path": "lwt-unix-httpaf/server_http.re",
    "content": "open Lwt.Infix;\n\nlet make_request_handler:\n  (\n    ~uri: Uri.t,\n    ~handler: Httpkit.Server.handler,\n    ~closer: unit => unit,\n    Unix.sockaddr\n  ) =>\n  Httpaf.Server_connection.request_handler =\n  (~uri, ~handler, ~closer, _client, reqd) => {\n    let req = reqd |> Httpaf.Reqd.request;\n    Logs.debug(m => m(\"Handling request...\"));\n    let respond = (~headers=?, status, content) => {\n      let headers =\n        (\n          switch (headers) {\n          | None => []\n          | Some(hs) => hs\n          }\n        )\n        @ [(\"content-length\", content |> String.length |> string_of_int)]\n        |> Httpaf.Headers.of_list;\n      let res =\n        Httpaf.Response.create(status |> Httpaf.Status.of_code, ~headers);\n      Httpaf.Reqd.respond_with_string(reqd, res, content);\n    };\n    Server_request.read_body(reqd)\n    >|= (\n      body => {\n        let uri = Uri.with_path(uri, req.target);\n        let req = Client_request.to_httpkit_request(~uri, ~body, req);\n        let () = handler(req, respond, closer);\n        ();\n      }\n    )\n    |> ignore;\n  };\n\nlet error_handler = (_client, ~request as _=?, err, _get) => {\n  Logs.err(m =>\n    m(\n      \"Something went wrong! %s\",\n      switch (err) {\n      | `Bad_gateway => \"Bad gateway\"\n      | `Bad_request => \"Bad request\"\n      | `Internal_server_error => \"Internal_server_error\"\n      | `Exn(exn) => Printexc.to_string(exn)\n      },\n    )\n  );\n  ();\n};\n\nlet listen:\n  (\n    ~address: [ | `Loopback | `Any | `Of_string(string)]=?,\n    ~port: int,\n    ~on_start: (~hoststring: string) => unit,\n    ~handler: Httpkit.Server.handler\n  ) =>\n  Lwt.t(unit) =\n  (~address=`Any, ~port, ~on_start, ~handler) => {\n    let host =\n      switch (address) {\n      | `Loopback => \"127.0.0.1\"\n      | `Any => \"0.0.0.0\"\n      | `Of_string(str) => str\n      };\n    let uri = Uri.make(~scheme=\"http\", ~host, ~port, ());\n\n    let (forever, awaker) = Lwt.wait();\n    let closer = () => Lwt.wakeup_later(awaker, ());\n\n    let address =\n      switch (address) {\n      | `Loopback => Unix.inet_addr_loopback\n      | `Any => Unix.inet_addr_any\n      | `Of_string(str) => Unix.inet_addr_of_string(str)\n      };\n    let listening_address = Unix.(ADDR_INET(address, port));\n\n    let connection_handler =\n      Httpaf_lwt_unix.Server.create_connection_handler(\n        ~config=Httpaf.Config.default,\n        ~request_handler=make_request_handler(~uri, ~handler, ~closer),\n        ~error_handler,\n      );\n\n    Lwt_io.establish_server_with_client_socket(\n      listening_address,\n      connection_handler,\n    )\n    >|= (_ => on_start(~hoststring=Uri.to_string(uri)))\n    |> ignore;\n\n    forever;\n  };\n"
  },
  {
    "path": "lwt-unix-httpaf/server_request.re",
    "content": "let read_body = reqd => {\n  let (next, awake) = Lwt.wait();\n\n  Lwt.async(() => {\n    let body = reqd |> Httpaf.Reqd.request_body;\n    let body_str = ref(\"\");\n    let on_eof = () => Lwt.wakeup_later(awake, Some(body_str^));\n    let rec on_read = (request_data, ~off, ~len) => {\n      let read = Bigstringaf.substring(~off, ~len, request_data);\n      body_str := body_str^ ++ read;\n      Httpaf.Body.schedule_read(body, ~on_read, ~on_eof);\n    };\n    Httpaf.Body.schedule_read(body, ~on_read, ~on_eof);\n    Lwt.return_unit;\n  });\n\n  next;\n};\n"
  },
  {
    "path": "src/dune",
    "content": "(library\n  (name httpkit)\n  (public_name httpkit)\n  (libraries httpaf h2 uri logs))\n"
  },
  {
    "path": "src/httpkit.re",
    "content": "module Method = H2.Method;\n\nmodule Status = H2.Status;\n\nmodule Request = {\n  type t = {\n    meth: Method.t,\n    uri: Uri.t,\n    body: option(string),\n    headers: list((string, string)),\n  };\n\n  let body = t => t.body;\n  let content_length = t =>\n    switch (t.body) {\n    | None => 0\n    | Some(body) => String.length(body)\n    };\n  let meth = t => t.meth;\n  let uri = t => t.uri;\n  let path = t => t.uri |> Uri.path_and_query;\n  let headers = t => t.headers;\n  let host = t => t.uri |> Uri.host_with_default;\n  let scheme = t =>\n    switch (t |> uri |> Uri.scheme) {\n    | None => \"\"\n    | Some(s) => s\n    };\n\n  let create = (~headers=[], ~body=\"\", meth, uri) => {\n    let host = Uri.host_with_default(uri);\n    let content_length = body |> String.length |> string_of_int;\n    let headers =\n      [(\"host\", host), (\"content-length\", content_length)]\n      @ (headers |> List.map(((k, v)) => (k |> String.lowercase_ascii, v)));\n    let body =\n      switch (body) {\n      | \"\" => None\n      | _ => Some(body)\n      };\n\n    {meth, uri, headers, body};\n  };\n\n  let to_string = req => {\n    (req.meth |> H2.Method.to_string)\n    ++ \" \"\n    ++ (req.uri |> Uri.path)\n    ++ \"\\n\"\n    ++ (req.headers |> H2.Headers.of_list |> H2.Headers.to_string)\n    ++ (\n      switch (req.body) {\n      | None => \"\"\n      | Some(s) => \"\\n\\n\" ++ s\n      }\n    );\n  };\n};\n\nmodule Server = {\n  type replier = (~headers: list((string, string))=?, int, string) => unit;\n\n  type closer = unit => unit;\n\n  type handler = (Request.t, replier, closer) => unit;\n};\n"
  }
]