Full Code of ostera/httpkit for AI

master ecfe4297bb3d cached
47 files
60.6 KB
17.9k tokens
5 symbols
1 requests
Download .txt
Repository: ostera/httpkit
Branch: master
Commit: ecfe4297bb3d
Files: 47
Total size: 60.6 KB

Directory structure:
gitextract_lfbuuy6e/

├── .gitattributes
├── .gitignore
├── 3rdparty/
│   ├── dune-project
│   ├── httpaf-lwt-unix/
│   │   ├── buffer.ml
│   │   ├── buffer.mli
│   │   ├── dune
│   │   ├── httpaf_lwt_unix.ml
│   │   ├── httpaf_lwt_unix.mli
│   │   ├── ssl_io.ml
│   │   └── tls_io.ml
│   └── httpaf-lwt-unix.opam
├── README.md
├── bench/
│   ├── .gitignore
│   ├── Gemfile
│   ├── README.md
│   ├── echo.go
│   ├── echo.js
│   ├── echo.py
│   └── echo.rb
├── dune-project
├── esy.json
├── examples/
│   ├── dune
│   ├── echo_server_http.re
│   ├── echo_server_http2.re
│   ├── request_http.re
│   └── request_http2.re
├── httpkit-lwt-unix-h2.opam
├── httpkit-lwt-unix-httpaf.opam
├── httpkit.opam
├── lwt-unix-h2/
│   ├── client_http.re
│   ├── client_https.re
│   ├── client_request.re
│   ├── client_response.re
│   ├── dune
│   ├── httpkit_lwt_unix_h2.re
│   ├── server_http.re
│   └── server_request.re
├── lwt-unix-httpaf/
│   ├── client_http.re
│   ├── client_https.re
│   ├── client_request.re
│   ├── client_response.re
│   ├── dune
│   ├── httpkit_lwt_unix_httpaf.re
│   ├── server_http.re
│   └── server_request.re
└── src/
    ├── dune
    └── httpkit.re

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitattributes
================================================
bench/* linguist-vendored
*.re linguist-language=Reason
*.rei linguist-language=Reason
*.ml linguist-language=OCaml
*.mli linguist-language=OCaml


================================================
FILE: .gitignore
================================================
_esy
_build
_public
.merlin
/lua
/lua_modules
*.install


================================================
FILE: 3rdparty/dune-project
================================================
(lang dune 1.9)
(name httpaf-lwt-unix)


================================================
FILE: 3rdparty/httpaf-lwt-unix/buffer.ml
================================================
open Lwt.Infix

(* Based on the Buffer module in httpaf_async.ml. *)
type t =
  { buffer      : Lwt_bytes.t
  ; mutable off : int
  ; mutable len : int }

let create size =
  let buffer = Lwt_bytes.create size in
  { buffer; off = 0; len = 0 }

let compress t =
  if t.len = 0
  then begin
    t.off <- 0;
    t.len <- 0;
  end else if t.off > 0
  then begin
    Lwt_bytes.blit t.buffer t.off t.buffer 0 t.len;
    t.off <- 0;
  end

let get t ~f =
  let n = f t.buffer ~off:t.off ~len:t.len in
  t.off <- t.off + n;
  t.len <- t.len - n;
  if t.len = 0
  then t.off <- 0;
  n

let put t ~f =
  compress t;
  f t.buffer ~off:(t.off + t.len) ~len:(Lwt_bytes.length t.buffer - t.len)
  >>= fun n ->
  t.len <- t.len + n;
  Lwt.return n


================================================
FILE: 3rdparty/httpaf-lwt-unix/buffer.mli
================================================
type t

val create : int -> t

val get : t -> f:(Lwt_bytes.t -> off:int -> len:int -> int) -> int
val put : t -> f:(Lwt_bytes.t -> off:int -> len:int -> int Lwt.t) -> int Lwt.t


================================================
FILE: 3rdparty/httpaf-lwt-unix/dune
================================================
(library
 (name httpaf_lwt_unix)
 (public_name httpaf-lwt-unix)
 (libraries faraday-lwt-unix httpaf lwt.unix ssl lwt_ssl)
 (modules buffer httpaf_lwt_unix tls_io ssl_io)
 (flags (:standard -safe-string)))


================================================
FILE: 3rdparty/httpaf-lwt-unix/httpaf_lwt_unix.ml
================================================
(*----------------------------------------------------------------------------
    Copyright (c) 2018 Inhabited Type LLC.
    Copyright (c) 2018 Anton Bachin

    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions
    are met:

    1. Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.

    2. Redistributions in binary form must reproduce the above copyright
       notice, this list of conditions and the following disclaimer in the
       documentation and/or other materials provided with the distribution.

    3. Neither the name of the author nor the names of his contributors
       may be used to endorse or promote products derived from this software
       without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
    OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
    ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.
  ----------------------------------------------------------------------------*)

open Lwt.Infix

let read fd buffer =
  Lwt.catch
    (fun () ->
      Buffer.put buffer ~f:(fun bigstring ~off ~len ->
        Lwt_bytes.read fd bigstring off len))
    (function
    | Unix.Unix_error (Unix.EBADF, _, _) as exn ->
      Lwt.fail exn
    | exn ->
      Lwt.async (fun () ->
        Lwt_unix.close fd);
      Lwt.fail exn)

  >>= fun bytes_read ->
  if bytes_read = 0 then
    Lwt.return `Eof
  else
    Lwt.return (`Ok bytes_read)


let shutdown socket command =
  try Lwt_unix.shutdown socket command
  with Unix.Unix_error (Unix.ENOTCONN, _, _) -> ()

module Config = Httpaf.Config

module Server = struct
  module Server_connection = Httpaf.Server_connection

  let start_read_write_loops
    ?(readf=read)
    ?(writev=Faraday_lwt_unix.writev_of_fd)
    ~config
    ~socket
    connection =
    let read_buffer = Buffer.create config.Config.read_buffer_size in
    let read_loop_exited, notify_read_loop_exited = Lwt.wait () in

    let rec read_loop () =
      let rec read_loop_step () =
        match Server_connection.next_read_operation connection with
        | `Read ->
          readf socket read_buffer >>= begin function
          | `Eof ->
            Buffer.get read_buffer ~f:(fun bigstring ~off ~len ->
              Server_connection.read_eof connection bigstring ~off ~len)
            |> ignore;
            read_loop_step ()
          | `Ok _ ->
            Buffer.get read_buffer ~f:(fun bigstring ~off ~len ->
              Server_connection.read connection bigstring ~off ~len)
            |> ignore;
            read_loop_step ()
          end

        | `Yield ->
          Server_connection.yield_reader connection read_loop;
          Lwt.return_unit

        | `Close ->
          Lwt.wakeup_later notify_read_loop_exited ();
          if not (Lwt_unix.state socket = Lwt_unix.Closed) then begin
            shutdown socket Unix.SHUTDOWN_RECEIVE
          end;
          Lwt.return_unit
      in

      Lwt.async (fun () ->
        Lwt.catch
          read_loop_step
          (fun exn ->
            Server_connection.report_exn connection exn;
            Lwt.return_unit))
    in


    let writev = writev socket in
    let write_loop_exited, notify_write_loop_exited = Lwt.wait () in

    let rec write_loop () =
      let rec write_loop_step () =
        match Server_connection.next_write_operation connection with
        | `Write io_vectors ->
          writev io_vectors >>= fun result ->
          Server_connection.report_write_result connection result;
          write_loop_step ()

        | `Yield ->
          Server_connection.yield_writer connection write_loop;
          Lwt.return_unit

        | `Close _ ->
          Lwt.wakeup_later notify_write_loop_exited ();
          if not (Lwt_unix.state socket = Lwt_unix.Closed) then begin
            shutdown socket Unix.SHUTDOWN_SEND
          end;
          Lwt.return_unit
      in

      Lwt.async (fun () ->
        Lwt.catch
          write_loop_step
          (fun exn ->
            Server_connection.report_exn connection exn;
            Lwt.return_unit))
    in


    read_loop ();
    write_loop ();
    Lwt.join [read_loop_exited; write_loop_exited] >>= fun () ->

    if Lwt_unix.state socket <> Lwt_unix.Closed then
      Lwt.catch
        (fun () -> Lwt_unix.close socket)
        (fun _exn -> Lwt.return_unit)
    else
      Lwt.return_unit

  let create_connection_handler ?(config=Config.default) ~request_handler ~error_handler =
    fun client_addr socket ->
      let connection =
        Server_connection.create
          ~config
          ~error_handler:(error_handler client_addr)
          (request_handler client_addr)
      in
      start_read_write_loops ~config ~socket connection

  module TLS = struct
    let create_connection_handler
      ?server
      ?certfile
      ?keyfile
      ?(config=Config.default)
      ~request_handler
      ~error_handler =
      let make_tls_server = Tls_io.make_server ?server ?certfile ?keyfile in
      fun client_addr socket ->
        let connection =
          Server_connection.create
            ~config
            ~error_handler:(error_handler client_addr)
            (request_handler client_addr)
        in
        make_tls_server socket >>= fun tls_server ->
        let readf = Tls_io.readf tls_server in
        let writev = Tls_io.writev tls_server in
        start_read_write_loops ~config ~readf ~writev ~socket connection
        >>= Lwt.return
  end

  module SSL = struct
    let create_connection_handler
      ?server
      ?certfile
      ?keyfile
      ?(config=Config.default)
      ~request_handler
      ~error_handler =
      let make_ssl_server = Ssl_io.make_server ?server ?certfile ?keyfile in
      fun client_addr socket ->
        let connection =
          Server_connection.create
            ~config
            ~error_handler:(error_handler client_addr)
            (request_handler client_addr)
        in
        make_ssl_server socket >>= fun tls_server ->
        let readf = Ssl_io.readf tls_server in
        let writev = Ssl_io.writev tls_server in
        start_read_write_loops ~config ~readf ~writev ~socket connection
        >>= Lwt.return
  end
end



module Client = struct
  module Client_connection = Httpaf.Client_connection

  let start_read_write_loops
    ?(readf=read)
    ?(writev=Faraday_lwt_unix.writev_of_fd)
    ~config
    ~socket
    connection =
    let read_buffer = Buffer.create config.Config.read_buffer_size in
    let read_loop_exited, notify_read_loop_exited = Lwt.wait () in

    let read_loop () =
      let rec read_loop_step () =
        match Client_connection.next_read_operation connection with
        | `Read ->
          readf socket read_buffer >>= begin function
          | `Eof ->
            Buffer.get read_buffer ~f:(fun bigstring ~off ~len ->
              Client_connection.read_eof connection bigstring ~off ~len)
            |> ignore;
            read_loop_step ()
          | `Ok _ ->
            Buffer.get read_buffer ~f:(fun bigstring ~off ~len ->
              Client_connection.read connection bigstring ~off ~len)
            |> ignore;
            read_loop_step ()
          end

        | `Close ->
          Lwt.wakeup_later notify_read_loop_exited ();
          if not (Lwt_unix.state socket = Lwt_unix.Closed) then begin
            shutdown socket Unix.SHUTDOWN_RECEIVE
          end;
          Lwt.return_unit
      in

      Lwt.async (fun () ->
        Lwt.catch
          read_loop_step
          (fun exn ->
            Client_connection.report_exn connection exn;
            Lwt.return_unit))
    in


    let writev = writev socket in
    let write_loop_exited, notify_write_loop_exited = Lwt.wait () in

    let rec write_loop () =
      let rec write_loop_step () =
        match Client_connection.next_write_operation connection with
        | `Write io_vectors ->
          writev io_vectors >>= fun result ->
          Client_connection.report_write_result connection result;
          write_loop_step ()

        | `Yield ->
          Client_connection.yield_writer connection write_loop;
          Lwt.return_unit

        | `Close _ ->
          Lwt.wakeup_later notify_write_loop_exited ();
          Lwt.return_unit
      in

      Lwt.async (fun () ->
        Lwt.catch
          write_loop_step
          (fun exn ->
            Client_connection.report_exn connection exn;
            Lwt.return_unit))
    in


    read_loop ();
    write_loop ();

    Lwt.async (fun () ->
      Lwt.join [read_loop_exited; write_loop_exited] >>= fun () ->

      if Lwt_unix.state socket <> Lwt_unix.Closed then
        Lwt.catch
          (fun () -> Lwt_unix.close socket)
          (fun _exn -> Lwt.return_unit)
      else
        Lwt.return_unit)

  let request ?(config=Config.default) socket request ~error_handler ~response_handler =
    let request_body, connection =
      Client_connection.request ~config request ~error_handler ~response_handler
    in

    start_read_write_loops ~config ~socket connection;
    request_body

  module TLS = struct
    let request ?client ?(config=Config.default) socket request ~error_handler ~response_handler =
      let request_body, connection =
        Client_connection.request ~config request ~error_handler ~response_handler
      in

      Lwt.async(fun () ->
        Tls_io.make_client ?client socket >|= fun tls_client ->
        let readf = Tls_io.readf tls_client in
        let writev = Tls_io.writev tls_client in

        start_read_write_loops ~config ~readf ~writev ~socket connection);
      request_body
  end

  module SSL = struct
    let request ?client ?(config=Config.default) socket request ~error_handler ~response_handler =
      let request_body, connection =
        Client_connection.request ~config request ~error_handler ~response_handler
      in

      Lwt.async(fun () ->
        Ssl_io.make_client ?client socket >|= fun tls_client ->
        let readf = Ssl_io.readf tls_client in
        let writev = Ssl_io.writev tls_client in

        start_read_write_loops ~config ~readf ~writev ~socket connection);
      request_body
  end
end


================================================
FILE: 3rdparty/httpaf-lwt-unix/httpaf_lwt_unix.mli
================================================
open Httpaf


(* The function that results from [create_connection_handler] should be passed
   to [Lwt_io.establish_server_with_client_socket]. For an example, see
   [examples/lwt_echo_server.ml]. *)
module Server : sig
  val create_connection_handler
    :  ?config         : Config.t
    -> request_handler : (Unix.sockaddr -> Server_connection.request_handler)
    -> error_handler   : (Unix.sockaddr -> Server_connection.error_handler)
    -> Unix.sockaddr
    -> Lwt_unix.file_descr
    -> unit Lwt.t

  module TLS : sig
    val create_connection_handler
      :  ?server         : Tls_io.server
      -> ?certfile       : string
      -> ?keyfile        : string
      -> ?config         : Config.t
      -> request_handler : (Unix.sockaddr -> Server_connection.request_handler)
      -> error_handler   : (Unix.sockaddr -> Server_connection.error_handler)
      -> Unix.sockaddr
      -> Lwt_unix.file_descr
      -> unit Lwt.t
  end

  module SSL : sig
    val create_connection_handler
      :  ?server         : Ssl_io.server
      -> ?certfile       : string
      -> ?keyfile        : string
      -> ?config         : Config.t
      -> request_handler : (Unix.sockaddr -> Server_connection.request_handler)
      -> error_handler   : (Unix.sockaddr -> Server_connection.error_handler)
      -> Unix.sockaddr
      -> Lwt_unix.file_descr
      -> unit Lwt.t
  end
end

(* For an example, see [examples/lwt_get.ml]. *)
module Client : sig
  val request
    :  ?config          : Config.t
    -> Lwt_unix.file_descr
    -> Request.t
    -> error_handler    : Client_connection.error_handler
    -> response_handler : Client_connection.response_handler
    -> [`write] Body.t

  module TLS : sig
    val request
      :  ?client          : Tls_io.client
      -> ?config          : Config.t
      -> Lwt_unix.file_descr
      -> Request.t
      -> error_handler    : Client_connection.error_handler
      -> response_handler : Client_connection.response_handler
      -> [`write] Body.t
  end

  module SSL : sig
    val request
      :  ?client          : Ssl_io.client
      -> ?config          : Config.t
      -> Lwt_unix.file_descr
      -> Request.t
      -> error_handler    : Client_connection.error_handler
      -> response_handler : Client_connection.response_handler
      -> [`write] Body.t
  end
end


================================================
FILE: 3rdparty/httpaf-lwt-unix/ssl_io.ml
================================================
open Lwt.Infix

let () = Ssl.init ()

let readf socket =
  fun _fd buffer ->
  Lwt.catch
    (fun () ->
      Buffer.put buffer ~f:(fun bigstring ~off ~len ->
        Lwt_unix.blocking (Lwt_ssl.get_fd socket) >>= fun _ ->
        Lwt_ssl.read_bytes socket bigstring off len))
    (function
    | Unix.Unix_error (Unix.EBADF, _, _) as exn ->
      Lwt.fail exn
    | exn ->
      Lwt.async (fun () ->
        Lwt_ssl.ssl_shutdown socket >>= fun () ->
        Lwt_ssl.close socket);
      Lwt.fail exn)
  >>= fun bytes_read ->
    if bytes_read = 0 then
      Lwt.return `Eof
    else
      Lwt.return (`Ok bytes_read)

let writev socket _fd =
  fun iovecs ->
  Lwt.catch
    (fun () ->
      Lwt_list.fold_left_s (fun acc {Faraday.buffer; off; len} ->
        Lwt_ssl.write_bytes socket buffer off len
        >|= fun written -> acc + written) 0 iovecs
      >|= fun n -> `Ok n)
    (function
    | Unix.Unix_error (Unix.EBADF, "check_descriptor", _) ->
      Lwt.return `Closed
    | exn ->
      Lwt.fail exn)

type client = Lwt_ssl.socket
type server = Lwt_ssl.socket

let make_client ?client socket =
  match client with
  | Some client -> Lwt.return client
  | None ->
    let client_ctx = Ssl.create_context Ssl.SSLv23 Ssl.Client_context in
    Ssl.disable_protocols client_ctx [Ssl.SSLv23];
    Ssl.honor_cipher_order client_ctx;
    Lwt_ssl.ssl_connect socket client_ctx

let make_server ?server ?certfile ?keyfile socket
  =
  match server, certfile, keyfile with
  | Some server, _, _ -> Lwt.return server
  | None, Some cert, Some priv_key ->
    let server_ctx = Ssl.create_context Ssl.SSLv23 Ssl.Server_context in
    Ssl.disable_protocols server_ctx [Ssl.SSLv23];
    Ssl.use_certificate server_ctx cert priv_key;
    Lwt_ssl.ssl_accept socket server_ctx
  | _ ->
    Lwt.fail (Invalid_argument "Certfile and Keyfile required when server isn't provided")


================================================
FILE: 3rdparty/httpaf-lwt-unix/tls_io.ml
================================================
let readf _tls =
  fun _fd _buffer ->
  Lwt.fail_with "Tls not available"

let writev _tls _fd =
  fun _iovecs ->
  Lwt.fail_with "Tls not available"

type client = [ `Tls_not_available ]
type server = [ `Tls_not_available ]

let[@ocaml.warning "-21"] make_client ?client:_ =
  failwith "TLS not available";
  fun _socket -> Lwt.return `Tls_not_available

let[@ocaml.warning "-21"] make_server ?server:_ ?certfile:_ ?keyfile:_ =
  failwith "TLS not available";
  fun _socket -> Lwt.fail_with "TLS not available"


================================================
FILE: 3rdparty/httpaf-lwt-unix.opam
================================================


================================================
FILE: README.md
================================================
# ⚡️HttpKit — high-level, high-performance HTTP1.1/2 clients/servers in Reason

> NOTE: under heavy reconstruction. Latest stable version was [`660d1c8`](https://github.com/ostera/httpkit/tree/660d1c8b7438d207be2717495d8590a529bf5a1f)

HttpKit is a high-level library for building and consuming web servers over
HTTP, HTTPS, and HTTP2.

It serves as a thin layer over `h2` and `http/af`, and when it can it allows you
to seamlessly transition from one to the other.

0. [Roadmap](#roadmap)
1. [Getting Started](#getting-started)
1. [Running the Examples](#running-the-examples)

## Roadmap

| Feature          | HTTP/1.1 | HTTPS/1.1 | HTTP/2 | HTTPS/2 |
|------------------|----------|-----------|--------|---------|
| Listen as Server | Yes      | No        | Yes    | No      |
| Send Request     | Yes      | Yes       | No     | No      |
| Server Push      | -        | -         | No     | No      |
|                  |          |           |        |         |

## Getting Started

#### Usage

`httpkit` can be used both to build servers and to make requests as a client.

Documentation is still a work-in-progress, but there's examples in the
`examples` section that can give you a better idea of how to use the libraries.
In short:

For making a request:

```reason
open Lwt_result.Infix;

module Httpkit = Httpkit_lwt_unix_httpaf;

let req =
  Httpkit.Request.create(
    ~headers=[("User-Agent", "Reason HttpKit")],
    `GET,
    Uri.of_string("http://api.github.com/repos/ostera/httpkit"),
  );

/* Send over HTTP */
req
|> Httpkit.Client.Http.send
>>= Httpkit.Client.Response.body
|> Lwt_main.run

