Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No error raised when timeout occurs reading response body #187

Open
AndrewCarterUK opened this issue Sep 11, 2020 · 1 comment · May be fixed by #188
Open

No error raised when timeout occurs reading response body #187

AndrewCarterUK opened this issue Sep 11, 2020 · 1 comment · May be fixed by #188

Comments

@AndrewCarterUK
Copy link

Current Behaviour

If a timeout occurs before the client has received the full response body, no error is triggered despite the fact that the length of the returned body does not match the Content-Length header.

Expected Behaviour

If a timeout occurs before the client has received the full response body, an error condition should be raised.

Possible Fix

In client_connection.ml:

  let set_error_and_handle t error =
    Reader.force_close t.reader;
    begin match !(t.state) with
    | Closed -> ()
    | Awaiting_response ->
      set_error_and_handle_without_shutdown t error;
    | Received_response(_, response_body) ->
      Body.close_reader response_body;
      Body.execute_read response_body;
      set_error_and_handle_without_shutdown t error;
    end
  ;;

The order of instructions here is that the response body is closed before the error condition is raised. This triggered a handler for EOF before the error is set.

Setting the error first, fixes the issue in my testing:

  let set_error_and_handle t error =
    Reader.force_close t.reader;
    begin match !(t.state) with
    | Closed -> ()
    | Awaiting_response ->
      set_error_and_handle_without_shutdown t error;
    | Received_response(_, response_body) ->
      set_error_and_handle_without_shutdown t error;
      Body.close_reader response_body;
      Body.execute_read response_body;
    end
  ;;
@AndrewCarterUK AndrewCarterUK changed the title Deferred result resolves to Ok when timeout occurs reading request body No error raised when timeout occurs reading response body Sep 11, 2020
@dpatti
Copy link
Collaborator

dpatti commented Sep 11, 2020

To be clear, the "timeout" here came from a runtime, though in principal it can be substituted with any arbitrary Client_connection.report_exn.

dpatti added a commit that referenced this issue Sep 12, 2020
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.
@dpatti dpatti linked a pull request Sep 12, 2020 that will close this issue
dpatti added a commit that referenced this issue Sep 12, 2020
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants