Skip to content

Commit eefa89c

Browse files
authored
test: normalize compressed IPv6 addresses in dev server output (#4878)
* test: normalize compressed IPv6 addresses in dev server output The IPv6 pattern only matched the full eight-group form, so a unique local address such as [fdb2:2c26:f4e4::1] reached the serve snapshots unchanged, and a full address would have kept its brackets twice. Match the bracketed host in any form, except the [::1] loopback, and replace it with its brackets. * test: only replace bracketed text that is an IPv6 address The pattern also matched tokens such as [1:2] or [dead:beef]. Check the bracket contents with net.isIPv6 before replacing them, and cover normalizeStderr's IPv6 handling with unit tests.
1 parent 6f597bf commit eefa89c

2 files changed

Lines changed: 41 additions & 2 deletions

File tree

‎test/api/normalize-stderr.test.js‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
"use strict";
2+
3+
const { normalizeStderr } = require("../utils/test-utils");
4+
5+
const NETWORK_IPV6 = "<i> [webpack-dev-server] On Your Network (IPv6): ";
6+
7+
describe("normalizeStderr", () => {
8+
it("should replace a compressed IPv6 address, such as a unique local address", () => {
9+
expect(normalizeStderr(`${NETWORK_IPV6}http://[fdb2:2c26:f4e4::1]:8080/`)).toBe(
10+
`${NETWORK_IPV6}http://[x:x:x:x:x:x:x:x]:<port>/`,
11+
);
12+
});
13+
14+
it("should replace a full IPv6 address with its brackets", () => {
15+
expect(normalizeStderr(`${NETWORK_IPV6}http://[2001:db8:0:0:0:0:0:1]:8080/`)).toBe(
16+
`${NETWORK_IPV6}http://[x:x:x:x:x:x:x:x]:<port>/`,
17+
);
18+
});
19+
20+
it("should keep the IPv6 loopback", () => {
21+
expect(
22+
normalizeStderr(
23+
"<i> [webpack-dev-server] Loopback: http://localhost:8080/, http://[::1]:8080/",
24+
),
25+
).toBe("<i> [webpack-dev-server] Loopback: http://localhost:<port>/, http://[::1]:<port>/");
26+
});
27+
28+
it("should leave bracketed text that is not an IPv6 address", () => {
29+
expect(normalizeStderr("[1:2] [dead:beef] [webpack-dev-server]")).toBe(
30+
"[1:2] [dead:beef] [webpack-dev-server]",
31+
);
32+
});
33+
});

‎test/utils/test-utils.js‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
const { exec } = require("node:child_process");
44
const fs = require("node:fs");
5+
const { isIPv6 } = require("node:net");
56
const path = require("node:path");
67
const { stripVTControlCharacters } = require("node:util");
78
const concat = require("concat-stream");
@@ -268,7 +269,12 @@ const normalizeStdout = (stdout) => {
268269
};
269270

270271
const IPV4 = /(25[0-5]|2[0-4][0-9]|1?[0-9][0-9]{1,2})(\.(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})){3}/g;
271-
const IPV6 = /([0-9a-f]){1,4}(:([0-9a-f]){1,4}){7}/gi;
272+
// A bracketed IPv6 host in a URL, in full or compressed ("::") form, e.g. a unique local
273+
// address such as `[fdb2:2c26:f4e4::1]`. The loopback `[::1]` and bracketed text that is not
274+
// an IPv6 address stay as they are.
275+
const IPV6 = /\[([0-9a-f:.]+)(%[^\]]+)?\]/gi;
276+
const replaceIPv6 = (match, address) =>
277+
address !== "::1" && isIPv6(address) ? "[x:x:x:x:x:x:x:x]" : match;
272278

273279
const normalizeStderr = (stderr) => {
274280
if (typeof stderr !== "string") {
@@ -283,7 +289,7 @@ const normalizeStderr = (stderr) => {
283289
normalizedStderr = normalizeCwd(normalizedStderr);
284290

285291
normalizedStderr = normalizedStderr.replaceAll(IPV4, "x.x.x.x");
286-
normalizedStderr = normalizedStderr.replaceAll(IPV6, "[x:x:x:x:x:x:x:x]");
292+
normalizedStderr = normalizedStderr.replaceAll(IPV6, replaceIPv6);
287293
normalizedStderr = normalizedStderr.replaceAll(/:[0-9]+\//g, ":<port>/");
288294

289295
if (!/On Your Network \(IPv6\)/.test(stderr)) {

0 commit comments

Comments
 (0)