From 29ddd7ff4ab81bfc8714c1f1a1aff96b99ca263b Mon Sep 17 00:00:00 2001 From: Etienne Millon Date: Wed, 24 Jul 2019 17:04:54 +0200 Subject: [PATCH 1/2] Async client: do not read body if there is none Responses with code 204 (No content) and 304 (Not modified) do not have bodies. They can come with no Content-Length header, in which case the transfer encoding is inferred as `Transfer.Unknown`. When trying to read the nonexistent body, it would do so using `Transfer_io.Unknown.read`, which attempts to read until EOF, which can cause hangs. There is some logic in `Response.has_body` to determine if we should attempt to read a body at all. This was hooked in the `Lwt` backend but not in the `Async` one. Closes #666 --- cohttp-async/src/client.ml | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/cohttp-async/src/client.ml b/cohttp-async/src/client.ml index 5227e19ea6..97426f1c13 100644 --- a/cohttp-async/src/client.ml +++ b/cohttp-async/src/client.ml @@ -50,10 +50,17 @@ let read_request ic = | `Eof -> failwith "Connection closed by remote host" | `Invalid reason -> failwith reason | `Ok res -> - (* Build a response pipe for the body *) - let reader = Response.make_body_reader res ic in - let pipe = Body_raw.pipe_of_body Response.read_body_chunk reader in - (res, pipe) + begin + match Response.has_body res with + | `Yes | `Unknown -> + (* Build a response pipe for the body *) + let reader = Response.make_body_reader res ic in + let pipe = Body_raw.pipe_of_body Response.read_body_chunk reader in + (res, pipe) + | `No -> + let pipe = Pipe.of_list [] in + (res, pipe) + end let request ?interrupt ?ssl_config ?uri ?(body=`Empty) req = (* Connect to the remote side *) From 816409ab1c6cb7add03c84fa992da9c8e232389f Mon Sep 17 00:00:00 2001 From: Etienne Millon Date: Thu, 25 Jul 2019 09:29:39 +0200 Subject: [PATCH 2/2] Rename to read_response --- cohttp-async/src/client.ml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cohttp-async/src/client.ml b/cohttp-async/src/client.ml index 97426f1c13..eaafebb1f7 100644 --- a/cohttp-async/src/client.ml +++ b/cohttp-async/src/client.ml @@ -45,7 +45,7 @@ module Net = struct Conduit_async.V2.connect ?interrupt mode end -let read_request ic = +let read_response ic = Response.read ic >>| function | `Eof -> failwith "Connection closed by remote host" | `Invalid reason -> failwith reason @@ -74,7 +74,7 @@ let request ?interrupt ?ssl_config ?uri ?(body=`Empty) req = Request.write (fun writer -> Body_raw.write_body Request.write_body body writer) req oc >>= fun () -> - read_request ic >>| fun (resp, body) -> + read_response ic >>| fun (resp, body) -> don't_wait_for ( Pipe.closed body >>= fun () -> Deferred.all_unit [Reader.close ic; Writer.close oc]); @@ -103,7 +103,7 @@ let callv ?interrupt ?ssl_config uri reqs = if Pipe.is_closed reqs && (!resp_c >= !reqs_c) then return `Eof else - ic |> read_request >>| fun (resp, body) -> + ic |> read_response >>| fun (resp, body) -> Int.incr resp_c; last_body_drained := Pipe.closed body; `Ok (resp, `Pipe body)