Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: ipv6 output #5270

Merged
merged 9 commits into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 21 additions & 11 deletions lib/Server.js
Original file line number Diff line number Diff line change
Expand Up @@ -388,10 +388,10 @@ class Server {

/**
* @param {string} gatewayOrFamily or family
* @param {boolean} [isInternal=false] ip should be internal
* @param {boolean} [isInternal] ip should be internal
* @returns {string | undefined}
*/
static findIp(gatewayOrFamily, isInternal = false) {
static findIp(gatewayOrFamily, isInternal) {
if (gatewayOrFamily === "v4" || gatewayOrFamily === "v6") {
let host;

Expand All @@ -406,14 +406,21 @@ class Server {
return false;
}

if (network.internal !== isInternal) {
if (
typeof isInternal !== "undefined" &&
network.internal !== isInternal
) {
return false;
}

if (gatewayOrFamily === "v6") {
const range = ipaddr.parse(network.address).range();

if (range !== "ipv4Mapped" && range !== "uniqueLocal") {
if (
range !== "ipv4Mapped" &&
range !== "uniqueLocal" &&
range !== "loopback"
) {
return false;
}
}
Expand Down Expand Up @@ -458,7 +465,7 @@ class Server {
* @returns {Promise<string | undefined>}
*/
static async internalIP(family) {
return Server.findIp(family);
return Server.findIp(family, false);
}

// TODO remove me in the next major release, we have `findIp`
Expand All @@ -467,7 +474,7 @@ class Server {
* @returns {string | undefined}
*/
static internalIPSync(family) {
return Server.findIp(family);
return Server.findIp(family, false);
}

/**
Expand All @@ -476,11 +483,13 @@ class Server {
*/
static async getHostname(hostname) {
if (hostname === "local-ip") {
return Server.findIp("v4") || Server.findIp("v6") || "0.0.0.0";
return (
Server.findIp("v4", false) || Server.findIp("v6", false) || "0.0.0.0"
);
} else if (hostname === "local-ipv4") {
return Server.findIp("v4") || "0.0.0.0";
return Server.findIp("v4", false) || "0.0.0.0";
} else if (hostname === "local-ipv6") {
return Server.findIp("v6") || "::";
return Server.findIp("v6", false) || "::";
}

return hostname;
Expand Down Expand Up @@ -2829,14 +2838,15 @@ class Server {

if (parsedIP.range() === "unspecified") {
localhost = prettyPrintURL("localhost");
loopbackIPv6 = prettyPrintURL("::1");

const networkIPv4 = Server.findIp("v4");
const networkIPv4 = Server.findIp("v4", false);

if (networkIPv4) {
networkUrlIPv4 = prettyPrintURL(networkIPv4);
}

const networkIPv6 = Server.findIp("v6");
const networkIPv6 = Server.findIp("v6", false);

if (networkIPv6) {
networkUrlIPv6 = prettyPrintURL(networkIPv6);
Expand Down
4 changes: 2 additions & 2 deletions test/cli/host-option.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ const { testBin, normalizeStderr } = require("../helpers/test-bin");
const port = require("../ports-map")["cli-host"];
const Server = require("../../lib/Server");

const localIPv4 = Server.findIp("v4");
const localIPv6 = Server.findIp("v6");
const localIPv4 = Server.findIp("v4", false);
const localIPv6 = Server.findIp("v6", false);

describe('"host" CLI option', () => {
it('should work using "--host 0.0.0.0" (IPv4)', async () => {
Expand Down
151 changes: 78 additions & 73 deletions test/e2e/host.test.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,53 @@
"use strict";

const http = require("http");
const webpack = require("webpack");
const Server = require("../../lib/Server");
const config = require("../fixtures/client-config/webpack.config");
const runBrowser = require("../helpers/run-browser");
const port = require("../ports-map").host;

const ipv4 = Server.findIp("v4");
const ipv6 = Server.findIp("v6");
// macos requires root for using ip v6
const isMacOS = process.platform === "darwin";
const ipv4 = Server.findIp("v4", false);
const ipv6 = Server.findIp("v6", false);

function getAddress(host, hostname) {
async function getAddress(host, hostname) {
let address;

if (
typeof host === "undefined" ||
(typeof host === "string" && host === "<not-specified>")
(typeof host === "string" && (host === "<not-specified>" || host === "::"))
) {
address = "::";
} else if (typeof host === "string" && host === "0.0.0.0") {
} else if (host === "0.0.0.0") {
address = "0.0.0.0";
} else if (typeof host === "string" && host === "localhost") {
address = parseFloat(process.versions.node) >= 18 ? "::1" : "127.0.0.1";
} else if (host === "::1") {
address = "::1";
} else if (host === "localhost") {
// It can be `127.0.0.1` or `::1` on different OS
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader("Content-Type", "text/plain");
res.end("Hello World\n");
});

await new Promise((resolve) => {
server.listen({ host: "localhost", port: 23100 }, resolve);
});

address = server.address().address;

await new Promise((resolve, reject) => {
server.close((err) => {
if (err) {
reject(err);
return;
}

resolve();
});
});
} else if (host === "local-ipv6") {
address = "::";
} else {
address = hostname;
}
Expand All @@ -37,28 +62,17 @@ describe("host", () => {
undefined,
"0.0.0.0",
"::",
"localhost",
"::1",
"localhost",
"127.0.0.1",
"local-ip",
"local-ipv4",
"local-ipv6",
];

for (let host of hosts) {
for (const host of hosts) {
it(`should work using "${host}" host and port as number`, async () => {
const compiler = webpack(config);

if (!ipv6 || isMacOS) {
if (host === "::") {
host = "127.0.0.1";
} else if (host === "::1") {
host = "127.0.0.1";
} else if (host === "local-ipv6") {
host = "127.0.0.1";
}
}

const devServerOptions = { port };

if (host !== "<not-specified>") {
Expand All @@ -69,24 +83,28 @@ describe("host", () => {

let hostname = host;

if (hostname === "0.0.0.0") {
hostname = "127.0.0.1";
} else if (
hostname === "<not-specified>" ||
typeof hostname === "undefined" ||
hostname === "::" ||
hostname === "::1"
) {
if (hostname === "<not-specified>" || typeof hostname === "undefined") {
// If host is omitted, the server will accept connections on the unspecified IPv6 address (::) when IPv6 is available, or the unspecified IPv4 address (0.0.0.0) otherwise.
hostname = ipv6 ? `[${ipv6}]` : ipv4;
} else if (hostname === "0.0.0.0") {
hostname = ipv4;
} else if (hostname === "::") {
// In most operating systems, listening to the unspecified IPv6 address (::) may cause the net.Server to also listen on the unspecified IPv4 address (0.0.0.0).
hostname = ipv6 ? `[${ipv6}]` : ipv4;
} else if (hostname === "::1") {
hostname = "[::1]";
} else if (hostname === "local-ip" || hostname === "local-ipv4") {
hostname = ipv4;
} else if (hostname === "local-ipv6") {
hostname = `[${ipv6}]`;
// For test env where network ipv6 doesn't work
hostname = ipv6 ? `[${ipv6}]` : "[::1]";
}

await server.start();

expect(server.server.address()).toMatchObject(getAddress(host, hostname));
expect(server.server.address()).toMatchObject(
await getAddress(host, hostname),
);

const { page, browser } = await runBrowser();

Expand Down Expand Up @@ -121,17 +139,6 @@ describe("host", () => {

it(`should work using "${host}" host and port as string`, async () => {
const compiler = webpack(config);

if (!ipv6 || isMacOS) {
if (host === "::") {
host = "127.0.0.1";
} else if (host === "::1") {
host = "127.0.0.1";
} else if (host === "local-ipv6") {
host = "127.0.0.1";
}
}

const devServerOptions = { port: `${port}` };

if (host !== "<not-specified>") {
Expand All @@ -142,24 +149,28 @@ describe("host", () => {

let hostname = host;

if (hostname === "0.0.0.0") {
hostname = "127.0.0.1";
} else if (
hostname === "<not-specified>" ||
typeof hostname === "undefined" ||
hostname === "::" ||
hostname === "::1"
) {
if (hostname === "<not-specified>" || typeof hostname === "undefined") {
// If host is omitted, the server will accept connections on the unspecified IPv6 address (::) when IPv6 is available, or the unspecified IPv4 address (0.0.0.0) otherwise.
hostname = ipv6 ? `[${ipv6}]` : ipv4;
} else if (hostname === "0.0.0.0") {
hostname = ipv4;
} else if (hostname === "::") {
// In most operating systems, listening to the unspecified IPv6 address (::) may cause the net.Server to also listen on the unspecified IPv4 address (0.0.0.0).
hostname = ipv6 ? `[${ipv6}]` : ipv4;
} else if (hostname === "::1") {
hostname = "[::1]";
} else if (hostname === "local-ip" || hostname === "local-ipv4") {
hostname = ipv4;
} else if (hostname === "local-ipv6") {
hostname = `[${ipv6}]`;
// For test env where network ipv6 doesn't work
hostname = ipv6 ? `[${ipv6}]` : "[::1]";
}

await server.start();

expect(server.server.address()).toMatchObject(getAddress(host, hostname));
expect(server.server.address()).toMatchObject(
await getAddress(host, hostname),
);

const { page, browser } = await runBrowser();

Expand Down Expand Up @@ -197,16 +208,6 @@ describe("host", () => {

process.env.WEBPACK_DEV_SERVER_BASE_PORT = port;

if (!ipv6 || isMacOS) {
if (host === "::") {
host = "127.0.0.1";
} else if (host === "::1") {
host = "127.0.0.1";
} else if (host === "local-ipv6") {
host = "127.0.0.1";
}
}

const devServerOptions = { port: "auto" };

if (host !== "<not-specified>") {
Expand All @@ -217,24 +218,28 @@ describe("host", () => {

let hostname = host;

if (hostname === "0.0.0.0") {
hostname = "127.0.0.1";
} else if (
hostname === "<not-specified>" ||
typeof hostname === "undefined" ||
hostname === "::" ||
hostname === "::1"
) {
if (hostname === "<not-specified>" || typeof hostname === "undefined") {
// If host is omitted, the server will accept connections on the unspecified IPv6 address (::) when IPv6 is available, or the unspecified IPv4 address (0.0.0.0) otherwise.
hostname = ipv6 ? `[${ipv6}]` : ipv4;
} else if (hostname === "0.0.0.0") {
hostname = ipv4;
} else if (hostname === "::") {
// In most operating systems, listening to the unspecified IPv6 address (::) may cause the net.Server to also listen on the unspecified IPv4 address (0.0.0.0).
hostname = ipv6 ? `[${ipv6}]` : ipv4;
} else if (hostname === "::1") {
hostname = "[::1]";
} else if (hostname === "local-ip" || hostname === "local-ipv4") {
hostname = ipv4;
} else if (hostname === "local-ipv6") {
hostname = `[${ipv6}]`;
// For test env where network ipv6 doesn't work
hostname = ipv6 ? `[${ipv6}]` : "[::1]";
}

await server.start();

expect(server.server.address()).toMatchObject(getAddress(host, hostname));
expect(server.server.address()).toMatchObject(
await getAddress(host, hostname),
);

const address = server.server.address();
const { page, browser } = await runBrowser();
Expand Down
2 changes: 1 addition & 1 deletion types/lib/Server.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1126,7 +1126,7 @@ declare class Server<
static isAbsoluteURL(URL: string): boolean;
/**
* @param {string} gatewayOrFamily or family
* @param {boolean} [isInternal=false] ip should be internal
* @param {boolean} [isInternal] ip should be internal
* @returns {string | undefined}
*/
static findIp(
Expand Down
Loading