1616#include < string>
1717#include < vector>
1818
19+ using node::kAllowedInEnvironment ;
1920using node::kDisallowedInEnvironment ;
2021using v8::Array;
2122using v8::ArrayBuffer;
@@ -47,14 +48,15 @@ Worker::Worker(Environment* env,
4748 Local<Object> wrap,
4849 const std::string& url,
4950 std::shared_ptr<PerIsolateOptions> per_isolate_opts,
50- std::vector<std::string>&& exec_argv)
51+ std::vector<std::string>&& exec_argv,
52+ std::shared_ptr<KVStore> env_vars)
5153 : AsyncWrap(env, wrap, AsyncWrap::PROVIDER_WORKER),
5254 per_isolate_opts_ (per_isolate_opts),
5355 exec_argv_(exec_argv),
5456 platform_(env->isolate_data ()->platform()),
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.
@@ -441,6 +443,7 @@ Worker::~Worker() {
441443
442444void Worker::New (const FunctionCallbackInfo<Value>& args) {
443445 Environment* env = Environment::GetCurrent (args);
446+ Isolate* isolate = args.GetIsolate ();
444447
445448 CHECK (args.IsConstructCall ());
446449
@@ -451,24 +454,81 @@ void Worker::New(const FunctionCallbackInfo<Value>& args) {
451454
452455 std::string url;
453456 std::shared_ptr<PerIsolateOptions> per_isolate_opts = nullptr ;
457+ std::shared_ptr<KVStore> env_vars = nullptr ;
454458
455459 std::vector<std::string> exec_argv_out;
456- bool has_explicit_exec_argv = false ;
457460
458- CHECK_EQ (args.Length (), 3 );
461+ CHECK_EQ (args.Length (), 4 );
459462 // Argument might be a string or URL
460463 if (!args[0 ]->IsNullOrUndefined ()) {
461464 Utf8Value value (
462- args.GetIsolate (),
463- args[0 ]->ToString (env->context ()).FromMaybe (Local<String>()));
465+ isolate, args[0 ]->ToString (env->context ()).FromMaybe (Local<String>()));
464466 url.append (value.out (), value.length ());
465467 }
466468
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>();
469530 // The first argument is reserved for program name, but we don't need it
470531 // in workers.
471- has_explicit_exec_argv = true ;
472532 std::vector<std::string> exec_argv = {" " };
473533 uint32_t length = array->Length ();
474534 for (uint32_t i = 0 ; i < length; i++) {
@@ -490,8 +550,6 @@ void Worker::New(const FunctionCallbackInfo<Value>& args) {
490550
491551 std::vector<std::string> invalid_args{};
492552 std::vector<std::string> errors{};
493- per_isolate_opts.reset (new PerIsolateOptions ());
494-
495553 // Using invalid_args as the v8_args argument as it stores unknown
496554 // options for the per isolate parser.
497555 options_parser::Parse (
@@ -518,40 +576,24 @@ void Worker::New(const FunctionCallbackInfo<Value>& args) {
518576 USE (args.This ()->Set (env->context (), key, error));
519577 return ;
520578 }
521- }
522- if (!has_explicit_exec_argv)
579+ } else {
523580 exec_argv_out = env->exec_argv ();
581+ }
524582
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);
528589
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>();
531592 CHECK_EQ (limit_info->Length (), kTotalResourceLimitCount );
532593 limit_info->CopyContents (worker->resource_limits_ ,
533594 sizeof (worker->resource_limits_ ));
534595}
535596
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-
555597void Worker::StartThread (const FunctionCallbackInfo<Value>& args) {
556598 Worker* w;
557599 ASSIGN_OR_RETURN_UNWRAP (&w, args.This ());
@@ -723,8 +765,6 @@ void InitWorker(Local<Object> target,
723765 w->InstanceTemplate ()->SetInternalFieldCount (1 );
724766 w->Inherit (AsyncWrap::GetConstructorTemplate (env));
725767
726- env->SetProtoMethod (w, " setEnvVars" , Worker::SetEnvVars);
727- env->SetProtoMethod (w, " cloneParentEnvVars" , Worker::CloneParentEnvVars);
728768 env->SetProtoMethod (w, " startThread" , Worker::StartThread);
729769 env->SetProtoMethod (w, " stopThread" , Worker::StopThread);
730770 env->SetProtoMethod (w, " ref" , Worker::Ref);
0 commit comments