diff --git a/README.md b/README.md index d9fc0405a5..2db9474f14 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,10 @@ HTTP parser, and implementations using various asynchronous programming libraries: * `Cohttp_lwt_unix` uses the [Lwt](https://ocsigen.org/lwt/) library, and - specifically the UNIX bindings. + specifically the UNIX bindings. It uses [ocaml-tls](https://github.com/mirleft/ocaml-tls) + as the TLS implementation to handle HTTPS connections. * `Cohttp_async` uses the [Async](https://realworldocaml.org/v1/en/html/concurrent-programming-with-async.html) - library. + library and `async_ssl` to handle HTTPS connections. * `Cohttp_lwt` exposes an OS-independent Lwt interface, which is used by the [Mirage](https://mirage.io/) interface to generate standalone microkernels (use the cohttp-mirage subpackage). @@ -104,12 +105,10 @@ There's a few things to notice: * We must trigger lwt's event loop for the request to run. `Lwt_main.run` will run the event loop and return with final value of `body` which we then print. -Note that in order to request an HTTPS page like in the above example, -you'll need Cohttp to have been compiled with SSL or TLS. For SSL, you'll -need to install both [`ssl`](https://github.com/savonet/ocaml-ssl) and -[`lwt_ssl`](https://github.com/ocsigen/lwt_ssl) before installing `cohttp`. -The TLS route will require installing -[`tls`](https://github.com/mirleft/ocaml-tls) before `cohttp`. +Note that `Cohttp_lwt_unix`/`Cohttp_async` is able to request an HTTPS page +by default. For `Cohttp_lwt_unix`, we use [ocaml-tls](https://github.com/mirleft/ocaml-tls.git) +(but the user is able to use `lwt_ssl` if he wants). For `Cohttp_async`, we use +`async_ssl` (but the user is able to use `ocaml-tls`). Consult the following modules for reference: @@ -125,12 +124,17 @@ to dig in and customise it for their needs. The following is an example of a ```ocaml open Lwt.Infix +let resolve_unix_socket = function + | IP _ -> Lwt.return_none + | Domain v -> match Domain_name.to_string v with + | "docker" -> Lwt.return_some (Unix.ADDR_UNIX "/var/run/docker.sock") + | _ -> Lwt.return_none + let t = - let resolver = - let h = Hashtbl.create 1 in - Hashtbl.add h "docker" (`Unix_domain_socket "/var/run/docker.sock"); - Resolver_lwt_unix.static h in - let ctx = Cohttp_lwt_unix.Client.custom_ctx ~resolver () in + let ctx = + Conduit_lwt.add + ~priority:0 (* highest priority *) + Conduit_lwt.TCP.protocol resolve_unix_socket Conduit.empty in Cohttp_lwt_unix.Client.get ~ctx (Uri.of_string "http://docker/version") >>= fun (resp, body) -> let open Cohttp in let code = resp |> Response.status |> Code.code_of_status in diff --git a/cohttp-async/src/client.mli b/cohttp-async/src/client.mli index 0e22e8affd..d74fc253db 100644 --- a/cohttp-async/src/client.mli +++ b/cohttp-async/src/client.mli @@ -8,7 +8,17 @@ val request : (Cohttp.Response.t * Body.t) Async_kernel.Deferred.t (** Send an HTTP request with arbitrary method and a body - Infers the transfer encoding *) + Infers the transfer encoding. Depending on the given [uri], + we choose a way to start a communication such as: + + {ul + {- If the scheme is [https], we try to initiate an SSL connection with + the given [ssl_ctx] or a default one on the default port ([*:443]) or + the specified one.} + {- If the scheme is [httpunix], we use a UNIX domain socket.} + {- If the scheme ie [http], we try an usual TCP/IP connection on the + default port ([*:80]) or the specified one.}} +*) val call : ?ssl_ctx:Conduit_async_ssl.context -> ?headers:Cohttp.Header.t -> diff --git a/cohttp-lwt-unix-nossl/src/server.mli b/cohttp-lwt-unix-nossl/src/server.mli index d24c938780..dbbe3db351 100644 --- a/cohttp-lwt-unix-nossl/src/server.mli +++ b/cohttp-lwt-unix-nossl/src/server.mli @@ -10,14 +10,30 @@ val respond_file : fname:string -> unit -> (Cohttp.Response.t * Cohttp_lwt.Body.t) Lwt.t -(** [create ?timeout ?backlog ?stop ?on_exn ?ctx ?mode t] is a new +(** [create ?timeout ?backlog ?stop ?on_exn cfg protocol service t] is a new HTTP server. - When provided, [mode] selects the connection type. By default it - is using a TCP socket listening on port 8080. + The user can decide to start a simple HTTP server (without encryption) + or one with TLS encryption. It depends on what the user gives as [cfg], + [protocol] and [service]. Using [conduit-lwt-tls], the end-user is able + to make an encrypted HTTP server with: - When provided, [ctx] is the network context to use. By default is - {!Net.default_ctx}. + {[ + let run = + create cfg Conduit_lwt_tls.TCP.protocol Conduit_lwt_tls.TCP.service + ]} + + A simple HTTP server (with [conduit-lwt]) is: + + {[ + let run = + create cfg Conduit_lwt.TCP.protocol Conduit_lwt.TCP.service + ]} + + [cfg] depends on the given [service] - and let the user to define which + port the server use, and, in the case of {!Conduit_lwt_tls.TCP.service}, + which TLS certificate it uses. See [Conduit] for more information about + {i protocol} and {i service}. When provided, the [stop] thread will terminate the server if it ever becomes determined. diff --git a/cohttp-lwt-unix/src/net.mli b/cohttp-lwt-unix/src/net.mli index b5d8852a52..813021f7f9 100644 --- a/cohttp-lwt-unix/src/net.mli +++ b/cohttp-lwt-unix/src/net.mli @@ -22,15 +22,22 @@ type ctx = (Conduit.resolvers[@sexp.opaque]) [@@deriving sexp] val default_ctx : ctx -(** Exceptions from [conduit]. - - When the [recv] or the [send] {i syscalls} return an error, - [conduit] will reraise it. *) - val connect_uri : ctx:ctx -> Uri.t -> (Conduit_lwt.flow * Lwt_io.input Lwt_io.channel * Lwt_io.output Lwt_io.channel) Lwt.t +(** [connect_uri ~ctx uri] starts a {i flow} on the given [uri]. The choice of the + protocol (with or without encryption) is done by the {i scheme} of the given [uri]: + + {ul + {- If the scheme is [https], we will {b extend} [ctx] to be able to start a TLS connection + with a default TLS configuration (no authentication) on the default or user-specified port.} + {- If the scheme is [http], we will {b extend} [ctx] to be able to start a simple TCP/IP + connection on the default or user-specified port.}} + + These extensions have the highest priority ([Conduit] will try to initiate a communication with + them first). By {i extension}, we mean that the user is able to fill its own [ctx] and we don't + overlap resolution functions from the given [ctx]. *) val close_in : 'a Lwt_io.channel -> unit val close_out : 'a Lwt_io.channel -> unit diff --git a/cohttp-lwt/src/s.ml b/cohttp-lwt/src/s.ml index b5a618edec..855bca60fd 100644 --- a/cohttp-lwt/src/s.ml +++ b/cohttp-lwt/src/s.ml @@ -41,8 +41,8 @@ module type Client = sig type ctx (** [call ?ctx ?headers ?body ?chunked meth uri] will resolve the - [uri] to a concrete network endpoint using the resolver initialized - in [ctx]. It will then issue an HTTP request with method [meth], + [uri] to a concrete network endpoint using the {!Conduit.resolvers} [ctx]. + It will then issue an HTTP request with method [meth], adding request headers from [headers] if present. If a [body] is specified then that will be included with the request, using chunked encoding if [chunked] is true. The default is to disable @@ -50,7 +50,14 @@ module type Client = sig In most cases you should use the more specific helper calls in the interface rather than invoke this function directly. See {!head}, - {!get} and {!post} for some examples. *) + {!get} and {!post} for some examples. + + Depending on [ctx], the library is able to send a simple HTTP request + or an encrypted one with a secured protocol (such as TLS). By default + (on [cohttp-lwt-unix]), [ctx] tries to initiate a secured connection + with TLS (it uses [ocaml-tls]) on [*:443] or on the specified port by + the user. If the peer is not available, [cohttp]/[conduit] tries the usual + ([*:80]) or the specified port by the user in a non-secured way. *) val call : ?ctx:ctx -> ?headers:Cohttp.Header.t -> diff --git a/cohttp-lwt/src/server.mli b/cohttp-lwt/src/server.mli index 3e9485d2d8..e701575134 100644 --- a/cohttp-lwt/src/server.mli +++ b/cohttp-lwt/src/server.mli @@ -1,5 +1,5 @@ (** The [Make] functor glues together a {! Cohttp.S.IO } implementation - to send requests down a connection that is established by the {! Net } - module. The resulting module satisfies the {! Server } module type. *) + to send requests down a connection that is established by the user. + The resulting module satisfies the {! Server } module type. *) module Make (IO:S.IO) : S.Server with module IO = IO