From 3a68a8117f1094fa21e1ecb36a9c6ed02d23ae23 Mon Sep 17 00:00:00 2001 From: ud2 Date: Sat, 21 Feb 2026 22:41:21 +0800 Subject: [PATCH] fix(ext/node): support ipv6 host in `node:http` --- ext/node/polyfills/http.ts | 14 +++++++++----- tests/unit_node/http_test.ts | 17 +++++++++++++++-- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/ext/node/polyfills/http.ts b/ext/node/polyfills/http.ts index 59079a130a92e5..feea2e149609a1 100644 --- a/ext/node/polyfills/http.ts +++ b/ext/node/polyfills/http.ts @@ -98,8 +98,12 @@ import { methods as METHODS } from "node:_http_common"; import { deprecate } from "node:util"; const { internalRidSymbol } = core; -const { ArrayIsArray, StringPrototypeToLowerCase, SafeArrayIterator } = - primordials; +const { + ArrayIsArray, + StringPrototypeIncludes, + StringPrototypeToLowerCase, + SafeArrayIterator, +} = primordials; type Chunk = string | Buffer | Uint8Array; @@ -969,9 +973,9 @@ class ClientRequest extends OutgoingMessage { path = "/" + path; } const url = new URL( - `${protocol}//${auth ? `${auth}@` : ""}${host}${ - port === 80 ? "" : `:${port}` - }${path}`, + `${protocol}//${auth ? `${auth}@` : ""}${ + StringPrototypeIncludes(host, ":") ? `[${host}]` : host + }${port === 80 ? "" : `:${port}`}${path}`, ); url.hash = hash; return url.href; diff --git a/tests/unit_node/http_test.ts b/tests/unit_node/http_test.ts index 9e2225c7b47e02..269279c93cf9bf 100644 --- a/tests/unit_node/http_test.ts +++ b/tests/unit_node/http_test.ts @@ -2,7 +2,7 @@ // deno-lint-ignore-file no-console -import EventEmitter from "node:events"; +import { EventEmitter, once } from "node:events"; import http, { IncomingMessage, type RequestOptions, @@ -11,7 +11,7 @@ import http, { import url from "node:url"; import https from "node:https"; import zlib from "node:zlib"; -import net, { Socket } from "node:net"; +import net, { type AddressInfo, Socket } from "node:net"; import fs from "node:fs"; import { text } from "node:stream/consumers"; @@ -441,6 +441,19 @@ Deno.test("[node/http] request with headers", async () => { await promise; }); +Deno.test("[node/http] request with ipv6 host", async () => { + const server = http.createServer((_req, res) => res.end()).listen(0, "::1"); + await once(server, "listening"); + const { port } = server.address() as AddressInfo; + const req = http.request(`http://[::1]:${port}`).end(); + const [res] = await once(req, "response") as [IncomingMessage]; + assertEquals(res.statusCode, 200); + res.resume(); + await once(res, "end"); + server.close(); + await once(server, "close"); +}); + Deno.test("[node/http] non-string buffer response", { // TODO(kt3k): Enable sanitizer. A "zlib" resource is leaked in this test case. sanitizeResources: false,