Skip to content

Commit

Permalink
refactor: improve host resolution and wildcard host handling (#4479)
Browse files Browse the repository at this point in the history
  • Loading branch information
chenjiahan authored Feb 4, 2025
1 parent 8ec8eed commit 12cb066
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 53 deletions.
15 changes: 12 additions & 3 deletions packages/core/src/server/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -342,14 +342,23 @@ const getIpv4Interfaces = () => {
return Array.from(ipv4Interfaces.values());
};

export const isWildcardHost = (host: string): boolean => {
const wildcardHosts = new Set([
'0.0.0.0',
'::',
'0000:0000:0000:0000:0000:0000:0000:0000',
]);
return wildcardHosts.has(host);
};

const isLoopbackHost = (host: string) => {
const loopbackHosts = [
const loopbackHosts = new Set([
'localhost',
'127.0.0.1',
'::1',
'0000:0000:0000:0000:0000:0000:0000:0001',
];
return loopbackHosts.includes(host);
]);
return loopbackHosts.has(host);
};

export const getHostInUrl = (host: string): string => {
Expand Down
76 changes: 26 additions & 50 deletions packages/core/src/server/hmrFallback.ts
Original file line number Diff line number Diff line change
@@ -1,71 +1,47 @@
import { promises as dns } from 'node:dns';
import type { DevConfig, ServerConfig } from '../types/config';

type Hostname = {
host?: string;
name: string;
};

const wildcardHosts = new Set([
'0.0.0.0',
'::',
'0000:0000:0000:0000:0000:0000:0000:0000',
]);

export async function resolveHostname(
optionsHost: string | undefined,
): Promise<Hostname> {
let host: string | undefined;
if (optionsHost === undefined) {
// Use a secure default
host = 'localhost';
} else {
host = optionsHost;
}

// Set host name to localhost when possible
let name = host === undefined || wildcardHosts.has(host) ? 'localhost' : host;

if (host === 'localhost') {
const localhostAddr = await getLocalhostAddressIfDiffersFromDNS();
if (localhostAddr) {
name = localhostAddr;
}
}

return { host, name };
}
import { isWildcardHost } from './helper';

/**
* Returns resolved localhost address when `dns.lookup` result differs from DNS
* Checks if localhost resolves differently between node's default DNS lookup
* and explicit DNS lookup.
*
* `dns.lookup` result is same when defaultResultOrder is `verbatim`.
* Even if defaultResultOrder is `ipv4first`, `dns.lookup` result maybe same.
* For example, when IPv6 is not supported on that machine/network.
* Returns the resolved address if there's a difference, undefined otherwise.
* This helps detect cases where IPv4/IPv6 resolution might vary.
*/
export async function getLocalhostAddressIfDiffersFromDNS(): Promise<
export async function getLocalhostResolvedAddress(): Promise<
string | undefined
> {
const [nodeResult, dnsResult] = await Promise.all([
const [defaultLookup, explicitLookup] = await Promise.all([
dns.lookup('localhost'),
dns.lookup('localhost', { verbatim: true }),
]);
const isSame =
nodeResult.family === dnsResult.family &&
nodeResult.address === dnsResult.address;
return isSame ? undefined : nodeResult.address;
const match =
defaultLookup.family === explicitLookup.family &&
defaultLookup.address === explicitLookup.address;
return match ? undefined : defaultLookup.address;
}

async function resolveHostname(host: string | undefined = 'localhost') {
if (host === 'localhost') {
const resolvedAddress = await getLocalhostResolvedAddress();
if (resolvedAddress) {
return resolvedAddress;
}
}

// If possible, set the host name to localhost
return host === undefined || isWildcardHost(host) ? 'localhost' : host;
}

export async function getResolvedClientConfig(
clientConfig: DevConfig['client'],
serverConfig: ServerConfig,
): Promise<DevConfig['client']> {
const resolvedServerHostname = (await resolveHostname(serverConfig.host))
.name;
const resolvedServerPort = serverConfig.port!;
const resolvedHost = await resolveHostname(serverConfig.host);
return {
...clientConfig,
host: resolvedServerHostname,
port: resolvedServerPort,
host: resolvedHost,
port: serverConfig.port,
};
}

1 comment on commit 12cb066

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Ran ecosystem CI: Open

suite result
modernjs ❌ failure
plugins ✅ success
rspress ✅ success
rslib ✅ success
examples ✅ success

Please sign in to comment.