16
16
#include < string>
17
17
#include < vector>
18
18
19
+ using node::kAllowedInEnvironment ;
19
20
using node::kDisallowedInEnvironment ;
20
21
using v8::Array;
21
22
using v8::ArrayBuffer;
@@ -46,14 +47,15 @@ Worker::Worker(Environment* env,
46
47
Local<Object> wrap,
47
48
const std::string& url,
48
49
std::shared_ptr<PerIsolateOptions> per_isolate_opts,
49
- std::vector<std::string>&& exec_argv)
50
+ std::vector<std::string>&& exec_argv,
51
+ std::shared_ptr<KVStore> env_vars)
50
52
: AsyncWrap(env, wrap, AsyncWrap::PROVIDER_WORKER),
51
53
per_isolate_opts_ (per_isolate_opts),
52
54
exec_argv_(exec_argv),
53
55
platform_(env->isolate_data ()->platform()),
54
56
start_profiler_idle_notifier_(env->profiler_idle_notifier_started ()),
55
57
thread_id_(Environment::AllocateThreadId()),
56
- env_vars_(env-> env_vars () ) {
58
+ env_vars_(env_vars) {
57
59
Debug (this , " Creating new worker instance with thread id %llu" , thread_id_);
58
60
59
61
// Set up everything that needs to be set up in the parent environment.
@@ -441,6 +443,7 @@ Worker::~Worker() {
441
443
442
444
void Worker::New (const FunctionCallbackInfo<Value>& args) {
443
445
Environment* env = Environment::GetCurrent (args);
446
+ Isolate* isolate = args.GetIsolate ();
444
447
445
448
CHECK (args.IsConstructCall ());
446
449
@@ -451,24 +454,81 @@ void Worker::New(const FunctionCallbackInfo<Value>& args) {
451
454
452
455
std::string url;
453
456
std::shared_ptr<PerIsolateOptions> per_isolate_opts = nullptr ;
457
+ std::shared_ptr<KVStore> env_vars = nullptr ;
454
458
455
459
std::vector<std::string> exec_argv_out;
456
- bool has_explicit_exec_argv = false ;
457
460
458
- CHECK_EQ (args.Length (), 3 );
461
+ CHECK_EQ (args.Length (), 4 );
459
462
// Argument might be a string or URL
460
463
if (!args[0 ]->IsNullOrUndefined ()) {
461
464
Utf8Value value (
462
- args.GetIsolate (),
463
- args[0 ]->ToString (env->context ()).FromMaybe (Local<String>()));
465
+ isolate, args[0 ]->ToString (env->context ()).FromMaybe (Local<String>()));
464
466
url.append (value.out (), value.length ());
465
467
}
466
468
467
- if (args[1 ]->IsArray ()) {
468
- Local<Array> array = args[1 ].As <Array>();
469
+ if (args[1 ]->IsNull ()) {
470
+ // Means worker.env = { ...process.env }.
471
+ env_vars = env->env_vars ()->Clone (isolate);
472
+ } else if (args[1 ]->IsObject ()) {
473
+ // User provided env.
474
+ env_vars = KVStore::CreateMapKVStore ();
475
+ env_vars->AssignFromObject (isolate->GetCurrentContext (),
476
+ args[1 ].As <Object>());
477
+ } else {
478
+ // Env is shared.
479
+ env_vars = env->env_vars ();
480
+ }
481
+
482
+ if (args[1 ]->IsObject () || args[2 ]->IsArray ()) {
483
+ per_isolate_opts.reset (new PerIsolateOptions ());
484
+
485
+ HandleEnvOptions (
486
+ per_isolate_opts->per_env , [isolate, &env_vars](const char * name) {
487
+ MaybeLocal<String> value =
488
+ env_vars->Get (isolate, OneByteString (isolate, name));
489
+ return value.IsEmpty () ? std::string{}
490
+ : std::string (*String::Utf8Value (
491
+ isolate, value.ToLocalChecked ()));
492
+ });
493
+
494
+ #ifndef NODE_WITHOUT_NODE_OPTIONS
495
+ MaybeLocal<String> maybe_node_opts =
496
+ env_vars->Get (isolate, OneByteString (isolate, " NODE_OPTIONS" ));
497
+ if (!maybe_node_opts.IsEmpty ()) {
498
+ std::string node_options (
499
+ *String::Utf8Value (isolate, maybe_node_opts.ToLocalChecked ()));
500
+ std::vector<std::string> errors{};
501
+ std::vector<std::string> env_argv =
502
+ ParseNodeOptionsEnvVar (node_options, &errors);
503
+ // [0] is expected to be the program name, add dummy string.
504
+ env_argv.insert (env_argv.begin (), " " );
505
+ std::vector<std::string> invalid_args{};
506
+ options_parser::Parse (&env_argv,
507
+ nullptr ,
508
+ &invalid_args,
509
+ per_isolate_opts.get (),
510
+ kAllowedInEnvironment ,
511
+ &errors);
512
+ if (errors.size () > 0 && args[1 ]->IsObject ()) {
513
+ // Only fail for explicitly provided env, this protects from failures
514
+ // when NODE_OPTIONS from parent's env is used (which is the default).
515
+ Local<Value> error;
516
+ if (!ToV8Value (env->context (), errors).ToLocal (&error)) return ;
517
+ Local<String> key =
518
+ FIXED_ONE_BYTE_STRING (env->isolate (), " invalidNodeOptions" );
519
+ // Ignore the return value of Set() because exceptions bubble up to JS
520
+ // when we return anyway.
521
+ USE (args.This ()->Set (env->context (), key, error));
522
+ return ;
523
+ }
524
+ }
525
+ #endif
526
+ }
527
+
528
+ if (args[2 ]->IsArray ()) {
529
+ Local<Array> array = args[2 ].As <Array>();
469
530
// The first argument is reserved for program name, but we don't need it
470
531
// in workers.
471
- has_explicit_exec_argv = true ;
472
532
std::vector<std::string> exec_argv = {" " };
473
533
uint32_t length = array->Length ();
474
534
for (uint32_t i = 0 ; i < length; i++) {
@@ -490,8 +550,6 @@ void Worker::New(const FunctionCallbackInfo<Value>& args) {
490
550
491
551
std::vector<std::string> invalid_args{};
492
552
std::vector<std::string> errors{};
493
- per_isolate_opts.reset (new PerIsolateOptions ());
494
-
495
553
// Using invalid_args as the v8_args argument as it stores unknown
496
554
// options for the per isolate parser.
497
555
options_parser::Parse (
@@ -518,40 +576,24 @@ void Worker::New(const FunctionCallbackInfo<Value>& args) {
518
576
USE (args.This ()->Set (env->context (), key, error));
519
577
return ;
520
578
}
521
- }
522
- if (!has_explicit_exec_argv)
579
+ } else {
523
580
exec_argv_out = env->exec_argv ();
581
+ }
524
582
525
- Worker* worker =
526
- new Worker (env, args.This (), url, per_isolate_opts,
527
- std::move (exec_argv_out));
583
+ Worker* worker = new Worker (env,
584
+ args.This (),
585
+ url,
586
+ per_isolate_opts,
587
+ std::move (exec_argv_out),
588
+ env_vars);
528
589
529
- CHECK (args[2 ]->IsFloat64Array ());
530
- Local<Float64Array> limit_info = args[2 ].As <Float64Array>();
590
+ CHECK (args[3 ]->IsFloat64Array ());
591
+ Local<Float64Array> limit_info = args[3 ].As <Float64Array>();
531
592
CHECK_EQ (limit_info->Length (), kTotalResourceLimitCount );
532
593
limit_info->CopyContents (worker->resource_limits_ ,
533
594
sizeof (worker->resource_limits_ ));
534
595
}
535
596
536
- void Worker::CloneParentEnvVars (const FunctionCallbackInfo<Value>& args) {
537
- Worker* w;
538
- ASSIGN_OR_RETURN_UNWRAP (&w, args.This ());
539
- CHECK (w->thread_joined_ ); // The Worker has not started yet.
540
-
541
- w->env_vars_ = w->env ()->env_vars ()->Clone (args.GetIsolate ());
542
- }
543
-
544
- void Worker::SetEnvVars (const FunctionCallbackInfo<Value>& args) {
545
- Worker* w;
546
- ASSIGN_OR_RETURN_UNWRAP (&w, args.This ());
547
- CHECK (w->thread_joined_ ); // The Worker has not started yet.
548
-
549
- CHECK (args[0 ]->IsObject ());
550
- w->env_vars_ = KVStore::CreateMapKVStore ();
551
- w->env_vars_ ->AssignFromObject (args.GetIsolate ()->GetCurrentContext (),
552
- args[0 ].As <Object>());
553
- }
554
-
555
597
void Worker::StartThread (const FunctionCallbackInfo<Value>& args) {
556
598
Worker* w;
557
599
ASSIGN_OR_RETURN_UNWRAP (&w, args.This ());
@@ -722,8 +764,6 @@ void InitWorker(Local<Object> target,
722
764
w->InstanceTemplate ()->SetInternalFieldCount (1 );
723
765
w->Inherit (AsyncWrap::GetConstructorTemplate (env));
724
766
725
- env->SetProtoMethod (w, " setEnvVars" , Worker::SetEnvVars);
726
- env->SetProtoMethod (w, " cloneParentEnvVars" , Worker::CloneParentEnvVars);
727
767
env->SetProtoMethod (w, " startThread" , Worker::StartThread);
728
768
env->SetProtoMethod (w, " stopThread" , Worker::StopThread);
729
769
env->SetProtoMethod (w, " ref" , Worker::Ref);
0 commit comments