| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent da8c526 commit 219b1b8
11 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1903,6 +1903,12 @@ The fulfilled value of a linking promise is not a `vm.SourceTextModule` object. | |||
| 1903 | 1903 | The current module's status does not allow for this operation. The specific | |
| 1904 | 1904 | meaning of the error depends on the specific function. | |
| 1905 | 1905 | ||
| 1906 | + <a id="ERR_WORKER_INVALID_EXEC_ARGV"></a> | ||
| 1907 | + ### ERR_WORKER_INVALID_EXEC_ARGV | ||
| 1908 | + | ||
| 1909 | + The `execArgv` option passed to the `Worker` constructor contains | ||
| 1910 | + invalid flags. | ||
| 1911 | + | ||
| 1906 | 1912 | <a id="ERR_WORKER_PATH"></a> | |
| 1907 | 1913 | ### ERR_WORKER_PATH | |
| 1908 | 1914 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -316,13 +316,16 @@ if (isMainThread) { | |||
| 316 | 316 | occur as described in the [HTML structured clone algorithm][], and an error | |
| 317 | 317 | will be thrown if the object cannot be cloned (e.g. because it contains | |
| 318 | 318 | `function`s). | |
| 319 | - * stdin {boolean} If this is set to `true`, then `worker.stdin` will | ||
| 319 | + * `stdin` {boolean} If this is set to `true`, then `worker.stdin` will | ||
| 320 | 320 | provide a writable stream whose contents will appear as `process.stdin` | |
| 321 | 321 | inside the Worker. By default, no data is provided. | |
| 322 | - * stdout {boolean} If this is set to `true`, then `worker.stdout` will | ||
| 322 | + * `stdout` {boolean} If this is set to `true`, then `worker.stdout` will | ||
| 323 | 323 | not automatically be piped through to `process.stdout` in the parent. | |
| 324 | - * stderr {boolean} If this is set to `true`, then `worker.stderr` will | ||
| 324 | + * `stderr` {boolean} If this is set to `true`, then `worker.stderr` will | ||
| 325 | 325 | not automatically be piped through to `process.stderr` in the parent. | |
| 326 | + * `execArgv` {string[]} List of node CLI options passed to the worker. | ||
| 327 | + V8 options (such as `--max-old-space-size`) and options that affect the | ||
| 328 | + process (such as `--title`) are not supported. | ||
| 326 | 329 | ||
| 327 | 330 | ### Event: 'error' | |
| 328 | 331 | <!-- YAML | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -992,6 +992,9 @@ E('ERR_VM_MODULE_NOT_LINKED', | |||
| 992 | 992 | E('ERR_VM_MODULE_NOT_MODULE', | |
| 993 | 993 | 'Provided module is not an instance of Module', Error); | |
| 994 | 994 | E('ERR_VM_MODULE_STATUS', 'Module status %s', Error); | |
| 995 | + E('ERR_WORKER_INVALID_EXEC_ARGV', (errors) => | ||
| 996 | + `Initiated Worker with invalid execArgv flags: ${errors.join(', ')}`, | ||
| 997 | + Error); | ||
| 995 | 998 | E('ERR_WORKER_PATH', | |
| 996 | 999 | 'The worker script filename must be an absolute path or a relative ' + | |
| 997 | 1000 | 'path starting with \'./\' or \'../\'. Received "%s"', | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -8,6 +8,8 @@ const { | |||
| 8 | 8 | ERR_WORKER_PATH, | |
| 9 | 9 | ERR_WORKER_UNSERIALIZABLE_ERROR, | |
| 10 | 10 | ERR_WORKER_UNSUPPORTED_EXTENSION, | |
| 11 | + ERR_WORKER_INVALID_EXEC_ARGV, | ||
| 12 | + ERR_INVALID_ARG_TYPE, | ||
| 11 | 13 | } = require('internal/errors').codes; | |
| 12 | 14 | const { validateString } = require('internal/validators'); | |
| 13 | 15 | ||
@@ -49,7 +51,11 @@ class Worker extends EventEmitter { | |||
| 49 | 51 | super(); | |
| 50 | 52 | debug(`[${threadId}] create new worker`, filename, options); | |
| 51 | 53 | validateString(filename, 'filename'); | |
| 52 | - | ||
| 54 | + if (options.execArgv && !Array.isArray(options.execArgv)) { | ||
| 55 | + throw new ERR_INVALID_ARG_TYPE('options.execArgv', | ||
| 56 | + 'array', | ||
| 57 | + options.execArgv); | ||
| 58 | + } | ||
| 53 | 59 | if (!options.eval) { | |
| 54 | 60 | if (!path.isAbsolute(filename) && | |
| 55 | 61 | !filename.startsWith('./') && | |
@@ -68,7 +74,10 @@ class Worker extends EventEmitter { | |||
| 68 | 74 | ||
| 69 | 75 | const url = options.eval ? null : pathToFileURL(filename); | |
| 70 | 76 | // Set up the C++ handle for the worker, as well as some internal wiring. | |
| 71 | - this[kHandle] = new WorkerImpl(url); | ||
| 77 | + this[kHandle] = new WorkerImpl(url, options.execArgv); | ||
| 78 | + if (this[kHandle].invalidExecArgv) { | ||
| 79 | + throw new ERR_WORKER_INVALID_EXEC_ARGV(this[kHandle].invalidExecArgv); | ||
| 80 | + } | ||
| 72 | 81 | this[kHandle].onexit = (code) => this[kOnExit](code); | |
| 73 | 82 | this[kPort] = this[kHandle].messagePort; | |
| 74 | 83 | this[kPort].on('message', (data) => this[kOnMessage](data)); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -595,6 +595,11 @@ inline std::shared_ptr<PerIsolateOptions> IsolateData::options() { | |||
| 595 | 595 | return options_; | |
| 596 | 596 | } | |
| 597 | 597 | ||
| 598 | + inline void IsolateData::set_options( | ||
| 599 | + std::shared_ptr<PerIsolateOptions> options) { | ||
| 600 | + options_ = options; | ||
| 601 | + } | ||
| 602 | + | ||
| 598 | 603 | void Environment::CreateImmediate(native_immediate_callback cb, | |
| 599 | 604 | void* data, | |
| 600 | 605 | v8::Local<v8::Object> obj, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -392,6 +392,7 @@ class IsolateData { | |||
| 392 | 392 | inline uint32_t* zero_fill_field() const; | |
| 393 | 393 | inline MultiIsolatePlatform* platform() const; | |
| 394 | 394 | inline std::shared_ptr<PerIsolateOptions> options(); | |
| 395 | + inline void set_options(std::shared_ptr<PerIsolateOptions> options); | ||
| 395 | 396 | ||
| 396 | 397 | #define VP(PropertyName, StringValue) V(v8::Private, PropertyName) | |
| 397 | 398 | #define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -9,7 +9,9 @@ | |||
| 9 | 9 | #include "async_wrap-inl.h" | |
| 10 | 10 | ||
| 11 | 11 | #include <string> | |
| 12 | + #include <vector> | ||
| 12 | 13 | ||
| 14 | + using node::options_parser::kDisallowedInEnvironment; | ||
| 13 | 15 | using v8::ArrayBuffer; | |
| 14 | 16 | using v8::Context; | |
| 15 | 17 | using v8::Function; | |
@@ -67,7 +69,10 @@ void WaitForWorkerInspectorToStop(Environment* child) {} | |||
| 67 | 69 | ||
| 68 | 70 | } // anonymous namespace | |
| 69 | 71 | ||
| 70 | - Worker::Worker(Environment* env, Local<Object> wrap, const std::string& url) | ||
| 72 | + Worker::Worker(Environment* env, | ||
| 73 | + Local<Object> wrap, | ||
| 74 | + const std::string& url, | ||
| 75 | + std::shared_ptr<PerIsolateOptions> per_isolate_opts) | ||
| 71 | 76 | : AsyncWrap(env, wrap, AsyncWrap::PROVIDER_WORKER), url_(url) { | |
| 72 | 77 | // Generate a new thread id. | |
| 73 | 78 | { | |
@@ -112,6 +117,9 @@ Worker::Worker(Environment* env, Local<Object> wrap, const std::string& url) | |||
| 112 | 117 | &loop_, | |
| 113 | 118 | env->isolate_data()->platform(), | |
| 114 | 119 | array_buffer_allocator_.get())); | |
| 120 | + if (per_isolate_opts != nullptr) { | ||
| 121 | + isolate_data_->set_options(per_isolate_opts); | ||
| 122 | + } | ||
| 115 | 123 | CHECK(isolate_data_); | |
| 116 | 124 | ||
| 117 | 125 | Local<Context> context = NewContext(isolate_); | |
@@ -390,14 +398,67 @@ void Worker::New(const FunctionCallbackInfo<Value>& args) { | |||
| 390 | 398 | } | |
| 391 | 399 | ||
| 392 | 400 | std::string url; | |
| 401 | + std::shared_ptr<PerIsolateOptions> per_isolate_opts = nullptr; | ||
| 402 | + | ||
| 393 | 403 | // Argument might be a string or URL | |
| 394 | - if (args.Length() == 1 && !args[0]->IsNullOrUndefined()) { | ||
| 404 | + if (args.Length() > 0 && !args[0]->IsNullOrUndefined()) { | ||
| 395 | 405 | Utf8Value value( | |
| 396 | 406 | args.GetIsolate(), | |
| 397 | 407 | args[0]->ToString(env->context()).FromMaybe(v8::Local<v8::String>())); | |
| 398 | 408 | url.append(value.out(), value.length()); | |
| 409 | + | ||
| 410 | + if (args.Length() > 1 && args[1]->IsArray()) { | ||
| 411 | + v8::Local<v8::Array> array = args[1].As<v8::Array>(); | ||
| 412 | + // The first argument is reserved for program name, but we don't need it | ||
| 413 | + // in workers. | ||
| 414 | + std::vector<std::string> exec_argv = {""}; | ||
| 415 | + uint32_t length = array->Length(); | ||
| 416 | + for (uint32_t i = 0; i < length; i++) { | ||
| 417 | + v8::Local<v8::Value> arg; | ||
| 418 | + if (!array->Get(env->context(), i).ToLocal(&arg)) { | ||
| 419 | + return; | ||
| 420 | + } | ||
| 421 | + v8::MaybeLocal<v8::String> arg_v8_string = | ||
| 422 | + arg->ToString(env->context()); | ||
| 423 | + if (arg_v8_string.IsEmpty()) { | ||
| 424 | + return; | ||
| 425 | + } | ||
| 426 | + Utf8Value arg_utf8_value( | ||
| 427 | + args.GetIsolate(), | ||
| 428 | + arg_v8_string.FromMaybe(v8::Local<v8::String>())); | ||
| 429 | + std::string arg_string(arg_utf8_value.out(), arg_utf8_value.length()); | ||
| 430 | + exec_argv.push_back(arg_string); | ||
| 431 | + } | ||
| 432 | + | ||
| 433 | + std::vector<std::string> invalid_args{}; | ||
| 434 | + std::vector<std::string> errors{}; | ||
| 435 | + per_isolate_opts.reset(new PerIsolateOptions()); | ||
| 436 | + | ||
| 437 | + // Using invalid_args as the v8_args argument as it stores unknown | ||
| 438 | + // options for the per isolate parser. | ||
| 439 | + options_parser::PerIsolateOptionsParser::instance.Parse( | ||
| 440 | + &exec_argv, | ||
| 441 | + nullptr, | ||
| 442 | + &invalid_args, | ||
| 443 | + per_isolate_opts.get(), | ||
| 444 | + kDisallowedInEnvironment, | ||
| 445 | + &errors); | ||
| 446 | + | ||
| 447 | + // The first argument is program name. | ||
| 448 | + invalid_args.erase(invalid_args.begin()); | ||
| 449 | + if (errors.size() > 0 || invalid_args.size() > 0) { | ||
| 450 | + v8::Local<v8::Value> value = | ||
| 451 | + ToV8Value(env->context(), | ||
| 452 | + errors.size() > 0 ? errors : invalid_args) | ||
| 453 | + .ToLocalChecked(); | ||
| 454 | + Local<String> key = | ||
| 455 | + FIXED_ONE_BYTE_STRING(env->isolate(), "invalidExecArgv"); | ||
| 456 | + args.This()->Set(env->context(), key, value).FromJust(); | ||
| 457 | + return; | ||
| 458 | + } | ||
| 459 | + } | ||
| 399 | 460 | } | |
| 400 | - new Worker(env, args.This(), url); | ||
| 461 | + new Worker(env, args.This(), url, per_isolate_opts); | ||
| 401 | 462 | } | |
| 402 | 463 | ||
| 403 | 464 | void Worker::StartThread(const FunctionCallbackInfo<Value>& args) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -12,7 +12,10 @@ namespace worker { | |||
| 12 | 12 | // A worker thread, as represented in its parent thread. | |
| 13 | 13 | class Worker : public AsyncWrap { | |
| 14 | 14 | public: | |
| 15 | - Worker(Environment* env, v8::Local<v8::Object> wrap, const std::string& url); | ||
| 15 | + Worker(Environment* env, | ||
| 16 | + v8::Local<v8::Object> wrap, | ||
| 17 | + const std::string& url, | ||
| 18 | + std::shared_ptr<PerIsolateOptions> per_isolate_opts); | ||
| 16 | 19 | ~Worker(); | |
| 17 | 20 | ||
| 18 | 21 | // Run the worker. This is only called from the worker thread. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -269,3 +269,13 @@ assert.strictEqual( | |||
| 269 | 269 | ||
| 270 | 270 | restoreStdout(); | |
| 271 | 271 | } | |
| 272 | + | ||
| 273 | + { | ||
| 274 | + const error = new errors.codes.ERR_WORKER_INVALID_EXEC_ARGV( | ||
| 275 | + ['--foo, --bar'] | ||
| 276 | + ); | ||
| 277 | + assert.strictEqual( | ||
| 278 | + error.message, | ||
| 279 | + 'Initiated Worker with invalid execArgv flags: --foo, --bar' | ||
| 280 | + ); | ||
| 281 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,35 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + | ||
| 3 | + const common = require('../common'); | ||
| 4 | + const assert = require('assert'); | ||
| 5 | + const { Worker } = require('worker_threads'); | ||
| 6 | + | ||
| 7 | + { | ||
| 8 | + const expectedErr = common.expectsError({ | ||
| 9 | + code: 'ERR_INVALID_ARG_TYPE', | ||
| 10 | + type: TypeError | ||
| 11 | + }, 2); | ||
| 12 | + | ||
| 13 | + assert.throws(() => { | ||
| 14 | + new Worker(__filename, { execArgv: 'hello' }); | ||
| 15 | + }, expectedErr); | ||
| 16 | + assert.throws(() => { | ||
| 17 | + new Worker(__filename, { execArgv: 6 }); | ||
| 18 | + }, expectedErr); | ||
| 19 | + } | ||
| 20 | + | ||
| 21 | + { | ||
| 22 | + const expectedErr = common.expectsError({ | ||
| 23 | + code: 'ERR_WORKER_INVALID_EXEC_ARGV', | ||
| 24 | + type: Error | ||
| 25 | + }, 3); | ||
| 26 | + assert.throws(() => { | ||
| 27 | + new Worker(__filename, { execArgv: ['--foo'] }); | ||
| 28 | + }, expectedErr); | ||
| 29 | + assert.throws(() => { | ||
| 30 | + new Worker(__filename, { execArgv: ['--title=blah'] }); | ||
| 31 | + }, expectedErr); | ||
| 32 | + assert.throws(() => { | ||
| 33 | + new Worker(__filename, { execArgv: ['--redirect-warnings'] }); | ||
| 34 | + }, expectedErr); | ||
| 35 | + } | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments