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 1a9496a

Browse filesBrowse files
mceachenBethGriggs
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 9a79020 commit 1a9496a
Copy full SHA for 1a9496a

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,
@@ -1366,27 +1367,54 @@ const backslashRegEx = /\\/g;
13661367
const newlineRegEx = /\n/g;
13671368
const carriageReturnRegEx = /\r/g;
13681369
const tabRegEx = /\t/g;
1370+
1371+
function encodePathChars(filepath) {
1372+
if (filepath.includes('%'))
1373+
filepath = filepath.replace(percentRegEx, '%25');
1374+
// In posix, backslash is a valid character in paths:
1375+
if (!isWindows && filepath.includes('\\'))
1376+
filepath = filepath.replace(backslashRegEx, '%5C');
1377+
if (filepath.includes('\n'))
1378+
filepath = filepath.replace(newlineRegEx, '%0A');
1379+
if (filepath.includes('\r'))
1380+
filepath = filepath.replace(carriageReturnRegEx, '%0D');
1381+
if (filepath.includes('\t'))
1382+
filepath = filepath.replace(tabRegEx, '%09');
1383+
return filepath;
1384+
}
1385+
13691386
function pathToFileURL(filepath) {
1370-
let resolved = path.resolve(filepath);
1371-
// path.resolve strips trailing slashes so we must add them back
1372-
const filePathLast = filepath.charCodeAt(filepath.length - 1);
1373-
if ((filePathLast === CHAR_FORWARD_SLASH ||
1374-
(isWindows && filePathLast === CHAR_BACKWARD_SLASH)) &&
1375-
resolved[resolved.length - 1] !== path.sep)
1376-
resolved += '/';
13771387
const outURL = new URL('file://');
1378-
if (resolved.includes('%'))
1379-
resolved = resolved.replace(percentRegEx, '%25');
1380-
// In posix, "/" is a valid character in paths
1381-
if (!isWindows && resolved.includes('\\'))
1382-
resolved = resolved.replace(backslashRegEx, '%5C');
1383-
if (resolved.includes('\n'))
1384-
resolved = resolved.replace(newlineRegEx, '%0A');
1385-
if (resolved.includes('\r'))
1386-
resolved = resolved.replace(carriageReturnRegEx, '%0D');
1387-
if (resolved.includes('\t'))
1388-
resolved = resolved.replace(tabRegEx, '%09');
1389-
outURL.pathname = resolved;
1388+
if (isWindows && filepath.startsWith('\\\\')) {
1389+
// UNC path format: \\server\share\resource
1390+
const paths = filepath.split('\\');
1391+
if (paths.length <= 3) {
1392+
throw new ERR_INVALID_ARG_VALUE(
1393+
'filepath',
1394+
filepath,
1395+
'Missing UNC resource path'
1396+
);
1397+
}
1398+
const hostname = paths[2];
1399+
if (hostname.length === 0) {
1400+
throw new ERR_INVALID_ARG_VALUE(
1401+
'filepath',
1402+
filepath,
1403+
'Empty UNC servername'
1404+
);
1405+
}
1406+
outURL.hostname = domainToASCII(hostname);
1407+
outURL.pathname = encodePathChars(paths.slice(3).join('/'));
1408+
} else {
1409+
let resolved = path.resolve(filepath);
1410+
// path.resolve strips trailing slashes so we must add them back
1411+
const filePathLast = filepath.charCodeAt(filepath.length - 1);
1412+
if ((filePathLast === CHAR_FORWARD_SLASH ||
1413+
(isWindows && filePathLast === CHAR_BACKWARD_SLASH)) &&
1414+
resolved[resolved.length - 1] !== path.sep)
1415+
resolved += '/';
1416+
outURL.pathname = encodePathChars(resolved);
1417+
}
13901418
return outURL;
13911419
}
13921420

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.