summaryrefslogtreecommitdiff
path: root/ext/http/00_serve.js
diff options
context:
space:
mode:
authorMatt Mastracci <matthew@mastracci.com>2023-05-31 17:20:39 -0600
committerGitHub <noreply@github.com>2023-05-31 23:20:39 +0000
commit077d3d1bb3f20e5fec9345deb7e3ad042885fad6 (patch)
treefd5f07c29d25ec263a9e777451dbbf7949e9258c /ext/http/00_serve.js
parent926d493f1967faa143205ad02a9c35f757829603 (diff)
refactor(ext/http): Expose internal serveHttpOnListener API for HTTP2 (#19331)
For the first implementation of node:http2, we'll use the internal version of `Deno.serve` which allows us to listen on a raw TCP connection rather than a listener. This is mostly a refactoring, and hooking up of `op_http_serve_on` that was never previously exposed (but designed for this purpose).
Diffstat (limited to 'ext/http/00_serve.js')
-rw-r--r--ext/http/00_serve.js102
1 files changed, 63 insertions, 39 deletions
diff --git a/ext/http/00_serve.js b/ext/http/00_serve.js
index e3926280b..d84244ee4 100644
--- a/ext/http/00_serve.js
+++ b/ext/http/00_serve.js
@@ -34,7 +34,8 @@ import {
readableStreamForRid,
ReadableStreamPrototype,
} from "ext:deno_web/06_streams.js";
-import { TcpConn } from "ext:deno_net/01_net.js";
+import { listen, TcpConn } from "ext:deno_net/01_net.js";
+import { listenTls } from "ext:deno_net/02_tls.js";
const {
ObjectPrototypeIsPrototypeOf,
PromisePrototypeCatch,
@@ -54,6 +55,7 @@ const {
op_http_get_request_method_and_url,
op_http_read_request_body,
op_http_serve,
+ op_http_serve_on,
op_http_set_promise_complete,
op_http_set_response_body_bytes,
op_http_set_response_body_resource,
@@ -71,6 +73,7 @@ const {
"op_http_get_request_method_and_url",
"op_http_read_request_body",
"op_http_serve",
+ "op_http_serve_on",
"op_http_set_promise_complete",
"op_http_set_response_body_bytes",
"op_http_set_response_body_resource",
@@ -340,12 +343,21 @@ class InnerRequest {
}
class CallbackContext {
+ abortController;
+ responseBodies;
scheme;
fallbackHost;
serverRid;
closed;
- initialize(args) {
+ constructor(signal, args) {
+ signal?.addEventListener(
+ "abort",
+ () => this.close(),
+ { once: true },
+ );
+ this.abortController = new AbortController();
+ this.responseBodies = new SafeSet();
this.serverRid = args[0];
this.scheme = args[1];
this.fallbackHost = args[2];
@@ -500,7 +512,9 @@ async function asyncResponse(responseBodies, req, status, stream) {
*
* This function returns a promise that will only reject in the case of abnormal exit.
*/
-function mapToCallback(responseBodies, context, signal, callback, onError) {
+function mapToCallback(context, callback, onError) {
+ const responseBodies = context.responseBodies;
+ const signal = context.abortController.signal;
return async function (req) {
// Get the response from the user-provided callback. If that fails, use onError. If that fails, return a fallback
// 500 error.
@@ -611,18 +625,7 @@ function serve(arg1, arg2) {
reusePort: options.reusePort ?? false,
};
- const abortController = new AbortController();
-
- const responseBodies = new SafeSet();
- const context = new CallbackContext();
- const callback = mapToCallback(
- responseBodies,
- context,
- abortController.signal,
- handler,
- onError,
- );
-
+ let listener;
if (wantsHttps) {
if (!options.cert || !options.key) {
throw new TypeError(
@@ -632,37 +635,56 @@ function serve(arg1, arg2) {
listenOpts.cert = options.cert;
listenOpts.key = options.key;
listenOpts.alpnProtocols = ["h2", "http/1.1"];
- const listener = Deno.listenTls(listenOpts);
+ listener = listenTls(listenOpts);
listenOpts.port = listener.addr.port;
- context.initialize(op_http_serve(
- listener.rid,
- ));
} else {
- const listener = Deno.listen(listenOpts);
+ listener = listen(listenOpts);
listenOpts.port = listener.addr.port;
- context.initialize(op_http_serve(
- listener.rid,
- ));
}
- signal?.addEventListener(
- "abort",
- () => context.close(),
- { once: true },
- );
-
- const onListen = options.onListen ?? function ({ port }) {
- // If the hostname is "0.0.0.0", we display "localhost" in console
- // because browsers in Windows don't resolve "0.0.0.0".
- // See the discussion in https://github.com/denoland/deno_std/issues/1165
- const hostname = listenOpts.hostname == "0.0.0.0"
- ? "localhost"
- : listenOpts.hostname;
- console.log(`Listening on ${context.scheme}${hostname}:${port}/`);
+ const onListen = (scheme) => {
+ const port = listenOpts.port;
+ if (options.onListen) {
+ options.onListen({ port });
+ } else {
+ // If the hostname is "0.0.0.0", we display "localhost" in console
+ // because browsers in Windows don't resolve "0.0.0.0".
+ // See the discussion in https://github.com/denoland/deno_std/issues/1165
+ const hostname = listenOpts.hostname == "0.0.0.0"
+ ? "localhost"
+ : listenOpts.hostname;
+ console.log(`Listening on ${scheme}${hostname}:${port}/`);
+ }
};
- onListen({ port: listenOpts.port });
+ return serveHttpOnListener(listener, signal, handler, onError, onListen);
+}
+
+/**
+ * Serve HTTP/1.1 and/or HTTP/2 on an arbitrary listener.
+ */
+function serveHttpOnListener(listener, signal, handler, onError, onListen) {
+ const context = new CallbackContext(signal, op_http_serve(listener.rid));
+ const callback = mapToCallback(context, handler, onError);
+
+ onListen(context.scheme);
+
+ return serveHttpOn(context, callback);
+}
+
+/**
+ * Serve HTTP/1.1 and/or HTTP/2 on an arbitrary connection.
+ */
+function serveHttpOnConnection(connection, signal, handler, onError, onListen) {
+ const context = new CallbackContext(signal, op_http_serve_on(connection.rid));
+ const callback = mapToCallback(context, handler, onError);
+
+ onListen(context.scheme);
+
+ return serveHttpOn(context, callback);
+}
+function serveHttpOn(context, callback) {
let ref = true;
let currentPromise = null;
const promiseIdSymbol = SymbolFor("Deno.core.internalPromiseId");
@@ -710,7 +732,7 @@ function serve(arg1, arg2) {
});
}
- for (const streamRid of new SafeSetIterator(responseBodies)) {
+ for (const streamRid of new SafeSetIterator(context.responseBodies)) {
core.tryClose(streamRid);
}
})();
@@ -734,5 +756,7 @@ function serve(arg1, arg2) {
internals.addTrailers = addTrailers;
internals.upgradeHttpRaw = upgradeHttpRaw;
+internals.serveHttpOnListener = serveHttpOnListener;
+internals.serveHttpOnConnection = serveHttpOnConnection;
export { serve, upgradeHttpRaw };