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 {
|
const {
|
||||||
ERR_ARG_NOT_ITERABLE,
|
ERR_ARG_NOT_ITERABLE,
|
||||||
ERR_INVALID_ARG_TYPE,
|
ERR_INVALID_ARG_TYPE,
|
||||||
|
ERR_INVALID_ARG_VALUE,
|
||||||
ERR_INVALID_CALLBACK,
|
ERR_INVALID_CALLBACK,
|
||||||
ERR_INVALID_FILE_URL_HOST,
|
ERR_INVALID_FILE_URL_HOST,
|
||||||
ERR_INVALID_FILE_URL_PATH,
|
ERR_INVALID_FILE_URL_PATH,
|
||||||
@ -1365,7 +1366,45 @@ const backslashRegEx = /\\/g;
|
|||||||
const newlineRegEx = /\n/g;
|
const newlineRegEx = /\n/g;
|
||||||
const carriageReturnRegEx = /\r/g;
|
const carriageReturnRegEx = /\r/g;
|
||||||
const tabRegEx = /\t/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) {
|
function pathToFileURL(filepath) {
|
||||||
|
const outURL = new URL('file://');
|
||||||
|
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);
|
let resolved = path.resolve(filepath);
|
||||||
// path.resolve strips trailing slashes so we must add them back
|
// path.resolve strips trailing slashes so we must add them back
|
||||||
const filePathLast = filepath.charCodeAt(filepath.length - 1);
|
const filePathLast = filepath.charCodeAt(filepath.length - 1);
|
||||||
@ -1373,19 +1412,8 @@ function pathToFileURL(filepath) {
|
|||||||
(isWindows && filePathLast === CHAR_BACKWARD_SLASH)) &&
|
(isWindows && filePathLast === CHAR_BACKWARD_SLASH)) &&
|
||||||
resolved[resolved.length - 1] !== path.sep)
|
resolved[resolved.length - 1] !== path.sep)
|
||||||
resolved += '/';
|
resolved += '/';
|
||||||
const outURL = new URL('file://');
|
outURL.pathname = encodePathChars(resolved);
|
||||||
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;
|
|
||||||
return outURL;
|
return outURL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +94,9 @@ assert.throws(() => url.fileURLToPath('https://a/b/c'), {
|
|||||||
// Euro sign (BMP code point)
|
// Euro sign (BMP code point)
|
||||||
{ path: 'C:\\€', fileURL: 'file:///C:/%E2%82%AC' },
|
{ path: 'C:\\€', fileURL: 'file:///C:/%E2%82%AC' },
|
||||||
// Rocket emoji (non-BMP code point)
|
// 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 {
|
} else {
|
||||||
testCases = [
|
testCases = [
|
||||||
|
@ -23,6 +23,26 @@ const url = require('url');
|
|||||||
assert.ok(fileURL.includes('%25'));
|
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;
|
let testCases;
|
||||||
if (isWindows) {
|
if (isWindows) {
|
||||||
@ -68,7 +88,9 @@ const url = require('url');
|
|||||||
// Euro sign (BMP code point)
|
// Euro sign (BMP code point)
|
||||||
{ path: 'C:\\€', expected: 'file:///C:/%E2%82%AC' },
|
{ path: 'C:\\€', expected: 'file:///C:/%E2%82%AC' },
|
||||||
// Rocket emoji (non-BMP code point)
|
// 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 {
|
} else {
|
||||||
testCases = [
|
testCases = [
|
||||||
|
Loading…
x
Reference in New Issue
Block a user