mirror of
https://github.com/zebrajr/node.git
synced 2026-01-15 12:15:26 +00:00
workers: add support for data: URLs
PR-URL: https://github.com/nodejs/node/pull/34584 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Bradley Farias <bradley.meck@gmail.com> Reviewed-By: Jan Krems <jan.krems@gmail.com>
This commit is contained in:
committed by
James M Snell
parent
24cc4a6e7d
commit
ffa5b068ce
@@ -621,6 +621,10 @@ if (isMainThread) {
|
||||
<!-- YAML
|
||||
added: v10.5.0
|
||||
changes:
|
||||
- version: REPLACEME
|
||||
pr-url: https://github.com/nodejs/node/pull/34584
|
||||
description: The `filename` parameter can be a WHATWG `URL` object using
|
||||
`data:` protocol.
|
||||
- version: REPLACEME
|
||||
pr-url: https://github.com/nodejs/node/pull/34394
|
||||
description: The `trackUnmanagedFds` option was set to `true` by default.
|
||||
@@ -654,7 +658,9 @@ changes:
|
||||
* `filename` {string|URL} The path to the Worker’s main script or module. Must
|
||||
be either an absolute path or a relative path (i.e. relative to the
|
||||
current working directory) starting with `./` or `../`, or a WHATWG `URL`
|
||||
object using `file:` protocol.
|
||||
object using `file:` or `data:` protocol.
|
||||
When using a [`data:` URL][], the data is interpreted based on MIME type using
|
||||
the [ECMAScript module loader][].
|
||||
If `options.eval` is `true`, this is a string containing JavaScript code
|
||||
rather than a path.
|
||||
* `options` {Object}
|
||||
@@ -902,6 +908,7 @@ active handle in the event system. If the worker is already `unref()`ed calling
|
||||
[`AsyncResource`]: async_hooks.html#async_hooks_class_asyncresource
|
||||
[`Buffer`]: buffer.html
|
||||
[`Buffer.allocUnsafe()`]: buffer.html#buffer_static_method_buffer_allocunsafe_size
|
||||
[ECMAScript module loader]: esm.html#esm_data_imports
|
||||
[`ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST`]: errors.html#errors_err_missing_message_port_in_transfer_list
|
||||
[`ERR_WORKER_NOT_RUNNING`]: errors.html#ERR_WORKER_NOT_RUNNING
|
||||
[`EventEmitter`]: events.html
|
||||
@@ -953,3 +960,4 @@ active handle in the event system. If the worker is already `unref()`ed calling
|
||||
[child processes]: child_process.html
|
||||
[contextified]: vm.html#vm_what_does_it_mean_to_contextify_an_object
|
||||
[v8.serdes]: v8.html#v8_serialization_api
|
||||
[`data:` URL]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs
|
||||
|
||||
@@ -1470,6 +1470,9 @@ E('ERR_WORKER_PATH', (filename) =>
|
||||
(filename.startsWith('file://') ?
|
||||
' Wrap file:// URLs with `new URL`.' : ''
|
||||
) +
|
||||
(filename.startsWith('data:text/javascript') ?
|
||||
' Wrap data: URLs with `new URL`.' : ''
|
||||
) +
|
||||
` Received "${filename}"`,
|
||||
TypeError);
|
||||
E('ERR_WORKER_UNSERIALIZABLE_ERROR',
|
||||
|
||||
@@ -149,7 +149,7 @@ port.on('message', (message) => {
|
||||
debug(`[${threadId}] starts worker script ${filename} ` +
|
||||
`(eval = ${eval}) at cwd = ${process.cwd()}`);
|
||||
port.postMessage({ type: UP_AND_RUNNING });
|
||||
if (doEval) {
|
||||
if (doEval === 'classic') {
|
||||
const { evalScript } = require('internal/process/execution');
|
||||
const name = '[worker eval]';
|
||||
// This is necessary for CJS module compilation.
|
||||
@@ -161,6 +161,11 @@ port.on('message', (message) => {
|
||||
});
|
||||
process.argv.splice(1, 0, name);
|
||||
evalScript(name, filename);
|
||||
} else if (doEval === 'module') {
|
||||
const { evalModule } = require('internal/process/execution');
|
||||
evalModule(filename).catch((e) => {
|
||||
workerOnGlobalUncaughtException(e, true);
|
||||
});
|
||||
} else {
|
||||
// script filename
|
||||
// runMain here might be monkey-patched by users in --require.
|
||||
|
||||
@@ -45,7 +45,7 @@ function evalModule(source, print) {
|
||||
const { log } = require('internal/console/global');
|
||||
const { loadESM } = require('internal/process/esm_loader');
|
||||
const { handleMainPromise } = require('internal/modules/run_main');
|
||||
handleMainPromise(loadESM(async (loader) => {
|
||||
return handleMainPromise(loadESM(async (loader) => {
|
||||
const { result } = await loader.eval(source);
|
||||
if (print) {
|
||||
log(result);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
const {
|
||||
ArrayIsArray,
|
||||
JSONStringify,
|
||||
MathMax,
|
||||
ObjectCreate,
|
||||
ObjectEntries,
|
||||
@@ -100,7 +101,7 @@ class Worker extends EventEmitter {
|
||||
argv = options.argv.map(String);
|
||||
}
|
||||
|
||||
let url;
|
||||
let url, doEval;
|
||||
if (options.eval) {
|
||||
if (typeof filename !== 'string') {
|
||||
throw new ERR_INVALID_ARG_VALUE(
|
||||
@@ -110,7 +111,13 @@ class Worker extends EventEmitter {
|
||||
);
|
||||
}
|
||||
url = null;
|
||||
doEval = 'classic';
|
||||
} else if (isURLInstance(filename) && filename.protocol === 'data:') {
|
||||
url = null;
|
||||
doEval = 'module';
|
||||
filename = `import ${JSONStringify(`${filename}`)}`;
|
||||
} else {
|
||||
doEval = false;
|
||||
if (isURLInstance(filename)) {
|
||||
url = filename;
|
||||
filename = fileURLToPath(filename);
|
||||
@@ -201,7 +208,7 @@ class Worker extends EventEmitter {
|
||||
argv,
|
||||
type: messageTypes.LOAD_SCRIPT,
|
||||
filename,
|
||||
doEval: !!options.eval,
|
||||
doEval,
|
||||
cwdCounter: cwdCounter || workerIo.sharedCwdCounter,
|
||||
workerData: options.workerData,
|
||||
publicPort: port2,
|
||||
|
||||
25
test/parallel/test-worker-data-url.js
Normal file
25
test/parallel/test-worker-data-url.js
Normal file
@@ -0,0 +1,25 @@
|
||||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
const { Worker } = require('worker_threads');
|
||||
const assert = require('assert');
|
||||
|
||||
new Worker(new URL('data:text/javascript,'))
|
||||
.on('error', common.mustNotCall(() => {}));
|
||||
new Worker(new URL('data:text/javascript,export{}'))
|
||||
.on('error', common.mustNotCall(() => {}));
|
||||
|
||||
new Worker(new URL('data:text/plain,'))
|
||||
.on('error', common.mustCall(() => {}));
|
||||
new Worker(new URL('data:text/javascript,module.exports={}'))
|
||||
.on('error', common.mustCall(() => {}));
|
||||
|
||||
new Worker(new URL('data:text/javascript,await Promise.resolve()'))
|
||||
.on('error', common.mustNotCall(() => {}));
|
||||
new Worker(new URL('data:text/javascript,await Promise.reject()'))
|
||||
.on('error', common.mustCall(() => {}));
|
||||
new Worker(new URL('data:text/javascript,await new Promise(()=>{})'))
|
||||
.on(
|
||||
'exit',
|
||||
common.mustCall((exitCode) => { assert.strictEqual(exitCode, 13); })
|
||||
);
|
||||
@@ -33,6 +33,10 @@ const { Worker } = require('worker_threads');
|
||||
() => { new Worker('file:///file_url'); },
|
||||
/Wrap file:\/\/ URLs with `new URL`/
|
||||
);
|
||||
assert.throws(
|
||||
() => { new Worker('data:text/javascript,'); },
|
||||
/Wrap data: URLs with `new URL`/
|
||||
);
|
||||
assert.throws(
|
||||
() => { new Worker('relative_no_dot'); },
|
||||
// eslint-disable-next-line node-core/no-unescaped-regexp-dot
|
||||
@@ -47,6 +51,4 @@ const { Worker } = require('worker_threads');
|
||||
};
|
||||
assert.throws(() => { new Worker(new URL('https://www.url.com')); },
|
||||
expectedErr);
|
||||
assert.throws(() => { new Worker(new URL('data:application/javascript,')); },
|
||||
expectedErr);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user