/* Send over HTTPS */
req
|> Httpkit.Client.Https.send
>>= Httpkit.Client.Response.body
|> Lwt_main.run
```

For making a server:

```reason
module Httpkit = Httpkit_lwt_unix_httpaf;

let port = 8080;

let on_start = (~hoststring) =>
  Logs.app(m => m("Running on %s", hoststring));

let handler: Httpkit.Server.handler =
  (req, reply, kill_server) => {
    let method = req |> Httpkit.Request.meth |> H2.Method.to_string;
    let path = req |> Httpkit.Request.path;
    Logs.app(m => m("%s %s", method, path));
    reply(200, "hi");
    kill_server();
  };

/* Start server over HTTP */
Httpkit.Server.Http.listen(~port, ~address=`Any, ~handler, ~on_start)
|> Lwt_main.run;

/* Start server over HTTPS */
Httpkit.Server.Http.listen(~port, ~address=`Any, ~handler, ~on_start)
|> Lwt_main.run;
```

#### Installing with esy

You can install by dropping the following dependencies in your `package.json`:

```json
{
  "dependencies": {
    "@opam/httpkit": "*",
    "@opam/httpkit-lwt-unix-httpaf": "*",
    "@opam/logs": "*",
    "@opam/fmt": "*",
    // ...
  },
  "resolutions": {
    "@opam/httpkit": "ostera/httpkit:httpkit.opam#f738417",
    "@opam/httpkit-lwt-unix-httpaf": "ostera/httpkit:httpkit-lwt-unix-httpaf.opam#f738417",
  }
}
```

> NOTE: For `httpkit` make sure you're using the latest commit hash!

## Running the Examples

All of the examples are runnable as binaries after compilation, so you can
either run `esy build` and find them within
`./_esy/default/build/default/examples/*.exe` or you can ask dune to run them
for you:

```sh
ostera/httpkit λ esy dune exec ./examples/Request.exe
```


================================================
FILE: bench/.gitignore
================================================
echo


================================================
FILE: bench/Gemfile
================================================
source "https://rubygems.org"

gem "rack"


================================================
FILE: bench/README.md
================================================
# Benchmarking HttpKit ⚡️

In order to ensure that `httpkit` stays fast, here you'll find a number of small
servers written in other languages to benchmark against.

They should all do the same thing:

1. Log down the time, method and path
2. Reply with the path

They will all be called with the same command:

```sh
wrk2 \
  --threads=12 \
  --connections=400 \
  --duration=30s \
  --rate 30K
  https://localhost:8080/bench-it-chewie!
```
## Results

| Lang    | Lib                 |   KB/s   | RPS   | Total Req |
|---------|---------------------|----------|-------|-----------|
| OCaml   | httpkit+http/af+lwt | 414.17KB | 10874 |   326230  |
| OCaml   | http/af+lwt         | 414.76KB | 10890 |   326792  |
| Ruby    | rack                | 149.70KB |   806 |    24349  |
| Node.js | stdlib http         | 591.80KB |  5179 |   155767  |
| Golang  | stdlib http         |   0.95MB | 13314 |   399390  |
| Python  | BaseHTTPServer      |  65.50KB |   519 |    15704  |

## Details

### OCaml/httpkit+httpaf+lwt

```sh
ostera/httpkit λ wrk2 --threads=12 --connections=400 --duration=30s --rate 30K http://localhost:9999/what
Running 30s test @ http://localhost:9999/what
  12 threads and 400 connections
  Thread calibration: mean lat.: 3092.528ms, rate sampling interval: 11714ms
  Thread calibration: mean lat.: 3241.606ms, rate sampling interval: 12107ms
  Thread calibration: mean lat.: 3183.128ms, rate sampling interval: 11763ms
  Thread calibration: mean lat.: 3235.211ms, rate sampling interval: 12009ms
  Thread calibration: mean lat.: 3109.703ms, rate sampling interval: 11780ms
  Thread calibration: mean lat.: 3214.701ms, rate sampling interval: 12017ms
  Thread calibration: mean lat.: 3174.243ms, rate sampling interval: 11862ms
  Thread calibration: mean lat.: 3067.300ms, rate sampling interval: 11575ms
  Thread calibration: mean lat.: 3066.558ms, rate sampling interval: 11755ms
  Thread calibration: mean lat.: 3101.464ms, rate sampling interval: 11722ms
  Thread calibration: mean lat.: 3084.410ms, rate sampling interval: 11829ms
  Thread calibration: mean lat.: 3075.844ms, rate sampling interval: 11444ms
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    12.87s     3.62s   20.76s    58.95%
    Req/Sec     0.92k    18.58     0.95k    58.33%
  326230 requests in 30.00s, 12.13MB read
  Socket errors: connect 0, read 40, write 3, timeout 4
Requests/sec:  10874.67
Transfer/sec:    414.17KB
```

### OCaml/httpaf+lwt

```sh
ostera/httpkit λ wrk2 --threads=12 --connections=400 --duration=30s --rate 30K http://localhost:9999/what
Running 30s test @ http://localhost:9999/what
  12 threads and 400 connections
  Thread calibration: mean lat.: 3103.933ms, rate sampling interval: 11304ms
  Thread calibration: mean lat.: 3074.874ms, rate sampling interval: 11141ms
  Thread calibration: mean lat.: 3190.094ms, rate sampling interval: 11370ms
  Thread calibration: mean lat.: 2974.283ms, rate sampling interval: 10543ms
  Thread calibration: mean lat.: 2987.974ms, rate sampling interval: 11091ms
  Thread calibration: mean lat.: 2895.381ms, rate sampling interval: 10919ms
  Thread calibration: mean lat.: 2908.596ms, rate sampling interval: 10870ms
  Thread calibration: mean lat.: 3164.646ms, rate sampling interval: 11526ms
  Thread calibration: mean lat.: 3000.368ms, rate sampling interval: 11182ms
  Thread calibration: mean lat.: 3051.481ms, rate sampling interval: 11386ms
  Thread calibration: mean lat.: 3005.150ms, rate sampling interval: 11165ms
  Thread calibration: mean lat.: 2956.432ms, rate sampling interval: 10960ms
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    12.55s     3.75s   21.20s    59.01%
    Req/Sec     0.91k    15.95     0.95k    75.00%
  326792 requests in 30.01s, 12.15MB read
  Socket errors: connect 0, read 97, write 4, timeout 11
Requests/sec:  10890.16
Transfer/sec:    414.76KB
```

### Ruby/Rack

```sh
ostera/httpkit λ wrk2 --threads=12 --connections=400 --duration=30s --rate 30K http://localhost:8080/bench-it-chewie!
Running 30s test @ http://localhost:8080/bench-it-chewie!
  12 threads and 400 connections
  Thread calibration: mean lat.: 4611.970ms, rate sampling interval: 16515ms
  Thread calibration: mean lat.: 4602.015ms, rate sampling interval: 16154ms
  Thread calibration: mean lat.: 4654.559ms, rate sampling interval: 16613ms
  Thread calibration: mean lat.: 4516.088ms, rate sampling interval: 16179ms
  Thread calibration: mean lat.: 4601.379ms, rate sampling interval: 16269ms
  Thread calibration: mean lat.: 4900.919ms, rate sampling interval: 16449ms
  Thread calibration: mean lat.: 4552.994ms, rate sampling interval: 16523ms
  Thread calibration: mean lat.: 9223372036854776.000ms, rate sampling interval: 10ms
  Thread calibration: mean lat.: 9223372036854776.000ms, rate sampling interval: 10ms
  Thread calibration: mean lat.: 9223372036854776.000ms, rate sampling interval: 10ms
  Thread calibration: mean lat.: 9223372036854776.000ms, rate sampling interval: 10ms
  Thread calibration: mean lat.: 4669.880ms, rate sampling interval: 16556ms
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    17.89s     5.12s   27.25s    57.47%
    Req/Sec     0.11      3.31   108.00     99.89%
  24349 requests in 30.18s, 4.41MB read
  Socket errors: connect 0, read 0, write 0, timeout 4276
Requests/sec:    806.78
Transfer/sec:    149.70KB
```

### Node/Http

```sh
ostera/httpkit λ wrk2 --threads=12 --connections=400 --duration=30s --rate 30K http://localhost:8080/bench-it-chewie!
Running 30s test @ http://localhost:8080/bench-it-chewie!
  12 threads and 400 connections
  Thread calibration: mean lat.: 3976.372ms, rate sampling interval: 13983ms
  Thread calibration: mean lat.: 4418.043ms, rate sampling interval: 15417ms
  Thread calibration: mean lat.: 4419.606ms, rate sampling interval: 15417ms
  Thread calibration: mean lat.: 4413.743ms, rate sampling interval: 15409ms
  Thread calibration: mean lat.: 4421.132ms, rate sampling interval: 15417ms
  Thread calibration: mean lat.: 4418.656ms, rate sampling interval: 15417ms
  Thread calibration: mean lat.: 4422.277ms, rate sampling interval: 15417ms
  Thread calibration: mean lat.: 4420.156ms, rate sampling interval: 15409ms
  Thread calibration: mean lat.: 4420.646ms, rate sampling interval: 15409ms
  Thread calibration: mean lat.: 3972.669ms, rate sampling interval: 13885ms
  Thread calibration: mean lat.: 4421.550ms, rate sampling interval: 15417ms
  Thread calibration: mean lat.: 3966.959ms, rate sampling interval: 13877ms
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    16.14s     4.73s   24.72s    56.45%
    Req/Sec   456.33      0.75   458.00    100.00%
  155767 requests in 30.07s, 17.38MB read
  Socket errors: connect 0, read 1, write 0, timeout 0
Requests/sec:   5179.50
Transfer/sec:    591.80KB
```

### Golang/Http

The golang standard library `http` module seems flexible enough for us to build
an incredibly fast echo server! Closer to 3 times faster than node's, and around
2000 requests per second more than `httpkit`.

If the superior type-safety offered by `httpkit` is not what you're looking for,
have a look at this:

```sh
ostera/httpkit λ wrk2 --threads=12 --connections=400 --duration=30s --rate 30K http://localhost:8080/bench-it-chewie!
Running 30s test @ http://localhost:8080/bench-it-chewie!
  12 threads and 400 connections
  Thread calibration: mean lat.: 2694.872ms, rate sampling interval: 9592ms
  Thread calibration: mean lat.: 2674.729ms, rate sampling interval: 9551ms
  Thread calibration: mean lat.: 2644.030ms, rate sampling interval: 9437ms
  Thread calibration: mean lat.: 2680.816ms, rate sampling interval: 9568ms
  Thread calibration: mean lat.: 2667.644ms, rate sampling interval: 9502ms
  Thread calibration: mean lat.: 2691.502ms, rate sampling interval: 9560ms
  Thread calibration: mean lat.: 2490.139ms, rate sampling interval: 8781ms
  Thread calibration: mean lat.: 2652.057ms, rate sampling interval: 9461ms
  Thread calibration: mean lat.: 2665.217ms, rate sampling interval: 9519ms
  Thread calibration: mean lat.: 2687.348ms, rate sampling interval: 9584ms
  Thread calibration: mean lat.: 2697.834ms, rate sampling interval: 9560ms
  Thread calibration: mean lat.: 2684.353ms, rate sampling interval: 9519ms
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    11.02s     3.20s   17.10s    58.01%
    Req/Sec     1.09k    23.03     1.12k    62.50%
  399390 requests in 30.00s, 28.57MB read
Requests/sec:  13314.83
Transfer/sec:      0.95MB
```

### Python/BaseHTTPServer

```sh
ostera/httpkit λ wrk2 --threads=12 --connections=400 --duration=30s --rate 30K http://localhost:8080/bench-it-chewie!
Running 30s test @ http://localhost:8080/bench-it-chewie!
  12 threads and 400 connections
  Thread calibration: mean lat.: 4190.046ms, rate sampling interval: 14639ms
  Thread calibration: mean lat.: 4269.527ms, rate sampling interval: 14483ms
  Thread calibration: mean lat.: 4213.688ms, rate sampling interval: 15704ms
  Thread calibration: mean lat.: 3632.081ms, rate sampling interval: 14434ms
  Thread calibration: mean lat.: 3932.717ms, rate sampling interval: 13344ms
  Thread calibration: mean lat.: 4980.591ms, rate sampling interval: 15450ms
  Thread calibration: mean lat.: 3027.887ms, rate sampling interval: 12361ms
  Thread calibration: mean lat.: 4010.051ms, rate sampling interval: 12828ms
  Thread calibration: mean lat.: 4807.472ms, rate sampling interval: 18104ms
  Thread calibration: mean lat.: 4543.476ms, rate sampling interval: 14524ms
  Thread calibration: mean lat.: 4214.574ms, rate sampling interval: 14008ms
  Thread calibration: mean lat.: 4466.553ms, rate sampling interval: 16506ms
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    10.99s     2.92s   20.97s    63.93%
    Req/Sec     6.50      1.89    10.00     91.67%
  15704 requests in 30.20s, 1.93MB read
  Socket errors: connect 0, read 1533, write 57, timeout 4489
Requests/sec:    519.94
Transfer/sec:     65.50KB
```

### Lua/http
### Rust/hyper+tokio


================================================
FILE: bench/echo.go
================================================
package main

import (
	"bytes"
	"log"
	"net/http"
)

const DefaultPort = "8080"

func EchoHandler(writer http.ResponseWriter, request *http.Request) {
	stamp := request.Method + " " + request.URL.Path
	log.Println(stamp)
	buf := bytes.NewBufferString(request.URL.Path)
	request.Write(buf)
}

func main() {
	log.Println("Listening on port " + DefaultPort)
	http.HandleFunc("/", EchoHandler)
	http.ListenAndServe(":"+DefaultPort, nil)
}


================================================
FILE: bench/echo.js
================================================
const httpServer = require('http');

httpServer.createServer((req, res) => {
  console.log(new Date(), req.method, req.url);
  res.end(req.url);
})
.listen(8080, () => console.log("Server started..."));;


================================================
FILE: bench/echo.py
================================================
from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer

PORT_NUMBER = 8080

class handler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-Length',len(self.path))
        self.end_headers()
        self.wfile.write(self.path)
        return

server = HTTPServer(('', PORT_NUMBER), handler)
print 'Listening on port ' , PORT_NUMBER
server.serve_forever()


================================================
FILE: bench/echo.rb
================================================
require 'rack'
 
app = Proc.new do |env|
  req = Rack::Request.new(env)
  meth = req.request_method
  path = req.path
  now = Time.now
  puts "#{now} - #{meth} #{path}"
  ['200', {'Content-Type' => 'text/html'}, [path]]
end
 
Rack::Handler::WEBrick.run app


================================================
FILE: dune-project
================================================
(lang dune 1.5)
(name httpkit)
(using fmt 1.0)


================================================
FILE: esy.json
================================================
{
  "dependencies": {
    "@esy-ocaml/reason": "3.4.0",
    "@opam/dune": "*",
    "@opam/fmt": "*",
    "@opam/h2": "0.2.0",
    "@opam/h2-lwt": "0.2.0",
    "@opam/h2-lwt-unix": "0.2.0",
    "@opam/httpaf": "*",
    "@opam/logs": "*",
    "@opam/lwt": "4.2.1",
    "@opam/lwt_ssl": "1.1.2",
    "@opam/merlin": "*",
    "@opam/odoc": "*",
    "@opam/uri": "*",
    "@opam/yojson": "*",
    "ocaml": "~4.7.0",
    "refmterr": "*"
  },
  "resolutions": {
    "@opam/conf-libev": "esy-packages/libev:package.json#86d244e",
    "@opam/conf-autoconf": "esy-packages/esy-autoconf:package.json#71a8836",
    "@opam/conf-openssl": {
      "source": "no-source:",
      "override": {
        "dependencies": {
          "@opam/conf-pkg-config": "*",
          "@esy-packages/esy-openssl": "esy-packages/esy-openssl#f6107d6",
          "@opam/conf-autoconf": "*"
        }
      }
    },
    "@opam/httpaf": "anmonteiro/httpaf:httpaf.opam#6d2c80e3a16ecf85d74df76005ab68136457e111",
    "@opam/ssl": "anmonteiro/ocaml-ssl:ssl.opam#b965d15"
  }
}


================================================
FILE: examples/dune
================================================
(executable
  (name request_http)
  (modules request_http)
	(ocamlopt_flags -O3)
  (libraries httpkit-lwt-unix-httpaf httpkit logs.fmt fmt.tty))

(executable
  (name request_http2)
  (modules request_http2)
	(ocamlopt_flags -O3)
  (libraries httpkit-lwt-unix-h2 httpkit logs.fmt fmt.tty))

(executable
  (name echo_server_http)
  (modules echo_server_http)
	(ocamlopt_flags -O3)
  (libraries httpkit-lwt-unix-httpaf httpkit logs.fmt fmt.tty))

(executable
  (name echo_server_http2)
  (modules echo_server_http2)
	(ocamlopt_flags -O3)
  (libraries httpkit-lwt-unix-h2 httpkit logs.fmt fmt.tty))


================================================
FILE: examples/echo_server_http.re
================================================
/** Handle sigpipe internally */
Sys.(set_signal(sigpipe, Signal_ignore));

