1616#include < string>
1717#include < vector>
1818
19+ using node::kAllowedInEnvironment ;
1920using node::kDisallowedInEnvironment ;
2021using v8::Array;
2122using v8::ArrayBuffer;
@@ -46,15 +47,16 @@ Worker::Worker(Environment* env,
4647 Local<Object> wrap,
4748 const std::string& url,
4849 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)
5052 : AsyncWrap(env, wrap, AsyncWrap::PROVIDER_WORKER),
5153 per_isolate_opts_ (per_isolate_opts),
5254 exec_argv_(exec_argv),
5355 platform_(env->isolate_data ()->platform()),
5456 array_buffer_allocator_(ArrayBufferAllocator::Create()),
5557 start_profiler_idle_notifier_(env->profiler_idle_notifier_started ()),
5658 thread_id_(Environment::AllocateThreadId()),
57- env_vars_(env-> env_vars () ) {
59+ env_vars_(env_vars) {
5860 Debug (this , " Creating new worker instance with thread id %llu" , thread_id_);
5961
6062 // Set up everything that needs to be set up in the parent environment.
@@ -445,6 +447,7 @@ Worker::~Worker() {
445447
446448void Worker::New (const FunctionCallbackInfo<Value>& args) {
447449 Environment* env = Environment::GetCurrent (args);
450+ Isolate* isolate = args.GetIsolate ();
448451
449452 CHECK (args.IsConstructCall ());
450453
@@ -455,24 +458,81 @@ void Worker::New(const FunctionCallbackInfo<Value>& args) {
455458
456459 std::string url;
457460 std::shared_ptr<PerIsolateOptions> per_isolate_opts = nullptr ;
461+ std::shared_ptr<KVStore> env_vars = nullptr ;
458462
459463 std::vector<std::string> exec_argv_out;
460- bool has_explicit_exec_argv = false ;
461464
462- CHECK_EQ (args.Length (), 3 );
465+ CHECK_EQ (args.Length (), 4 );
463466 // Argument might be a string or URL
464467 if (!args[0 ]->IsNullOrUndefined ()) {
465468 Utf8Value value (
466- args.GetIsolate (),
467- args[0 ]->ToString (env->context ()).FromMaybe (Local<String>()));
469+ isolate, args[0 ]->ToString (env->context ()).FromMaybe (Local<String>()));
468470 url.append (value.out (), value.length ());
469471 }
470472
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>();
473534 // The first argument is reserved for program name, but we don't need it
474535 // in workers.
475- has_explicit_exec_argv = true ;
476536 std::vector<std::string> exec_argv = {" " };
477537 uint32_t length = array->Length ();
478538 for (uint32_t i = 0 ; i < length; i++) {
@@ -494,8 +554,6 @@ void Worker::New(const FunctionCallbackInfo<Value>& args) {
494554
495555 std::vector<std::string> invalid_args{};
496556 std::vector<std::string> errors{};
497- per_isolate_opts.reset (new PerIsolateOptions ());
498-
499557 // Using invalid_args as the v8_args argument as it stores unknown
500558 // options for the per isolate parser.
501559 options_parser::Parse (
@@ -522,40 +580,24 @@ void Worker::New(const FunctionCallbackInfo<Value>& args) {
522580 USE (args.This ()->Set (env->context (), key, error));
523581 return ;
524582 }
525- }
526- if (!has_explicit_exec_argv)
583+ } else {
527584 exec_argv_out = env->exec_argv ();
585+ }
528586
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);
532593
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>();
535596 CHECK_EQ (limit_info->Length (), kTotalResourceLimitCount );
536597 limit_info->CopyContents (worker->resource_limits_ ,
537598 sizeof (worker->resource_limits_ ));
538599}
539600
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-
559601void Worker::StartThread (const FunctionCallbackInfo<Value>& args) {
560602 Worker* w;
561603 ASSIGN_OR_RETURN_UNWRAP (&w, args.This ());
@@ -663,8 +705,6 @@ void InitWorker(Local<Object> target,
663705 w->InstanceTemplate ()->SetInternalFieldCount (1 );
664706 w->Inherit (AsyncWrap::GetConstructorTemplate (env));
665707
666- env->SetProtoMethod (w, " setEnvVars" , Worker::SetEnvVars);
667- env->SetProtoMethod (w, " cloneParentEnvVars" , Worker::CloneParentEnvVars);
668708 env->SetProtoMethod (w, " startThread" , Worker::StartThread);
669709 env->SetProtoMethod (w, " stopThread" , Worker::StopThread);
670710 env->SetProtoMethod (w, " ref" , Worker::Ref);
0 commit comments