Skip to content

Commit

Permalink
add a few missing dependencies to dream.opam; allow the dune-project …
Browse files Browse the repository at this point in the history
…to run cram tests; add a cram test for aantron#118; propose a small fix for aantron#118
  • Loading branch information
pm-mck committed Oct 3, 2021
1 parent 431cf8c commit 93fe295
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 32 deletions.
4 changes: 4 additions & 0 deletions dream.opam
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ depends: [
"conf-libev" {os != "win32"}
"cstruct" {>= "6.0.0"}
"dune" {>= "2.7.0"} # --instrument-with.
"emile"
"fmt" {>= "0.8.7"} # `Italic.
"graphql_parser"
"graphql-lwt"
Expand All @@ -64,9 +65,12 @@ depends: [
"lwt_ssl"
"logs" {>= "0.5.0"}
"magic-mime"
"mimic"
"mirage-clock"
"mirage-crypto" {>= "0.8.1"} # AES-256-GCM.
"mirage-crypto-rng" {>= "0.8.0"} # Signature of initialize.
"mirage-time"
"mirage-stack"
"multipart_form" {>= "0.3.0"}
"ocaml" {>= "4.08.0"}
"ssl" {>= "0.5.8"} # Ssl.get_negotiated_alpn_protocol.
Expand Down
1 change: 1 addition & 0 deletions dune-project
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
(lang dune 2.7)
(cram enable)
70 changes: 38 additions & 32 deletions src/http/error_handler.ml
Original file line number Diff line number Diff line change
Expand Up @@ -117,40 +117,46 @@ let customize template (error : Dream.error) =

(* First, log the error. *)

let log_handler condition (error : Dream.error) =
let client =
match error.client with
| None -> ""
| Some client -> " (" ^ client ^ ")"
in

let layer =
match error.layer with
| `TLS -> ["TLS" ^ client]
| `HTTP -> ["HTTP" ^ client]
| `HTTP2 -> ["HTTP/2" ^ client]
| `WebSocket -> ["WebSocket" ^ client]
| `App -> []
in

let description, backtrace =
match condition with
| `String string -> string, ""
| `Exn exn ->
let backtrace = Printexc.get_backtrace () in
Printexc.to_string exn, backtrace
in

let message = String.concat ": " (layer @ [description]) in

select_log error.severity (fun log ->
log ?request:error.request "%s" message);
backtrace |> Dream__middleware.Log.iter_backtrace (fun line ->
select_log error.severity (fun log ->
log ?request:error.request "%s" line))
in
begin match error.condition with
| `Response _ -> ()
| `String _ | `Exn _ as condition ->

let client =
match error.client with
| None -> ""
| Some client -> " (" ^ client ^ ")"
in

let layer =
match error.layer with
| `TLS -> ["TLS" ^ client]
| `HTTP -> ["HTTP" ^ client]
| `HTTP2 -> ["HTTP/2" ^ client]
| `WebSocket -> ["WebSocket" ^ client]
| `App -> []
in

let description, backtrace =
match condition with
| `String string -> string, ""
| `Exn exn ->
let backtrace = Printexc.get_backtrace () in
Printexc.to_string exn, backtrace
in

let message = String.concat ": " (layer @ [description]) in

select_log error.severity (fun log ->
log ?request:error.request "%s" message);
backtrace |> Dream__middleware.Log.iter_backtrace (fun line ->
select_log error.severity (fun log ->
log ?request:error.request "%s" line))
(* TODO is this the right place to handle lower level connection resets? *)
| `Exn (Unix.Unix_error (Unix.ECONNRESET, _, _)) ->
let condition = `String "Connection Reset at Client" in
let severity = `Info in
log_handler condition {error with condition; severity}
| `String _ | `Exn _ as condition -> log_handler condition error
end;

(* If Dream will not send a response for this error, we are done after
Expand Down
2 changes: 2 additions & 0 deletions test/cram/dune
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
(cram
(applies_to :whole_subtree))
6 changes: 6 additions & 0 deletions test/cram/http/dune
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
(executable
(name econnreset)
(libraries dream))

(cram
(deps %{exe:econnreset.exe}))
34 changes: 34 additions & 0 deletions test/cram/http/econnreset.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
(* This file is part of Dream, released under the MIT license. See LICENSE.md
for details, or visit https://github.com/aantron/dream.
Copyright 2021 Anton Bachin *)

let serve port =
print_endline "server mode";
Dream.run ~greeting:false ~port (fun _ -> Unix.sleepf 10.0; Dream.html "Hello")

let client port =
print_endline "client mode";
let open Unix in
let fd = socket PF_INET6 SOCK_STREAM 0 in
(* force the client to send a TCP RST packet if it fails during connection *)
setsockopt_optint fd SO_LINGER (Some 0);
let _ = connect fd (ADDR_INET (inet6_addr_loopback ,port)) in
ignore @@ failwith "sending RST";
shutdown fd SHUTDOWN_ALL

let () =
let server = ref(false) in
let port = ref(-1) in
let usage = "Test for ECONNRESET errors being reported" in
Arg.parse [
"-p", Set_int port, "sets the port (required)";
"-s", Set server, "enables the server on port [port], if not set sends a TCP RST on [port]"
] (fun _ -> ()) usage;

let port = !port in
if port > 65535 || port < 1025 then failwith "Port argument (-p) must set and be between 1025-65535";

if !server then serve port
else client port

18 changes: 18 additions & 0 deletions test/cram/http/issue_118_econnreset.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Start a Dream server

$ ./econnreset.exe -s -p 9191 &> test.log &
$ export PID=$!
$ sleep 1

Force a connection reset - will log a few errors

$ ./econnreset.exe -p 9191

Does the log contain an error line for the ECONNRESET? An error code of [1] is "good", meaning no line was found.

$ kill "${PID}"
$ cat test.log | grep 'ERROR' | grep 'ECONNRESET'

Does the log contain an info line with custom string for the ECONNRESET?

$ cat test.log | grep 'INFO' | grep 'Connection Reset at Client' | wc -l

0 comments on commit 93fe295

Please sign in to comment.