/** Setup loggers */
Fmt_tty.setup_std_outputs();
Logs.set_level(Some(Logs.Debug));
Logs.set_reporter(Logs_fmt.reporter());

module Httpkit = Httpkit_lwt_unix_httpaf;

let port = 8080;

let on_start = (~hoststring) =>
  Logs.app(m => m("Running on %s", hoststring));

let handler: Httpkit.Server.handler =
  (req, reply, close) => {
    let method = req |> Httpkit.Request.meth |> H2.Method.to_string;
    let path = req |> Httpkit.Request.path;
    Logs.app(m => m("%s %s", method, path));
    reply(200, "hi");
    close();
  };

Httpkit.Server.Http.listen(~port, ~address=`Any, ~handler, ~on_start)
|> Lwt_main.run;


================================================
FILE: examples/echo_server_http2.re
================================================
/** Handle sigpipe internally */
Sys.(set_signal(sigpipe, Signal_ignore));

/** Setup loggers */
Fmt_tty.setup_std_outputs();
Logs.set_level(Some(Logs.Debug));
Logs.set_reporter(Logs_fmt.reporter());

module Httpkit = Httpkit_lwt_unix_h2;

let port = 8080;

let on_start = (~hoststring) =>
  Logs.app(m => m("Running on %s", hoststring));

let handler: Httpkit.Server.handler =
  (req, reply, close) => {
    let method = req |> Httpkit.Request.meth |> H2.Method.to_string;
    let path = req |> Httpkit.Request.path;
    Logs.app(m => m("%s %s", method, path));
    reply(200, "hi");
    close();
  };

Httpkit.Server.Http.listen(~port, ~address=`Any, ~handler, ~on_start)
|> Lwt_main.run;


