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 08832e7

Browse filesBrowse files
aduh95targos
authored andcommitted
esm: improve error when calling import.meta.resolve from data: URL
PR-URL: #49516 Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent e5db8d4 commit 08832e7
Copy full SHA for 08832e7

File tree

Expand file treeCollapse file tree

4 files changed

+75
-11
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

4 files changed

+75
-11
lines changed
Open diff view settings
Collapse file

‎doc/api/errors.md‎

Copy file name to clipboardExpand all lines: doc/api/errors.md
+22Lines changed: 22 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -2956,6 +2956,26 @@ import 'package-name'; // supported
29562956

29572957
`import` with URL schemes other than `file` and `data` is unsupported.
29582958

2959+
<a id="ERR_UNSUPPORTED_RESOLVE_REQUEST"></a>
2960+
2961+
### `ERR_UNSUPPORTED_RESOLVE_REQUEST`
2962+
2963+
An attempt was made to resolve an invalid module referrer. This can happen when
2964+
importing or calling `import.meta.resolve()` with either:
2965+
2966+
* a bare specifier that is not a builtin module from a module whose URL scheme
2967+
is not `file`.
2968+
* a [relative URL][] from a module whose URL scheme is not a [special scheme][].
2969+
2970+
```mjs
2971+
try {
2972+
// Trying to import the package 'bare-specifier' from a `data:` URL module:
2973+
await import('data:text/javascript,import "bare-specifier"');
2974+
} catch (e) {
2975+
console.log(e.code); // ERR_UNSUPPORTED_RESOLVE_REQUEST
2976+
}
2977+
```
2978+
29592979
<a id="ERR_USE_AFTER_CLOSE"></a>
29602980

29612981
### `ERR_USE_AFTER_CLOSE`
@@ -3719,7 +3739,9 @@ The native call from `process.cpuUsage` could not be processed.
37193739
[event emitter-based]: events.md#class-eventemitter
37203740
[file descriptors]: https://en.wikipedia.org/wiki/File_descriptor
37213741
[policy]: permissions.md#policies
3742+
[relative URL]: https://url.spec.whatwg.org/#relative-url-string
37223743
[self-reference a package using its name]: packages.md#self-referencing-a-package-using-its-name
3744+
[special scheme]: https://url.spec.whatwg.org/#special-scheme
37233745
[stream-based]: stream.md
37243746
[syscall]: https://man7.org/linux/man-pages/man2/syscalls.2.html
37253747
[try-catch]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch
Collapse file

‎lib/internal/errors.js‎

Copy file name to clipboardExpand all lines: lib/internal/errors.js
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1863,6 +1863,9 @@ E('ERR_UNSUPPORTED_ESM_URL_SCHEME', (url, supported) => {
18631863
msg += `. Received protocol '${url.protocol}'`;
18641864
return msg;
18651865
}, Error);
1866+
E('ERR_UNSUPPORTED_RESOLVE_REQUEST',
1867+
'Failed to resolve module specifier "%s" from "%s": Invalid relative URL or base scheme is not hierarchical.',
1868+
TypeError);
18661869
E('ERR_USE_AFTER_CLOSE', '%s was closed', Error);
18671870

18681871
// This should probably be a `TypeError`.
Collapse file

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

Copy file name to clipboardExpand all lines: lib/internal/modules/esm/resolve.js
+28-11Lines 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
const inputTypeFlag = 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

