ocaml-cohttp icon indicating copy to clipboard operation
ocaml-cohttp copied to clipboard

Cohttp_lwt: body not consumed - leaking stream!

Open mseri opened this issue 5 years ago • 4 comments

This often still happened to me, I found out that I had to drain the body every time it was unused: e.g in redirects

| 301 | 302 | 307 | 308 ->
      let* () = Cohttp_lwt.Body.drain_body body in

mseri avatar Nov 06 '20 09:11 mseri

We could add a finalizer to the request handler that drains the body, but note that this still encourages poor behavior. You should start reading the body as soon as it's possible to allow pipelining to proceed.

Another option is to change the callback type to something like:

val drain_body : Body.t -> read_body Lwt.t (* no-op if the user already drained the body. *)
type callback = Request.t * Body.t -> (Response.t * read_body) Lwt.t

rgrinberg avatar Nov 06 '20 22:11 rgrinberg

The problem with the finalizer is that we cannot really call Lwt from it, otherwise we are forced to link unix in cohttp-lwt, at least we could not see how here: https://github.com/mirage/ocaml-cohttp/pull/696#discussion_r435838790

Calling the callback, maybe, would make things less ergonomic?

I think you make a good point that this fix would encourage bad behavior though. At least now we have a warning logged. Should I just add a paragraph about this in the readme then? What do you think?

mseri avatar Nov 06 '20 23:11 mseri

Wait, my bad. I initially thought you were referring to the problem on the server side. In which case we already use the finalizer appropriately. My suggestion above would improve the behavior further

On the client side, passing an explicit sink for the body is the safest bet.

(** Can be a GADT or just a fold *)
type 'a sink

val slurp : string sink

val discard : unit sink

val stream : (string -> unit Lwt.t) -> unit sink

val await : 'a sink -> 'a Lwt.t

val call : Uri.t -> Request.t -> 'a sink -> (Response.t * 'a Lwt.t) Lwt.t

In the above, I included await, but we call await already and just return its result.

rgrinberg avatar Nov 06 '20 23:11 rgrinberg

Partly related issue: https://github.com/mirage/ocaml-cohttp/issues/578

mseri avatar Mar 27 '21 19:03 mseri