================================================
FILE: examples/request_http.re
================================================
open Lwt_result.Infix;

/** Handle sigpipe internally */
Sys.(set_signal(sigpipe, Signal_ignore));

/** Setup loggers */
Fmt_tty.setup_std_outputs();
Logs.set_level(Some(Logs.Debug));
Logs.set_reporter(Logs_fmt.reporter());

module Httpkit = Httpkit_lwt_unix_httpaf;

/**
  Sample HTTPS Request using No Authentication :tm:
*/

let https_url = Sys.argv[1];
Logs.app(m => m("Requesting: %s", https_url));
switch (
  Httpkit.Request.create(
    ~headers=[
      ("User-Agent", "Reason HttpKit"),
      ("Accept", "*/*"),
    ],
    `GET,
    https_url |> Uri.of_string,
  )
  |> Httpkit.Client.Https.send
  >>= Httpkit.Client.Response.body
  |> Lwt_main.run
) {
| exception e => Logs.err(m => m("%s", Printexc.to_string(e)))
| Ok(body) => Logs.app(m => m("Response: %s", body))
| Error(`Connection_error(`Invalid_response_body_length(req))) =>
  let str = Buffer.create(1024);
  let fmt = Format.formatter_of_buffer(str);
  Httpaf.Response.pp_hum(fmt, req);
  Logs.err(m =>
    m(
      "Connection Error (Invalid response body length): %s",
      str |> Buffer.to_bytes |> Bytes.to_string,
    )
  );
| Error(`Connection_error(`Malformed_response(str))) =>
  Logs.err(m => m("Connection Error (Malformed response): %s", str))
| Error(`Connection_error(`Exn(ex))) =>
  Logs.err(m =>
    m("Connection Error (Exception): %s", ex |> Printexc.to_string)
  )
};


================================================
FILE: examples/request_http2.re
================================================
open Lwt_result.Infix;

/** Handle sigpipe internally */
Sys.(set_signal(sigpipe, Signal_ignore));

/** Setup loggers */
Fmt_tty.setup_std_outputs();
Logs.set_level(Some(Logs.Debug));
Logs.set_reporter(Logs_fmt.reporter());

module Httpkit = Httpkit_lwt_unix_h2;

/**
  Sample HTTPS Request using No Authentication :tm:
*/

let https_url = Sys.argv[1];
Logs.app(m => m("Requesting: %s", https_url));
switch (
  Httpkit.Request.create(`GET, https_url |> Uri.of_string)
  |> Httpkit.Client.Https.send
  >>= Httpkit.Client.Response.body
  |> Lwt_main.run
) {
| exception e => Logs.err(m => m("%s", Printexc.to_string(e)))
| Ok(body) => Logs.app(m => m("Response: %s", body))
| Error(`Connection_error(`Invalid_response_body_length(req))) =>
  let str = Buffer.create(1024);
  let fmt = Format.formatter_of_buffer(str);
  H2.Response.pp_hum(fmt, req);
  Logs.err(m =>
    m(
      "Connection Error (Invalid response body length): %s",
      str |> Buffer.to_bytes |> Bytes.to_string,
    )
  );
| Error(`Connection_error(`Malformed_response(str))) =>
  Logs.err(m => m("Connection Error (Malformed response): %s", str))
| Error(`Connection_error(`Exn(ex))) =>
  Logs.err(m =>
    m("Connection Error (Exception): %s", ex |> Printexc.to_string)
  )
| Error(`Connection_error(`Protocol_error)) =>
  Logs.err(m => m("Connection Error (Protocol Error)"))
};


