Skip to content

Commit

Permalink
src: allow per-Environment set of env vars
Browse files Browse the repository at this point in the history
Abstract the `process.env` backing mechanism in C++ to allow
different kinds of backing stores for `process.env` for different
Environments.

PR-URL: #26544
Fixes: #24947
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Vse Mozhet Byt <vsemozhetbyt@gmail.com>
Reviewed-By: Yongsheng Zhang <zyszys98@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
  • Loading branch information
addaleax authored and BethGriggs committed Apr 4, 2019
1 parent b95aa2d commit 21e7b62
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 84 deletions.
8 changes: 8 additions & 0 deletions src/env-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,14 @@ inline uint64_t Environment::timer_base() const {
return timer_base_;
}

inline std::shared_ptr<KVStore> Environment::envvars() {
return envvars_;
}

inline void Environment::set_envvars(std::shared_ptr<KVStore> envvars) {
envvars_ = envvars;
}

inline bool Environment::printed_error() const {
return printed_error_;
}
Expand Down
4 changes: 3 additions & 1 deletion src/env.cc
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ Environment::Environment(IsolateData* isolate_data,
set_as_callback_data_template(templ);
}

set_envvars(per_process::real_environment);

// We create new copies of the per-Environment option sets, so that it is
// easier to modify them after Environment creation. The defaults are
// part of the per-Isolate option set, for which in turn the defaults are
Expand Down Expand Up @@ -221,7 +223,7 @@ Environment::Environment(IsolateData* isolate_data,
should_abort_on_uncaught_toggle_[0] = 1;

std::string debug_cats;
credentials::SafeGetenv("NODE_DEBUG_NATIVE", &debug_cats);
credentials::SafeGetenv("NODE_DEBUG_NATIVE", &debug_cats, this);
set_debug_categories(debug_cats, true);

isolate()->GetHeapProfiler()->AddBuildEmbedderGraphCallback(
Expand Down
20 changes: 20 additions & 0 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,23 @@ class AsyncRequest : public MemoryRetainer {
std::atomic_bool stopped_ {true};
};

class KVStore {
public:
virtual v8::Local<v8::String> Get(v8::Isolate* isolate,
v8::Local<v8::String> key) const = 0;
virtual void Set(v8::Isolate* isolate,
v8::Local<v8::String> key,
v8::Local<v8::String> value) = 0;
virtual int32_t Query(v8::Isolate* isolate,
v8::Local<v8::String> key) const = 0;
virtual void Delete(v8::Isolate* isolate, v8::Local<v8::String> key) = 0;
virtual v8::Local<v8::Array> Enumerate(v8::Isolate* isolate) const = 0;
};

namespace per_process {
extern std::shared_ptr<KVStore> real_environment;
}

class AsyncHooks {
public:
// Reason for both UidFields and Fields are that one is stored as a double*
Expand Down Expand Up @@ -789,6 +806,8 @@ class Environment {
inline ImmediateInfo* immediate_info();
inline TickInfo* tick_info();
inline uint64_t timer_base() const;
inline std::shared_ptr<KVStore> envvars();
inline void set_envvars(std::shared_ptr<KVStore> envvars);

inline IsolateData* isolate_data() const;

Expand Down Expand Up @@ -1075,6 +1094,7 @@ class Environment {
ImmediateInfo immediate_info_;
TickInfo tick_info_;
const uint64_t timer_base_;
std::shared_ptr<KVStore> envvars_;
bool printed_error_ = false;
bool emit_env_nonstring_warning_ = true;
bool emit_err_name_warning_ = true;
Expand Down
24 changes: 21 additions & 3 deletions src/node_credentials.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@ using v8::Array;
using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::HandleScope;
using v8::Isolate;
using v8::Local;
using v8::MaybeLocal;
using v8::NewStringType;
using v8::Object;
using v8::String;
using v8::TryCatch;
using v8::Uint32;
using v8::Value;

Expand All @@ -30,13 +33,27 @@ bool linux_at_secure = false;
namespace credentials {

// Look up environment variable unless running as setuid root.
bool SafeGetenv(const char* key, std::string* text) {
bool SafeGetenv(const char* key, std::string* text, Environment* env) {
#if !defined(__CloudABI__) && !defined(_WIN32)
if (per_process::linux_at_secure || getuid() != geteuid() ||
getgid() != getegid())
goto fail;
#endif

if (env != nullptr) {
HandleScope handle_scope(env->isolate());
TryCatch ignore_errors(env->isolate());
MaybeLocal<String> value = env->envvars()->Get(
env->isolate(),
String::NewFromUtf8(env->isolate(), key, NewStringType::kNormal)
.ToLocalChecked());
if (value.IsEmpty()) goto fail;
String::Utf8Value utf8_value(env->isolate(), value.ToLocalChecked());
if (*utf8_value == nullptr) goto fail;
*text = std::string(*utf8_value, utf8_value.length());
return true;
}

{
Mutex::ScopedLock lock(per_process::env_var_mutex);
if (const char* value = getenv(key)) {
Expand All @@ -52,10 +69,11 @@ bool SafeGetenv(const char* key, std::string* text) {

static void SafeGetenv(const FunctionCallbackInfo<Value>& args) {
CHECK(args[0]->IsString());
Isolate* isolate = args.GetIsolate();
Environment* env = Environment::GetCurrent(args);
Isolate* isolate = env->isolate();
Utf8Value strenvtag(isolate, args[0]);
std::string text;
if (!SafeGetenv(*strenvtag, &text)) return;
if (!SafeGetenv(*strenvtag, &text, env)) return;
Local<Value> result =
ToV8Value(isolate->GetCurrentContext(), text).ToLocalChecked();
args.GetReturnValue().Set(result);
Expand Down
Loading

0 comments on commit 21e7b62

Please sign in to comment.