1 #include "node_errors.h"
2 #include "util-inl.h"
3 #include "base_object-inl.h"
4
5 namespace node {
6 namespace util {
7
8 using v8::ALL_PROPERTIES;
9 using v8::Array;
10 using v8::ArrayBufferView;
11 using v8::BigInt;
12 using v8::Boolean;
13 using v8::Context;
14 using v8::External;
15 using v8::FunctionCallbackInfo;
16 using v8::FunctionTemplate;
17 using v8::Global;
18 using v8::IndexFilter;
19 using v8::Integer;
20 using v8::Isolate;
21 using v8::KeyCollectionMode;
22 using v8::Local;
23 using v8::Object;
24 using v8::ONLY_CONFIGURABLE;
25 using v8::ONLY_ENUMERABLE;
26 using v8::ONLY_WRITABLE;
27 using v8::Private;
28 using v8::Promise;
29 using v8::PropertyFilter;
30 using v8::Proxy;
31 using v8::SKIP_STRINGS;
32 using v8::SKIP_SYMBOLS;
33 using v8::String;
34 using v8::Uint32;
35 using v8::Value;
36
GetOwnNonIndexProperties(const FunctionCallbackInfo<Value> & args)37 static void GetOwnNonIndexProperties(
38 const FunctionCallbackInfo<Value>& args) {
39 Environment* env = Environment::GetCurrent(args);
40 Local<Context> context = env->context();
41
42 CHECK(args[0]->IsObject());
43 CHECK(args[1]->IsUint32());
44
45 Local<Object> object = args[0].As<Object>();
46
47 Local<Array> properties;
48
49 PropertyFilter filter =
50 static_cast<PropertyFilter>(args[1].As<Uint32>()->Value());
51
52 if (!object->GetPropertyNames(
53 context, KeyCollectionMode::kOwnOnly,
54 filter,
55 IndexFilter::kSkipIndices)
56 .ToLocal(&properties)) {
57 return;
58 }
59 args.GetReturnValue().Set(properties);
60 }
61
GetConstructorName(const FunctionCallbackInfo<Value> & args)62 static void GetConstructorName(
63 const FunctionCallbackInfo<Value>& args) {
64 CHECK(args[0]->IsObject());
65
66 Local<Object> object = args[0].As<Object>();
67 Local<String> name = object->GetConstructorName();
68
69 args.GetReturnValue().Set(name);
70 }
71
GetExternalValue(const FunctionCallbackInfo<Value> & args)72 static void GetExternalValue(
73 const FunctionCallbackInfo<Value>& args) {
74 CHECK(args[0]->IsExternal());
75 Isolate* isolate = args.GetIsolate();
76 Local<External> external = args[0].As<External>();
77
78 void* ptr = external->Value();
79 uint64_t value = reinterpret_cast<uint64_t>(ptr);
80 Local<BigInt> ret = BigInt::NewFromUnsigned(isolate, value);
81 args.GetReturnValue().Set(ret);
82 }
83
GetPromiseDetails(const FunctionCallbackInfo<Value> & args)84 static void GetPromiseDetails(const FunctionCallbackInfo<Value>& args) {
85 // Return undefined if it's not a Promise.
86 if (!args[0]->IsPromise())
87 return;
88
89 auto isolate = args.GetIsolate();
90
91 Local<Promise> promise = args[0].As<Promise>();
92
93 int state = promise->State();
94 Local<Value> values[2] = { Integer::New(isolate, state) };
95 size_t number_of_values = 1;
96 if (state != Promise::PromiseState::kPending)
97 values[number_of_values++] = promise->Result();
98 Local<Array> ret = Array::New(isolate, values, number_of_values);
99 args.GetReturnValue().Set(ret);
100 }
101
GetProxyDetails(const FunctionCallbackInfo<Value> & args)102 static void GetProxyDetails(const FunctionCallbackInfo<Value>& args) {
103 // Return undefined if it's not a proxy.
104 if (!args[0]->IsProxy())
105 return;
106
107 Local<Proxy> proxy = args[0].As<Proxy>();
108
109 // TODO(BridgeAR): Remove the length check as soon as we prohibit access to
110 // the util binding layer. It's accessed in the wild and `esm` would break in
111 // case the check is removed.
112 if (args.Length() == 1 || args[1]->IsTrue()) {
113 Local<Value> ret[] = {
114 proxy->GetTarget(),
115 proxy->GetHandler()
116 };
117
118 args.GetReturnValue().Set(
119 Array::New(args.GetIsolate(), ret, arraysize(ret)));
120 } else {
121 Local<Value> ret = proxy->GetTarget();
122
123 args.GetReturnValue().Set(ret);
124 }
125 }
126
PreviewEntries(const FunctionCallbackInfo<Value> & args)127 static void PreviewEntries(const FunctionCallbackInfo<Value>& args) {
128 if (!args[0]->IsObject())
129 return;
130
131 Environment* env = Environment::GetCurrent(args);
132 bool is_key_value;
133 Local<Array> entries;
134 if (!args[0].As<Object>()->PreviewEntries(&is_key_value).ToLocal(&entries))
135 return;
136 // Fast path for WeakMap and WeakSet.
137 if (args.Length() == 1)
138 return args.GetReturnValue().Set(entries);
139
140 Local<Value> ret[] = {
141 entries,
142 Boolean::New(env->isolate(), is_key_value)
143 };
144 return args.GetReturnValue().Set(
145 Array::New(env->isolate(), ret, arraysize(ret)));
146 }
147
IndexToPrivateSymbol(Environment * env,uint32_t index)148 inline Local<Private> IndexToPrivateSymbol(Environment* env, uint32_t index) {
149 #define V(name, _) &Environment::name,
150 static Local<Private> (Environment::*const methods[])() const = {
151 PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V)
152 };
153 #undef V
154 CHECK_LT(index, arraysize(methods));
155 return (env->*methods[index])();
156 }
157
GetHiddenValue(const FunctionCallbackInfo<Value> & args)158 static void GetHiddenValue(const FunctionCallbackInfo<Value>& args) {
159 Environment* env = Environment::GetCurrent(args);
160
161 CHECK(args[0]->IsObject());
162 CHECK(args[1]->IsUint32());
163
164 Local<Object> obj = args[0].As<Object>();
165 uint32_t index = args[1].As<Uint32>()->Value();
166 Local<Private> private_symbol = IndexToPrivateSymbol(env, index);
167 Local<Value> ret;
168 if (obj->GetPrivate(env->context(), private_symbol).ToLocal(&ret))
169 args.GetReturnValue().Set(ret);
170 }
171
SetHiddenValue(const FunctionCallbackInfo<Value> & args)172 static void SetHiddenValue(const FunctionCallbackInfo<Value>& args) {
173 Environment* env = Environment::GetCurrent(args);
174
175 CHECK(args[0]->IsObject());
176 CHECK(args[1]->IsUint32());
177
178 Local<Object> obj = args[0].As<Object>();
179 uint32_t index = args[1].As<Uint32>()->Value();
180 Local<Private> private_symbol = IndexToPrivateSymbol(env, index);
181 bool ret;
182 if (obj->SetPrivate(env->context(), private_symbol, args[2]).To(&ret))
183 args.GetReturnValue().Set(ret);
184 }
185
Sleep(const FunctionCallbackInfo<Value> & args)186 static void Sleep(const FunctionCallbackInfo<Value>& args) {
187 CHECK(args[0]->IsUint32());
188 uint32_t msec = args[0].As<Uint32>()->Value();
189 uv_sleep(msec);
190 }
191
ArrayBufferViewHasBuffer(const FunctionCallbackInfo<Value> & args)192 void ArrayBufferViewHasBuffer(const FunctionCallbackInfo<Value>& args) {
193 CHECK(args[0]->IsArrayBufferView());
194 args.GetReturnValue().Set(args[0].As<ArrayBufferView>()->HasBuffer());
195 }
196
197 class WeakReference : public BaseObject {
198 public:
WeakReference(Environment * env,Local<Object> object,Local<Object> target)199 WeakReference(Environment* env, Local<Object> object, Local<Object> target)
200 : BaseObject(env, object) {
201 MakeWeak();
202 target_.Reset(env->isolate(), target);
203 target_.SetWeak();
204 }
205
New(const FunctionCallbackInfo<Value> & args)206 static void New(const FunctionCallbackInfo<Value>& args) {
207 Environment* env = Environment::GetCurrent(args);
208 CHECK(args.IsConstructCall());
209 CHECK(args[0]->IsObject());
210 new WeakReference(env, args.This(), args[0].As<Object>());
211 }
212
Get(const FunctionCallbackInfo<Value> & args)213 static void Get(const FunctionCallbackInfo<Value>& args) {
214 WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder());
215 Isolate* isolate = args.GetIsolate();
216 if (!weak_ref->target_.IsEmpty())
217 args.GetReturnValue().Set(weak_ref->target_.Get(isolate));
218 }
219
IncRef(const FunctionCallbackInfo<Value> & args)220 static void IncRef(const FunctionCallbackInfo<Value>& args) {
221 WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder());
222 weak_ref->reference_count_++;
223 if (weak_ref->target_.IsEmpty()) return;
224 if (weak_ref->reference_count_ == 1) weak_ref->target_.ClearWeak();
225 }
226
DecRef(const FunctionCallbackInfo<Value> & args)227 static void DecRef(const FunctionCallbackInfo<Value>& args) {
228 WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder());
229 CHECK_GE(weak_ref->reference_count_, 1);
230 weak_ref->reference_count_--;
231 if (weak_ref->target_.IsEmpty()) return;
232 if (weak_ref->reference_count_ == 0) weak_ref->target_.SetWeak();
233 }
234
235 SET_MEMORY_INFO_NAME(WeakReference)
236 SET_SELF_SIZE(WeakReference)
237 SET_NO_MEMORY_INFO()
238
239 private:
240 Global<Object> target_;
241 uint64_t reference_count_ = 0;
242 };
243
GuessHandleType(const FunctionCallbackInfo<Value> & args)244 static void GuessHandleType(const FunctionCallbackInfo<Value>& args) {
245 Environment* env = Environment::GetCurrent(args);
246 int fd;
247 if (!args[0]->Int32Value(env->context()).To(&fd)) return;
248 CHECK_GE(fd, 0);
249
250 uv_handle_type t = uv_guess_handle(fd);
251 const char* type = nullptr;
252
253 switch (t) {
254 case UV_TCP:
255 type = "TCP";
256 break;
257 case UV_TTY:
258 type = "TTY";
259 break;
260 case UV_UDP:
261 type = "UDP";
262 break;
263 case UV_FILE:
264 type = "FILE";
265 break;
266 case UV_NAMED_PIPE:
267 type = "PIPE";
268 break;
269 case UV_UNKNOWN_HANDLE:
270 type = "UNKNOWN";
271 break;
272 default:
273 ABORT();
274 }
275
276 args.GetReturnValue().Set(OneByteString(env->isolate(), type));
277 }
278
Initialize(Local<Object> target,Local<Value> unused,Local<Context> context,void * priv)279 void Initialize(Local<Object> target,
280 Local<Value> unused,
281 Local<Context> context,
282 void* priv) {
283 Environment* env = Environment::GetCurrent(context);
284
285 #define V(name, _) \
286 target->Set(context, \
287 FIXED_ONE_BYTE_STRING(env->isolate(), #name), \
288 Integer::NewFromUnsigned(env->isolate(), index++)).Check();
289 {
290 uint32_t index = 0;
291 PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V)
292 }
293 #undef V
294
295 #define V(name) \
296 target->Set(context, \
297 FIXED_ONE_BYTE_STRING(env->isolate(), #name), \
298 Integer::New(env->isolate(), Promise::PromiseState::name)) \
299 .FromJust()
300 V(kPending);
301 V(kFulfilled);
302 V(kRejected);
303 #undef V
304
305 env->SetMethodNoSideEffect(target, "getHiddenValue", GetHiddenValue);
306 env->SetMethod(target, "setHiddenValue", SetHiddenValue);
307 env->SetMethodNoSideEffect(target, "getPromiseDetails", GetPromiseDetails);
308 env->SetMethodNoSideEffect(target, "getProxyDetails", GetProxyDetails);
309 env->SetMethodNoSideEffect(target, "previewEntries", PreviewEntries);
310 env->SetMethodNoSideEffect(target, "getOwnNonIndexProperties",
311 GetOwnNonIndexProperties);
312 env->SetMethodNoSideEffect(target, "getConstructorName", GetConstructorName);
313 env->SetMethodNoSideEffect(target, "getExternalValue", GetExternalValue);
314 env->SetMethod(target, "sleep", Sleep);
315
316 env->SetMethod(target, "arrayBufferViewHasBuffer", ArrayBufferViewHasBuffer);
317 Local<Object> constants = Object::New(env->isolate());
318 NODE_DEFINE_CONSTANT(constants, ALL_PROPERTIES);
319 NODE_DEFINE_CONSTANT(constants, ONLY_WRITABLE);
320 NODE_DEFINE_CONSTANT(constants, ONLY_ENUMERABLE);
321 NODE_DEFINE_CONSTANT(constants, ONLY_CONFIGURABLE);
322 NODE_DEFINE_CONSTANT(constants, SKIP_STRINGS);
323 NODE_DEFINE_CONSTANT(constants, SKIP_SYMBOLS);
324 target->Set(context,
325 FIXED_ONE_BYTE_STRING(env->isolate(), "propertyFilter"),
326 constants).Check();
327
328 Local<String> should_abort_on_uncaught_toggle =
329 FIXED_ONE_BYTE_STRING(env->isolate(), "shouldAbortOnUncaughtToggle");
330 CHECK(target
331 ->Set(env->context(),
332 should_abort_on_uncaught_toggle,
333 env->should_abort_on_uncaught_toggle().GetJSArray())
334 .FromJust());
335
336 Local<FunctionTemplate> weak_ref =
337 env->NewFunctionTemplate(WeakReference::New);
338 weak_ref->InstanceTemplate()->SetInternalFieldCount(
339 WeakReference::kInternalFieldCount);
340 weak_ref->Inherit(BaseObject::GetConstructorTemplate(env));
341 env->SetProtoMethod(weak_ref, "get", WeakReference::Get);
342 env->SetProtoMethod(weak_ref, "incRef", WeakReference::IncRef);
343 env->SetProtoMethod(weak_ref, "decRef", WeakReference::DecRef);
344 env->SetConstructorFunction(target, "WeakReference", weak_ref);
345
346 env->SetMethod(target, "guessHandleType", GuessHandleType);
347 }
348
349 } // namespace util
350 } // namespace node
351
352 NODE_MODULE_CONTEXT_AWARE_INTERNAL(util, node::util::Initialize)
353