diff options
author | Anna Henningsen <anna@addaleax.net> | 2019-03-13 17:32:37 +0300 |
---|---|---|
committer | Anna Henningsen <anna@addaleax.net> | 2019-03-31 00:25:34 +0300 |
commit | 1ee37aac09f263b00029561542cf3bea5db5113b (patch) | |
tree | 918a05206a11d3c0c29ca53f77411acdc5e4ae6d /src/node_env_var.cc | |
parent | f5b5fe3937ec353e43d30ae976725e0773e14c6f (diff) |
src: implement generic backend for process.env
Allow a generic string-based backing store, with no significance
to the remainder of the process, as a store for `process.env`.
PR-URL: https://github.com/nodejs/node/pull/26544
Fixes: https://github.com/nodejs/node/issues/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>
Diffstat (limited to 'src/node_env_var.cc')
-rw-r--r-- | src/node_env_var.cc | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/src/node_env_var.cc b/src/node_env_var.cc index 6bd799e19f8..2df7275b175 100644 --- a/src/node_env_var.cc +++ b/src/node_env_var.cc @@ -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; @@ -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>(); @@ -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); |