diff --git a/ext/http/00_serve.ts b/ext/http/00_serve.ts index c8ddaa64be..be1f1f8096 100644 --- a/ext/http/00_serve.ts +++ b/ext/http/00_serve.ts @@ -583,7 +583,7 @@ type RawServeOptions = { const kLoadBalanced = Symbol("kLoadBalanced"); -function mapAnyAddrToLocalhostForWindows(hostname: string) { +function formatHostName(hostname: string): 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 @@ -593,7 +593,9 @@ function mapAnyAddrToLocalhostForWindows(hostname: string) { ) { return "localhost"; } - return hostname; + + // Add brackets around ipv6 hostname + return StringPrototypeIncludes(hostname, ":") ? `[${hostname}]` : hostname; } function serve(arg1, arg2) { @@ -690,10 +692,8 @@ function serve(arg1, arg2) { if (options.onListen) { options.onListen(addr); } else { - const hostname = mapAnyAddrToLocalhostForWindows(addr.hostname); - const host = StringPrototypeIncludes(hostname, ":") - ? `[${hostname}]` - : hostname; + const host = formatHostName(addr.hostname); + // deno-lint-ignore no-console console.log(`Listening on ${scheme}${host}:${addr.port}/`); } @@ -868,10 +868,11 @@ function registerDeclarativeServer(exports) { const nThreads = serveWorkerCount > 1 ? ` with ${serveWorkerCount} threads` : ""; - const hostname_ = mapAnyAddrToLocalhostForWindows(hostname); + const host = formatHostName(hostname); + // deno-lint-ignore no-console console.debug( - `%cdeno serve%c: Listening on %chttp://${hostname_}:${port}/%c${nThreads}`, + `%cdeno serve%c: Listening on %chttp://${host}:${port}/%c${nThreads}`, "color: green", "color: inherit", "color: yellow", diff --git a/tests/unit/serve_test.ts b/tests/unit/serve_test.ts index 19a8ccad1b..9d23f8df25 100644 --- a/tests/unit/serve_test.ts +++ b/tests/unit/serve_test.ts @@ -872,6 +872,36 @@ Deno.test({ permissions: { net: true } }, async function validPortString() { await server.shutdown(); }); +Deno.test({ permissions: { net: true } }, async function ipv6Hostname() { + const ac = new AbortController(); + let url = ""; + + const consoleLog = console.log; + console.log = (msg) => { + try { + const match = msg.match(/Listening on (http:\/\/(.*?):(\d+)\/)/); + assert(!!match, `Didn't match ${msg}`); + url = match[1]; + } finally { + ac.abort(); + } + }; + + try { + const server = Deno.serve({ + handler: () => new Response(), + hostname: "::1", + port: 0, + signal: ac.signal, + }); + assertEquals(server.addr.transport, "tcp"); + assert(new URL(url), `Not a valid URL "${url}"`); + await server.shutdown(); + } finally { + console.log = consoleLog; + } +}); + Deno.test({ permissions: { net: true } }, function invalidPortFloat() { assertThrows( () =>