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

Make server response type abstract and allow streaming in cohttp-eio #1024

Merged
merged 3 commits into from
May 30, 2024

Conversation

talex5
Copy link
Contributor

@talex5 talex5 commented Feb 28, 2024

This fixes #998.

The first commit adds an abstract response type and then uses type response = Http.Response.t * Body.t in cohttp-lwt and cohttp-eio to keep the final types the same (cohttp-async already defined this type anyway and so didn't need any updates).

The second is just a few trivial changes to cohttp-eio to make the third commit diff smaller.

The third commit changes the response type in cohttp-eio to type response = writer -> unit. This allows
handlers to write the response inside the function, rather than returning a request to cohttp to write it later. That's useful because it allows e.g. streaming from an open file and then closing it afterwards.

Partial application means that code using respond_string etc will continue to work as before.

This also exposes a more polymorphic version of the respond function that accepts sub-types of Flow.source, so that callers don't need to cast the body.

/cc @mefyl

@mefyl
Copy link
Contributor

mefyl commented Feb 29, 2024

Looks good to me!

I would even suggest making Cohttp_eio.Server.respond's status argument default to OK, just like Cohttp.Response.make, so that one need only replace (Cohttp.Response.make (), body) with Cohttp_eio.Server.respond ~body () to adapt to this change.

We might even make body positional since it's required anyway, making the signature:

val respond :
  ?headers:Http.Header.t ->
  ?flush:bool ->
  ?status:Http.Status.t ->
  _ Eio.Flow.source ->
  response IO.t

So that the simplest form becomes Cohttp_eio.Server.respond body.

@talex5
Copy link
Contributor Author

talex5 commented Mar 5, 2024

That probably is a better API, but it's trying to implement the signatures in the shared cohttp package, so they would have to be extra functions with different names if we did that. Maybe something for a separate PR?

CHANGES.md Show resolved Hide resolved

type t = {
conn_closed : conn -> unit;
handler : conn -> Http.Request.t -> body -> response_action IO.t;
handler : conn -> Http.Request.t -> body -> IO.ic -> IO.oc -> unit;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My only concern is that the change to old-style response was done to align the APIs, with this they APIs are diverging again (at least in the expectations and signatures)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, although not when using the normal response functions. So it's certainly possible to write code that works with both.

@mseri
Copy link
Collaborator

mseri commented May 17, 2024

What is the status of this? I'd like to make a RC release of cohttp in the next couple of weeks. @mefyl and @talex5 do you think we should merge it as is or it needs further discussion?

@mefyl
Copy link
Contributor

mefyl commented May 17, 2024

AFAIR this looks fine to me and we can merge it.

@mseri
Copy link
Collaborator

mseri commented May 20, 2024

@talex5 can you have a look at the conflict? I think after that we could merge

This will allow cohttp-eio to use a different type in future, which
should make streaming easier.
Makes next commit easier to read:

- Use `respond` helpers in example. Avoids it having to change.
- Remove useless `IO.t` and `>>=`.
- Move some functions later in the file, and they'll need to use
  `write`.
This changes the response type to `writer -> unit`. This allows
handlers to write the response inside the function, rather than
returning a request to cohttp to write it later. That's useful because
it allows e.g. streaming from an open file and then closing it
afterwards.

Partial application means that code using `respond_string` etc will
continue to work as before.

This also exposes a more polymorphic version of the `respond` function
that accepts sub-types of `Flow.source`, so that callers don't need to
cast the body.
@talex5
Copy link
Contributor Author

talex5 commented May 29, 2024

I rebased this. The conflict was due to #1025. If I understand the logic there correctly, this is what cohttp-lwt now does:

  1. The user's handler uses e.g. respond* to create an HTTP 1.1 response, possibly missing the connection header, and returns it.
  2. cohttp-lwt then notices that this isn't appropriate for the request and creates a fixed-up response with the correct header for the request (though still always HTTP 1.1, by the look of it).

The seems a bit odd. It would perhaps make more sense to create the response correctly in the first place, but that would require passing the request to respond, etc, which would be an API change.

For cohttp-eio, I modified the (abstract) writer type to include the request, so respond can build a correct response by itself. The test is simplified a bit because (as with Lwt's responders) the response is always HTTP 1.1, so Http.Response.is_keep_alive is always true when the header is missing.

@mseri
Copy link
Collaborator

mseri commented May 30, 2024

Thanks. I think it may be worth revising the api for cohttp-lwt but it could be done in a future 7.0 release

@mseri mseri merged commit 1d9e14b into mirage:master May 30, 2024
10 of 19 checks passed
@talex5 talex5 deleted the abstract-response branch June 9, 2024 16:02
avsm added a commit to avsm/opam-repository that referenced this pull request Nov 21, 2024
CHANGES:

- bump minimum dune version to 3.8 (@avsm)
- cohttp-eio: Use system authenticator in example.
- http, cohttp: remove the scheme field from requests. This means that
  [Request.uri] no longer returns the same URI as was to create the request
  with [Request.make] (@rgrinberg 1086)
- cohttp-eio: Remove unused `Client_intf` module (talex5 mirage/ocaml-cohttp#1081)
- cohttp-eio: Make server response type abstract and allow streaming in cohttp-eio (talex5 mirage/ocaml-cohttp#1024)
- cohttp-{lwt,eio}: server: add connection header to response if not present (ushitora-anqou mirage/ocaml-cohttp#1025)
- cohttp-curl: Curl no longer prepends the first HTTP request header to the output. (jonahbeckford mirage/ocaml-cohttp#1030, mirage/ocaml-cohttp#987)
- cohttp-eio: client: use permissive argument type for make_generic
- cohttp-eio: Improve error handling in example server (talex5 mirage/ocaml-cohttp#1023)
- cohttp-eio: Don't blow up `Server.callback` on client disconnections. (mefyl mirage/ocaml-cohttp#1015)
- http: Fix assertion in `Source.to_string_trim` when `pos <> 0` (mefyl mirage/ocaml-cohttp#1017)
- cohttp: `Cohttp.Request.make_for_client` no longer allows setting both
  `~chunked:true` and `~body_length`.
- cohttp-lwt-unix: Don't blow up when certificates are not available and no-network requests are made. (akuhlens mirage/ocaml-cohttp#1027)
  + Makes `cohttp-lwt.S.default_ctx` lazy.
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 this pull request may close these issues.

Make response type abstract
3 participants