mirror of
https://github.com/denoland/deno.git
synced 2024-12-23 15:49:44 -05:00
feat(node): HTTPS server (#19362)
This commit is contained in:
parent
2fdbea763e
commit
28b04b285e
3 changed files with 97 additions and 16 deletions
|
@ -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();
|
||||
});
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue