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