From 4e5a9d83b780861cecce2916d10a445b3198bf53 Mon Sep 17 00:00:00 2001 From: Rain Date: Mon, 16 Feb 2026 20:54:31 +0800 Subject: [PATCH] fix(gateway): preserve unbracketed IPv6 host headers --- src/gateway/net.test.ts | 13 +++++++++++++ src/gateway/net.ts | 4 ++++ 2 files changed, 17 insertions(+) diff --git a/src/gateway/net.test.ts b/src/gateway/net.test.ts index 722fd7fc7..fa1ea9f50 100644 --- a/src/gateway/net.test.ts +++ b/src/gateway/net.test.ts @@ -5,8 +5,21 @@ import { isTrustedProxyAddress, pickPrimaryLanIPv4, resolveGatewayListenHosts, + resolveHostName, } from "./net.js"; +describe("resolveHostName", () => { + it("returns hostname without port for IPv4/hostnames", () => { + expect(resolveHostName("localhost:18789")).toBe("localhost"); + expect(resolveHostName("127.0.0.1:18789")).toBe("127.0.0.1"); + }); + + it("handles bracketed and unbracketed IPv6 loopback hosts", () => { + expect(resolveHostName("[::1]:18789")).toBe("::1"); + expect(resolveHostName("::1")).toBe("::1"); + }); +}); + describe("isTrustedProxyAddress", () => { describe("exact IP matching", () => { it("returns true when IP matches exactly", () => { diff --git a/src/gateway/net.ts b/src/gateway/net.ts index a96e86460..ee3c762d5 100644 --- a/src/gateway/net.ts +++ b/src/gateway/net.ts @@ -40,6 +40,10 @@ export function resolveHostName(hostHeader?: string): string { return host.slice(1, end); } } + // Unbracketed IPv6 host (e.g. "::1") has no port and should be returned as-is. + if (net.isIP(host) === 6) { + return host; + } const [name] = host.split(":"); return name ?? ""; }