diff --git a/lib/internal/url.js b/lib/internal/url.js index 8c04ac70c07c..f089ff3439c9 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -23,6 +23,7 @@ const { StringPrototypeIndexOf, StringPrototypeSlice, StringPrototypeStartsWith, + StringPrototypeToUpperCase, StringPrototypeToWellFormed, Symbol, SymbolIterator, @@ -1685,7 +1686,8 @@ function pathToFileURL(filepath, options = kEmptyObject) { // Handle extended UNC path and standard UNC path // "\\?\UNC\" path prefix should be ignored. // Ref: https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation - const isExtendedUNC = StringPrototypeStartsWith(resolved, '\\\\?\\UNC\\'); + const isExtendedUNC = StringPrototypeStartsWith(resolved, '\\\\?\\') && + StringPrototypeToUpperCase(StringPrototypeSlice(resolved, 4, 8)) === 'UNC\\'; const prefixLength = isExtendedUNC ? 8 : 2; const hostnameEndIndex = StringPrototypeIndexOf(resolved, '\\', prefixLength); if (hostnameEndIndex === -1) { @@ -1695,7 +1697,7 @@ function pathToFileURL(filepath, options = kEmptyObject) { 'Missing UNC resource path', ); } - if (hostnameEndIndex === 2) { + if (hostnameEndIndex === prefixLength) { throw new ERR_INVALID_ARG_VALUE( 'path', resolved, diff --git a/test/parallel/test-url-pathtofileurl.js b/test/parallel/test-url-pathtofileurl.js index 290cac41037c..816bf7377eca 100644 --- a/test/parallel/test-url-pathtofileurl.js +++ b/test/parallel/test-url-pathtofileurl.js @@ -95,6 +95,22 @@ const url = require('url'); code: 'ERR_INVALID_ARG_VALUE', }); + // Missing server in extended UNC: + assert.throws(() => url.pathToFileURL('\\\\?\\UNC\\\\no-server'), { + code: 'ERR_INVALID_ARG_VALUE', + }); + assert.throws(() => url.pathToFileURL('\\\\?\\unc\\\\no-server'), { + code: 'ERR_INVALID_ARG_VALUE', + }); + + // Missing share or resource in extended UNC: + assert.throws(() => url.pathToFileURL('\\\\?\\UNC\\host'), { + code: 'ERR_INVALID_ARG_VALUE', + }); + assert.throws(() => url.pathToFileURL('\\\\?\\unc\\host'), { + code: 'ERR_INVALID_ARG_VALUE', + }); + // Regression test for direct String.prototype.startsWith call assert.throws(() => url.pathToFileURL([ '\\\\', @@ -173,6 +189,10 @@ const windowsTestCases = [ { path: '\\\\nas\\My Docs\\File.doc', expected: 'file://nas/My%20Docs/File.doc' }, // Extended UNC path { path: '\\\\?\\UNC\\server\\share\\folder\\file.txt', expected: 'file://server/share/folder/file.txt' }, + // Lowercase extended UNC path + { path: '\\\\?\\unc\\server\\share\\folder\\file.txt', expected: 'file://server/share/folder/file.txt' }, + // Mixed-case extended UNC path + { path: '\\\\?\\Unc\\server\\share\\folder\\file.txt', expected: 'file://server/share/folder/file.txt' }, ]; const alphabet = String.fromCharCode(...Array.from({ length: 26 }, (_, i) => 'a'.charCodeAt() + i)); const posixTestCases = [