url: move bad port deprecation in legacy url to end-of-life

Calling `url.parse()` with a URL that has a bad port
will now throw an error instead of emitting a deprecation
warning. It's been deprecated for ~ 3 years now.

PR-URL: https://github.com/nodejs/node/pull/58617
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
This commit is contained in:
James M Snell 2025-06-07 08:01:15 -07:00
parent 66632648ba
commit 3aaa2ebe19
4 changed files with 14 additions and 32 deletions

View File

@ -3548,6 +3548,9 @@ issued for `url.parse()` vulnerabilities.
<!-- YAML <!-- YAML
changes: changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/58617
description: End-of-Life.
- version: - version:
- v20.0.0 - v20.0.0
pr-url: https://github.com/nodejs/node/pull/45526 pr-url: https://github.com/nodejs/node/pull/45526
@ -3559,11 +3562,11 @@ changes:
description: Documentation-only deprecation. description: Documentation-only deprecation.
--> -->
Type: Runtime Type: End-of-Life
[`url.parse()`][] accepts URLs with ports that are not numbers. This behavior [`url.parse()`][] used to accept URLs with ports that are not numbers. This
might result in host name spoofing with unexpected input. These URLs will throw behavior might result in host name spoofing with unexpected input. These URLs
an error in future versions of Node.js, as the [WHATWG URL API][] does already. will throw an error (which the [WHATWG URL API][] also does).
### DEP0171: Setters for `http.IncomingMessage` headers and trailers ### DEP0171: Setters for `http.IncomingMessage` headers and trailers

View File

@ -41,6 +41,7 @@ const querystring = require('querystring');
const { const {
ERR_INVALID_ARG_TYPE, ERR_INVALID_ARG_TYPE,
ERR_INVALID_URL, ERR_INVALID_URL,
ERR_INVALID_ARG_VALUE,
} = require('internal/errors').codes; } = require('internal/errors').codes;
const { const {
validateString, validateString,
@ -501,7 +502,6 @@ Url.prototype.parse = function parse(url, parseQueryString, slashesDenoteHost) {
return this; return this;
}; };
let warnInvalidPort = true;
function getHostname(self, rest, hostname, url) { function getHostname(self, rest, hostname, url) {
for (let i = 0; i < hostname.length; ++i) { for (let i = 0; i < hostname.length; ++i) {
const code = hostname.charCodeAt(i); const code = hostname.charCodeAt(i);
@ -513,12 +513,8 @@ function getHostname(self, rest, hostname, url) {
if (!isValid) { if (!isValid) {
// If leftover starts with :, then it represents an invalid port. // If leftover starts with :, then it represents an invalid port.
// But url.parse() is lenient about it for now. if (code === CHAR_COLON) {
// Issue a warning and continue. throw new ERR_INVALID_ARG_VALUE('url', 'Invalid port in url', url);
if (warnInvalidPort && code === CHAR_COLON) {
const detail = `The URL ${url} is invalid. Future versions of Node.js will throw an error.`;
process.emitWarning(detail, 'DeprecationWarning', 'DEP0170');
warnInvalidPort = false;
} }
self.hostname = hostname.slice(0, i); self.hostname = hostname.slice(0, i);
return `/${hostname.slice(i)}${rest}`; return `/${hostname.slice(i)}${rest}`;

View File

@ -862,22 +862,6 @@ const parseTests = {
href: 'http://a%22%20%3C\'b:b@cd/e?f' href: 'http://a%22%20%3C\'b:b@cd/e?f'
}, },
// Git urls used by npm
'git+ssh://git@github.com:npm/npm': {
protocol: 'git+ssh:',
slashes: true,
auth: 'git',
host: 'github.com',
port: null,
hostname: 'github.com',
hash: null,
search: null,
query: null,
pathname: '/:npm/npm',
path: '/:npm/npm',
href: 'git+ssh://git@github.com/:npm/npm'
},
'https://*': { 'https://*': {
protocol: 'https:', protocol: 'https:',
slashes: true, slashes: true,

View File

@ -83,9 +83,7 @@ if (common.hasIntl) {
badURLs.forEach((badURL) => { badURLs.forEach((badURL) => {
common.spawnPromisified(process.execPath, ['-e', `url.parse(${JSON.stringify(badURL)})`]) common.spawnPromisified(process.execPath, ['-e', `url.parse(${JSON.stringify(badURL)})`])
.then(common.mustCall(({ code, stdout, stderr }) => { .then(common.mustCall(({ code, stdout, stderr }) => {
assert.strictEqual(code, 0); assert.strictEqual(code, 1);
assert.strictEqual(stdout, '');
assert.match(stderr, /\[DEP0170\] DeprecationWarning:/);
})); }));
}); });
@ -94,10 +92,11 @@ if (common.hasIntl) {
DeprecationWarning: { DeprecationWarning: {
// eslint-disable-next-line @stylistic/js/max-len // eslint-disable-next-line @stylistic/js/max-len
DEP0169: '`url.parse()` behavior is not standardized and prone to errors that have security implications. Use the WHATWG URL API instead. CVEs are not issued for `url.parse()` vulnerabilities.', DEP0169: '`url.parse()` behavior is not standardized and prone to errors that have security implications. Use the WHATWG URL API instead. CVEs are not issued for `url.parse()` vulnerabilities.',
DEP0170: `The URL ${badURLs[0]} is invalid. Future versions of Node.js will throw an error.`,
}, },
}); });
badURLs.forEach((badURL) => { badURLs.forEach((badURL) => {
url.parse(badURL); assert.throws(() => url.parse(badURL), {
code: 'ERR_INVALID_ARG_VALUE',
});
}); });
} }