diff --git a/std/http/server.ts b/std/http/server.ts index f1ced0577b..9e21843515 100644 --- a/std/http/server.ts +++ b/std/http/server.ts @@ -1,5 +1,5 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. -const { listen, copy, toAsyncIterator } = Deno; +const { listen, listenTLS, copy, toAsyncIterator } = Deno; type Listener = Deno.Listener; type Conn = Deno.Conn; type Reader = Deno.Reader; @@ -401,6 +401,61 @@ export async function listenAndServe( } } +/** Options for creating an HTTPS server. */ +export type HTTPSOptions = Omit; + +/** + * Create an HTTPS server with given options + * @param options Server configuration + * @return Async iterable server instance for incoming requests + * + * const body = new TextEncoder().encode("Hello HTTPS"); + * const options = { + * hostname: "localhost", + * port: 443, + * certFile: "./path/to/localhost.crt", + * keyFile: "./path/to/localhost.key", + * }; + * for await (const req of serveTLS(options)) { + * req.respond({ body }); + * } + */ +export function serveTLS(options: HTTPSOptions): Server { + const tlsOptions: Deno.ListenTLSOptions = { + ...options, + transport: "tcp" + }; + const listener = listenTLS(tlsOptions); + return new Server(listener); +} + +/** + * Create an HTTPS server with given options and request handler + * @param options Server configuration + * @param handler Request handler + * + * const body = new TextEncoder().encode("Hello HTTPS"); + * const options = { + * hostname: "localhost", + * port: 443, + * certFile: "./path/to/localhost.crt", + * keyFile: "./path/to/localhost.key", + * }; + * listenAndServeTLS(options, (req) => { + * req.respond({ body }); + * }); + */ +export async function listenAndServeTLS( + options: HTTPSOptions, + handler: (req: ServerRequest) => void +): Promise { + const server = serveTLS(options); + + for await (const request of server) { + handler(request); + } +} + export interface Response { status?: number; headers?: Headers; diff --git a/std/http/server_test.ts b/std/http/server_test.ts index 7917aeddd8..5baeaa144d 100644 --- a/std/http/server_test.ts +++ b/std/http/server_test.ts @@ -529,4 +529,55 @@ test({ } }); +test({ + name: "[http] serveTLS", + async fn(): Promise { + // Runs a simple server as another process + const p = Deno.run({ + args: [ + Deno.execPath(), + "http/testdata/simple_https_server.ts", + "--allow-net", + "--allow-read" + ], + stdout: "piped" + }); + + try { + const r = new TextProtoReader(new BufReader(p.stdout!)); + const s = await r.readLine(); + assert(s !== Deno.EOF && s.includes("server listening")); + + let serverIsRunning = true; + p.status() + .then( + (): void => { + serverIsRunning = false; + } + ) + .catch((_): void => {}); // Ignores the error when closing the process. + + // Requests to the server and immediately closes the connection + const conn = await Deno.dialTLS({ + hostname: "localhost", + port: 4503, + certFile: "http/testdata/tls/RootCA.pem" + }); + await Deno.writeAll( + conn, + new TextEncoder().encode("GET / HTTP/1.0\r\n\r\n") + ); + const res = new Uint8Array(100); + const nread = assertNotEOF(await conn.read(res)); + conn.close(); + const resStr = new TextDecoder().decode(res.subarray(0, nread)); + assert(resStr.includes("Hello HTTPS")); + assert(serverIsRunning); + } finally { + // Stops the sever. + p.close(); + } + } +}); + runIfMain(import.meta); diff --git a/std/http/testdata/simple_https_server.ts b/std/http/testdata/simple_https_server.ts new file mode 100644 index 0000000000..655457c947 --- /dev/null +++ b/std/http/testdata/simple_https_server.ts @@ -0,0 +1,16 @@ +// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. +// This is an example of a https server +import { serveTLS } from "../server.ts"; + +const tlsOptions = { + hostname: "localhost", + port: 4503, + certFile: "./http/testdata/tls/localhost.crt", + keyFile: "./http/testdata/tls/localhost.key", +}; +const s = serveTLS(tlsOptions); +console.log(`Simple HTTPS server listening on ${tlsOptions.hostname}:${tlsOptions.port}`); +const body = new TextEncoder().encode("Hello HTTPS"); +for await (const req of s) { + req.respond({ body }); +} diff --git a/std/http/testdata/tls b/std/http/testdata/tls new file mode 120000 index 0000000000..f6fd22ed86 --- /dev/null +++ b/std/http/testdata/tls @@ -0,0 +1 @@ +../../../cli/tests/tls \ No newline at end of file