+## v5.2.0 (2023-07-07)
+
+- cohttp-lwt server: call conn_closed before drainig the body of response on error (pirbo)
+
## v5.1.0 (2023-04-04)
- cohttp,cohttp-async server: correctly close broken streams (reported by Stéphane Glondu, fix by samhot and anuragsoni)
+ ```clean_dup``` enables the user to clean headers that follows the {{:https://tools.ietf.org/html/rfc7230#section-3.2.2} RFC7230§3.2.2} (no duplicate, except ```set-cookie```)
+ ```get_multi_concat``` has been added to get a result similar to the previous ```get``` function.
-- Cohttp.Header: performance improvement (mseri, anuragsoni #778)
+- Cohttp.Header: performance improvement (mseri, anuragsoni #778)
**Breaking** the headers are no-longer lowercased when parsed, the headers key comparison is case insensitive instead.
-- cohttp-lwt-unix: Adopt ocaml-conduit 5.0.0 (smorimoto #787)
+- cohttp-lwt-unix: Adopt ocaml-conduit 5.0.0 (smorimoto #787)
**Breaking** `Conduit_lwt_unix.connect`'s `ctx` param type chaged from `ctx` to `ctx Lazy.t`
- cohttp-mirage: fix deprecated fmt usage (tmcgilchrist #783)
+version: "5.2.0"
opam-version: "2.0"
maintainer: "anil@recoil.org"
authors: [
"dune" {>= "2.0"}
"async_kernel" {>= "v0.14.0"}
"async_unix" {>= "v0.14.0"}
- "async" {>= "v0.14.0"}
+ "async" {>= "v0.14.0" & < "v0.16.0"}
"base" {>= "v0.11.0"}
- "core" {with-test}
+ "core" {with-test & < "v0.15.0"}
"core_unix" {>= "v0.14.0"}
"cohttp" {= version}
"conduit-async" {>= "1.2.0"}
["dune" "runtest" "-p" name "-j" jobs] {with-test}
]
available: arch != "s390x"
-dev-repo: "git+https://github.com/mirage/ocaml-cohttp.git"
+dev-repo: "git+https://github.com/mirage/ocaml-cohttp.git"
\ No newline at end of file
+version: "5.2.0"
opam-version: "2.0"
maintainer: "anil@recoil.org"
authors: [
["dune" "build" "-p" name "-j" jobs]
["dune" "runtest" "-p" name "-j" jobs] {with-test}
]
-dev-repo: "git+https://github.com/mirage/ocaml-cohttp.git"
+dev-repo: "git+https://github.com/mirage/ocaml-cohttp.git"
\ No newline at end of file
+version: "5.2.0"
opam-version: "2.0"
maintainer: "anil@recoil.org"
authors: [
"dune" {>= "2.0"}
"conduit-lwt" {>= "5.0.0"}
"conduit-lwt-unix" {>= "5.0.0"}
- "cmdliner"
+ "cmdliner" {>= "1.1.0"}
"magic-mime"
"logs"
"fmt" {>= "0.8.2"}
["dune" "build" "-p" name "-j" jobs]
["dune" "runtest" "-p" name "-j" jobs] {with-test}
]
-dev-repo: "git+https://github.com/mirage/ocaml-cohttp.git"
+dev-repo: "git+https://github.com/mirage/ocaml-cohttp.git"
\ No newline at end of file
open Cmdliner
let uri =
- let loc : Uri.t Arg.converter =
+ let loc : Uri.t Arg.conv =
let parse s =
try `Ok (Uri.of_string s) with Failure _ -> `Error "unable to parse URI"
in
Arg.(value & opt (some string) None & info [ "o" ] ~docv:"FILE" ~doc)
let cmd =
- let doc = "retrieve a remote URI contents" in
- let man =
- [
- `S "DESCRIPTION";
- `P
- "$(tname) fetches the remote $(i,URI) and prints it to standard \
- output. The output file can also be specified with the $(b,-o) \
- option, and more verbose debugging out obtained via the $(b,-v) \
- option.";
- `S "BUGS";
- `P
- "Report them via e-mail to <mirageos-devel@lists.xenproject.org>, or \
- on the issue tracker at \
- <https://github.com/mirage/ocaml-cohttp/issues>";
- `S "SEE ALSO";
- `P "$(b,curl)(1), $(b,wget)(1)";
- ]
+ let info =
+ let version = Cohttp.Conf.version in
+ let doc = "retrieve a remote URI contents" in
+ let man =
+ [
+ `S "DESCRIPTION";
+ `P
+ "$(tname) fetches the remote $(i,URI) and prints it to standard \
+ output. The output file can also be specified with the $(b,-o) \
+ option, and more verbose debugging out obtained via the $(b,-v) \
+ option.";
+ `S "BUGS";
+ `P
+ "Report them via e-mail to <mirageos-devel@lists.xenproject.org>, or \
+ on the issue tracker at \
+ <https://github.com/mirage/ocaml-cohttp/issues>";
+ `S "SEE ALSO";
+ `P "$(b,curl)(1), $(b,wget)(1)";
+ ]
+ in
+ Cmd.info "cohttp-curl" ~version ~doc ~man
in
- ( Term.(pure run_client $ verb $ ofile $ uri $ meth),
- Term.info "cohttp-curl" ~version:Cohttp.Conf.version ~doc ~man )
+ let term = Term.(const run_client $ verb $ ofile $ uri $ meth) in
+ Cmd.v info term
-let () = match Term.eval cmd with `Error _ -> exit 1 | _ -> exit 0
+let () = exit @@ Cmd.eval cmd
Arg.(value & opt (some string) None & info [ "k" ] ~docv:"SSL_KEY" ~doc)
let cmd =
- let doc = "a simple http proxy" in
- let man =
- [
- `S "DESCRIPTION";
- `P "$(tname) sets up a simple http proxy with lwt as backend";
- `S "BUGS";
- `P
- "Report them via e-mail to <mirageos-devel@lists.xenproject.org>, or \
- on the issue tracker at \
- <https://github.com/mirage/ocaml-cohttp/issues>";
- ]
+ let info =
+ let version = Cohttp.Conf.version in
+ let doc = "a simple http proxy" in
+ let man =
+ [
+ `S "DESCRIPTION";
+ `P "$(tname) sets up a simple http proxy with lwt as backend";
+ `S "BUGS";
+ `P
+ "Report them via e-mail to <mirageos-devel@lists.xenproject.org>, or \
+ on the issue tracker at \
+ <https://github.com/mirage/ocaml-cohttp/issues>";
+ ]
+ in
+ Cmd.info "cohttp-proxy" ~version ~doc ~man
in
- ( Term.(pure lwt_start_proxy $ port $ host $ verb $ ssl_cert $ ssl_key),
- Term.info "cohttp-proxy" ~version:Cohttp.Conf.version ~doc ~man )
+ let term =
+ Term.(const lwt_start_proxy $ port $ host $ verb $ ssl_cert $ ssl_key)
+ in
+ Cmd.v info term
-let () = match Term.eval cmd with `Error _ -> exit 1 | _ -> exit 0
+let () = exit @@ Cmd.eval cmd
Arg.(value & pos 0 dir "." & info [] ~docv:"DOCROOT" ~doc)
let cmd =
- let doc = "a simple http server" in
- let man =
- [
- `S "DESCRIPTION";
- `P "$(tname) sets up a simple http server with lwt as backend";
- `S "BUGS";
- `P
- "Report them via e-mail to <mirageos-devel@lists.xenproject.org>, or \
- on the issue tracker at \
- <https://github.com/mirage/ocaml-cohttp/issues>";
- ]
+ let info =
+ let version = Cohttp.Conf.version in
+ let doc = "a simple http server" in
+ let man =
+ [
+ `S "DESCRIPTION";
+ `P "$(tname) sets up a simple http server with lwt as backend";
+ `S "BUGS";
+ `P
+ "Report them via e-mail to <mirageos-devel@lists.xenproject.org>, or \
+ on the issue tracker at \
+ <https://github.com/mirage/ocaml-cohttp/issues>";
+ ]
+ in
+ Cmd.info "cohttp-server" ~version ~doc ~man
+ in
+ let term =
+ Term.(const lwt_start_server $ doc_root $ port $ host $ index $ verb $ tls)
in
- ( Term.(pure lwt_start_server $ doc_root $ port $ host $ index $ verb $ tls),
- Term.info "cohttp-server" ~version:Cohttp.Conf.version ~doc ~man )
+ Cmd.v info term
-let () = match Term.eval cmd with `Error _ -> exit 1 | _ -> exit 0
+let () = exit @@ Cmd.eval cmd
(executables
(names cohttp_curl_lwt cohttp_proxy_lwt cohttp_server_lwt)
- (libraries cohttp-lwt-unix cohttp_server logs logs.lwt logs.fmt logs.cli
- cmdliner conduit-lwt fmt.tty)
+ (libraries
+ cohttp-lwt-unix
+ cohttp_server
+ logs
+ logs.lwt
+ logs.fmt
+ logs.cli
+ cmdliner
+ conduit-lwt
+ fmt.tty)
(package cohttp-lwt-unix)
(public_names cohttp-curl-lwt cohttp-proxy-lwt cohttp-server-lwt))
+version: "5.2.0"
opam-version: "2.0"
maintainer: "anil@recoil.org"
authors: [
["dune" "build" "-p" name "-j" jobs]
["dune" "runtest" "-p" name "-j" jobs] {with-test}
]
-dev-repo: "git+https://github.com/mirage/ocaml-cohttp.git"
+dev-repo: "git+https://github.com/mirage/ocaml-cohttp.git"
\ No newline at end of file
`Response rsp))
(fun () -> Body.drain_body body)
- let handle_response ~keep_alive oc res body handle_client =
+ let handle_response ~keep_alive oc res body conn_closed handle_client =
IO.catch (fun () ->
let flush = Response.flush res in
Response.write ~flush
(fun writer -> Body.write_body (Response.write_body writer) body)
- res oc
- >>= fun () -> if keep_alive then handle_client oc else Lwt.return_unit)
+ res oc)
>>= function
- | Ok () -> Lwt.return_unit
+ | Ok () ->
+ if keep_alive then handle_client oc
+ else
+ let () = conn_closed () in
+ Lwt.return_unit
| Error e ->
Log.info (fun m -> m "IO error while writing body: %a" IO.pp_error e);
+ conn_closed ();
Body.drain_body body
-
- let rec handle_client ic oc conn callback =
+ let rec handle_client ic oc conn spec =
Request.read ic >>= function
- | `Eof -> Lwt.return_unit
+ | `Eof ->
+ spec.conn_closed conn;
+ Lwt.return_unit
| `Invalid data ->
Log.err (fun m -> m "invalid input %s while handling client" data);
+ spec.conn_closed conn;
Lwt.return_unit
| `Ok req -> (
let body = read_body ic req in
- handle_request callback conn req body >>= function
+ handle_request spec.callback conn req body >>= function
| `Response (res, body) ->
let keep_alive = Request.is_keep_alive req in
- handle_response ~keep_alive oc res body (fun oc ->
- handle_client ic oc conn callback)
+ handle_response ~keep_alive oc res body
+ (fun () -> spec.conn_closed conn)
+ (fun oc -> handle_client ic oc conn spec)
| `Expert (res, io_handler) ->
Response.write_header res oc >>= fun () ->
- io_handler ic oc >>= fun () ->
- handle_client ic oc conn callback)
+ io_handler ic oc >>= fun () -> handle_client ic oc conn spec)
let callback spec io_id ic oc =
let conn_id = Cohttp.Connection.create () in
let conn_closed () = spec.conn_closed (io_id, conn_id) in
- Lwt.finalize
+ Lwt.catch
(fun () ->
- IO.catch (fun () -> handle_client ic oc (io_id, conn_id) spec.callback)
+ IO.catch (fun () -> handle_client ic oc (io_id, conn_id) spec)
>>= function
| Ok () -> Lwt.return_unit
| Error e ->
Log.info (fun m ->
m "IO error while handling client: %a" IO.pp_error e);
+ conn_closed ();
Lwt.return_unit)
- (fun () ->
- (* Clean up resources when the response stream terminates and call
- * the user callback *)
- conn_closed () |> Lwt.return)
+ (fun e ->
+ conn_closed ();
+ Lwt.fail e)
end
+version: "5.2.0"
opam-version: "2.0"
maintainer: "anil@recoil.org"
authors: ["Anil Madhavapeddy" "Thomas Gazagnaire"]
["dune" "build" "-p" name "-j" jobs]
["dune" "runtest" "-p" name "-j" jobs] {with-test}
]
-dev-repo: "git+https://github.com/mirage/ocaml-cohttp.git"
+dev-repo: "git+https://github.com/mirage/ocaml-cohttp.git"
\ No newline at end of file
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * %%NAME%% %%VERSION%%
+ * cohttp v5.2.0
*)
open Lwt.Infix
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * %%NAME%% %%VERSION%%
+ * cohttp v5.2.0
*)
open Lwt.Infix
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * %%NAME%% %%VERSION%%
+ * cohttp v5.2.0
*)
(** Cohttp IO implementation using Mirage channels. *)
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * %%NAME%% %%VERSION%%
+ * cohttp v5.2.0
*)
module Key = Mirage_kv.Key
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * %%NAME%% %%VERSION%%
+ * cohttp v5.2.0
*)
(** Serve static HTTP sites from a Mirage key-value store. *)
+version: "5.2.0"
opam-version: "2.0"
maintainer: "anil@recoil.org"
authors: [
["dune" "build" "-p" name "-j" jobs]
["dune" "runtest" "-p" name "-j" jobs] {with-test}
]
-dev-repo: "git+https://github.com/mirage/ocaml-cohttp.git"
+dev-repo: "git+https://github.com/mirage/ocaml-cohttp.git"
\ No newline at end of file
+version: "5.2.0"
opam-version: "2.0"
maintainer: "anil@recoil.org"
authors: [
["dune" "build" "-p" name "-j" jobs]
["dune" "runtest" "-p" name "-j" jobs] {with-test}
]
-dev-repo: "git+https://github.com/mirage/ocaml-cohttp.git"
+dev-repo: "git+https://github.com/mirage/ocaml-cohttp.git"
\ No newline at end of file
(lang dune 2.0)
(name cohttp)
+(version v5.2.0)