Skip to content

Commit 729e2f2

Browse files
addaleaxBethGriggs
authored andcommitted
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: #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> Signed-off-by: Beth Griggs <Bethany.Griggs@uk.ibm.com>
1 parent d3840bc commit 729e2f2

File tree

2 files changed

+124
-0
lines changed

2 files changed

+124
-0
lines changed

src/env.h

+6
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,12 @@ class KVStore {
543543
v8::Local<v8::String> key) const = 0;
544544
virtual void Delete(v8::Isolate* isolate, v8::Local<v8::String> key) = 0;
545545
virtual v8::Local<v8::Array> Enumerate(v8::Isolate* isolate) const = 0;
546+
547+
virtual std::shared_ptr<KVStore> Clone(v8::Isolate* isolate) const;
548+
virtual v8::Maybe<bool> AssignFromObject(v8::Local<v8::Context> context,
549+
v8::Local<v8::Object> entries);
550+
551+
static std::shared_ptr<KVStore> CreateGenericKVStore();
546552
};
547553

548554
namespace per_process {

src/node_env_var.cc

+118
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,17 @@ using v8::Array;
1414
using v8::Boolean;
1515
using v8::Context;
1616
using v8::EscapableHandleScope;
17+
using v8::HandleScope;
1718
using v8::Integer;
1819
using v8::Isolate;
20+
using v8::Just;
1921
using v8::Local;
22+
using v8::Maybe;
2023
using v8::MaybeLocal;
2124
using v8::Name;
2225
using v8::NamedPropertyHandlerConfiguration;
2326
using v8::NewStringType;
27+
using v8::Nothing;
2428
using v8::Object;
2529
using v8::ObjectTemplate;
2630
using v8::PropertyCallbackInfo;
@@ -36,6 +40,24 @@ class RealEnvStore final : public KVStore {
3640
Local<Array> Enumerate(Isolate* isolate) const override;
3741
};
3842

43+
class GenericKVStore final : public KVStore {
44+
public:
45+
Local<String> Get(Isolate* isolate, Local<String> key) const override;
46+
void Set(Isolate* isolate, Local<String> key, Local<String> value) override;
47+
int32_t Query(Isolate* isolate, Local<String> key) const override;
48+
void Delete(Isolate* isolate, Local<String> key) override;
49+
Local<Array> Enumerate(Isolate* isolate) const override;
50+
51+
std::shared_ptr<KVStore> Clone(Isolate* isolate) const override;
52+
53+
GenericKVStore() {}
54+
GenericKVStore(const GenericKVStore& other) : map_(other.map_) {}
55+
56+
private:
57+
mutable Mutex mutex_;
58+
std::unordered_map<std::string, std::string> map_;
59+
};
60+
3961
namespace per_process {
4062
Mutex env_var_mutex;
4163
std::shared_ptr<KVStore> real_environment = std::make_shared<RealEnvStore>();
@@ -181,6 +203,102 @@ Local<Array> RealEnvStore::Enumerate(Isolate* isolate) const {
181203
return Array::New(isolate, env_v.data(), env_v.size());
182204
}
183205

206+
std::shared_ptr<KVStore> KVStore::Clone(v8::Isolate* isolate) const {
207+
HandleScope handle_scope(isolate);
208+
Local<Context> context = isolate->GetCurrentContext();
209+
210+
std::shared_ptr<KVStore> copy = KVStore::CreateGenericKVStore();
211+
Local<Array> keys = Enumerate(isolate);
212+
uint32_t keys_length = keys->Length();
213+
for (uint32_t i = 0; i < keys_length; i++) {
214+
Local<Value> key = keys->Get(context, i).ToLocalChecked();
215+
CHECK(key->IsString());
216+
copy->Set(isolate, key.As<String>(), Get(isolate, key.As<String>()));
217+
}
218+
return copy;
219+
}
220+
221+
Local<String> GenericKVStore::Get(Isolate* isolate, Local<String> key) const {
222+
Mutex::ScopedLock lock(mutex_);
223+
String::Utf8Value str(isolate, key);
224+
auto it = map_.find(std::string(*str, str.length()));
225+
if (it == map_.end()) return Local<String>();
226+
return String::NewFromUtf8(isolate, it->second.data(),
227+
NewStringType::kNormal, it->second.size())
228+
.ToLocalChecked();
229+
}
230+
231+
void GenericKVStore::Set(Isolate* isolate, Local<String> key,
232+
Local<String> value) {
233+
Mutex::ScopedLock lock(mutex_);
234+
String::Utf8Value key_str(isolate, key);
235+
String::Utf8Value value_str(isolate, value);
236+
if (*key_str != nullptr && *value_str != nullptr) {
237+
map_[std::string(*key_str, key_str.length())] =
238+
std::string(*value_str, value_str.length());
239+
}
240+
}
241+
242+
int32_t GenericKVStore::Query(Isolate* isolate, Local<String> key) const {
243+
Mutex::ScopedLock lock(mutex_);
244+
String::Utf8Value str(isolate, key);
245+
auto it = map_.find(std::string(*str, str.length()));
246+
return it == map_.end() ? -1 : 0;
247+
}
248+
249+
void GenericKVStore::Delete(Isolate* isolate, Local<String> key) {
250+
Mutex::ScopedLock lock(mutex_);
251+
String::Utf8Value str(isolate, key);
252+
map_.erase(std::string(*str, str.length()));
253+
}
254+
255+
Local<Array> GenericKVStore::Enumerate(Isolate* isolate) const {
256+
Mutex::ScopedLock lock(mutex_);
257+
std::vector<Local<Value>> values;
258+
values.reserve(map_.size());
259+
for (const auto& pair : map_) {
260+
values.emplace_back(
261+
String::NewFromUtf8(isolate, pair.first.data(),
262+
NewStringType::kNormal, pair.first.size())
263+
.ToLocalChecked());
264+
}
265+
return Array::New(isolate, values.data(), values.size());
266+
}
267+
268+
std::shared_ptr<KVStore> GenericKVStore::Clone(Isolate* isolate) const {
269+
return std::make_shared<GenericKVStore>(*this);
270+
}
271+
272+
std::shared_ptr<KVStore> KVStore::CreateGenericKVStore() {
273+
return std::make_shared<GenericKVStore>();
274+
}
275+
276+
Maybe<bool> KVStore::AssignFromObject(Local<Context> context,
277+
Local<Object> entries) {
278+
Isolate* isolate = context->GetIsolate();
279+
HandleScope handle_scope(isolate);
280+
Local<Array> keys;
281+
if (!entries->GetOwnPropertyNames(context).ToLocal(&keys))
282+
return Nothing<bool>();
283+
uint32_t keys_length = keys->Length();
284+
for (uint32_t i = 0; i < keys_length; i++) {
285+
Local<Value> key;
286+
if (!keys->Get(context, i).ToLocal(&key))
287+
return Nothing<bool>();
288+
if (!key->IsString()) continue;
289+
290+
Local<Value> value;
291+
Local<String> value_string;
292+
if (!entries->Get(context, key.As<String>()).ToLocal(&value) ||
293+
!value->ToString(context).ToLocal(&value_string)) {
294+
return Nothing<bool>();
295+
}
296+
297+
Set(isolate, key.As<String>(), value_string);
298+
}
299+
return Just(true);
300+
}
301+
184302
static void EnvGetter(Local<Name> property,
185303
const PropertyCallbackInfo<Value>& info) {
186304
Environment* env = Environment::GetCurrent(info);

0 commit comments

Comments
 (0)