================================================
FILE: httpkit-lwt-unix-h2.opam
================================================
opam-version: "2.0"
name: "httpkit-lwt-unix-h2"
version: "0.13"
synopsis: "High-level, High-performance HTTP(S) Clients/Servers with Lwt"
maintainer: "Leandro Ostera <leandro@ostera.io>"
authors: "Leandro Ostera <leandro@ostera.io>"
license: "MIT"
homepage: "https//github.com/ostera/httpkit"
bug-reports: "https//github.com/ostera/httpkit/issues"
depends: [
  "httpkit"
  "h2"
  "h2-lwt"
  "h2-lwt-unix"
  "lwt"
  "lwt_ssl"
  "ssl"
  "tls"

  "dune" {build}
  "reason" {build}
]
build: ["dune" "build" "-p" name]
install: ["dune" "install" name "--prefix" prefix "--root" "."]


================================================
FILE: httpkit-lwt-unix-httpaf.opam
================================================
opam-version: "2.0"
name: "httpkit-lwt-unix-httpaf"
version: "0.13"
synopsis: "High-level, High-performance HTTP(S) Clients/Servers with Lwt"
maintainer: "Leandro Ostera <leandro@ostera.io>"
authors: "Leandro Ostera <leandro@ostera.io>"
license: "MIT"
homepage: "https//github.com/ostera/httpkit"
bug-reports: "https//github.com/ostera/httpkit/issues"
depends: [
  "httpkit"
  "httpaf"
  "httpaf-lwt-unix"
  "lwt"
  "ssl"
  "tls"

  "dune" {build}
  "reason" {build}
]
build: ["dune" "build" "-p" name]
install: ["dune" "install" name "--prefix" prefix "--root" "."]


================================================
FILE: httpkit.opam
================================================
opam-version: "2.0"
name: "httpkit"
version: "0.13"
synopsis: "High-level, High-performance HTTP(S) Clients/Servers"
maintainer: "Leandro Ostera <leandro@ostera.io>"
authors: "Leandro Ostera <leandro@ostera.io>"
license: "MIT"
homepage: "https//github.com/ostera/httpkit"
bug-reports: "https//github.com/ostera/httpkit/issues"
depends: [
  "logs"
  "uri"
  "httpaf"
  "h2"

  "dune" {build}
  "reason" {build}
]
build: ["dune" "build" "-p" name]
install: ["dune" "install" name "--prefix" prefix "--root" "."]


================================================
FILE: lwt-unix-h2/client_http.re
================================================
open Lwt.Infix;

let send:
  (~config: H2.Config.t=?, Httpkit.Request.t) =>
  Lwt_result.t(
    (H2.Response.t, H2.Body.t([ | `read])),
    [> | `Connection_error(H2.Client_connection.error)],
  ) =
  (~config=H2.Config.default, req) => {
    let uri = Httpkit.Request.uri(req);

    let response_handler = (notify_response_received, response, response_body) => {
      Logs.debug(m => m("Handling response..."));
      Lwt.wakeup_later(
        notify_response_received,
        (response, response_body) |> Lwt_result.return,
      );
    };

    let error_handler = (notify_response_received, error) => {
      Logs.debug(m => m("Handling errors..."));
      Lwt.wakeup_later(
        notify_response_received,
        `Connection_error(error) |> Lwt_result.fail,
      );
    };

    let host = Uri.host_with_default(uri);
    let port =
      switch (Uri.port(uri)) {
      | None => "443"
      | Some(number) => string_of_int(number)
      };

    Lwt_unix.getaddrinfo(host, port, [Unix.(AI_FAMILY(PF_INET))])
    >>= (
      addresses => {
        Logs.debug(m => m("Got address..."));
        let socket_addr = List.hd(addresses).Unix.ai_addr;
        let socket = Lwt_unix.socket(Unix.PF_INET, Unix.SOCK_STREAM, 0);

        Lwt_unix.connect(socket, socket_addr)
        >>= (
          () => {
            Logs.debug(m => m("Opened socket..."));
            let (response_received, notify_response_received) = Lwt.wait();
            let response_handler = response_handler(notify_response_received);
            let error_handler = error_handler(notify_response_received);

            let write_body = request_body => {
              Logs.debug(m => m("Writing body..."));
              switch (Httpkit.Request.body(req)) {
              | None => ()
              | Some(str) => H2.Body.write_string(request_body, str)
              };
              H2.Body.close_writer(request_body);
              Logs.debug(m => m("Closed writer..."));
              response_received >>= (x => x);
            };

            let request = Client_request.of_httpkit_request(req);

            H2_lwt_unix.Client.create_connection(
              ~config,
              ~error_handler,
              socket,
            )
            >>= (
              connection => {
                H2_lwt_unix.Client.request(
                  connection,
                  request,
                  ~error_handler,
                  ~response_handler,
                )
                |> write_body;
              }
            );
          }
        );
      }
    );
  };


================================================
FILE: lwt-unix-h2/client_https.re
================================================
open Lwt.Infix;

Ssl_threads.init();
Ssl.init();
let default_ssl_context = Ssl.create_context(Ssl.SSLv23, Ssl.Client_context);
Ssl.disable_protocols(default_ssl_context, [Ssl.SSLv23]);
Ssl.set_context_alpn_protos(default_ssl_context, ["h2"]);
Ssl.honor_cipher_order(default_ssl_context);

let send:
  (~config: H2.Config.t=?, Httpkit.Request.t) =>
  Lwt_result.t(
    (H2.Response.t, H2.Body.t([ | `read])),
    [> | `Connection_error(H2.Client_connection.error)],
  ) =
  (~config=H2.Config.default, req) => {
    let uri = Httpkit.Request.uri(req);

    let response_handler = (notify_response_received, response, response_body) => {
      Logs.debug(m => m("Handling response..."));
      Lwt.wakeup_later(
        notify_response_received,
        (response, response_body) |> Lwt_result.return,
      );
    };

    let error_handler = (notify_response_received, error) => {
      Logs.debug(m => m("Handling errors..."));
      Lwt.wakeup_later(
        notify_response_received,
        `Connection_error(error) |> Lwt_result.fail,
      );
    };

    let host = Uri.host_with_default(uri);
    let port =
      switch (Uri.port(uri)) {
      | None => "443"
      | Some(number) => string_of_int(number)
      };

    Lwt_unix.getaddrinfo(host, port, [Unix.(AI_FAMILY(PF_INET))])
    >>= (
      addresses => {
        let socket_addr = List.hd(addresses).Unix.ai_addr;
        let socket = Lwt_unix.socket(Unix.PF_INET, Unix.SOCK_STREAM, 0);

        Lwt_unix.connect(socket, socket_addr)
        >>= (
          () => {
            Lwt_ssl.ssl_connect(socket, default_ssl_context)
            >>= (
              ssl_client => {
                let (response_received, notify_response_received) =
                  Lwt.wait();
                let response_handler =
                  response_handler(notify_response_received);
                let error_handler = error_handler(notify_response_received);

                let write_body = request_body => {
                  switch (Httpkit.Request.body(req)) {
                  | None => ()
                  | Some(str) => H2.Body.write_string(request_body, str)
                  };
                  H2.Body.flush(
                    request_body,
                    () => {
                      H2.Body.close_writer(request_body);
                      Logs.debug(m => m("Closed body writer..."));
                    },
                  );
                  response_received >>= (x => x);
                };

                let request = Client_request.of_httpkit_request(req);

                Logs.debug(m => {
                  let buffer = Buffer.create(1024);
                  let fmt = Format.formatter_of_buffer(buffer);
                  H2.Request.pp_hum(fmt, request);
                  m("%s", buffer |> Buffer.contents);
                });

                let handle_ssl_connection = connection =>
                  H2_lwt_unix.Client.SSL.request(
                    connection,
                    request,
                    ~error_handler,
                    ~response_handler,
                  )
                  |> write_body;

                let connect = () =>
                  H2_lwt_unix.Client.SSL.create_connection(
                    ~client=ssl_client,
                    ~config,
                    ~error_handler,
                    socket,
                  );

                connect() >>= handle_ssl_connection;
              }
            );
          }
        );
      }
    );
  };


================================================
FILE: lwt-unix-h2/client_request.re
================================================
let of_httpkit_request = req => {
  open Httpkit;
  let host = req |> Request.host;
  let scheme = req |> Request.scheme;
  let meth = req |> Request.meth;
  let path = req |> Request.path;

  let headers =
    [
      (":authority", host),
      (":method", meth |> Method.to_string),
      (":path", path),
      (":scheme", scheme),
    ]
    @ (req |> Request.headers)
    |> H2.Headers.of_list;

  H2.Request.create(~headers, ~scheme, meth, path);
};

let to_httpkit_request = (~body, ~uri, req) => {
  Httpkit.Request.create(
    ~headers=req.H2.Request.headers |> H2.Headers.to_list,
    ~body=
      switch (body) {
      | None => ""
      | Some(b) => b
      },
    req.meth,
    uri,
  );
};


