From 84404b498a73d8217337be440e0acdfce607fcf0 Mon Sep 17 00:00:00 2001 From: Doug Patti Date: Sat, 12 Sep 2020 13:48:55 -0400 Subject: [PATCH] report exceptions before closing the body In #148 we made sure the close and flush the body so that the receiver wouldn't potentially be left waiting. This changes the order so that the error handler is always called first, and then the body eof is sent. In practice, user code will typically wait for the response handler to be called, and at that point their only signal that the request is complete is to wait for the body eof. Likewise, the signal that there was an error and the request will not complete is the error handler. You can imagine having some client setup code that looks like this: ```ocaml let result = Ivar.create () in let on_eof () = Ivar.fill_if_empty result (Ok ()) in let error_handler e = Ivar.fill_if_empty result (Error e) in (* ... *) ``` By making sure we fire the error handler first, the user can correctly identify the result of the request and not accidentally mark it as complete. Fixes #187. --- lib_test/test_client_connection.ml | 33 ++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/lib_test/test_client_connection.ml b/lib_test/test_client_connection.ml index 1209ebc6..786cac8f 100644 --- a/lib_test/test_client_connection.ml +++ b/lib_test/test_client_connection.ml @@ -207,6 +207,38 @@ let test_report_exn () = !error_message ;; +let test_report_exn_during_body_read () = + let request' = Request.create `GET "/" in + let response = Response.create `OK in + + let body_done = ref false in + let error_message = ref None in + let body, t = + request + request' + ~response_handler:(fun _ body -> + let on_read _ ~off:_ ~len:_ = () in + let on_eof () = body_done := true in + Body.schedule_read body ~on_read ~on_eof) + ~error_handler:(function + | `Exn (Failure msg) -> + Alcotest.(check bool) "body is not complete" false !body_done; + error_message := Some msg + | _ -> assert false) + in + Body.close_writer body; + write_request t request'; + writer_closed t; + reader_ready t; + read_response t response; + report_exn t (Failure "something went wrong"); + connection_is_shutdown t; + Alcotest.(check (option string)) "something went wrong" + (Some "something went wrong") + !error_message; + Alcotest.(check bool) "body is complete" true !body_done; +;; + let test_input_shrunk () = let request' = Request.create `GET "/" in let response = Response.create `OK in (* not actually writen to the channel *) @@ -268,6 +300,7 @@ let tests = ; "Response EOF", `Quick, test_response_eof ; "Response header order preserved", `Quick, test_response_header_order ; "report_exn" , `Quick, test_report_exn + ; "report_exn_during_body_read", `Quick, test_report_exn_during_body_read ; "input_shrunk", `Quick, test_input_shrunk ; "failed response parse", `Quick, test_failed_response_parse ]