1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-24 08:09:08 -05:00

feat(node): HTTPS server (#19362)

This commit is contained in:
Leo Kettmeir 2023-06-13 04:15:08 +02:00 committed by Bartek Iwańczuk
parent 2fdbea763e
commit 28b04b285e
No known key found for this signature in database
GPG key ID: 0C6BCDDC3B3AD750
3 changed files with 97 additions and 16 deletions

View file

@ -6,6 +6,7 @@ import https from "node:https";
import {
assert,
assertEquals,
fail,
} from "../../../test_util/std/testing/asserts.ts";
import { assertSpyCalls, spy } from "../../../test_util/std/testing/mock.ts";
import { deferred } from "../../../test_util/std/async/deferred.ts";
@ -617,3 +618,34 @@ Deno.test("[node/http] ClientRequest search params", async () => {
await def;
assertEquals(body, "foo=bar");
});
Deno.test("[node/http] HTTPS server", async () => {
const promise = deferred<void>();
const promise2 = deferred<void>();
const client = Deno.createHttpClient({
caCerts: [Deno.readTextFileSync("cli/tests/testdata/tls/RootCA.pem")],
});
const server = https.createServer({
cert: Deno.readTextFileSync("cli/tests/testdata/tls/localhost.crt"),
key: Deno.readTextFileSync("cli/tests/testdata/tls/localhost.key"),
}, (_req, res) => {
res.end("success!");
});
server.listen(() => {
// deno-lint-ignore no-explicit-any
fetch(`https://localhost:${(server.address() as any).port}`, {
client,
}).then(async (res) => {
assertEquals(res.status, 200);
assertEquals(await res.text(), "success!");
server.close();
promise2.resolve();
});
})
.on("error", () => fail());
server.on("close", () => {
promise.resolve();
});
await Promise.all([promise, promise2]);
client.close();
});

View file

@ -18,6 +18,7 @@ import { nextTick } from "ext:deno_node/_next_tick.ts";
import {
validateBoolean,
validateInteger,
validateObject,
validatePort,
} from "ext:deno_node/internal/validators.mjs";
import {
@ -1443,16 +1444,16 @@ export class IncomingMessageForServer extends NodeReadable {
}
}
type ServerHandler = (
export type ServerHandler = (
req: IncomingMessageForServer,
res: ServerResponse,
) => void;
export function Server(handler?: ServerHandler): ServerImpl {
return new ServerImpl(handler);
export function Server(opts, requestListener?: ServerHandler): ServerImpl {
return new ServerImpl(opts, requestListener);
}
class ServerImpl extends EventEmitter {
export class ServerImpl extends EventEmitter {
#httpConnections: Set<Deno.HttpConn> = new Set();
#listener?: Deno.Listener;
@ -1464,12 +1465,24 @@ class ServerImpl extends EventEmitter {
#servePromise: Deferred<void>;
listening = false;
constructor(handler?: ServerHandler) {
constructor(opts, requestListener?: ServerHandler) {
super();
if (typeof opts === "function") {
requestListener = opts;
opts = kEmptyObject;
} else if (opts == null) {
opts = kEmptyObject;
} else {
validateObject(opts, "options");
}
this._opts = opts;
this.#servePromise = deferred();
this.#servePromise.then(() => this.emit("close"));
if (handler !== undefined) {
this.on("request", handler);
if (requestListener !== undefined) {
this.on("request", requestListener);
}
}
@ -1498,12 +1511,12 @@ class ServerImpl extends EventEmitter {
port,
} as Deno.NetAddr;
this.listening = true;
nextTick(() => this.#serve());
nextTick(() => this._serve());
return this;
}
#serve() {
_serve() {
const ac = new AbortController();
const handler = (request: Request, info: Deno.ServeHandlerInfo) => {
const req = new IncomingMessageForServer(request, info.remoteAddr);
@ -1536,6 +1549,7 @@ class ServerImpl extends EventEmitter {
this.#addr!.port = port;
this.emit("listening");
},
...this._additionalServeOptions?.(),
},
);
if (this.#unref) {
@ -1598,8 +1612,8 @@ class ServerImpl extends EventEmitter {
Server.prototype = ServerImpl.prototype;
export function createServer(handler?: ServerHandler) {
return Server(handler);
export function createServer(opts, requestListener?: ServerHandler) {
return Server(opts, requestListener);
}
/** Makes an HTTP request. */

View file

@ -10,14 +10,49 @@ import {
} from "ext:deno_node/http.ts";
import { Agent as HttpAgent } from "ext:deno_node/_http_agent.mjs";
import { createHttpClient } from "ext:deno_fetch/22_http_client.js";
import {
type ServerHandler,
ServerImpl as HttpServer,
} from "ext:deno_node/http.ts";
import { validateObject } from "ext:deno_node/internal/validators.mjs";
import { kEmptyObject } from "ext:deno_node/internal/util.mjs";
import { Buffer } from "ext:deno_node/buffer.ts";
export class Server {
constructor() {
notImplemented("https.Server.prototype.constructor");
export class Server extends HttpServer {
constructor(opts, requestListener?: ServerHandler) {
if (typeof opts === "function") {
requestListener = opts;
opts = kEmptyObject;
} else if (opts == null) {
opts = kEmptyObject;
} else {
validateObject(opts, "options");
}
if (opts.cert && Array.isArray(opts.cert)) {
notImplemented("https.Server.opts.cert array type");
}
if (opts.key && Array.isArray(opts.key)) {
notImplemented("https.Server.opts.key array type");
}
super(opts, requestListener);
}
_additionalServeOptions() {
return {
cert: this._opts.cert instanceof Buffer
? this._opts.cert.toString()
: this._opts.cert,
key: this._opts.key instanceof Buffer
? this._opts.key.toString()
: this._opts.key,
};
}
}
export function createServer() {
notImplemented("https.createServer");
export function createServer(opts, requestListener?: ServerHandler) {
return new Server(opts, requestListener);
}
interface HttpsRequestOptions extends RequestOptions {