Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: all build clean test examples
.PHONY: all build clean test examples h1spec

build:
dune build @install
Expand All @@ -11,6 +11,9 @@ test:
examples:
dune build @examples

h1spec:
./scripts/run-h1spec.sh

watch:
dune build {httpun,httpun-async,httpun-lwt-unix}.install @runtest --watch

Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ opam install httpun

Check the [`examples`][examples] folder.

To run the black-box HTTP/1.1 `h1spec` suite from the Nix dev shell:

```bash
nix develop -c make h1spec
```

[examples]: https://github.com/anmonteiro/httpun/tree/master/examples

## License
Expand Down
1 change: 1 addition & 0 deletions examples/lwt/dune
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
(names
lwt_get
lwt_get_pipelined
lwt_h1spec_server
lwt_post
lwt_echo_post
lwt_https_get
Expand Down
50 changes: 50 additions & 0 deletions examples/lwt/lwt_h1spec_server.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
open Base
open Lwt.Infix
module Arg = Stdlib.Arg
module Buffer = Stdlib.Buffer
open Httpun
open Httpun_lwt_unix

let error_handler (_ : Unix.sockaddr) = Httpun_examples.Server.error_handler

let request_handler (_ : Unix.sockaddr) { Gluten.reqd; _ } =
let request = Reqd.request reqd in
let request_body = Reqd.request_body reqd in
let body = Buffer.create 128 in
let rec on_read buffer ~off ~len =
Buffer.add_string body (Bigstringaf.substring ~off ~len buffer);
Body.Reader.schedule_read request_body ~on_eof ~on_read
and on_eof () =
let response_headers =
Headers.of_list [ "content-length", Int.to_string (Buffer.length body) ]
in
let response_headers =
match Headers.get request.headers "content-type" with
| None -> response_headers
| Some value -> Headers.add response_headers "content-type" value
in
Reqd.respond_with_string
reqd
(Response.create ~headers:response_headers `OK)
(Buffer.contents body)
in
Body.Reader.schedule_read request_body ~on_eof ~on_read

let main port =
let listen_address = Unix.(ADDR_INET (inet_addr_loopback, port)) in
Lwt.async (fun () ->
Lwt_io.establish_server_with_client_socket
listen_address
(Server.create_connection_handler ~request_handler ~error_handler)
>|= fun _server ->
Stdio.printf "Listening on port %i for h1spec.\n%!" port);
let forever, _ = Lwt.wait () in
Lwt_main.run forever

let () =
let port = ref 8080 in
Arg.parse
[ "-p", Arg.Set_int port, " Listening port number (8080 by default)" ]
ignore
"Echoes request bodies for h1spec. Runs forever.";
main !port
33 changes: 32 additions & 1 deletion nix/default.nix
Original file line number Diff line number Diff line change
@@ -1,8 +1,25 @@
{ nix-filter, lib, stdenv, ocamlPackages, doCheck ? true }:
{
nix-filter,
lib,
stdenv,
ocamlPackages,
fetchFromGitHub,
writeShellApplication,
deno,
lsof,
doCheck ? true,
}:

with ocamlPackages;

let
h1specSrc = fetchFromGitHub {
owner = "uNetworking";
repo = "h1spec";
rev = "f0a5650a20c575fbea0f7179a3a9cfa50f20ba6e";
hash = "sha256-a71IlHg9oofIQ8wEu9JeQbgoJZ+RAwZKFp4uEXiALhw=";
};

genSrc = { dirs, files }:
with nix-filter; filter {
root = ./..;
Expand All @@ -14,6 +31,20 @@ let
} // args);

httpunPkgs = rec {
h1spec = writeShellApplication {
name = "h1spec";
runtimeInputs = [ deno ];
text = ''
exec deno run --allow-net ${h1specSrc}/http_test.ts "$@"
'';
};

httpun-h1spec = writeShellApplication {
name = "httpun-h1spec";
runtimeInputs = [ h1spec lsof ocamlPackages.dune ];
text = builtins.readFile ../scripts/run-h1spec.sh;
};

httpun-types = buildHttpun {
pname = "httpun-types";
src = genSrc {
Expand Down
3 changes: 2 additions & 1 deletion nix/shell.nix
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ with pkgs;

(mkShell {
OCAMLRUNPARAM = "b";
nativeBuildInputs =
nativeBuildInputs = [ packages.h1spec ]
++
lib.optionals release-mode [
cacert
curl
Expand Down
53 changes: 53 additions & 0 deletions scripts/run-h1spec.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/usr/bin/env bash

set -euo pipefail

port="${1:-8080}"
host="${H1SPEC_HOST:-127.0.0.1}"

find_repo_root() {
local dir="${PWD}"
while [[ "${dir}" != "/" ]]; do
if [[ -f "${dir}/dune-project" ]]; then
printf '%s\n' "${dir}"
return 0
fi
dir="$(dirname "${dir}")"
done
return 1
}

repo_root="$(find_repo_root || true)"
if [[ -z "${repo_root}" ]]; then
printf 'Could not find repo root from %s\n' "${PWD}" >&2
exit 1
fi

cd "${repo_root}"

server_pid=''
cleanup() {
if [[ -n "${server_pid}" ]] && kill -0 "${server_pid}" 2>/dev/null; then
kill "${server_pid}"
wait "${server_pid}" 2>/dev/null || true
fi
}
trap cleanup EXIT INT TERM

dune build examples/lwt/lwt_h1spec_server.exe
dune exec ./examples/lwt/lwt_h1spec_server.exe -- -p "${port}" &
server_pid=$!

for _ in $(seq 1 50); do
if lsof -n -iTCP:"${port}" -sTCP:LISTEN >/dev/null 2>&1; then
break
fi
sleep 0.1
done

if ! lsof -n -iTCP:"${port}" -sTCP:LISTEN >/dev/null 2>&1; then
printf 'Timed out waiting for server on port %s\n' "${port}" >&2
exit 1
fi

h1spec "${host}" "${port}"
Loading