@@ -884,22 +885,37 @@ function shouldBeTreatedAsRelativeOrAbsolutePath(specifier) {
884885
* @param {boolean} preserveSymlinks - Whether to preserve symlinks in the resolved URL.
885886
*/
886887
function moduleResolve(specifier, base, conditions, preserveSymlinks) {
887-
const isRemote = base.protocol === 'http:' ||
888-
base.protocol === 'https:';
888+
const protocol = typeof base === 'string' ?
889+
StringPrototypeSlice(base, 0, StringPrototypeIndexOf(base, ':') + 1) :
890+
base.protocol;
891+
const isData = protocol === 'data:';
892+
const isRemote =
893+
isData ||
894+
protocol === 'http:' ||
895+
protocol === 'https:';
889896
// Order swapped from spec for minor perf gain.
890897
// Ok since relative URLs cannot parse as URLs.
891898
let resolved;
892899
if (shouldBeTreatedAsRelativeOrAbsolutePath(specifier)) {
893-
resolved = new URL(specifier, base);
894-
} else if (!isRemote && specifier[0] === '#') {
900+
try {
901+
resolved = new URL(specifier, base);
902+
} catch (cause) {
903+
const error = new ERR_UNSUPPORTED_RESOLVE_REQUEST(specifier, base);
904+
setOwnProperty(error, 'cause', cause);
905+
throw error;
906+
}
907+
} else if (protocol === 'file:' && specifier[0] === '#') {
895908
resolved = packageImportsResolve(specifier, base, conditions);
896909
} else {
897910
try {
898911
resolved = new URL(specifier);
899-
} catch {
900-
if (!isRemote) {
901-
resolved = packageResolve(specifier, base, conditions);
912+
} catch (cause) {
913+
if (isRemote && !BuiltinModule.canBeRequiredWithoutScheme(specifier)) {
914+
const error = new ERR_UNSUPPORTED_RESOLVE_REQUEST(specifier, base);
915+
setOwnProperty(error, 'cause', cause);
916+
throw error;
902917
}
918+
resolved = packageResolve(specifier, base, conditions);
903919
}
904920
}
905921
if (resolved.protocol !== 'file:') {
@@ -1073,7 +1089,7 @@ function defaultResolve(specifier, context = {}) {
10731089
}
10741090
}
10751091

1076-
let parsed;
1092+
let parsed, protocol;
10771093
try {
10781094
if (shouldBeTreatedAsRelativeOrAbsolutePath(specifier)) {
10791095
parsed = new URL(specifier, parsedParentURL);
@@ -1082,7 +1098,7 @@ function defaultResolve(specifier, context = {}) {
10821098
}
10831099

10841100
// Avoid accessing the `protocol` property due to the lazy getters.
1085-
const protocol = parsed.protocol;
1101+
protocol = parsed.protocol;
10861102
if (protocol === 'data:' ||
10871103
(experimentalNetworkImports &&
10881104
(
@@ -1109,7 +1125,8 @@ function defaultResolve(specifier, context = {}) {
11091125
if (maybeReturn) { return maybeReturn; }
11101126

11111127
// This must come after checkIfDisallowedImport
1112-
if (parsed && parsed.protocol === 'node:') { return { __proto__: null, url: specifier }; }
1128+
protocol ??= parsed?.protocol;
1129+
if (protocol === 'node:') { return { __proto__: null, url: specifier }; }
11131130

11141131

11151132
const isMain = parentURL === undefined;
Collapse file

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

Copy file name to clipboardExpand all lines: test/es-module/test-esm-import-meta-resolve.mjs
+22Lines 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+
{ ...await import('data:text/javascript,export default import.meta.resolve("http://some-absolute/url")') },
41+
{ default: 'http://some-absolute/url' },
42+
);
43+
assert.deepStrictEqual(
44+
{ ...await import('data:text/javascript,export default import.meta.resolve("some://weird/protocol")') },
45+
{ default: 'some://weird/protocol' },
46+
);
47+
assert.deepStrictEqual(
48+
{ ...await import(`data:text/javascript,export default import.meta.resolve("baz/", ${JSON.stringify(fixtures)})`) },
49+
{ default: fixtures + 'node_modules/baz/' },
50+
);
51+
assert.deepStrictEqual(
52+
{ ...await import('data:text/javascript,export default import.meta.resolve("fs")') },
53+
{ default: 'node:fs' },
54+
);
55+
await assert.rejects(import('data:text/javascript,export default import.meta.resolve("does-not-exist")'), {
56+
code: 'ERR_UNSUPPORTED_RESOLVE_REQUEST',
57+
});
58+
await assert.rejects(import('data:text/javascript,export default import.meta.resolve("./relative")'), {
59+
code: 'ERR_UNSUPPORTED_RESOLVE_REQUEST',
60+
});
3961

4062
{
4163
const cp = spawn(execPath, [

0 commit comments

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