================================================
FILE: lwt-unix-h2/client_response.re
================================================
let body:
  ((H2.Response.t, H2.Body.t([ | `read]))) => Lwt.t(result(string, 'b)) =
  ((_response, body)) => {
    open Lwt.Infix;
    let buffer = Buffer.create(1024);
    Logs.debug(m => m("Buffering response..."));
    let (next, wakeup) = Lwt.wait();
    Lwt.async(() => {
      let rec read_response = () =>
        H2.Body.schedule_read(
          body,
          ~on_eof=
            () => Lwt.wakeup_later(wakeup, Ok(Buffer.contents(buffer))),
          ~on_read=
            (response_fragment, ~off, ~len) => {
              let response_fragment_string = Bytes.create(len);
              Lwt_bytes.blit_to_bytes(
                response_fragment,
                off,
                response_fragment_string,
                0,
                len,
              );
              Buffer.add_bytes(buffer, response_fragment_string);
              read_response();
            },
        );
      read_response() |> Lwt.return;
    })
    |> ignore;
    next >>= Lwt_result.lift;
  };


================================================
FILE: lwt-unix-h2/dune
================================================
(library
  (name httpkit_lwt_unix_h2)
  (public_name httpkit-lwt-unix-h2)
  (libraries httpkit h2 h2-lwt h2-lwt-unix lwt lwt.unix uri logs logs.lwt fpath bigstringaf))


================================================
FILE: lwt-unix-h2/httpkit_lwt_unix_h2.re
================================================
module Method = Httpkit.Method;

module Status = Httpkit.Status;

module Request = Httpkit.Request;

module Server = {
  include Httpkit.Server;
  module Http = Server_http;
};

module Client = {
  module Https = Client_https;
  module Http = Client_http;
  module Response = Client_response;
};


================================================
FILE: lwt-unix-h2/server_http.re
================================================
open Lwt.Infix;

let make_request_handler:
  (
    ~uri: Uri.t,
    ~handler: Httpkit.Server.handler,
    ~closer: unit => unit,
    Unix.sockaddr
  ) =>
  H2.Server_connection.request_handler =
  (~uri, ~handler, ~closer, _client, reqd) => {
    let req = reqd |> H2.Reqd.request;
    Logs.debug(m => m("Handling request..."));
    let respond = (~headers=?, status, content) => {
      let headers =
        (
          switch (headers) {
          | None => []
          | Some(hs) => hs
          }
        )
        @ [("content-length", content |> String.length |> string_of_int)]
        |> H2.Headers.of_list;
      let res =
        H2.Response.create(status |> H2.Status.of_code, ~headers);
      H2.Reqd.respond_with_string(reqd, res, content);
    };
    Server_request.read_body(reqd)
    >|= (
      body => {
        let uri = Uri.with_path(uri, req.target);
        let req = Client_request.to_httpkit_request(~uri, ~body, req);
        let () = handler(req, respond, closer);
        ();
      }
    )
    |> ignore;
  };

let error_handler = (_client, ~request as _=?, err, _get) => {
  Logs.err(m =>
    m(
      "Something went wrong! %s",
      switch (err) {
      | `Bad_gateway => "Bad gateway"
      | `Bad_request => "Bad request"
      | `Internal_server_error => "Internal_server_error"
      | `Exn(exn) => Printexc.to_string(exn)
      },
    )
  );
  ();
};

let listen:
  (
    ~address: [ | `Loopback | `Any | `Of_string(string)]=?,
    ~port: int,
    ~on_start: (~hoststring: string) => unit,
    ~handler: Httpkit.Server.handler
  ) =>
  Lwt.t(unit) =
  (~address=`Any, ~port, ~on_start, ~handler) => {
    let host =
      switch (address) {
      | `Loopback => "127.0.0.1"
      | `Any => "0.0.0.0"
      | `Of_string(str) => str
      };
    let uri = Uri.make(~scheme="http", ~host, ~port, ());

    let (forever, awaker) = Lwt.wait();
    let closer = () => Lwt.wakeup_later(awaker, ());

    let address =
      switch (address) {
      | `Loopback => Unix.inet_addr_loopback
      | `Any => Unix.inet_addr_any
      | `Of_string(str) => Unix.inet_addr_of_string(str)
      };
    let listening_address = Unix.(ADDR_INET(address, port));

    let connection_handler =
      H2_lwt_unix.Server.create_connection_handler(
        ~config=H2.Config.default,
        ~request_handler=make_request_handler(~uri, ~handler, ~closer),
        ~error_handler,
      );

    Lwt_io.establish_server_with_client_socket(
      listening_address,
      connection_handler,
    )
    >|= (_ => on_start(~hoststring=Uri.to_string(uri)))
    |> ignore;

    forever;
  };


================================================
FILE: lwt-unix-h2/server_request.re
================================================
let read_body = reqd => {
  let (next, awake) = Lwt.wait();

  Lwt.async(() => {
    let body = reqd |> H2.Reqd.request_body;
    let body_str = ref("");
    let on_eof = () => Lwt.wakeup_later(awake, Some(body_str^));
    let rec on_read = (request_data, ~off, ~len) => {
      let read = Bigstringaf.substring(~off, ~len, request_data);
      body_str := body_str^ ++ read;
      H2.Body.schedule_read(body, ~on_read, ~on_eof);
    };
    H2.Body.schedule_read(body, ~on_read, ~on_eof);
    Lwt.return_unit;
  });

  next;
};


================================================
FILE: lwt-unix-httpaf/client_http.re
================================================
open Lwt.Infix;

let send:
  (~config: Httpaf.Config.t=?, Httpkit.Request.t) =>
  Lwt_result.t(
    (Httpaf.Response.t, Httpaf.Body.t([ | `read])),
    [> | `Connection_error(Httpaf.Client_connection.error)],
  ) =
  (~config=Httpaf.Config.default, req) => {
    let uri = Httpkit.Request.uri(req);

    let response_handler = (notify_response_received, response, response_body) => {
      Logs.debug(m => m("Handling response..."));
      Lwt.wakeup_later(
        notify_response_received,
        (response, response_body) |> Lwt_result.return,
      );
    };

    let error_handler = (notify_response_received, error) => {
      Logs.debug(m => m("Handling errors..."));
      Lwt.wakeup_later(
        notify_response_received,
        `Connection_error(error) |> Lwt_result.fail,
      );
    };

    let host = Uri.host_with_default(uri);
    let port =
      switch (Uri.port(uri)) {
      | None => "80"
      | Some(number) => string_of_int(number)
      };

    Logs.debug(m => m("Getting address for %s:%s", host, port));
    Lwt_unix.getaddrinfo(host, port, [Unix.(AI_FAMILY(PF_INET))])
    >>= (
      addresses => {
        let socket_addr = List.hd(addresses).Unix.ai_addr;
        let socket = Lwt_unix.socket(Unix.PF_INET, Unix.SOCK_STREAM, 0);
        Logs.debug(m => m("Opening socket to %s:%s", host, port));
        Lwt_unix.connect(socket, socket_addr)
        >>= (
          () => {
            let (response_received, notify_response_received) = Lwt.wait();
            let response_handler = response_handler(notify_response_received);
            let error_handler = error_handler(notify_response_received);

            let write_body = request_body => {
              switch (Httpkit.Request.body(req)) {
              | None => ()
              | Some(str) => Httpaf.Body.write_string(request_body, str)
              };
              Httpaf.Body.close_writer(request_body);
              Logs.debug(m => m("Request sent. Awaiting for response..."));
              response_received >>= (x => x);
            };

            let request = Client_request.of_httpkit_request(req);

            Logs.debug(m =>
              m("Sending request: \n\n%s", req |> Httpkit.Request.to_string)
            );
            Httpaf_lwt_unix.Client.request(
              ~config,
              ~error_handler,
              ~response_handler,
              socket,
              request,
            )
            |> write_body;
          }
        );
      }
    );
  };


================================================
FILE: lwt-unix-httpaf/client_https.re
================================================
open Lwt.Infix;

