diff --git a/ext/http/00_serve.ts b/ext/http/00_serve.ts index c8f4e0604b1990..c8ddaa64becd40 100644 --- a/ext/http/00_serve.ts +++ b/ext/http/00_serve.ts @@ -583,6 +583,19 @@ type RawServeOptions = { const kLoadBalanced = Symbol("kLoadBalanced"); +function mapAnyAddrToLocalhostForWindows(hostname: string) { + // 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 + if ( + (Deno.build.os === "windows") && + (hostname == "0.0.0.0" || hostname == "::") + ) { + return "localhost"; + } + return hostname; +} + function serve(arg1, arg2) { let options: RawServeOptions | undefined; let handler: RawHandler | undefined; @@ -672,22 +685,15 @@ function serve(arg1, arg2) { } const addr = listener.addr; - // 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 = (addr.hostname == "0.0.0.0" || addr.hostname == "::") && - (Deno.build.os === "windows") - ? "localhost" - : addr.hostname; - addr.hostname = hostname; const onListen = (scheme) => { if (options.onListen) { options.onListen(addr); } else { - const host = StringPrototypeIncludes(addr.hostname, ":") - ? `[${addr.hostname}]` - : addr.hostname; + const hostname = mapAnyAddrToLocalhostForWindows(addr.hostname); + const host = StringPrototypeIncludes(hostname, ":") + ? `[${hostname}]` + : hostname; // deno-lint-ignore no-console console.log(`Listening on ${scheme}${host}:${addr.port}/`); } @@ -862,9 +868,10 @@ function registerDeclarativeServer(exports) { const nThreads = serveWorkerCount > 1 ? ` with ${serveWorkerCount} threads` : ""; + const hostname_ = mapAnyAddrToLocalhostForWindows(hostname); // deno-lint-ignore no-console console.debug( - `%cdeno serve%c: Listening on %chttp://${hostname}:${port}/%c${nThreads}`, + `%cdeno serve%c: Listening on %chttp://${hostname_}:${port}/%c${nThreads}`, "color: green", "color: inherit", "color: yellow", diff --git a/tests/unit/serve_test.ts b/tests/unit/serve_test.ts index fde6c7bee6f61f..19a8ccad1bda8a 100644 --- a/tests/unit/serve_test.ts +++ b/tests/unit/serve_test.ts @@ -4191,3 +4191,19 @@ Deno.test({ 'Operation `"op_net_listen_unix"` not supported on non-unix platforms.', ); }); + +Deno.test({ + name: "onListen callback gets 0.0.0.0 hostname as is", +}, async () => { + const { promise, resolve } = Promise.withResolvers<{ hostname: string }>(); + + const server = Deno.serve({ + handler: (_) => new Response("ok"), + hostname: "0.0.0.0", + port: 0, + onListen: resolve, + }); + const { hostname } = await promise; + assertEquals(hostname, "0.0.0.0"); + await server.shutdown(); +}); diff --git a/tests/unit_node/net_test.ts b/tests/unit_node/net_test.ts index f49ff0ef08c852..708d06386caf38 100644 --- a/tests/unit_node/net_test.ts +++ b/tests/unit_node/net_test.ts @@ -79,6 +79,7 @@ Deno.test("[node/net] net.connect().unref() works", async () => { port: 0, // any available port will do handler: () => new Response("hello"), onListen: async ({ port, hostname }) => { + hostname = Deno.build.os === "windows" ? "localhost" : hostname; const { stdout, stderr } = await new Deno.Command(Deno.execPath(), { args: [ "eval",