Skip to content

Commit a6b3569

Browse files
aduh95richardlau
authored andcommitted
esm: improve error when calling import.meta.resolve from data: URL
PR-URL: #49516 Reviewed-By: James M Snell <[email protected]>
1 parent 94f8ee8 commit a6b3569

File tree

4 files changed

+75
-11
lines changed

4 files changed

+75
-11
lines changed

‎doc/api/errors.md‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2993,6 +2993,26 @@ import 'package-name' // supported
29932993

29942994
`import` with URL schemes other than `file` and `data` is unsupported.
29952995

2996+
<aid="ERR_UNSUPPORTED_RESOLVE_REQUEST"></a>
2997+
2998+
### `ERR_UNSUPPORTED_RESOLVE_REQUEST`
2999+
3000+
An attempt was made to resolve an invalid module referrer. This can happen when
3001+
importing or calling `import.meta.resolve()` with either:
3002+
3003+
* a bare specifier that is not a builtin module from a module whose URL scheme
3004+
is not `file`.
3005+
* a [relative URL][] from a module whose URL scheme is not a [special scheme][].
3006+
3007+
```mjs
3008+
try{
3009+
// Trying to import the package 'bare-specifier' from a `data:` URL module:
3010+
awaitimport('data:text/javascript,import "bare-specifier"');
3011+
} catch (e){
3012+
console.log(e.code); // ERR_UNSUPPORTED_RESOLVE_REQUEST
3013+
}
3014+
```
3015+
29963016
<aid="ERR_USE_AFTER_CLOSE"></a>
29973017

29983018
### `ERR_USE_AFTER_CLOSE`
@@ -3681,7 +3701,9 @@ The native call from `process.cpuUsage` could not be processed.
36813701
[event emitter-based]: events.md#class-eventemitter
36823702
[file descriptors]: https://en.wikipedia.org/wiki/File_descriptor
36833703
[policy]: permissions.md#policies
3704+
[relative URL]: https://url.spec.whatwg.org/#relative-url-string
36843705
[self-reference a package using its name]: packages.md#self-referencing-a-package-using-its-name
3706+
[special scheme]: https://url.spec.whatwg.org/#special-scheme
36853707
[stream-based]: stream.md
36863708
[syscall]: https://man7.org/linux/man-pages/man2/syscalls.2.html
36873709
[try-catch]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch

‎lib/internal/errors.js‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1868,6 +1868,9 @@ E('ERR_UNSUPPORTED_ESM_URL_SCHEME', (url, supported) =>{
18681868
msg+=`. Received protocol '${url.protocol}'`;
18691869
returnmsg;
18701870
},Error);
1871+
E('ERR_UNSUPPORTED_RESOLVE_REQUEST',
1872+
'Failed to resolve module specifier "%s" from "%s": Invalid relative URL or base scheme is not hierarchical.',
1873+
TypeError);
18711874
E('ERR_USE_AFTER_CLOSE','%s was closed',Error);
18721875

18731876
// This should probably be a `TypeError`.

