[ANN] shuttle v0.3.1 released

There’s a new version (0.8.1) of the library published to opam. Some highlights:

Shuttle

  • Buffered reader’s support timeouts for the refill operation. If a file descriptor is currently not ready for a read sys call, the reader will wait for the user-defined upper bound time span and raise an exception indicating a timeout was reached if the underlying file-descriptor isn’t ready for IO within that duration.
  • The buffered reader and writer optionally accept an Async Time_source. They default to wall clock, but this input can be used to provide alternate time sources that match the Time_source interface.

Shuttle_ssl

  • Client and Server SSL connections forward the SSL connection context to the user provided callbacks. This can be useful to access the session certificates for ensuring they meet the user’s expectations.

Shuttle_http

This is a new companion library that implements the HTTP/1.1 server codec. There is more work needed to ensure we cover the HTTP 1.1 spec properly, but this initial release includes a usable implementation of the most common use-cases. The library ships with a hand-rolled parser with decent performance and good test coverage (Thanks to ocaml-afl and afl-fuzz I found some bugs I otherwise wouldn’t have!!), and simple service definitions that can support HTTP keep-alive, fixed length and chunked bodies, streaming support to help work with large bodies, request pipelining and centralized error handling for any unhandled exception in the user handler or the I/O runtime. Most of the implementation of http_async directly within the shuttle project. Future work for the HTTP runtime will happen within shuttle, and http_async will focus on providing a more opinionated higher level interface for writing async http services.

Some additional features that aren’t necessarily related to the HTTP spec include timeout support for request header parsing (this helps shut down clients that are too slow), and a public api that provides enough control to allow scheduling resources cleanup for streaming response bodies (Resources backing a stream will be shutdown when the socket connection closes, either for EOF, user-action, or any unhandled error while the runtime performs i/o).

Examples

open Shuttle_http

let hello_world (request : Request.t) =
  return (Response.create ~body:(Body.string "Hello World") `Ok)
;;
open Shuttle_http

let my_service (ctx : Server.t) (request : Request.t) =
  let%map reader =
    (* This an example to show a stream that works with an external resource. *)
    Reader.open_file "<some file path>"
  in
  (* Create a pipe from the reader that we will use as a streaming response body. *)
  let reader_pipe = Reader.pipe reader in
  (* Register a callback that's called when the server handler is closed that will also
     close the pipe, in-turn closing the Reader and the underlying file descriptor. This
     is useful in scenarios where the connection is interrupted before the response body
     is fully exhausted and helps avoid resource leaks. This example is demonstrating how
     to do this manually using the server handler. Creating a response via
     [Server.respond_stream] will automatically register the action to close a stream on
     Server connection closing. *)
  upon (Server.closed ctx) (fun () -> Pipe.close_read reader_pipe);
  let response_stream = Body.of_pipe `Chunked reader_pipe in
  Response.create ~body:response_stream `Ok
;;

(* The same service written using the utility method for creating streaming responses. *)
let my_service (ctx : Server.t) (request : Request.t) =
  let%map reader = Reader.open_file "<some file path>" in
  let reader_pipe = Reader.pipe reader in
  return (Server.respond_stream ctx (Body.Stream.of_pipe `Chunked reader_pipe))
;;

The library is available via opam. If you try the library and experience any issues, or have further questions, please report an issue on the Github Issue tracker.

2 Likes