Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit f29ab40

Browse filesBrowse files
mceachenaddaleax
authored andcommitted
lib: add UNC support to url.pathToFileURL()
Fixes: #34736 PR-URL: #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>
1 parent b4d9e0d commit f29ab40
Copy full SHA for f29ab40

File tree

Expand file treeCollapse file tree

3 files changed

+73
-21
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

3 files changed

+73
-21
lines changed
Open diff view settings
Collapse file

‎lib/internal/url.js‎

Copy file name to clipboardExpand all lines: lib/internal/url.js
+47-19Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const { getConstructorOf, removeColors } = require('internal/util');
2727
const {
2828
ERR_ARG_NOT_ITERABLE,
2929
ERR_INVALID_ARG_TYPE,
30+
ERR_INVALID_ARG_VALUE,
3031
ERR_INVALID_CALLBACK,
3132
ERR_INVALID_FILE_URL_HOST,
3233
ERR_INVALID_FILE_URL_PATH,
@@ -1369,27 +1370,54 @@ const backslashRegEx = /\\/g;
13691370
const newlineRegEx = /\n/g;
13701371
const carriageReturnRegEx = /\r/g;
13711372
const tabRegEx = /\t/g;
1373+
1374+
function encodePathChars(filepath) {
1375+
if (filepath.includes('%'))
1376+
filepath = filepath.replace(percentRegEx, '%25');
1377+
// In posix, backslash is a valid character in paths:
1378+
if (!isWindows && filepath.includes('\\'))
1379+
filepath = filepath.replace(backslashRegEx, '%5C');
1380+
if (filepath.includes('\n'))
1381+
filepath = filepath.replace(newlineRegEx, '%0A');
1382+
if (filepath.includes('\r'))
1383+
filepath = filepath.replace(carriageReturnRegEx, '%0D');
1384+
if (filepath.includes('\t'))
1385+
filepath = filepath.replace(tabRegEx, '%09');
1386+
return filepath;
1387+
}
1388+
13721389
function pathToFileURL(filepath) {
1373-
let resolved = path.resolve(filepath);
1374-
// path.resolve strips trailing slashes so we must add them back
1375-
const filePathLast = filepath.charCodeAt(filepath.length - 1);
1376-
if ((filePathLast === CHAR_FORWARD_SLASH ||
1377-
(isWindows && filePathLast === CHAR_BACKWARD_SLASH)) &&
1378-
resolved[resolved.length - 1] !== path.sep)
1379-
resolved += '/';
13801390
const outURL = new URL('file://');
1381-
if (resolved.includes('%'))
1382-
resolved = resolved.replace(percentRegEx, '%25');
1383-
// In posix, "/" is a valid character in paths
1384-
if (!isWindows && resolved.includes('\\'))
1385-
resolved = resolved.replace(backslashRegEx, '%5C');
1386-
if (resolved.includes('\n'))
1387-
resolved = resolved.replace(newlineRegEx, '%0A');
1388-
if (resolved.includes('\r'))
1389-
resolved = resolved.replace(carriageReturnRegEx, '%0D');
1390-
if (resolved.includes('\t'))
1391-
resolved = resolved.replace(tabRegEx, '%09');
1392-
outURL.pathname = resolved;
1391+
if (isWindows && filepath.startsWith('\\\\')) {
1392+
// UNC path format: \\server\share\resource
1393+
const paths = filepath.split('\\');
1394+
if (paths.length <= 3) {
1395+
throw new ERR_INVALID_ARG_VALUE(
1396+
'filepath',
1397+
filepath,
1398+
'Missing UNC resource path'
1399+
);
1400+
}
1401+
const hostname = paths[2];
1402+
if (hostname.length === 0) {
1403+
throw new ERR_INVALID_ARG_VALUE(
1404+
'filepath',
1405+
filepath,
1406+
'Empty UNC servername'
1407+
);
1408+
}
1409+
outURL.hostname = domainToASCII(hostname);
1410+
outURL.pathname = encodePathChars(paths.slice(3).join('/'));
1411+
} else {
1412+
let resolved = path.resolve(filepath);
1413+
// path.resolve strips trailing slashes so we must add them back
1414+
const filePathLast = filepath.charCodeAt(filepath.length - 1);
1415+
if ((filePathLast === CHAR_FORWARD_SLASH ||
1416+
(isWindows && filePathLast === CHAR_BACKWARD_SLASH)) &&
1417+
resolved[resolved.length - 1] !== path.sep)
1418+
resolved += '/';
1419+
outURL.pathname = encodePathChars(resolved);
1420+
}
13931421
return outURL;
13941422
}
13951423

Collapse file

‎test/parallel/test-url-fileurltopath.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-url-fileurltopath.js
+3-1Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,9 @@ assert.throws(() => url.fileURLToPath('https://a/b/c'), {
9494
// Euro sign (BMP code point)
9595
{ path: 'C:\\€', fileURL: 'file:///C:/%E2%82%AC' },
9696
// Rocket emoji (non-BMP code point)
97-
{ path: 'C:\\🚀', fileURL: 'file:///C:/%F0%9F%9A%80' }
97+
{ path: 'C:\\🚀', fileURL: 'file:///C:/%F0%9F%9A%80' },
98+
// UNC path (see https://docs.microsoft.com/en-us/archive/blogs/ie/file-uris-in-windows)
99+
{ path: '\\\\nas\\My Docs\\File.doc', fileURL: 'file://nas/My%20Docs/File.doc' },
98100
];
99101
} else {
100102
testCases = [
Collapse file

‎test/parallel/test-url-pathtofileurl.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-url-pathtofileurl.js
+23-1Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,26 @@ const url = require('url');
2323
assert.ok(fileURL.includes('%25'));
2424
}
2525

26+
{
27+
if (isWindows) {
28+
// UNC path: \\server\share\resource
29+
30+
// Missing server:
31+
assert.throws(() => url.pathToFileURL('\\\\\\no-server'), {
32+
code: 'ERR_INVALID_ARG_VALUE'
33+
});
34+
35+
// Missing share or resource:
36+
assert.throws(() => url.pathToFileURL('\\\\host'), {
37+
code: 'ERR_INVALID_ARG_VALUE'
38+
});
39+
} else {
40+
// UNC paths on posix are considered a single path that has backslashes:
41+
const fileURL = url.pathToFileURL('\\\\nas\\share\\path.txt').href;
42+
assert.match(fileURL, /file:\/\/.+%5C%5Cnas%5Cshare%5Cpath\.txt$/);
43+
}
44+
}
45+
2646
{
2747
let testCases;
2848
if (isWindows) {
@@ -68,7 +88,9 @@ const url = require('url');
6888
// Euro sign (BMP code point)
6989
{ path: 'C:\\€', expected: 'file:///C:/%E2%82%AC' },
7090
// Rocket emoji (non-BMP code point)
71-
{ path: 'C:\\🚀', expected: 'file:///C:/%F0%9F%9A%80' }
91+
{ path: 'C:\\🚀', expected: 'file:///C:/%F0%9F%9A%80' },
92+
// UNC path (see https://docs.microsoft.com/en-us/archive/blogs/ie/file-uris-in-windows)
93+
{ path: '\\\\nas\\My Docs\\File.doc', expected: 'file://nas/My%20Docs/File.doc' }
7294
];
7395
} else {
7496
testCases = [

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.