summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBartek IwaƄczuk <biwanczuk@gmail.com>2023-05-19 02:59:23 +0200
committerGitHub <noreply@github.com>2023-05-19 02:59:23 +0200
commit5b0752234993ee69e47c32db478d2a296f73f396 (patch)
tree6501e364a82d6ff98845d87fe38744bda7fd1a70
parent8724ba9d084127147e2bb2c997a6bf2f38c9b3d2 (diff)
BREAKING(unstable): change return type of Deno.serve() API (#19189)
This commit changes the return type of an unstable `Deno.serve()` API to instead return a `Deno.Server` object that has a `finished` field. This change is done in preparation to be able to ref/unref the HTTP server.
-rw-r--r--cli/tests/unit/serve_test.ts15
-rw-r--r--cli/tsc/dts/lib.deno.unstable.d.ts37
-rw-r--r--ext/http/00_serve.js51
-rw-r--r--ext/node/polyfills/http.ts2
4 files changed, 64 insertions, 41 deletions
diff --git a/cli/tests/unit/serve_test.ts b/cli/tests/unit/serve_test.ts
index 5da300dc9..c6cfc45f3 100644
--- a/cli/tests/unit/serve_test.ts
+++ b/cli/tests/unit/serve_test.ts
@@ -6,7 +6,6 @@ import { TextProtoReader } from "../testdata/run/textproto.ts";
import {
assert,
assertEquals,
- assertRejects,
assertStringIncludes,
assertThrows,
Deferred,
@@ -50,7 +49,7 @@ Deno.test(async function httpServerShutsDownPortBeforeResolving() {
assertThrows(() => Deno.listen({ port: 4501 }));
ac.abort();
- await server;
+ await server.finished;
const listener = Deno.listen({ port: 4501 });
listener!.close();
@@ -93,7 +92,7 @@ Deno.test(async function httpServerRejectsOnAddrInUse() {
});
await listeningPromise;
- await assertRejects(
+ assertThrows(
() =>
Deno.serve({
handler: (_req) => new Response("ok"),
@@ -284,18 +283,18 @@ Deno.test({ permissions: { net: true } }, async function httpServerOverload2() {
Deno.test(
{ permissions: { net: true } },
- async function httpServerErrorOverloadMissingHandler() {
+ function httpServerErrorOverloadMissingHandler() {
// @ts-ignore - testing invalid overload
- await assertRejects(() => Deno.serve(), TypeError, "handler");
+ assertThrows(() => Deno.serve(), TypeError, "handler");
// @ts-ignore - testing invalid overload
- await assertRejects(() => Deno.serve({}), TypeError, "handler");
- await assertRejects(
+ assertThrows(() => Deno.serve({}), TypeError, "handler");
+ assertThrows(
// @ts-ignore - testing invalid overload
() => Deno.serve({ handler: undefined }),
TypeError,
"handler",
);
- await assertRejects(
+ assertThrows(
// @ts-ignore - testing invalid overload
() => Deno.serve(undefined, { handler: () => {} }),
TypeError,
diff --git a/cli/tsc/dts/lib.deno.unstable.d.ts b/cli/tsc/dts/lib.deno.unstable.d.ts
index 3a4344bd8..c0c0d16ad 100644
--- a/cli/tsc/dts/lib.deno.unstable.d.ts
+++ b/cli/tsc/dts/lib.deno.unstable.d.ts
@@ -1305,6 +1305,16 @@ declare namespace Deno {
/** **UNSTABLE**: New API, yet to be vetted.
*
+ * @category HTTP Server
+ */
+ export interface Server {
+ /** A promise that resolves once server finishes - eg. when aborted using
+ * the signal passed to {@linkcode ServeOptions.signal}.
+ */
+ finished: Promise<void>;
+ }
+ /** **UNSTABLE**: New API, yet to be vetted.
+ *
* Serves HTTP requests with the given handler.
*
* You can specify an object with a port and hostname option, which is the
@@ -1331,8 +1341,11 @@ declare namespace Deno {
* ```ts
* const ac = new AbortController();
*
- * Deno.serve({ signal: ac.signal }, (_req) => new Response("Hello, world"))
- * .then(() => console.log("Server closed"));
+ * const server = Deno.serve(
+ * { signal: ac.signal },
+ * (_req) => new Response("Hello, world")
+ * );
+ * server.finished.then(() => console.log("Server closed"));
*
* console.log("Closing server...");
* ac.abort();
@@ -1362,7 +1375,7 @@ declare namespace Deno {
*
* @category HTTP Server
*/
- export function serve(handler: ServeHandler): Promise<void>;
+ export function serve(handler: ServeHandler): Server;
/** **UNSTABLE**: New API, yet to be vetted.
*
* Serves HTTP requests with the given handler.
@@ -1391,8 +1404,11 @@ declare namespace Deno {
* ```ts
* const ac = new AbortController();
*
- * Deno.serve({ signal: ac.signal }, (_req) => new Response("Hello, world"))
- * .then(() => console.log("Server closed"));
+ * const server = Deno.serve(
+ * { signal: ac.signal },
+ * (_req) => new Response("Hello, world")
+ * );
+ * server.finished.then(() => console.log("Server closed"));
*
* console.log("Closing server...");
* ac.abort();
@@ -1425,7 +1441,7 @@ declare namespace Deno {
export function serve(
options: ServeOptions | ServeTlsOptions,
handler: ServeHandler,
- ): Promise<void>;
+ ): Server;
/** **UNSTABLE**: New API, yet to be vetted.
*
* Serves HTTP requests with the given handler.
@@ -1454,8 +1470,11 @@ declare namespace Deno {
* ```ts
* const ac = new AbortController();
*
- * Deno.serve({ signal: ac.signal }, (_req) => new Response("Hello, world"))
- * .then(() => console.log("Server closed"));
+ * const server = Deno.serve(
+ * { signal: ac.signal },
+ * (_req) => new Response("Hello, world")
+ * );
+ * server.finished.then(() => console.log("Server closed"));
*
* console.log("Closing server...");
* ac.abort();
@@ -1487,7 +1506,7 @@ declare namespace Deno {
*/
export function serve(
options: ServeInit & (ServeOptions | ServeTlsOptions),
- ): Promise<void>;
+ ): Server;
/** **UNSTABLE**: New API, yet to be vetted.
*
diff --git a/ext/http/00_serve.js b/ext/http/00_serve.js
index 35af49b04..9075ae651 100644
--- a/ext/http/00_serve.js
+++ b/ext/http/00_serve.js
@@ -563,7 +563,7 @@ function mapToCallback(responseBodies, context, signal, callback, onError) {
};
}
-async function serve(arg1, arg2) {
+function serve(arg1, arg2) {
let options = undefined;
let handler = undefined;
if (typeof arg1 === "function") {
@@ -653,33 +653,38 @@ async function serve(arg1, arg2) {
onListen({ port: listenOpts.port });
- while (true) {
- const rid = context.serverRid;
- let req;
- try {
- req = await op_http_wait(rid);
- } catch (error) {
- if (ObjectPrototypeIsPrototypeOf(BadResourcePrototype, error)) {
+ // Run the server
+ const finished = (async () => {
+ while (true) {
+ const rid = context.serverRid;
+ let req;
+ try {
+ req = await op_http_wait(rid);
+ } catch (error) {
+ if (ObjectPrototypeIsPrototypeOf(BadResourcePrototype, error)) {
+ break;
+ }
+ throw new Deno.errors.Http(error);
+ }
+ if (req === 0xffffffff) {
break;
}
- throw new Deno.errors.Http(error);
+ PromisePrototypeCatch(callback(req), (error) => {
+ // Abnormal exit
+ console.error(
+ "Terminating Deno.serve loop due to unexpected error",
+ error,
+ );
+ context.close();
+ });
}
- if (req === 0xffffffff) {
- break;
+
+ for (const streamRid of new SafeSetIterator(responseBodies)) {
+ core.tryClose(streamRid);
}
- PromisePrototypeCatch(callback(req), (error) => {
- // Abnormal exit
- console.error(
- "Terminating Deno.serve loop due to unexpected error",
- error,
- );
- context.close();
- });
- }
+ })();
- for (const streamRid of new SafeSetIterator(responseBodies)) {
- core.tryClose(streamRid);
- }
+ return { finished };
}
internals.upgradeHttpRaw = upgradeHttpRaw;
diff --git a/ext/node/polyfills/http.ts b/ext/node/polyfills/http.ts
index adc5845b5..065ad2e0f 100644
--- a/ext/node/polyfills/http.ts
+++ b/ext/node/polyfills/http.ts
@@ -1577,7 +1577,7 @@ class ServerImpl extends EventEmitter {
this.emit("listening");
},
},
- ).then(() => this.#servePromise!.resolve());
+ ).finished.then(() => this.#servePromise!.resolve());
}
setTimeout() {