@@ -27,24 +27,29 @@ using v8::PropertyCallbackInfo;
27
27
using v8::String;
28
28
using v8::Value;
29
29
30
+ class RealEnvStore final : public KVStore {
31
+ public:
32
+ Local<String> Get (Isolate* isolate, Local<String> key) const override ;
33
+ void Set (Isolate* isolate, Local<String> key, Local<String> value) override ;
34
+ int32_t Query (Isolate* isolate, Local<String> key) const override ;
35
+ void Delete (Isolate* isolate, Local<String> key) override ;
36
+ Local<Array> Enumerate (Isolate* isolate) const override ;
37
+ };
38
+
30
39
namespace per_process {
31
40
Mutex env_var_mutex;
41
+ std::shared_ptr<KVStore> real_environment = std::make_shared<RealEnvStore>();
32
42
} // namespace per_process
33
43
34
- static void EnvGetter (Local<Name> property,
35
- const PropertyCallbackInfo<Value>& info) {
36
- Isolate* isolate = info.GetIsolate ();
37
- if (property->IsSymbol ()) {
38
- return info.GetReturnValue ().SetUndefined ();
39
- }
44
+ Local<String> RealEnvStore::Get (Isolate* isolate,
45
+ Local<String> property) const {
40
46
Mutex::ScopedLock lock (per_process::env_var_mutex);
41
47
#ifdef __POSIX__
42
48
node::Utf8Value key (isolate, property);
43
49
const char * val = getenv (*key);
44
50
if (val) {
45
- return info.GetReturnValue ().Set (
46
- String::NewFromUtf8 (isolate, val, NewStringType::kNormal )
47
- .ToLocalChecked ());
51
+ return String::NewFromUtf8 (isolate, val, NewStringType::kNormal )
52
+ .ToLocalChecked ();
48
53
}
49
54
#else // _WIN32
50
55
node::TwoByteValue key (isolate, property);
@@ -62,106 +67,72 @@ static void EnvGetter(Local<Name> property,
62
67
isolate, two_byte_buffer, NewStringType::kNormal );
63
68
if (rc.IsEmpty ()) {
64
69
isolate->ThrowException (ERR_STRING_TOO_LONG (isolate));
65
- return ;
70
+ return Local<String>() ;
66
71
}
67
- return info. GetReturnValue (). Set ( rc.ToLocalChecked () );
72
+ return rc.ToLocalChecked ();
68
73
}
69
74
#endif
75
+ return Local<String>();
70
76
}
71
77
72
- static void EnvSetter (Local<Name> property,
73
- Local<Value> value,
74
- const PropertyCallbackInfo<Value>& info) {
75
- Environment* env = Environment::GetCurrent (info);
76
- // calling env->EmitProcessEnvWarning() sets a variable indicating that
77
- // warnings have been emitted. It should be called last after other
78
- // conditions leading to a warning have been met.
79
- if (env->options ()->pending_deprecation && !value->IsString () &&
80
- !value->IsNumber () && !value->IsBoolean () &&
81
- env->EmitProcessEnvWarning ()) {
82
- if (ProcessEmitDeprecationWarning (
83
- env,
84
- " Assigning any value other than a string, number, or boolean to a "
85
- " process.env property is deprecated. Please make sure to convert "
86
- " the "
87
- " value to a string before setting process.env with it." ,
88
- " DEP0104" )
89
- .IsNothing ())
90
- return ;
91
- }
92
-
78
+ void RealEnvStore::Set (Isolate* isolate,
79
+ Local<String> property,
80
+ Local<String> value) {
93
81
Mutex::ScopedLock lock (per_process::env_var_mutex);
94
82
#ifdef __POSIX__
95
- node::Utf8Value key (info. GetIsolate () , property);
96
- node::Utf8Value val (info. GetIsolate () , value);
83
+ node::Utf8Value key (isolate , property);
84
+ node::Utf8Value val (isolate , value);
97
85
setenv (*key, *val, 1 );
98
86
#else // _WIN32
99
- node::TwoByteValue key (info. GetIsolate () , property);
100
- node::TwoByteValue val (info. GetIsolate () , value);
87
+ node::TwoByteValue key (isolate , property);
88
+ node::TwoByteValue val (isolate , value);
101
89
WCHAR* key_ptr = reinterpret_cast <WCHAR*>(*key);
102
90
// Environment variables that start with '=' are read-only.
103
91
if (key_ptr[0 ] != L' =' ) {
104
92
SetEnvironmentVariableW (key_ptr, reinterpret_cast <WCHAR*>(*val));
105
93
}
106
94
#endif
107
- // Whether it worked or not, always return value.
108
- info.GetReturnValue ().Set (value);
109
95
}
110
96
111
- static void EnvQuery (Local<Name> property,
112
- const PropertyCallbackInfo<Integer>& info) {
97
+ int32_t RealEnvStore::Query (Isolate* isolate, Local<String> property) const {
113
98
Mutex::ScopedLock lock (per_process::env_var_mutex);
114
- int32_t rc = -1 ; // Not found unless proven otherwise.
115
- if (property->IsString ()) {
116
99
#ifdef __POSIX__
117
- node::Utf8Value key (info. GetIsolate () , property);
118
- if (getenv (*key)) rc = 0 ;
100
+ node::Utf8Value key (isolate , property);
101
+ if (getenv (*key)) return 0 ;
119
102
#else // _WIN32
120
- node::TwoByteValue key (info.GetIsolate (), property);
121
- WCHAR* key_ptr = reinterpret_cast <WCHAR*>(*key);
122
- SetLastError (ERROR_SUCCESS);
123
- if (GetEnvironmentVariableW (key_ptr, nullptr , 0 ) > 0 ||
124
- GetLastError () == ERROR_SUCCESS) {
125
- rc = 0 ;
126
- if (key_ptr[0 ] == L' =' ) {
127
- // Environment variables that start with '=' are hidden and read-only.
128
- rc = static_cast <int32_t >(v8::ReadOnly) |
103
+ node::TwoByteValue key (isolate, property);
104
+ WCHAR* key_ptr = reinterpret_cast <WCHAR*>(*key);
105
+ SetLastError (ERROR_SUCCESS);
106
+ if (GetEnvironmentVariableW (key_ptr, nullptr , 0 ) > 0 ||
107
+ GetLastError () == ERROR_SUCCESS) {
108
+ if (key_ptr[0 ] == L' =' ) {
109
+ // Environment variables that start with '=' are hidden and read-only.
110
+ return static_cast <int32_t >(v8::ReadOnly) |
129
111
static_cast <int32_t >(v8::DontDelete) |
130
112
static_cast <int32_t >(v8::DontEnum);
131
- }
132
113
}
133
- # endif
114
+ return 0 ;
134
115
}
135
- if (rc != -1 ) info.GetReturnValue ().Set (rc);
116
+ #endif
117
+ return -1 ;
136
118
}
137
119
138
- static void EnvDeleter (Local<Name> property,
139
- const PropertyCallbackInfo<Boolean >& info) {
120
+ void RealEnvStore::Delete (Isolate* isolate, Local<String> property) {
140
121
Mutex::ScopedLock lock (per_process::env_var_mutex);
141
- if (property->IsString ()) {
142
122
#ifdef __POSIX__
143
- node::Utf8Value key (info. GetIsolate () , property);
144
- unsetenv (*key);
123
+ node::Utf8Value key (isolate , property);
124
+ unsetenv (*key);
145
125
#else
146
- node::TwoByteValue key (info. GetIsolate () , property);
147
- WCHAR* key_ptr = reinterpret_cast <WCHAR*>(*key);
148
- SetEnvironmentVariableW (key_ptr, nullptr );
126
+ node::TwoByteValue key (isolate , property);
127
+ WCHAR* key_ptr = reinterpret_cast <WCHAR*>(*key);
128
+ SetEnvironmentVariableW (key_ptr, nullptr );
149
129
#endif
150
- }
151
-
152
- // process.env never has non-configurable properties, so always
153
- // return true like the tc39 delete operator.
154
- info.GetReturnValue ().Set (true );
155
130
}
156
131
157
- static void EnvEnumerator (const PropertyCallbackInfo<Array>& info) {
158
- Environment* env = Environment::GetCurrent (info);
159
- Isolate* isolate = env->isolate ();
160
-
132
+ Local<Array> RealEnvStore::Enumerate (Isolate* isolate) const {
161
133
Mutex::ScopedLock lock (per_process::env_var_mutex);
162
- Local<Array> envarr;
163
- int env_size = 0 ;
164
134
#ifdef __POSIX__
135
+ int env_size = 0 ;
165
136
while (environ[env_size]) {
166
137
env_size++;
167
138
}
@@ -177,7 +148,8 @@ static void EnvEnumerator(const PropertyCallbackInfo<Array>& info) {
177
148
#else // _WIN32
178
149
std::vector<Local<Value>> env_v;
179
150
WCHAR* environment = GetEnvironmentStringsW ();
180
- if (environment == nullptr ) return ; // This should not happen.
151
+ if (environment == nullptr )
152
+ return Array::New (isolate); // This should not happen.
181
153
WCHAR* p = environment;
182
154
while (*p) {
183
155
WCHAR* s;
@@ -198,16 +170,88 @@ static void EnvEnumerator(const PropertyCallbackInfo<Array>& info) {
198
170
if (rc.IsEmpty ()) {
199
171
isolate->ThrowException (ERR_STRING_TOO_LONG (isolate));
200
172
FreeEnvironmentStringsW (environment);
201
- return ;
173
+ return Local<Array>() ;
202
174
}
203
175
env_v.push_back (rc.ToLocalChecked ());
204
176
p = s + wcslen (s) + 1 ;
205
177
}
206
178
FreeEnvironmentStringsW (environment);
207
179
#endif
208
180
209
- envarr = Array::New (isolate, env_v.data (), env_v.size ());
210
- info.GetReturnValue ().Set (envarr);
181
+ return Array::New (isolate, env_v.data (), env_v.size ());
182
+ }
183
+
184
+ static void EnvGetter (Local<Name> property,
185
+ const PropertyCallbackInfo<Value>& info) {
186
+ Environment* env = Environment::GetCurrent (info);
187
+ if (property->IsSymbol ()) {
188
+ return info.GetReturnValue ().SetUndefined ();
189
+ }
190
+ CHECK (property->IsString ());
191
+ info.GetReturnValue ().Set (
192
+ env->envvars ()->Get (env->isolate (), property.As <String>()));
193
+ }
194
+
195
+ static void EnvSetter (Local<Name> property,
196
+ Local<Value> value,
197
+ const PropertyCallbackInfo<Value>& info) {
198
+ Environment* env = Environment::GetCurrent (info);
199
+ // calling env->EmitProcessEnvWarning() sets a variable indicating that
200
+ // warnings have been emitted. It should be called last after other
201
+ // conditions leading to a warning have been met.
202
+ if (env->options ()->pending_deprecation && !value->IsString () &&
203
+ !value->IsNumber () && !value->IsBoolean () &&
204
+ env->EmitProcessEnvWarning ()) {
205
+ if (ProcessEmitDeprecationWarning (
206
+ env,
207
+ " Assigning any value other than a string, number, or boolean to a "
208
+ " process.env property is deprecated. Please make sure to convert "
209
+ " the "
210
+ " value to a string before setting process.env with it." ,
211
+ " DEP0104" )
212
+ .IsNothing ())
213
+ return ;
214
+ }
215
+
216
+ Local<String> key;
217
+ Local<String> value_string;
218
+ if (!property->ToString (env->context ()).ToLocal (&key) ||
219
+ !value->ToString (env->context ()).ToLocal (&value_string)) {
220
+ return ;
221
+ }
222
+
223
+ env->envvars ()->Set (env->isolate (), key, value_string);
224
+
225
+ // Whether it worked or not, always return value.
226
+ info.GetReturnValue ().Set (value);
227
+ }
228
+
229
+ static void EnvQuery (Local<Name> property,
230
+ const PropertyCallbackInfo<Integer>& info) {
231
+ Environment* env = Environment::GetCurrent (info);
232
+ if (property->IsString ()) {
233
+ int32_t rc = env->envvars ()->Query (env->isolate (), property.As <String>());
234
+ if (rc != -1 ) info.GetReturnValue ().Set (rc);
235
+ }
236
+ }
237
+
238
+ static void EnvDeleter (Local<Name> property,
239
+ const PropertyCallbackInfo<Boolean >& info) {
240
+ Environment* env = Environment::GetCurrent (info);
241
+ if (property->IsString ()) {
242
+ env->envvars ()->Delete (env->isolate (), property.As <String>());
243
+ }
244
+
245
+ // process.env never has non-configurable properties, so always
246
+ // return true like the tc39 delete operator.
247
+ info.GetReturnValue ().Set (true );
248
+ }
249
+
250
+ static void EnvEnumerator (const PropertyCallbackInfo<Array>& info) {
251
+ Environment* env = Environment::GetCurrent (info);
252
+
253
+ info.GetReturnValue ().Set (
254
+ env->envvars ()->Enumerate (env->isolate ()));
211
255
}
212
256
213
257
MaybeLocal<Object> CreateEnvVarProxy (Local<Context> context,
0 commit comments