Skip to content

Commit ba639d0

Browse files
bmeckJakobJingleheimerjasnellljharbjsumners
authored andcommitted
esm: support https remotely and http locally under flag
Co-authored-by: Jacob Smith <[email protected]> Co-authored-by: James M Snell <[email protected]> Co-authored-by: Jordan Harband <[email protected]> Co-authored-by: James Sumners <[email protected]> PR-URL: #36328 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Geoffrey Booth <[email protected]>
1 parent c766159 commit ba639d0

33 files changed

+1000
-149
lines changed

doc/api/cli.md

+11
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,16 @@ added: v9.0.0
307307
Specify the `module` of a custom experimental [ECMAScript module loader][].
308308
`module` may be any string accepted as an [`import` specifier][].
309309

310+
### `--experimental-network-imports`
311+
312+
<!-- YAML
313+
added: REPLACEME
314+
-->
315+
316+
> Stability: 1 - Experimental
317+
318+
Enable experimental support for the `https:` protocol in `import` specifiers.
319+
310320
### `--experimental-policy`
311321

312322
<!-- YAML
@@ -1572,6 +1582,7 @@ Node.js options that are allowed are:
15721582
* `--experimental-json-modules`
15731583
* `--experimental-loader`
15741584
* `--experimental-modules`
1585+
* `--experimental-network-imports`
15751586
* `--experimental-policy`
15761587
* `--experimental-specifier-resolution`
15771588
* `--experimental-top-level-await`

doc/api/errors.md

+17
Original file line numberDiff line numberDiff line change
@@ -3117,6 +3117,23 @@ removed: v10.0.0
31173117

31183118
Used by the `Node-API` when `Constructor.prototype` is not an object.
31193119

3120+
<a id="ERR_NETWORK_IMPORT_BAD_RESPONSE"></a>
3121+
3122+
### `ERR_NETWORK_IMPORT_BAD_RESPONSE`
3123+
3124+
> Stability: 1 - Experimental
3125+
3126+
Response was received but was invalid when importing a module over the network.
3127+
3128+
<a id="ERR_NETWORK_IMPORT_DISALLOWED"></a>
3129+
3130+
### `ERR_NETWORK_IMPORT_DISALLOWED`
3131+
3132+
> Stability: 1 - Experimental
3133+
3134+
A network module attempted to load another module that it is not allowed to
3135+
load. Likely this restriction is for security reasons.
3136+
31203137
<a id="ERR_NO_LONGER_SUPPORTED"></a>
31213138

31223139
### `ERR_NO_LONGER_SUPPORTED`

doc/api/esm.md