‎lib/internal/modules/esm/resolve.js‎

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ const experimentalNetworkImports =
3737
getOptionValue('--experimental-network-imports');
3838
constinputTypeFlag=getOptionValue('--input-type');
3939
const{URL, pathToFileURL, fileURLToPath, isURL }=require('internal/url');
40-
const{ getCWDURL }=require('internal/util');
40+
const{ getCWDURL, setOwnProperty}=require('internal/util');
4141
const{canParse: URLCanParse}=internalBinding('url');
4242
const{legacyMainResolve: FSLegacyMainResolve}=internalBinding('fs');
4343
const{
@@ -51,6 +51,7 @@ const{
5151
ERR_PACKAGE_IMPORT_NOT_DEFINED,
5252
ERR_PACKAGE_PATH_NOT_EXPORTED,
5353
ERR_UNSUPPORTED_DIR_IMPORT,
54+
ERR_UNSUPPORTED_RESOLVE_REQUEST,
5455
ERR_NETWORK_IMPORT_DISALLOWED,
5556
}=require('internal/errors').codes;
5657

@@ -893,22 +894,37 @@ function shouldBeTreatedAsRelativeOrAbsolutePath(specifier){
893894
* @param{boolean} preserveSymlinks - Whether to preserve symlinks in the resolved URL.
894895
*/
895896
functionmoduleResolve(specifier,base,conditions,preserveSymlinks){
896-
constisRemote=base.protocol==='http:'||
897-
base.protocol==='https:';
897+
constprotocol=typeofbase==='string' ?
898+
StringPrototypeSlice(base,0,StringPrototypeIndexOf(base,':')+1) :
899+
base.protocol;
900+
constisData=protocol==='data:';
901+
constisRemote=
902+
isData||
903+
protocol==='http:'||
904+
protocol==='https:';
898905
// Order swapped from spec for minor perf gain.
899906
// Ok since relative URLs cannot parse as URLs.
900907
letresolved;
901908
if(shouldBeTreatedAsRelativeOrAbsolutePath(specifier)){
902-
resolved=newURL(specifier,base);
903-
}elseif(!isRemote&&specifier[0]==='#'){
909+
try{
910+
resolved=newURL(specifier,base);
911+
}catch(cause){
912+
consterror=newERR_UNSUPPORTED_RESOLVE_REQUEST(specifier,base);
913+
setOwnProperty(error,'cause',cause);
914+
throwerror;
915+
}
916+
}elseif(protocol==='file:'&&specifier[0]==='#'){
904917
resolved=packageImportsResolve(specifier,base,conditions);
905918
}else{
906919
try{
907920
resolved=newURL(specifier);
908-
}catch{
909-
if(!isRemote){
910-
resolved=packageResolve(specifier,base,conditions);
921+
}catch(cause){
922+
if(isRemote&&!BuiltinModule.canBeRequiredWithoutScheme(specifier)){
923+
consterror=newERR_UNSUPPORTED_RESOLVE_REQUEST(specifier,base);
924+
setOwnProperty(error,'cause',cause);
925+
throwerror;
911926
}
927+
resolved=packageResolve(specifier,base,conditions);
912928
}
913929
}
914930
if(resolved.protocol!=='file:'){
@@ -1082,7 +1098,7 @@ function defaultResolve(specifier, context ={}){
10821098
}
10831099
}
10841100

1085-
letparsed;
1101+
letparsed,protocol;
10861102
try{
10871103
if(shouldBeTreatedAsRelativeOrAbsolutePath(specifier)){
10881104
parsed=newURL(specifier,parsedParentURL);
@@ -1091,7 +1107,7 @@ function defaultResolve(specifier, context ={}){
10911107
}
10921108

10931109
// Avoid accessing the `protocol` property due to the lazy getters.
1094-
constprotocol=parsed.protocol;
1110+
protocol=parsed.protocol;
10951111
if(protocol==='data:'||
10961112
(experimentalNetworkImports&&
10971113
(
@@ -1118,7 +1134,8 @@ function defaultResolve(specifier, context ={}){
11181134
if(maybeReturn){returnmaybeReturn;}
11191135

11201136
// This must come after checkIfDisallowedImport
1121-
if(parsed&&parsed.protocol==='node:'){return{__proto__: null,url: specifier};}
1137+
protocol??=parsed?.protocol;
1138+
if(protocol==='node:'){return{__proto__: null,url: specifier};}
11221139

11231140

11241141
constisMain=parentURL===undefined;

‎test/es-module/test-esm-import-meta-resolve.mjs‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,28 @@ assert.strictEqual(import.meta.resolve('http://some-absolute/url'), 'http://some
3636
assert.strictEqual(import.meta.resolve('some://weird/protocol'),'some://weird/protocol');
3737
assert.strictEqual(import.meta.resolve('baz/',fixtures),
3838
fixtures+'node_modules/baz/');
39+
assert.deepStrictEqual(
40+
{ ...awaitimport('data:text/javascript,export default import.meta.resolve("http://some-absolute/url")')},
41+
{default: 'http://some-absolute/url'},
42+
);
43+
assert.deepStrictEqual(
44+
{ ...awaitimport('data:text/javascript,export default import.meta.resolve("some://weird/protocol")')},
45+
{default: 'some://weird/protocol'},
46+
);
47+
assert.deepStrictEqual(
48+
{ ...awaitimport(`data:text/javascript,export default import.meta.resolve("baz/", ${JSON.stringify(fixtures)})`)},
49+
{default: fixtures+'node_modules/baz/'},
50+
);
51+
assert.deepStrictEqual(
52+
{ ...awaitimport('data:text/javascript,export default import.meta.resolve("fs")')},
53+
{default: 'node:fs'},
54+
);
55+
awaitassert.rejects(import('data:text/javascript,export default import.meta.resolve("does-not-exist")'),{
56+
code: 'ERR_UNSUPPORTED_RESOLVE_REQUEST',
57+
});
58+
awaitassert.rejects(import('data:text/javascript,export default import.meta.resolve("./relative")'),{
59+
code: 'ERR_UNSUPPORTED_RESOLVE_REQUEST',
60+
});
3961

4062
{
4163
constcp=spawn(execPath,[

0 commit comments

Comments
(0)