Skip to content

Commit ceadb47

Browse files
bmeckJakobJingleheimerjasnellljharbjsumners
authored andcommittedFeb 10, 2022
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 52b1904 commit ceadb47

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
@@ -1574,6 +1584,7 @@ Node.js options that are allowed are:
15741584
* `--experimental-json-modules`
15751585
* `--experimental-loader`
15761586
* `--experimental-modules`
1587+
* `--experimental-network-imports`
15771588
* `--experimental-policy`
15781589
* `--experimental-specifier-resolution`
15791590
* `--experimental-top-level-await`

‎doc/api/errors.md

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

31203120
Used by the `Node-API` when `Constructor.prototype` is not an object.
31213121

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

31243141
### `ERR_NO_LONGER_SUPPORTED`

‎doc/api/esm.md

+65
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,71 @@ spawn(execPath, [
606606
});
607607
```
608608
609+
## HTTPS and HTTP imports
610+
611+
> Stability: 1 - Experimental
612+
613+
Importing network based modules using `https:` and `http:` is supported under
614+
the `--experimental-network-imports` flag. This allows web browser-like imports
615+
to work in Node.js with a few differences due to application stability and
616+
security concerns that are different when running in a privileged environment
617+
instead of a browser sandbox.
618+
619+
### Imports are limited to HTTP/1
620+
621+
Automatic protocol negotiation for HTTP/2 and HTTP/3 is not yet supported.
622+
623+
### HTTP is limited to loopback addresses
624+
625+
`http:` is vulnerable to man-in-the-middle attacks and is not allowed to be
626+
used for addresses outside of the IPv4 address `127.0.0.0/8` (`127.0.0.1` to
627+
`127.255.255.255`) and the IPv6 address `::1`. Support for `http:` is intended
628+
to be used for local development.
629+
630+
### Authentication is never sent to the destination server.
631+
632+
`Authorization`, `Cookie`, and `Proxy-Authorization` headers are not sent to the
633+
server. Avoid including user info in parts of imported URLs. A security model
634+
for safely using these on the server is being worked on.
635+
636+
### CORS is never checked on the destination server
Has conversations. Original line has conversations.
637+
638+
CORS is designed to allow a server to limit the consumers of an API to a
639+
specific set of hosts. This is not supported as it does not make sense for a
640+
server-based implementation.
641+
642+
### Cannot load non-network dependencies
643+
644+
These modules cannot access other modules that are not over `http:` or `https:`.
645+
To still access local modules while avoiding the security concern, pass in
646+
references to the local dependencies:
647+
648+
```mjs
649+
// file.mjs
650+
import worker_threads from 'worker_threads';
651+
import { configure, resize } from 'https://example.com/imagelib.mjs';
652+
configure({ worker_threads });
653+
```
654+
655+
```mjs
656+
// https://example.com/imagelib.mjs
657+
let worker_threads;
658+
export function configure(opts) {
659+
worker_threads = opts.worker_threads;
660+
}
661+
export function resize(img, size) {
662+
// Perform resizing in worker_thread to avoid main thread blocking
663+
}
664+
```
665+
666+
### Network-based loading is not enabled by default
667+
668+
For now, the `--experimental-network-imports` flag is required to enable loading
669+
resources over `http:` or `https:`. In the future, a different mechanism will be
670+
used to enforce this. Opt-in is required to prevent transitive dependencies
671+
inadvertently using potentially mutable state that could affect reliability
672+
of Node.js applications.
673+
609674
<i id="esm_experimental_loaders"></i>
610675
611676
## 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
@@ -1432,6 +1432,10 @@ E('ERR_NAPI_INVALID_TYPEDARRAY_ALIGNMENT',
14321432
'start offset of %s should be a multiple of %s', RangeError);
14331433
E('ERR_NAPI_INVALID_TYPEDARRAY_LENGTH',
14341434
'Invalid typed array length', RangeError);
1435+
E('ERR_NETWORK_IMPORT_BAD_RESPONSE',
1436+
"import '%s' received a bad response: %s", Error);
1437+
E('ERR_NETWORK_IMPORT_DISALLOWED',
1438+
"import of '%s' by %s is not supported: %s", Error);
14351439
E('ERR_NO_CRYPTO',
14361440
'Node.js is not compiled with OpenSSL crypto support', Error);
14371441
E('ERR_NO_ICU',
@@ -1593,12 +1597,13 @@ E('ERR_UNKNOWN_ENCODING', 'Unknown encoding: %s', TypeError);
15931597
E('ERR_UNKNOWN_FILE_EXTENSION',
15941598
'Unknown file extension "%s" for %s',
15951599
TypeError);
1596-
E('ERR_UNKNOWN_MODULE_FORMAT', 'Unknown module format: %s', RangeError);
1600+
E('ERR_UNKNOWN_MODULE_FORMAT', 'Unknown module format: %s for URL %s',
1601+
RangeError);
15971602
E('ERR_UNKNOWN_SIGNAL', 'Unknown signal: %s', TypeError);
15981603
E('ERR_UNSUPPORTED_DIR_IMPORT', "Directory import '%s' is not supported " +
15991604
'resolving ES modules imported from %s', Error);
1600-
E('ERR_UNSUPPORTED_ESM_URL_SCHEME', (url) => {
1601-
let msg = 'Only file and data URLs are supported by the default ESM loader';
1605+
E('ERR_UNSUPPORTED_ESM_URL_SCHEME', (url, supported) => {
1606+
let msg = `Only URLs with a scheme in: ${ArrayPrototypeJoin(supported, ', ')} are supported by the default ESM loader`;
16021607
if (isWindows && url.protocol.length === 2) {
16031608
msg +=
16041609
'. 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)
Please sign in to comment.