diff --git a/lib/Server.js b/lib/Server.js index bbfe8aa29d..c47026ca84 100644 --- a/lib/Server.js +++ b/lib/Server.js @@ -3050,6 +3050,32 @@ class Server { return false; } + /** + * Extracts and normalizes the hostname from a header, removing brackets for IPv6. + * @param {string} header header value + * @returns {string|null} hostname or null + */ + #parseHostnameFromHeader = function (header) { + if (!header) return null; + try { + // If the header does not have a scheme, prepend // so URL can parse it + const parseUrl = new URL( + /^(.+:)?\/\//.test(header) ? header : `//${header}`, + "http://localhost/", + ); + + let hostname = parseUrl.hostname; + // Normalize IPv6: remove brackets if present + if (hostname.startsWith("[") && hostname.endsWith("]")) { + hostname = hostname.slice(1, -1); + } + + return hostname; + } catch { + return null; + } + }; + /** * @private * @param {{ [key: string]: string | undefined }} headers headers @@ -3074,15 +3100,7 @@ class Server { return true; } - // use the node url-parser to retrieve the hostname from the host-header. - // TODO resolve me in the next major release - // eslint-disable-next-line n/no-deprecated-api - const { hostname } = url.parse( - // if header doesn't have scheme, add // for parsing. - /^(.+:)?\/\//.test(header) ? header : `//${header}`, - false, - true, - ); + const hostname = this.#parseHostnameFromHeader(header); if (hostname === null) { return false; @@ -3096,8 +3114,7 @@ class Server { // A note on IPv6 addresses: // header will always contain the brackets denoting // an IPv6-address in URLs, - // these are removed from the hostname in url.parse(), - // so we have the pure IPv6-address in hostname. + // these aren't removed from the hostname in new URL(), // For convenience, always allow localhost (hostname === 'localhost') // and its subdomains (hostname.endsWith(".localhost")). // allow hostname of listening address (hostname === this.options.host) @@ -3132,9 +3149,7 @@ class Server { return true; } - // TODO resolve me in the next major release - // eslint-disable-next-line n/no-deprecated-api - const origin = url.parse(originHeader, false, true).hostname; + const origin = this.#parseHostnameFromHeader(originHeader); if (origin === null) { return false; @@ -3154,13 +3169,7 @@ class Server { return true; } - // eslint-disable-next-line n/no-deprecated-api - const host = url.parse( - // if hostHeader doesn't have scheme, add // for parsing. - /^(.+:)?\/\//.test(hostHeader) ? hostHeader : `//${hostHeader}`, - false, - true, - ).hostname; + const host = this.#parseHostnameFromHeader(hostHeader); if (host === null) { return false; diff --git a/types/lib/Server.d.ts b/types/lib/Server.d.ts index 9ad8a3dca8..5ba932ce6e 100644 --- a/types/lib/Server.d.ts +++ b/types/lib/Server.d.ts @@ -1409,6 +1409,7 @@ declare class Server< * @param {((err?: Error) => void)=} callback callback */ stopCallback(callback?: ((err?: Error) => void) | undefined): void; + #private; } declare namespace Server { export {