worker: support relative paths

This commit adds support for relative paths in Worker.
Paths are relative to the current working directory.

PR-URL: https://github.com/nodejs/node/pull/21407
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Guy Bedford <guybedford@gmail.com>
Reviewed-By: Anatoli Papirovski <apapirovski@mac.com>
This commit is contained in:
itaysabato 2018-06-26 18:31:36 +03:00 committed by Benjamin Gruenbaum
parent 8326bea6c2
commit 8d33bbf168
7 changed files with 64 additions and 20 deletions

View File

@ -1754,10 +1754,11 @@ The fulfilled value of a linking promise is not a `vm.Module` object.
The current module's status does not allow for this operation. The specific The current module's status does not allow for this operation. The specific
meaning of the error depends on the specific function. meaning of the error depends on the specific function.
<a id="ERR_WORKER_NEED_ABSOLUTE_PATH"></a> <a id="ERR_WORKER_PATH"></a>
### ERR_WORKER_NEED_ABSOLUTE_PATH ### ERR_WORKER_PATH
The path for the main script of a worker is not an absolute path. The path for the main script of a worker is neither an absolute path
nor a relative path starting with `./` or `../`.
<a id="ERR_WORKER_UNSERIALIZABLE_ERROR"></a> <a id="ERR_WORKER_UNSERIALIZABLE_ERROR"></a>
### ERR_WORKER_UNSERIALIZABLE_ERROR ### ERR_WORKER_UNSERIALIZABLE_ERROR

View File

@ -306,7 +306,9 @@ if (isMainThread) {
### new Worker(filename[, options]) ### new Worker(filename[, options])
* `filename` {string} The absolute path to the Workers main script. * `filename` {string} The path to the Workers main script. Must be
either an absolute path or a relative path (i.e. relative to the
current working directory) starting with `./` or `../`.
If `options.eval` is true, this is a string containing JavaScript code rather If `options.eval` is true, this is a string containing JavaScript code rather
than a path. than a path.
* `options` {Object} * `options` {Object}

View File

@ -847,8 +847,9 @@ E('ERR_VM_MODULE_NOT_LINKED',
E('ERR_VM_MODULE_NOT_MODULE', E('ERR_VM_MODULE_NOT_MODULE',
'Provided module is not an instance of Module', Error); 'Provided module is not an instance of Module', Error);
E('ERR_VM_MODULE_STATUS', 'Module status %s', Error); E('ERR_VM_MODULE_STATUS', 'Module status %s', Error);
E('ERR_WORKER_NEED_ABSOLUTE_PATH', E('ERR_WORKER_PATH',
'The worker script filename must be an absolute path. Received "%s"', 'The worker script filename must be an absolute path or a relative ' +
'path starting with \'./\' or \'../\'. Received "%s"',
TypeError); TypeError);
E('ERR_WORKER_UNSERIALIZABLE_ERROR', E('ERR_WORKER_UNSERIALIZABLE_ERROR',
'Serializing an uncaught exception failed', Error); 'Serializing an uncaught exception failed', Error);

View File

@ -7,7 +7,7 @@ const util = require('util');
const { Readable, Writable } = require('stream'); const { Readable, Writable } = require('stream');
const { const {
ERR_INVALID_ARG_TYPE, ERR_INVALID_ARG_TYPE,
ERR_WORKER_NEED_ABSOLUTE_PATH, ERR_WORKER_PATH,
ERR_WORKER_UNSERIALIZABLE_ERROR, ERR_WORKER_UNSERIALIZABLE_ERROR,
ERR_WORKER_UNSUPPORTED_EXTENSION, ERR_WORKER_UNSUPPORTED_EXTENSION,
} = require('internal/errors').codes; } = require('internal/errors').codes;
@ -212,9 +212,15 @@ class Worker extends EventEmitter {
} }
if (!options.eval) { if (!options.eval) {
if (!path.isAbsolute(filename)) { if (!path.isAbsolute(filename) &&
throw new ERR_WORKER_NEED_ABSOLUTE_PATH(filename); !filename.startsWith('./') &&
!filename.startsWith('../') &&
!filename.startsWith('.' + path.sep) &&
!filename.startsWith('..' + path.sep)) {
throw new ERR_WORKER_PATH(filename);
} }
filename = path.resolve(filename);
const ext = path.extname(filename); const ext = path.extname(filename);
if (ext !== '.js' && ext !== '.mjs') { if (ext !== '.js' && ext !== '.mjs') {
throw new ERR_WORKER_UNSUPPORTED_EXTENSION(ext); throw new ERR_WORKER_UNSUPPORTED_EXTENSION(ext);

View File

@ -0,0 +1,17 @@
// Flags: --experimental-worker
'use strict';
const path = require('path');
const assert = require('assert');
const common = require('../common');
const { Worker, isMainThread, parentPort } = require('worker_threads');
if (isMainThread) {
const cwdName = path.relative('../', '.');
const relativePath = path.relative('.', __filename);
const w = new Worker(path.join('..', cwdName, relativePath));
w.on('message', common.mustCall((message) => {
assert.strictEqual(message, 'Hello, world!');
}));
} else {
parentPort.postMessage('Hello, world!');
}

View File

@ -0,0 +1,15 @@
// Flags: --experimental-worker
'use strict';
const path = require('path');
const assert = require('assert');
const common = require('../common');
const { Worker, isMainThread, parentPort } = require('worker_threads');
if (isMainThread) {
const w = new Worker('./' + path.relative('.', __filename));
w.on('message', common.mustCall((message) => {
assert.strictEqual(message, 'Hello, world!');
}));
} else {
parentPort.postMessage('Hello, world!');
}

View File

@ -1,21 +1,11 @@
// Flags: --experimental-worker // Flags: --experimental-worker
'use strict'; 'use strict';
const path = require('path');
const common = require('../common'); const common = require('../common');
const assert = require('assert'); const assert = require('assert');
const { Worker } = require('worker_threads'); const { Worker } = require('worker_threads');
{
const expectedErr = common.expectsError({
code: 'ERR_WORKER_NEED_ABSOLUTE_PATH',
type: TypeError
}, 4);
assert.throws(() => { new Worker('a.js'); }, expectedErr);
assert.throws(() => { new Worker('b'); }, expectedErr);
assert.throws(() => { new Worker('c/d.js'); }, expectedErr);
assert.throws(() => { new Worker('a.mjs'); }, expectedErr);
}
{ {
const expectedErr = common.expectsError({ const expectedErr = common.expectsError({
code: 'ERR_WORKER_UNSUPPORTED_EXTENSION', code: 'ERR_WORKER_UNSUPPORTED_EXTENSION',
@ -25,3 +15,15 @@ const { Worker } = require('worker_threads');
assert.throws(() => { new Worker('/c.wasm'); }, expectedErr); assert.throws(() => { new Worker('/c.wasm'); }, expectedErr);
assert.throws(() => { new Worker('/d.txt'); }, expectedErr); assert.throws(() => { new Worker('/d.txt'); }, expectedErr);
} }
{
const expectedErr = common.expectsError({
code: 'ERR_WORKER_PATH',
type: TypeError
}, 4);
const existingRelPathNoDot = path.relative('.', __filename);
assert.throws(() => { new Worker(existingRelPathNoDot); }, expectedErr);
assert.throws(() => { new Worker('relative_no_dot'); }, expectedErr);
assert.throws(() => { new Worker('file:///file_url'); }, expectedErr);
assert.throws(() => { new Worker('https://www.url.com'); }, expectedErr);
}