Skip to content

Commit

Permalink
src: implement generic backend for process.env
Browse files Browse the repository at this point in the history
Allow a generic string-based backing store, with no significance
to the remainder of the process, as a store for `process.env`.

PR-URL: #26544
Fixes: #24947
Reviewed-By: Ruben Bridgewater <[email protected]>
Reviewed-By: Vse Mozhet Byt <[email protected]>
Reviewed-By: Yongsheng Zhang <[email protected]>
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Benjamin Gruenbaum <[email protected]>
Reviewed-By: Joyee Cheung <[email protected]>
  • Loading branch information
addaleax authored and BethGriggs committed Apr 4, 2019
1 parent 21e7b62 commit 786a1d4
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,12 @@ class KVStore {
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;

virtual std::shared_ptr<KVStore> Clone(v8::Isolate* isolate) const;
virtual v8::Maybe<bool> AssignFromObject(v8::Local<v8::Context> context,
v8::Local<v8::Object> entries);

static std::shared_ptr<KVStore> CreateGenericKVStore();
};

namespace per_process {
Expand Down
118 changes: 118 additions & 0 deletions src/node_env_var.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,17 @@ using v8::Array;
using v8::Boolean;
using v8::Context;
using v8::EscapableHandleScope;
using v8::HandleScope;
using v8::Integer;
using v8::Isolate;
using v8::Just;
using v8::Local;
using v8::Maybe;
using v8::MaybeLocal;
using v8::Name;
using v8::NamedPropertyHandlerConfiguration;
using v8::NewStringType;
using v8::Nothing;
using v8::Object;
using v8::ObjectTemplate;
using v8::PropertyCallbackInfo;
Expand All @@ -36,6 +40,24 @@ class RealEnvStore final : public KVStore {
Local<Array> Enumerate(Isolate* isolate) const override;
};

class GenericKVStore final : public KVStore {
public:
Local<String> Get(Isolate* isolate, Local<String> key) const override;
void Set(Isolate* isolate, Local<String> key, Local<String> value) override;
int32_t Query(Isolate* isolate, Local<String> key) const override;
void Delete(Isolate* isolate, Local<String> key) override;
Local<Array> Enumerate(Isolate* isolate) const override;

std::shared_ptr<KVStore> Clone(Isolate* isolate) const override;

GenericKVStore() {}
GenericKVStore(const GenericKVStore& other) : map_(other.map_) {}

private:
mutable Mutex mutex_;
std::unordered_map<std::string, std::string> map_;
};

namespace per_process {
Mutex env_var_mutex;
std::shared_ptr<KVStore> real_environment = std::make_shared<RealEnvStore>();
Expand Down Expand Up @@ -181,6 +203,102 @@ Local<Array> RealEnvStore::Enumerate(Isolate* isolate) const {
return Array::New(isolate, env_v.data(), env_v.size());
}

std::shared_ptr<KVStore> KVStore::Clone(v8::Isolate* isolate) const {
HandleScope handle_scope(isolate);
Local<Context> context = isolate->GetCurrentContext();

std::shared_ptr<KVStore> copy = KVStore::CreateGenericKVStore();
Local<Array> keys = Enumerate(isolate);
uint32_t keys_length = keys->Length();
for (uint32_t i = 0; i < keys_length; i++) {
Local<Value> key = keys->Get(context, i).ToLocalChecked();
CHECK(key->IsString());
copy->Set(isolate, key.As<String>(), Get(isolate, key.As<String>()));
}
return copy;
}

Local<String> GenericKVStore::Get(Isolate* isolate, Local<String> key) const {
Mutex::ScopedLock lock(mutex_);
String::Utf8Value str(isolate, key);
auto it = map_.find(std::string(*str, str.length()));
if (it == map_.end()) return Local<String>();
return String::NewFromUtf8(isolate, it->second.data(),
NewStringType::kNormal, it->second.size())
.ToLocalChecked();
}

void GenericKVStore::Set(Isolate* isolate, Local<String> key,
Local<String> value) {
Mutex::ScopedLock lock(mutex_);
String::Utf8Value key_str(isolate, key);
String::Utf8Value value_str(isolate, value);
if (*key_str != nullptr && *value_str != nullptr) {
map_[std::string(*key_str, key_str.length())] =
std::string(*value_str, value_str.length());
}
}

int32_t GenericKVStore::Query(Isolate* isolate, Local<String> key) const {
Mutex::ScopedLock lock(mutex_);
String::Utf8Value str(isolate, key);
auto it = map_.find(std::string(*str, str.length()));
return it == map_.end() ? -1 : 0;
}

void GenericKVStore::Delete(Isolate* isolate, Local<String> key) {
Mutex::ScopedLock lock(mutex_);
String::Utf8Value str(isolate, key);
map_.erase(std::string(*str, str.length()));
}

Local<Array> GenericKVStore::Enumerate(Isolate* isolate) const {
Mutex::ScopedLock lock(mutex_);
std::vector<Local<Value>> values;
values.reserve(map_.size());
for (const auto& pair : map_) {
values.emplace_back(
String::NewFromUtf8(isolate, pair.first.data(),
NewStringType::kNormal, pair.first.size())
.ToLocalChecked());
}
return Array::New(isolate, values.data(), values.size());
}

std::shared_ptr<KVStore> GenericKVStore::Clone(Isolate* isolate) const {
return std::make_shared<GenericKVStore>(*this);
}

std::shared_ptr<KVStore> KVStore::CreateGenericKVStore() {
return std::make_shared<GenericKVStore>();
}

Maybe<bool> KVStore::AssignFromObject(Local<Context> context,
Local<Object> entries) {
Isolate* isolate = context->GetIsolate();
HandleScope handle_scope(isolate);
Local<Array> keys;
if (!entries->GetOwnPropertyNames(context).ToLocal(&keys))
return Nothing<bool>();
uint32_t keys_length = keys->Length();
for (uint32_t i = 0; i < keys_length; i++) {
Local<Value> key;
if (!keys->Get(context, i).ToLocal(&key))
return Nothing<bool>();
if (!key->IsString()) continue;

Local<Value> value;
Local<String> value_string;
if (!entries->Get(context, key.As<String>()).ToLocal(&value) ||
!value->ToString(context).ToLocal(&value_string)) {
return Nothing<bool>();
}

Set(isolate, key.As<String>(), value_string);
}
return Just(true);
}

static void EnvGetter(Local<Name> property,
const PropertyCallbackInfo<Value>& info) {
Environment* env = Environment::GetCurrent(info);
Expand Down

0 comments on commit 786a1d4

Please sign in to comment.