Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

worker: support relative paths #21407

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions doc/api/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -1741,10 +1741,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
meaning of the error depends on the specific function.

<a id="ERR_WORKER_NEED_ABSOLUTE_PATH"></a>
### ERR_WORKER_NEED_ABSOLUTE_PATH
<a id="ERR_WORKER_PATH"></a>
### 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>
### ERR_WORKER_UNSERIALIZABLE_ERROR
Expand Down
4 changes: 3 additions & 1 deletion doc/api/worker_threads.md
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,9 @@ if (isMainThread) {

### new Worker(filename, options)

* `filename` {string} The absolute path to the Worker’s main script.
* `filename` {string} The path to the Worker’s 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
than a path.
* `options` {Object}
Expand Down
5 changes: 3 additions & 2 deletions lib/internal/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -847,8 +847,9 @@ E('ERR_VM_MODULE_NOT_LINKED',
E('ERR_VM_MODULE_NOT_MODULE',
'Provided module is not an instance of Module', Error);
E('ERR_VM_MODULE_STATUS', 'Module status %s', Error);
E('ERR_WORKER_NEED_ABSOLUTE_PATH',
'The worker script filename must be an absolute path. Received "%s"',
E('ERR_WORKER_PATH',
'The worker script filename must be an absolute path or a relative ' +
'path starting with \'./\' or \'../\'. Received "%s"',
TypeError);
E('ERR_WORKER_UNSERIALIZABLE_ERROR',
'Serializing an uncaught exception failed', Error);
Expand Down
12 changes: 9 additions & 3 deletions lib/internal/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const util = require('util');
const { Readable, Writable } = require('stream');
const {
ERR_INVALID_ARG_TYPE,
ERR_WORKER_NEED_ABSOLUTE_PATH,
ERR_WORKER_PATH,
ERR_WORKER_UNSERIALIZABLE_ERROR,
ERR_WORKER_UNSUPPORTED_EXTENSION,
} = require('internal/errors').codes;
Expand Down Expand Up @@ -212,9 +212,15 @@ class Worker extends EventEmitter {
}

if (!options.eval) {
if (!path.isAbsolute(filename)) {
throw new ERR_WORKER_NEED_ABSOLUTE_PATH(filename);
if (!path.isAbsolute(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);
if (ext !== '.js' && ext !== '.mjs') {
throw new ERR_WORKER_UNSUPPORTED_EXTENSION(ext);
Expand Down
17 changes: 17 additions & 0 deletions test/parallel/test-worker-relative-path-double-dot.js
Original file line number Diff line number Diff line change
@@ -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!');
}
15 changes: 15 additions & 0 deletions test/parallel/test-worker-relative-path.js
Original file line number Diff line number Diff line change
@@ -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!');
}
24 changes: 13 additions & 11 deletions test/parallel/test-worker-unsupported-path.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,11 @@
// Flags: --experimental-worker
'use strict';

const path = require('path');
const common = require('../common');
const assert = require('assert');
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({
code: 'ERR_WORKER_UNSUPPORTED_EXTENSION',
Expand All @@ -25,3 +15,15 @@ const { Worker } = require('worker_threads');
assert.throws(() => { new Worker('/c.wasm'); }, 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);
}