type client_security = [
  | `No_authentication
];

let send:
  (
    ~config: Httpaf.Config.t=?,
    ~client: client_security=?,
    Httpkit.Request.t
  ) =>
  Lwt_result.t(
    (Httpaf.Response.t, Httpaf.Body.t([ | `read])),
    [> | `Connection_error(Httpaf.Client_connection.error)],
  ) =
  (~config=Httpaf.Config.default, ~client as _=`No_authentication, req) => {
    let uri = Httpkit.Request.uri(req);

    let response_handler = (notify_response_received, response, response_body) => {
      Logs.debug(m => m("Handling response..."));
      Lwt.wakeup_later(
        notify_response_received,
        (response, response_body) |> Lwt_result.return,
      );
    };

    let error_handler = (notify_response_received, error) => {
      Logs.debug(m => m("Handling errors..."));
      Lwt.wakeup_later(
        notify_response_received,
        `Connection_error(error) |> Lwt_result.fail,
      );
    };

    let host = Uri.host_with_default(uri);
    let port =
      switch (Uri.port(uri)) {
      | None => "443"
      | Some(number) => string_of_int(number)
      };

    Lwt_unix.getaddrinfo(host, port, [Unix.(AI_FAMILY(PF_INET))])
    >>= (
      addresses => {
        Logs.debug(m => m("Got address..."));
        let socket_addr = List.hd(addresses).Unix.ai_addr;
        let socket = Lwt_unix.socket(Unix.PF_INET, Unix.SOCK_STREAM, 0);

        Lwt_unix.connect(socket, socket_addr)
        >>= (
          () => {
            Logs.debug(m => m("Opened socket..."));
            let (response_received, notify_response_received) = Lwt.wait();
            let response_handler = response_handler(notify_response_received);
            let error_handler = error_handler(notify_response_received);

            let write_body = request_body => {
              Logs.debug(m => m("Writing body..."));
              switch (Httpkit.Request.body(req)) {
              | None => ()
              | Some(str) => Httpaf.Body.write_string(request_body, str)
              };
              Httpaf.Body.close_writer(request_body);
              response_received >>= (x => x);
            };

            let request = Client_request.of_httpkit_request(req);

            Httpaf_lwt_unix.Client.SSL.request(
              ~config,
              ~error_handler,
              ~response_handler,
              socket,
              request
            )
            |> write_body
          }
        );
      }
    );
  };


================================================
FILE: lwt-unix-httpaf/client_request.re
================================================
let of_httpkit_request = req => {
  Httpkit.(
    Httpaf.Request.create(
      ~headers=req |> Request.headers |> Httpaf.Headers.of_list,
      req |> Request.meth,
      req |> Request.path,
    )
  );
};

let to_httpkit_request = (~body, ~uri, req) => {
  Httpkit.Request.create(
    ~headers=req.Httpaf.Request.headers |> Httpaf.Headers.to_list,
    ~body=
      switch (body) {
      | None => ""
      | Some(b) => b
      },
    req.meth,
    uri,
  );
};


================================================
FILE: lwt-unix-httpaf/client_response.re
================================================
let body:
  ((Httpaf.Response.t, Httpaf.Body.t([ | `read]))) => Lwt_result.t(string, 'b) =
  ((_response, body)) => {
    open Lwt.Infix;
    let buffer = Buffer.create(2048);
    Logs.debug(m => m("Prepared buffer for response body..."));
    let (next, wakeup) = Lwt.wait();
    Lwt.async(() => {
      let rec read_response = () =>
        Httpaf.Body.schedule_read(
          body,
          ~on_eof=
            () => Lwt.wakeup_later(wakeup, Ok(Buffer.contents(buffer))),
          ~on_read=
            (response_fragment, ~off, ~len) => {
              let response_fragment_string = Bytes.create(len);
              Lwt_bytes.blit_to_bytes(
                response_fragment,
                off,
                response_fragment_string,
                0,
                len,
              );
              Buffer.add_bytes(buffer, response_fragment_string);
              read_response();
            },
        );
      read_response() |> Lwt.return;
    })
    |> ignore;
    next >>= Lwt_result.lift;
  };


================================================
FILE: lwt-unix-httpaf/dune
================================================
(library
  (name httpkit_lwt_unix_httpaf)
  (public_name httpkit-lwt-unix-httpaf)
  (libraries httpkit httpaf httpaf-lwt-unix lwt lwt.unix uri logs logs.lwt bigstringaf))


================================================
FILE: lwt-unix-httpaf/httpkit_lwt_unix_httpaf.re
================================================
module Method = Httpkit.Method;

module Status = Httpkit.Status;

module Request = Httpkit.Request;

module Server = {
  include Httpkit.Server;
  module Http = Server_http;
};

module Client = {
  module Https = Client_https;
  module Http = Client_http;
  module Response = Client_response;
};


================================================
FILE: lwt-unix-httpaf/server_http.re
================================================
open Lwt.Infix;

let make_request_handler:
  (
    ~uri: Uri.t,
    ~handler: Httpkit.Server.handler,
    ~closer: unit => unit,
    Unix.sockaddr
  ) =>
  Httpaf.Server_connection.request_handler =
  (~uri, ~handler, ~closer, _client, reqd) => {
    let req = reqd |> Httpaf.Reqd.request;
    Logs.debug(m => m("Handling request..."));
    let respond = (~headers=?, status, content) => {
      let headers =
        (
          switch (headers) {
          | None => []
          | Some(hs) => hs
          }
        )
        @ [("content-length", content |> String.length |> string_of_int)]
        |> Httpaf.Headers.of_list;
      let res =
        Httpaf.Response.create(status |> Httpaf.Status.of_code, ~headers);
      Httpaf.Reqd.respond_with_string(reqd, res, content);
    };
    Server_request.read_body(reqd)
    >|= (
      body => {
        let uri = Uri.with_path(uri, req.target);
        let req = Client_request.to_httpkit_request(~uri, ~body, req);
        let () = handler(req, respond, closer);
        ();
      }
    )
    |> ignore;
  };

let error_handler = (_client, ~request as _=?, err, _get) => {
  Logs.err(m =>
    m(
      "Something went wrong! %s",
      switch (err) {
      | `Bad_gateway => "Bad gateway"
      | `Bad_request => "Bad request"
      | `Internal_server_error => "Internal_server_error"
      | `Exn(exn) => Printexc.to_string(exn)
      },
    )
  );
  ();
};

let listen:
  (
    ~address: [ | `Loopback | `Any | `Of_string(string)]=?,
    ~port: int,
    ~on_start: (~hoststring: string) => unit,
    ~handler: Httpkit.Server.handler
  ) =>
  Lwt.t(unit) =
  (~address=`Any, ~port, ~on_start, ~handler) => {
    let host =
      switch (address) {
      | `Loopback => "127.0.0.1"
      | `Any => "0.0.0.0"
      | `Of_string(str) => str
      };
    let uri = Uri.make(~scheme="http", ~host, ~port, ());

    let (forever, awaker) = Lwt.wait();
    let closer = () => Lwt.wakeup_later(awaker, ());

    let address =
      switch (address) {
      | `Loopback => Unix.inet_addr_loopback
      | `Any => Unix.inet_addr_any
      | `Of_string(str) => Unix.inet_addr_of_string(str)
      };
    let listening_address = Unix.(ADDR_INET(address, port));

    let connection_handler =
      Httpaf_lwt_unix.Server.create_connection_handler(
        ~config=Httpaf.Config.default,
        ~request_handler=make_request_handler(~uri, ~handler, ~closer),
        ~error_handler,
      );

    Lwt_io.establish_server_with_client_socket(
      listening_address,
      connection_handler,
    )
    >|= (_ => on_start(~hoststring=Uri.to_string(uri)))
    |> ignore;

    forever;
  };


================================================
FILE: lwt-unix-httpaf/server_request.re
================================================
let read_body = reqd => {
  let (next, awake) = Lwt.wait();

  Lwt.async(() => {
    let body = reqd |> Httpaf.Reqd.request_body;
    let body_str = ref("");
    let on_eof = () => Lwt.wakeup_later(awake, Some(body_str^));
    let rec on_read = (request_data, ~off, ~len) => {
      let read = Bigstringaf.substring(~off, ~len, request_data);
      body_str := body_str^ ++ read;
      Httpaf.Body.schedule_read(body, ~on_read, ~on_eof);
    };
    Httpaf.Body.schedule_read(body, ~on_read, ~on_eof);
    Lwt.return_unit;
  });

  next;
};


================================================
FILE: src/dune
================================================
(library
  (name httpkit)
  (public_name httpkit)
  (libraries httpaf h2 uri logs))


================================================
FILE: src/httpkit.re
================================================
module Method = H2.Method;

module Status = H2.Status;

module Request = {
  type t = {
    meth: Method.t,
    uri: Uri.t,
    body: option(string),
    headers: list((string, string)),
  };

  let body = t => t.body;
  let content_length = t =>
    switch (t.body) {
    | None => 0
    | Some(body) => String.length(body)
    };
  let meth = t => t.meth;
  let uri = t => t.uri;
  let path = t => t.uri |> Uri.path_and_query;
  let headers = t => t.headers;
  let host = t => t.uri |> Uri.host_with_default;
  let scheme = t =>
    switch (t |> uri |> Uri.scheme) {
    | None => ""
    | Some(s) => s
    };

  let create = (~headers=[], ~body="", meth, uri) => {
    let host = Uri.host_with_default(uri);
    let content_length = body |> String.length |> string_of_int;
    let headers =
      [("host", host), ("content-length", content_length)]
      @ (headers |> List.map(((k, v)) => (k |> String.lowercase_ascii, v)));
    let body =
      switch (body) {
      | "" => None
      | _ => Some(body)
      };

    {meth, uri, headers, body};
  };

  let to_string = req => {
    (req.meth |> H2.Method.to_string)
    ++ " "
    ++ (req.uri |> Uri.path)
    ++ "\n"
    ++ (req.headers |> H2.Headers.of_list |> H2.Headers.to_string)
    ++ (
      switch (req.body) {
      | None => ""
      | Some(s) => "\n\n" ++ s
      }
    );
  };
};

module Server = {
  type replier = (~headers: list((string, string))=?, int, string) => unit;

  type closer = unit => unit;

  type handler = (Request.t, replier, closer) => unit;
};
Download .txt
gitextract_lfbuuy6e/

├── .gitattributes
├── .gitignore
├── 3rdparty/
│   ├── dune-project
│   ├── httpaf-lwt-unix/
│   │   ├── buffer.ml
│   │   ├── buffer.mli
│   │   ├── dune
│   │   ├── httpaf_lwt_unix.ml
│   │   ├── httpaf_lwt_unix.mli
│   │   ├── ssl_io.ml
│   │   └── tls_io.ml
│   └── httpaf-lwt-unix.opam
├── README.md
├── bench/
│   ├── .gitignore
│   ├── Gemfile
│   ├── README.md
│   ├── echo.go
│   ├── echo.js
│   ├── echo.py
│   └── echo.rb
├── dune-project
├── esy.json
├── examples/
│   ├── dune
│   ├── echo_server_http.re
│   ├── echo_server_http2.re
│   ├── request_http.re
│   └── request_http2.re
├── httpkit-lwt-unix-h2.opam
├── httpkit-lwt-unix-httpaf.opam
├── httpkit.opam
├── lwt-unix-h2/
│   ├── client_http.re
│   ├── client_https.re
│   ├── client_request.re
│   ├── client_response.re
│   ├── dune
│   ├── httpkit_lwt_unix_h2.re
│   ├── server_http.re
│   └── server_request.re
├── lwt-unix-httpaf/
│   ├── client_http.re
│   ├── client_https.re
│   ├── client_request.re
│   ├── client_response.re
│   ├── dune
│   ├── httpkit_lwt_unix_httpaf.re
│   ├── server_http.re
│   └── server_request.re
└── src/
    ├── dune
    └── httpkit.re
Download .txt
SYMBOL INDEX (5 symbols across 2 files)

FILE: bench/echo.go
  constant DefaultPort (line 9) | DefaultPort = "8080"
  function EchoHandler (line 11) | func EchoHandler(writer http.ResponseWriter, request *http.Request) {
  function main (line 18) | func main() {

FILE: bench/echo.py
  class handler (line 5) | class handler(BaseHTTPRequestHandler):
    method do_GET (line 6) | def do_GET(self):
Condensed preview — 47 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (67K chars).
[
  {
    "path": ".gitattributes",
    "chars": 146,
    "preview": "bench/* linguist-vendored\n*.re linguist-language=Reason\n*.rei linguist-language=Reason\n*.ml linguist-language=OCaml\n*.ml"
  },
  {
    "path": ".gitignore",
    "chars": 56,
    "preview": "_esy\n_build\n_public\n.merlin\n/lua\n/lua_modules\n*.install\n"
  },
  {
    "path": "3rdparty/dune-project",
    "chars": 39,
    "preview": "(lang dune 1.9)\n(name httpaf-lwt-unix)\n"
  },
  {
    "path": "3rdparty/httpaf-lwt-unix/buffer.ml",
    "chars": 734,
    "preview": "open Lwt.Infix\n\n(* Based on the Buffer module in httpaf_async.ml. *)\ntype t =\n  { buffer      : Lwt_bytes.t\n  ; mutable "
  },
  {
    "path": "3rdparty/httpaf-lwt-unix/buffer.mli",
    "chars": 177,
    "preview": "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_"
  },
  {
    "path": "3rdparty/httpaf-lwt-unix/dune",
    "chars": 205,
    "preview": "(library\n (name httpaf_lwt_unix)\n (public_name httpaf-lwt-unix)\n (libraries faraday-lwt-unix httpaf lwt.unix ssl lwt_ssl"
  },
  {
    "path": "3rdparty/httpaf-lwt-unix/httpaf_lwt_unix.ml",
    "chars": 10876,
    "preview": "(*----------------------------------------------------------------------------\n    Copyright (c) 2018 Inhabited Type LLC"
  },
  {
    "path": "3rdparty/httpaf-lwt-unix/httpaf_lwt_unix.mli",
    "chars": 2325,
    "preview": "open Httpaf\n\n\n(* The function that results from [create_connection_handler] should be passed\n   to [Lwt_io.establish_ser"
  },
  {
    "path": "3rdparty/httpaf-lwt-unix/ssl_io.ml",
    "chars": 1868,
    "preview": "open Lwt.Infix\n\nlet () = Ssl.init ()\n\nlet readf socket =\n  fun _fd buffer ->\n  Lwt.catch\n    (fun () ->\n      Buffer.put"
  },
  {
    "path": "3rdparty/httpaf-lwt-unix/tls_io.ml",
    "chars": 512,
    "preview": "let readf _tls =\n  fun _fd _buffer ->\n  Lwt.fail_with \"Tls not available\"\n\nlet writev _tls _fd =\n  fun _iovecs ->\n  Lwt."
  },
  {
    "path": "3rdparty/httpaf-lwt-unix.opam",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "README.md",
    "chars": 3224,
    "preview": "# ⚡️HttpKit — high-level, high-performance HTTP1.1/2 clients/servers in Reason\n\n> NOTE: under heavy reconstruction. Late"
  },
  {
    "path": "bench/.gitignore",
    "chars": 5,
    "preview": "echo\n"
  },
  {
    "path": "bench/Gemfile",
    "chars": 42,
    "preview": "source \"https://rubygems.org\"\n\ngem \"rack\"\n"
  },
  {
    "path": "bench/README.md",
    "chars": 10058,
    "preview": "# Benchmarking HttpKit ⚡️\n\nIn order to ensure that `httpkit` stays fast, here you'll find a number of small\nservers writ"
  },
  {
    "path": "bench/echo.go",
    "chars": 436,
    "preview": "package main\n\nimport (\n\t\"bytes\"\n\t\"log\"\n\t\"net/http\"\n)\n\nconst DefaultPort = \"8080\"\n\nfunc EchoHandler(writer http.ResponseW"
  },
  {
    "path": "bench/echo.js",
    "chars": 204,
    "preview": "const httpServer = require('http');\n\nhttpServer.createServer((req, res) => {\n  console.log(new Date(), req.method, req.u"
  },
  {
    "path": "bench/echo.py",
    "chars": 424,
    "preview": "from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer\n\nPORT_NUMBER = 8080\n\nclass handler(BaseHTTPRequestHandler):"
  },
  {
    "path": "bench/echo.rb",
    "chars": 257,
    "preview": "require 'rack'\n \napp = Proc.new do |env|\n  req = Rack::Request.new(env)\n  meth = req.request_method\n  path = req.path\n  "
  },
  {
    "path": "dune-project",
    "chars": 47,
    "preview": "(lang dune 1.5)\n(name httpkit)\n(using fmt 1.0)\n"
  },
  {
    "path": "esy.json",
    "chars": 1037,
    "preview": "{\n  \"dependencies\": {\n    \"@esy-ocaml/reason\": \"3.4.0\",\n    \"@opam/dune\": \"*\",\n    \"@opam/fmt\": \"*\",\n    \"@opam/h2\": \"0."
  },
  {
    "path": "examples/dune",
    "chars": 595,
    "preview": "(executable\n  (name request_http)\n  (modules request_http)\n\t(ocamlopt_flags -O3)\n  (libraries httpkit-lwt-unix-httpaf ht"
  },
  {
    "path": "examples/echo_server_http.re",
    "chars": 695,
    "preview": "/** Handle sigpipe internally */\nSys.(set_signal(sigpipe, Signal_ignore));\n\n/** Setup loggers */\nFmt_tty.setup_std_outpu"
  },
  {
    "path": "examples/echo_server_http2.re",
    "chars": 691,
    "preview": "/** Handle sigpipe internally */\nSys.(set_signal(sigpipe, Signal_ignore));\n\n/** Setup loggers */\nFmt_tty.setup_std_outpu"
  },
  {
    "path": "examples/request_http.re",
    "chars": 1356,
    "preview": "open Lwt_result.Infix;\n\n/** Handle sigpipe internally */\nSys.(set_signal(sigpipe, Signal_ignore));\n\n/** Setup loggers */"
  },
  {
    "path": "examples/request_http2.re",
    "chars": 1351,
    "preview": "open Lwt_result.Infix;\n\n/** Handle sigpipe internally */\nSys.(set_signal(sigpipe, Signal_ignore));\n\n/** Setup loggers */"
  },
  {
    "path": "httpkit-lwt-unix-h2.opam",
    "chars": 578,
    "preview": "opam-version: \"2.0\"\nname: \"httpkit-lwt-unix-h2\"\nversion: \"0.13\"\nsynopsis: \"High-level, High-performance HTTP(S) Clients/"
  },
  {
    "path": "httpkit-lwt-unix-httpaf.opam",
    "chars": 567,
    "preview": "opam-version: \"2.0\"\nname: \"httpkit-lwt-unix-httpaf\"\nversion: \"0.13\"\nsynopsis: \"High-level, High-performance HTTP(S) Clie"
  },
  {
    "path": "httpkit.opam",
    "chars": 510,
    "preview": "opam-version: \"2.0\"\nname: \"httpkit\"\nversion: \"0.13\"\nsynopsis: \"High-level, High-performance HTTP(S) Clients/Servers\"\nmai"
  },
  {
    "path": "lwt-unix-h2/client_http.re",
    "chars": 2565,
    "preview": "open Lwt.Infix;\n\nlet send:\n  (~config: H2.Config.t=?, Httpkit.Request.t) =>\n  Lwt_result.t(\n    (H2.Response.t, H2.Body."
  },
  {
    "path": "lwt-unix-h2/client_https.re",
    "chars": 3505,
    "preview": "open Lwt.Infix;\n\nSsl_threads.init();\nSsl.init();\nlet default_ssl_context = Ssl.create_context(Ssl.SSLv23, Ssl.Client_con"
  },
  {
    "path": "lwt-unix-h2/client_request.re",
    "chars": 704,
    "preview": "let of_httpkit_request = req => {\n  open Httpkit;\n  let host = req |> Request.host;\n  let scheme = req |> Request.scheme"
  },
  {
    "path": "lwt-unix-h2/client_response.re",
    "chars": 996,
    "preview": "let body:\n  ((H2.Response.t, H2.Body.t([ | `read]))) => Lwt.t(result(string, 'b)) =\n  ((_response, body)) => {\n    open "
  },
  {
    "path": "lwt-unix-h2/dune",
    "chars": 168,
    "preview": "(library\n  (name httpkit_lwt_unix_h2)\n  (public_name httpkit-lwt-unix-h2)\n  (libraries httpkit h2 h2-lwt h2-lwt-unix lwt"
  },
  {
    "path": "lwt-unix-h2/httpkit_lwt_unix_h2.re",
    "chars": 296,
    "preview": "module Method = Httpkit.Method;\n\nmodule Status = Httpkit.Status;\n\nmodule Request = Httpkit.Request;\n\nmodule Server = {\n "
  },
  {
    "path": "lwt-unix-h2/server_http.re",
    "chars": 2599,
    "preview": "open Lwt.Infix;\n\nlet make_request_handler:\n  (\n    ~uri: Uri.t,\n    ~handler: Httpkit.Server.handler,\n    ~closer: unit "
  },
  {
    "path": "lwt-unix-h2/server_request.re",
    "chars": 528,
    "preview": "let read_body = reqd => {\n  let (next, awake) = Lwt.wait();\n\n  Lwt.async(() => {\n    let body = reqd |> H2.Reqd.request_"
  },
  {
    "path": "lwt-unix-httpaf/client_http.re",
    "chars": 2491,
    "preview": "open Lwt.Infix;\n\nlet send:\n  (~config: Httpaf.Config.t=?, Httpkit.Request.t) =>\n  Lwt_result.t(\n    (Httpaf.Response.t, "
  },
  {
    "path": "lwt-unix-httpaf/client_https.re",
    "chars": 2447,
    "preview": "open Lwt.Infix;\n\ntype client_security = [\n  | `No_authentication\n];\n\nlet send:\n  (\n    ~config: Httpaf.Config.t=?,\n    ~"
  },
  {
    "path": "lwt-unix-httpaf/client_request.re",
    "chars": 462,
    "preview": "let of_httpkit_request = req => {\n  Httpkit.(\n    Httpaf.Request.create(\n      ~headers=req |> Request.headers |> Httpaf"
  },
  {
    "path": "lwt-unix-httpaf/client_response.re",
    "chars": 1022,
    "preview": "let body:\n  ((Httpaf.Response.t, Httpaf.Body.t([ | `read]))) => Lwt_result.t(string, 'b) =\n  ((_response, body)) => {\n  "
  },
  {
    "path": "lwt-unix-httpaf/dune",
    "chars": 171,
    "preview": "(library\n  (name httpkit_lwt_unix_httpaf)\n  (public_name httpkit-lwt-unix-httpaf)\n  (libraries httpkit httpaf httpaf-lwt"
  },
  {
    "path": "lwt-unix-httpaf/httpkit_lwt_unix_httpaf.re",
    "chars": 296,
    "preview": "module Method = Httpkit.Method;\n\nmodule Status = Httpkit.Status;\n\nmodule Request = Httpkit.Request;\n\nmodule Server = {\n "
  },
  {
    "path": "lwt-unix-httpaf/server_http.re",
    "chars": 2631,
    "preview": "open Lwt.Infix;\n\nlet make_request_handler:\n  (\n    ~uri: Uri.t,\n    ~handler: Httpkit.Server.handler,\n    ~closer: unit "
  },
  {
    "path": "lwt-unix-httpaf/server_request.re",
    "chars": 540,
    "preview": "let read_body = reqd => {\n  let (next, awake) = Lwt.wait();\n\n  Lwt.async(() => {\n    let body = reqd |> Httpaf.Reqd.requ"
  },
  {
    "path": "src/dune",
    "chars": 84,
    "preview": "(library\n  (name httpkit)\n  (public_name httpkit)\n  (libraries httpaf h2 uri logs))\n"
  },
  {
    "path": "src/httpkit.re",
    "chars": 1535,
    "preview": "module Method = H2.Method;\n\nmodule Status = H2.Status;\n\nmodule Request = {\n  type t = {\n    meth: Method.t,\n    uri: Uri"
  }
]

About this extraction

This page contains the full source code of the ostera/httpkit GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 47 files (60.6 KB), approximately 17.9k tokens, and a symbol index with 5 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!