Skip to content

Commit

Permalink
url: validate pathToFileURL(path) argument as string
Browse files Browse the repository at this point in the history
PR-URL: #49161
Reviewed-By: Joyee Cheung <[email protected]>
Reviewed-By: Antoine du Hamel <[email protected]>
  • Loading branch information
LiviaMedeiros authored and UlisesGascon committed Sep 10, 2023
1 parent 8d0913b commit ae40cb1
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 5 deletions.
4 changes: 2 additions & 2 deletions lib/internal/url.js
Original file line number Diff line number Diff line change
Expand Up @@ -1441,14 +1441,14 @@ function pathToFileURL(filepath) {
const hostnameEndIndex = StringPrototypeIndexOf(filepath, '\\', 2);
if (hostnameEndIndex === -1) {
throw new ERR_INVALID_ARG_VALUE(
'filepath',
'path',
filepath,
'Missing UNC resource path',
);
}
if (hostnameEndIndex === 2) {
throw new ERR_INVALID_ARG_VALUE(
'filepath',
'path',
filepath,
'Empty UNC servername',
);
Expand Down
11 changes: 10 additions & 1 deletion lib/url.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const {
domainToASCII,
domainToUnicode,
fileURLToPath,
pathToFileURL,
pathToFileURL: _pathToFileURL,
urlToHttpOptions,
unsafeProtocol,
hostlessProtocol,
Expand Down Expand Up @@ -1017,6 +1017,15 @@ Url.prototype.parseHost = function parseHost() {
if (host) this.hostname = host;
};

// When used internally, we are not obligated to associate TypeError with
// this function, so non-strings can be rejected by underlying implementation.
// Public API has to validate input and throw appropriate error.
function pathToFileURL(path) {
validateString(path, 'path');

return _pathToFileURL(path);
}

module.exports = {
// Original API
Url,
Expand Down
37 changes: 35 additions & 2 deletions test/parallel/test-url-pathtofileurl.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,30 @@ const url = require('url');

// Missing server:
assert.throws(() => url.pathToFileURL('\\\\\\no-server'), {
code: 'ERR_INVALID_ARG_VALUE'
code: 'ERR_INVALID_ARG_VALUE',
});

// Missing share or resource:
assert.throws(() => url.pathToFileURL('\\\\host'), {
code: 'ERR_INVALID_ARG_VALUE'
code: 'ERR_INVALID_ARG_VALUE',
});

// Regression test for direct String.prototype.startsWith call
assert.throws(() => url.pathToFileURL([
'\\\\',
{ [Symbol.toPrimitive]: () => 'blep\\blop' },
]), {
code: 'ERR_INVALID_ARG_TYPE',
});
assert.throws(() => url.pathToFileURL(['\\\\', 'blep\\blop']), {
code: 'ERR_INVALID_ARG_TYPE',
});
assert.throws(() => url.pathToFileURL({
[Symbol.toPrimitive]: () => '\\\\blep\\blop',
}), {
code: 'ERR_INVALID_ARG_TYPE',
});

} else {
// UNC paths on posix are considered a single path that has backslashes:
const fileURL = url.pathToFileURL('\\\\nas\\share\\path.txt').href;
Expand Down Expand Up @@ -144,3 +161,19 @@ const url = require('url');
assert.strictEqual(actual, expected);
}
}

// Test for non-string parameter
{
for (const badPath of [
undefined, null, true, 42, 42n, Symbol('42'), NaN, {}, [], () => {},
Promise.resolve('foo'),
new Date(),
new String('notPrimitive'),
{ toString() { return 'amObject'; } },
{ [Symbol.toPrimitive]: (hint) => 'amObject' },
]) {
assert.throws(() => url.pathToFileURL(badPath), {
code: 'ERR_INVALID_ARG_TYPE',
});
}
}

0 comments on commit ae40cb1

Please sign in to comment.