+65
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,71 @@ spawn(execPath, [
601601
});
602602
```
603603
604+
## HTTPS and HTTP imports
605+
606+
> Stability: 1 - Experimental
607+
608+
Importing network based modules using `https:` and `http:` is supported under
609+
the `--experimental-network-imports` flag. This allows web browser-like imports
610+
to work in Node.js with a few differences due to application stability and
611+
security concerns that are different when running in a privileged environment
612+
instead of a browser sandbox.
613+
614+
### Imports are limited to HTTP/1
615+
616+
Automatic protocol negotiation for HTTP/2 and HTTP/3 is not yet supported.
617+
618+
### HTTP is limited to loopback addresses
619+
620+
`http:` is vulnerable to man-in-the-middle attacks and is not allowed to be
621+
used for addresses outside of the IPv4 address `127.0.0.0/8` (`127.0.0.1` to
622+
`127.255.255.255`) and the IPv6 address `::1`. Support for `http:` is intended
623+
to be used for local development.
624+
625+
### Authentication is never sent to the destination server.
626+
627+
`Authorization`, `Cookie`, and `Proxy-Authorization` headers are not sent to the
628+
server. Avoid including user info in parts of imported URLs. A security model
629+
for safely using these on the server is being worked on.
630+
631+
### CORS is never checked on the destination server
632+
633+
CORS is designed to allow a server to limit the consumers of an API to a
634+
specific set of hosts. This is not supported as it does not make sense for a
635+
server-based implementation.
636+
637+
### Cannot load non-network dependencies
638+
639+
These modules cannot access other modules that are not over `http:` or `https:`.
640+
To still access local modules while avoiding the security concern, pass in
641+
references to the local dependencies:
642+
643+
```mjs
644+
// file.mjs
645+
import worker_threads from 'worker_threads';
646+
import { configure, resize } from 'https://example.com/imagelib.mjs';
647+
configure({ worker_threads });
648+
```
649+
650+
```mjs
651+
// https://example.com/imagelib.mjs
652+
let worker_threads;
653+
export function configure(opts) {
654+
worker_threads = opts.worker_threads;
655+
}
656+
export function resize(img, size) {
657+
// Perform resizing in worker_thread to avoid main thread blocking
658+
}
659+
```
660+
661+
### Network-based loading is not enabled by default
662+
663+
For now, the `--experimental-network-imports` flag is required to enable loading
664+
resources over `http:` or `https:`. In the future, a different mechanism will be
665+
used to enforce this. Opt-in is required to prevent transitive dependencies
666+
inadvertently using potentially mutable state that could affect reliability
667+
of Node.js applications.
668+
604669
<i id="esm_experimental_loaders"></i>
605670
606671
## Loaders

doc/node.1

+3
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@ Specify the
150150
.Ar module
151151
to use as a custom module loader.
152152
.
153+
.It Fl -experimental-network-imports
154+
Enable experimental support for loading modules using `import` over `https:`.
155+
.
153156
.It Fl -experimental-policy
154157
Use the specified file as a security policy.
155158
.

lib/internal/errors.js

+8-3
Original file line numberDiff line numberDiff line change
@@ -1434,6 +1434,10 @@ E('ERR_NAPI_INVALID_TYPEDARRAY_ALIGNMENT',
14341434
'start offset of %s should be a multiple of %s', RangeError);
14351435
E('ERR_NAPI_INVALID_TYPEDARRAY_LENGTH',
14361436
'Invalid typed array length', RangeError);
1437+
E('ERR_NETWORK_IMPORT_BAD_RESPONSE',
1438+
"import '%s' received a bad response: %s", Error);
1439+
E('ERR_NETWORK_IMPORT_DISALLOWED',
1440+
"import of '%s' by %s is not supported: %s", Error);
14371441
E('ERR_NO_CRYPTO',
14381442
'Node.js is not compiled with OpenSSL crypto support', Error);
14391443
E('ERR_NO_ICU',
@@ -1595,12 +1599,13 @@ E('ERR_UNKNOWN_ENCODING', 'Unknown encoding: %s', TypeError);
15951599
E('ERR_UNKNOWN_FILE_EXTENSION',
15961600
'Unknown file extension "%s" for %s',
15971601
TypeError);
1598-
E('ERR_UNKNOWN_MODULE_FORMAT', 'Unknown module format: %s', RangeError);
1602+
E('ERR_UNKNOWN_MODULE_FORMAT', 'Unknown module format: %s for URL %s',
1603+
RangeError);
15991604
E('ERR_UNKNOWN_SIGNAL', 'Unknown signal: %s', TypeError);
16001605
E('ERR_UNSUPPORTED_DIR_IMPORT', "Directory import '%s' is not supported " +
16011606
'resolving ES modules imported from %s', Error);
1602-
E('ERR_UNSUPPORTED_ESM_URL_SCHEME', (url) => {
1603-
let msg = 'Only file and data URLs are supported by the default ESM loader';
1607+
E('ERR_UNSUPPORTED_ESM_URL_SCHEME', (url, supported) => {
1608+
let msg = `Only URLs with a scheme in: ${ArrayPrototypeJoin(supported, ', ')} are supported by the default ESM loader`;
16041609
if (isWindows && url.protocol.length === 2) {
16051610
msg +=
16061611
'. On Windows, absolute paths must be valid file:// URLs';

lib/internal/main/check_syntax.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,16 @@ if (process.argv[1] && process.argv[1] !== '-') {
4545
});
4646
}
4747

48-
function checkSyntax(source, filename) {
48+
async function checkSyntax(source, filename) {
4949
const { getOptionValue } = require('internal/options');
5050
let isModule = false;
5151
if (filename === '[stdin]' || filename === '[eval]') {
5252
isModule = getOptionValue('--input-type') === 'module';
5353
} else {
5454
const { defaultResolve } = require('internal/modules/esm/resolve');
5555
const { defaultGetFormat } = require('internal/modules/esm/get_format');
56-
const { url } = defaultResolve(pathToFileURL(filename).toString());
57-
const format = defaultGetFormat(url);
56+
const { url } = await defaultResolve(pathToFileURL(filename).toString());
57+
const format = await defaultGetFormat(url);
5858
isModule = format === 'module';
5959
}
6060
if (isModule) {

0 commit comments

Comments
 (0)