lib: add UNC support to url.pathToFileURL()
Fixes: https://github.com/nodejs/node/issues/34736 PR-URL: https://github.com/nodejs/node/pull/34743 Reviewed-By: Guy Bedford <guybedford@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com>
This commit is contained in:
parent
9861962a5f
commit
7b8c6b0c00
@ -27,6 +27,7 @@ const { getConstructorOf, removeColors } = require('internal/util');
|
||||
const {
|
||||
ERR_ARG_NOT_ITERABLE,
|
||||
ERR_INVALID_ARG_TYPE,
|
||||
ERR_INVALID_ARG_VALUE,
|
||||
ERR_INVALID_CALLBACK,
|
||||
ERR_INVALID_FILE_URL_HOST,
|
||||
ERR_INVALID_FILE_URL_PATH,
|
||||
@ -1365,27 +1366,54 @@ const backslashRegEx = /\\/g;
|
||||
const newlineRegEx = /\n/g;
|
||||
const carriageReturnRegEx = /\r/g;
|
||||
const tabRegEx = /\t/g;
|
||||
|
||||
function encodePathChars(filepath) {
|
||||
if (filepath.includes('%'))
|
||||
filepath = filepath.replace(percentRegEx, '%25');
|
||||
// In posix, backslash is a valid character in paths:
|
||||
if (!isWindows && filepath.includes('\\'))
|
||||
filepath = filepath.replace(backslashRegEx, '%5C');
|
||||
if (filepath.includes('\n'))
|
||||
filepath = filepath.replace(newlineRegEx, '%0A');
|
||||
if (filepath.includes('\r'))
|
||||
filepath = filepath.replace(carriageReturnRegEx, '%0D');
|
||||
if (filepath.includes('\t'))
|
||||
filepath = filepath.replace(tabRegEx, '%09');
|
||||
return filepath;
|
||||
}
|
||||
|
||||
function pathToFileURL(filepath) {
|
||||
let resolved = path.resolve(filepath);
|
||||
// path.resolve strips trailing slashes so we must add them back
|
||||
const filePathLast = filepath.charCodeAt(filepath.length - 1);
|
||||
if ((filePathLast === CHAR_FORWARD_SLASH ||
|
||||
(isWindows && filePathLast === CHAR_BACKWARD_SLASH)) &&
|
||||
resolved[resolved.length - 1] !== path.sep)
|
||||
resolved += '/';
|
||||
const outURL = new URL('file://');
|
||||
if (resolved.includes('%'))
|
||||
resolved = resolved.replace(percentRegEx, '%25');
|
||||
// In posix, "/" is a valid character in paths
|
||||
if (!isWindows && resolved.includes('\\'))
|
||||
resolved = resolved.replace(backslashRegEx, '%5C');
|
||||
if (resolved.includes('\n'))
|
||||
resolved = resolved.replace(newlineRegEx, '%0A');
|
||||
if (resolved.includes('\r'))
|
||||
resolved = resolved.replace(carriageReturnRegEx, '%0D');
|
||||
if (resolved.includes('\t'))
|
||||
resolved = resolved.replace(tabRegEx, '%09');
|
||||
outURL.pathname = resolved;
|
||||
if (isWindows && filepath.startsWith('\\\\')) {
|
||||
// UNC path format: \\server\share\resource
|
||||
const paths = filepath.split('\\');
|
||||
if (paths.length <= 3) {
|
||||
throw new ERR_INVALID_ARG_VALUE(
|
||||
'filepath',
|
||||
filepath,
|
||||
'Missing UNC resource path'
|
||||
);
|
||||
}
|
||||
const hostname = paths[2];
|
||||
if (hostname.length === 0) {
|
||||
throw new ERR_INVALID_ARG_VALUE(
|
||||
'filepath',
|
||||
filepath,
|
||||
'Empty UNC servername'
|
||||
);
|
||||
}
|
||||
outURL.hostname = domainToASCII(hostname);
|
||||
outURL.pathname = encodePathChars(paths.slice(3).join('/'));
|
||||
} else {
|
||||
let resolved = path.resolve(filepath);
|
||||
// path.resolve strips trailing slashes so we must add them back
|
||||
const filePathLast = filepath.charCodeAt(filepath.length - 1);
|
||||
if ((filePathLast === CHAR_FORWARD_SLASH ||
|
||||
(isWindows && filePathLast === CHAR_BACKWARD_SLASH)) &&
|
||||
resolved[resolved.length - 1] !== path.sep)
|
||||
resolved += '/';
|
||||
outURL.pathname = encodePathChars(resolved);
|
||||
}
|
||||
return outURL;
|
||||
}
|
||||
|
||||
|
@ -94,7 +94,9 @@ assert.throws(() => url.fileURLToPath('https://a/b/c'), {
|
||||
// Euro sign (BMP code point)
|
||||
{ path: 'C:\\€', fileURL: 'file:///C:/%E2%82%AC' },
|
||||
// Rocket emoji (non-BMP code point)
|
||||
{ path: 'C:\\🚀', fileURL: 'file:///C:/%F0%9F%9A%80' }
|
||||
{ path: 'C:\\🚀', fileURL: 'file:///C:/%F0%9F%9A%80' },
|
||||
// UNC path (see https://docs.microsoft.com/en-us/archive/blogs/ie/file-uris-in-windows)
|
||||
{ path: '\\\\nas\\My Docs\\File.doc', fileURL: 'file://nas/My%20Docs/File.doc' },
|
||||
];
|
||||
} else {
|
||||
testCases = [
|
||||
|
@ -23,6 +23,26 @@ const url = require('url');
|
||||
assert.ok(fileURL.includes('%25'));
|
||||
}
|
||||
|
||||
{
|
||||
if (isWindows) {
|
||||
// UNC path: \\server\share\resource
|
||||
|
||||
// Missing server:
|
||||
assert.throws(() => url.pathToFileURL('\\\\\\no-server'), {
|
||||
code: 'ERR_INVALID_ARG_VALUE'
|
||||
});
|
||||
|
||||
// Missing share or resource:
|
||||
assert.throws(() => url.pathToFileURL('\\\\host'), {
|
||||
code: 'ERR_INVALID_ARG_VALUE'
|
||||
});
|
||||
} else {
|
||||
// UNC paths on posix are considered a single path that has backslashes:
|
||||
const fileURL = url.pathToFileURL('\\\\nas\\share\\path.txt').href;
|
||||
assert.match(fileURL, /file:\/\/.+%5C%5Cnas%5Cshare%5Cpath\.txt$/);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let testCases;
|
||||
if (isWindows) {
|
||||
@ -68,7 +88,9 @@ const url = require('url');
|
||||
// Euro sign (BMP code point)
|
||||
{ path: 'C:\\€', expected: 'file:///C:/%E2%82%AC' },
|
||||
// Rocket emoji (non-BMP code point)
|
||||
{ path: 'C:\\🚀', expected: 'file:///C:/%F0%9F%9A%80' }
|
||||
{ path: 'C:\\🚀', expected: 'file:///C:/%F0%9F%9A%80' },
|
||||
// UNC path (see https://docs.microsoft.com/en-us/archive/blogs/ie/file-uris-in-windows)
|
||||
{ path: '\\\\nas\\My Docs\\File.doc', expected: 'file://nas/My%20Docs/File.doc' }
|
||||
];
|
||||
} else {
|
||||
testCases = [
|
||||
|
Loading…
x
Reference in New Issue
Block a user