1 // Copyright 2022 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/inspector/v8-webdriver-serializer.h"
6 
7 #include "include/v8-container.h"
8 #include "include/v8-context.h"
9 #include "include/v8-date.h"
10 #include "include/v8-exception.h"
11 #include "include/v8-regexp.h"
12 #include "src/inspector/protocol/Forward.h"
13 #include "src/inspector/value-mirror.h"
14 
15 namespace v8_inspector {
16 
17 using protocol::Response;
18 // private
_serializeRecursively( v8::Local<v8::Value> value, v8::Local<v8::Context> context, int max_depth, std::unique_ptr<protocol::Value>* result)19 protocol::Response _serializeRecursively(
20     v8::Local<v8::Value> value, v8::Local<v8::Context> context, int max_depth,
21     std::unique_ptr<protocol::Value>* result) {
22   std::unique_ptr<ValueMirror> mirror = ValueMirror::create(context, value);
23   std::unique_ptr<protocol::Runtime::WebDriverValue> webDriver_value;
24   Response response =
25       mirror->buildWebDriverValue(context, max_depth - 1, &webDriver_value);
26   if (!response.IsSuccess()) return response;
27   if (!webDriver_value) return Response::InternalError();
28 
29   std::unique_ptr<protocol::DictionaryValue> result_dict =
30       protocol::DictionaryValue::create();
31 
32   result_dict->setValue(
33       protocol::String("type"),
34       protocol::StringValue::create(webDriver_value->getType()));
35   if (webDriver_value->hasValue())
36     result_dict->setValue(protocol::String("value"),
37                           webDriver_value->getValue(nullptr)->clone());
38 
39   (*result) = std::move(result_dict);
40   return Response::Success();
41 }
42 
descriptionForObject(v8::Isolate* isolate, v8::Local<v8::Object> object)43 String16 descriptionForObject(v8::Isolate* isolate,
44                               v8::Local<v8::Object> object) {
45   return toProtocolString(isolate, object->GetConstructorName());
46 }
47 
descriptionForDate(v8::Local<v8::Context> context, v8::Local<v8::Date> date)48 String16 descriptionForDate(v8::Local<v8::Context> context,
49                             v8::Local<v8::Date> date) {
50   v8::Isolate* isolate = context->GetIsolate();
51   v8::TryCatch tryCatch(isolate);
52   v8::Local<v8::String> description;
53   if (!date->ToString(context).ToLocal(&description)) {
54     return descriptionForObject(isolate, date);
55   }
56   return toProtocolString(isolate, description);
57 }
58 
_descriptionForRegExpFlags(v8::Local<v8::RegExp> value)59 String16 _descriptionForRegExpFlags(v8::Local<v8::RegExp> value) {
60   String16Builder result_string_builder;
61   v8::RegExp::Flags flags = value->GetFlags();
62   if (flags & v8::RegExp::Flags::kHasIndices) result_string_builder.append('d');
63   if (flags & v8::RegExp::Flags::kGlobal) result_string_builder.append('g');
64   if (flags & v8::RegExp::Flags::kIgnoreCase) result_string_builder.append('i');
65   if (flags & v8::RegExp::Flags::kLinear) result_string_builder.append('l');
66   if (flags & v8::RegExp::Flags::kMultiline) result_string_builder.append('m');
67   if (flags & v8::RegExp::Flags::kDotAll) result_string_builder.append('s');
68   if (flags & v8::RegExp::Flags::kUnicode) result_string_builder.append('u');
69   if (flags & v8::RegExp::Flags::kSticky) result_string_builder.append('y');
70   return result_string_builder.toString();
71 }
72 
_serializeRegexp( v8::Local<v8::RegExp> value, v8::Local<v8::Context> context, int max_depth, std::unique_ptr<protocol::Runtime::WebDriverValue>* result)73 protocol::Response _serializeRegexp(
74     v8::Local<v8::RegExp> value, v8::Local<v8::Context> context, int max_depth,
75     std::unique_ptr<protocol::Runtime::WebDriverValue>* result) {
76   *result = protocol::Runtime::WebDriverValue::create()
77                 .setType(protocol::Runtime::WebDriverValue::TypeEnum::Regexp)
78                 .build();
79 
80   std::unique_ptr<protocol::DictionaryValue> result_value =
81       protocol::DictionaryValue::create();
82 
83   result_value->setValue(protocol::String("pattern"),
84                          protocol::StringValue::create(toProtocolString(
85                              context->GetIsolate(), value->GetSource())));
86 
87   String16 flags = _descriptionForRegExpFlags(value);
88   if (!flags.isEmpty())
89     result_value->setValue(protocol::String("flags"),
90                            protocol::StringValue::create(flags));
91 
92   (*result)->setValue(std::move(result_value));
93   return Response::Success();
94 }
95 
_serializeDate( v8::Local<v8::Date> value, v8::Local<v8::Context> context, int max_depth, std::unique_ptr<protocol::Runtime::WebDriverValue>* result)96 protocol::Response _serializeDate(
97     v8::Local<v8::Date> value, v8::Local<v8::Context> context, int max_depth,
98     std::unique_ptr<protocol::Runtime::WebDriverValue>* result) {
99   *result = protocol::Runtime::WebDriverValue::create()
100                 .setType(protocol::Runtime::WebDriverValue::TypeEnum::Date)
101                 .build();
102 
103   (*result)->setValue(protocol::StringValue::create(
104       descriptionForDate(context, value.As<v8::Date>())));
105   return Response::Success();
106 }
107 
_serializeArrayValue( v8::Local<v8::Array> value, v8::Local<v8::Context> context, int max_depth, std::unique_ptr<protocol::Value>* result)108 protocol::Response _serializeArrayValue(
109     v8::Local<v8::Array> value, v8::Local<v8::Context> context, int max_depth,
110     std::unique_ptr<protocol::Value>* result) {
111   std::unique_ptr<protocol::ListValue> result_value =
112       protocol::ListValue::create();
113   uint32_t length = value->Length();
114   for (uint32_t i = 0; i < length; i++) {
115     v8::Local<v8::Value> element_value;
116     std::unique_ptr<protocol::Value> element_protocol_value;
117     if (!value->Get(context, i).ToLocal(&element_value))
118       return Response::InternalError();
119 
120     Response response = _serializeRecursively(element_value, context, max_depth,
121                                               &element_protocol_value);
122     if (!response.IsSuccess()) return response;
123 
124     result_value->pushValue(std::move(element_protocol_value));
125   }
126   *result = std::move(result_value);
127   return Response::Success();
128 }
129 
_serializeArray( v8::Local<v8::Array> value, v8::Local<v8::Context> context, int max_depth, std::unique_ptr<protocol::Runtime::WebDriverValue>* result)130 protocol::Response _serializeArray(
131     v8::Local<v8::Array> value, v8::Local<v8::Context> context, int max_depth,
132     std::unique_ptr<protocol::Runtime::WebDriverValue>* result) {
133   *result = protocol::Runtime::WebDriverValue::create()
134                 .setType(protocol::Runtime::WebDriverValue::TypeEnum::Array)
135                 .build();
136 
137   if (max_depth <= 0) return Response::Success();
138 
139   std::unique_ptr<protocol::Value> result_value;
140   Response response =
141       _serializeArrayValue(value, context, max_depth, &result_value);
142   if (!response.IsSuccess()) return response;
143 
144   (*result)->setValue(std::move(result_value));
145   return Response::Success();
146 }
147 
_serializeMap( v8::Local<v8::Map> value, v8::Local<v8::Context> context, int max_depth, std::unique_ptr<protocol::Runtime::WebDriverValue>* result)148 protocol::Response _serializeMap(
149     v8::Local<v8::Map> value, v8::Local<v8::Context> context, int max_depth,
150     std::unique_ptr<protocol::Runtime::WebDriverValue>* result) {
151   *result = protocol::Runtime::WebDriverValue::create()
152                 .setType(protocol::Runtime::WebDriverValue::TypeEnum::Map)
153                 .build();
154 
155   if (max_depth <= 0) return Response::Success();
156 
157   std::unique_ptr<protocol::ListValue> result_value =
158       protocol::ListValue::create();
159 
160   v8::Local<v8::Array> properties_and_values = value->AsArray();
161 
162   uint32_t length = properties_and_values->Length();
163   for (uint32_t i = 0; i < length; i += 2) {
164     v8::Local<v8::Value> key_value, property_value;
165     std::unique_ptr<protocol::Value> key_protocol_value,
166         property_protocol_value;
167 
168     if (!properties_and_values->Get(context, i).ToLocal(&key_value))
169       return Response::InternalError();
170     if (!properties_and_values->Get(context, i + 1).ToLocal(&property_value))
171       return Response::InternalError();
172     if (property_value->IsUndefined()) continue;
173 
174     if (key_value->IsString()) {
175       key_protocol_value = protocol::StringValue::create(
176           toProtocolString(context->GetIsolate(), key_value.As<v8::String>()));
177     } else {
178       Response response = _serializeRecursively(key_value, context, max_depth,
179                                                 &key_protocol_value);
180       if (!response.IsSuccess()) return response;
181     }
182 
183     Response response = _serializeRecursively(
184         property_value, context, max_depth, &property_protocol_value);
185     if (!response.IsSuccess()) return response;
186 
187     std::unique_ptr<protocol::ListValue> value_list =
188         protocol::ListValue::create();
189 
190     // command->pushValue(protocol::StringValue::create(method));
191     value_list->pushValue(std::move(key_protocol_value));
192     value_list->pushValue(std::move(property_protocol_value));
193 
194     result_value->pushValue(std::move(value_list));
195   }
196 
197   (*result)->setValue(std::move(result_value));
198   return Response::Success();
199 }
200 
_serializeSet( v8::Local<v8::Set> value, v8::Local<v8::Context> context, int max_depth, std::unique_ptr<protocol::Runtime::WebDriverValue>* result)201 protocol::Response _serializeSet(
202     v8::Local<v8::Set> value, v8::Local<v8::Context> context, int max_depth,
203     std::unique_ptr<protocol::Runtime::WebDriverValue>* result) {
204   *result = protocol::Runtime::WebDriverValue::create()
205                 .setType(protocol::Runtime::WebDriverValue::TypeEnum::Set)
206                 .build();
207 
208   if (max_depth <= 0) return Response::Success();
209 
210   std::unique_ptr<protocol::Value> result_value;
211   Response response =
212       _serializeArrayValue(value->AsArray(), context, max_depth, &result_value);
213   if (!response.IsSuccess()) return response;
214 
215   (*result)->setValue(std::move(result_value));
216   return Response::Success();
217 }
218 
_serializeObjectValue( v8::Local<v8::Object> value, v8::Local<v8::Context> context, int max_depth, std::unique_ptr<protocol::Value>* result)219 protocol::Response _serializeObjectValue(
220     v8::Local<v8::Object> value, v8::Local<v8::Context> context, int max_depth,
221     std::unique_ptr<protocol::Value>* result) {
222   std::unique_ptr<protocol::ListValue> result_list =
223       protocol::ListValue::create();
224   // Iterate through object's properties.
225   v8::Local<v8::Array> property_names;
226   if (!value->GetOwnPropertyNames(context).ToLocal(&property_names))
227     return Response::InternalError();
228   uint32_t length = property_names->Length();
229   for (uint32_t i = 0; i < length; i++) {
230     v8::Local<v8::Value> key_value, property_value;
231     std::unique_ptr<protocol::Value> key_protocol_value,
232         property_protocol_value;
233 
234     if (!property_names->Get(context, i).ToLocal(&key_value))
235       return Response::InternalError();
236 
237     if (key_value->IsString()) {
238       v8::Maybe<bool> hasRealNamedProperty =
239           value->HasRealNamedProperty(context, key_value.As<v8::String>());
240       // Don't access properties with interceptors.
241       if (hasRealNamedProperty.IsNothing() || !hasRealNamedProperty.FromJust())
242         continue;
243       key_protocol_value = protocol::StringValue::create(
244           toProtocolString(context->GetIsolate(), key_value.As<v8::String>()));
245     } else {
246       Response response = _serializeRecursively(key_value, context, max_depth,
247                                                 &key_protocol_value);
248       if (!response.IsSuccess()) return response;
249     }
250 
251     if (!value->Get(context, key_value).ToLocal(&property_value))
252       return Response::InternalError();
253     if (property_value->IsUndefined()) continue;
254 
255     Response response = _serializeRecursively(
256         property_value, context, max_depth, &property_protocol_value);
257     if (!response.IsSuccess()) return response;
258 
259     std::unique_ptr<protocol::ListValue> value_list =
260         protocol::ListValue::create();
261 
262     value_list->pushValue(std::move(key_protocol_value));
263     value_list->pushValue(std::move(property_protocol_value));
264 
265     result_list->pushValue(std::move(value_list));
266   }
267   (*result) = std::move(result_list);
268   return Response::Success();
269 }
270 
_serializeObject( v8::Local<v8::Object> value, v8::Local<v8::Context> context, int max_depth, std::unique_ptr<protocol::Runtime::WebDriverValue>* result)271 protocol::Response _serializeObject(
272     v8::Local<v8::Object> value, v8::Local<v8::Context> context, int max_depth,
273     std::unique_ptr<protocol::Runtime::WebDriverValue>* result) {
274   *result = protocol::Runtime::WebDriverValue::create()
275                 .setType(protocol::Runtime::WebDriverValue::TypeEnum::Object)
276                 .build();
277 
278   if (max_depth <= 0) return Response::Success();
279 
280   std::unique_ptr<protocol::Value> result_value;
281   Response response = _serializeObjectValue(value.As<v8::Object>(), context,
282                                             max_depth, &result_value);
283   if (!response.IsSuccess()) return response;
284 
285   (*result)->setValue(std::move(result_value));
286   return Response::Success();
287 }
288 
serializeV8Value( v8::Local<v8::Object> value, v8::Local<v8::Context> context, int max_depth, std::unique_ptr<protocol::Runtime::WebDriverValue>* result)289 protocol::Response V8WebDriverSerializer::serializeV8Value(
290     v8::Local<v8::Object> value, v8::Local<v8::Context> context, int max_depth,
291     std::unique_ptr<protocol::Runtime::WebDriverValue>* result) {
292   if (value->IsArray()) {
293     Response response =
294         _serializeArray(value.As<v8::Array>(), context, max_depth, result);
295     return response;
296   }
297   if (value->IsRegExp()) {
298     Response response =
299         _serializeRegexp(value.As<v8::RegExp>(), context, max_depth, result);
300     return response;
301   }
302   if (value->IsDate()) {
303     Response response =
304         _serializeDate(value.As<v8::Date>(), context, max_depth, result);
305     return response;
306   }
307   if (value->IsMap()) {
308     Response response =
309         _serializeMap(value.As<v8::Map>(), context, max_depth, result);
310     return response;
311   }
312   if (value->IsSet()) {
313     Response response =
314         _serializeSet(value.As<v8::Set>(), context, max_depth, result);
315     return response;
316   }
317   if (value->IsWeakMap()) {
318     *result = protocol::Runtime::WebDriverValue::create()
319                   .setType(protocol::Runtime::WebDriverValue::TypeEnum::Weakmap)
320                   .build();
321     return Response::Success();
322   }
323   if (value->IsWeakSet()) {
324     *result = protocol::Runtime::WebDriverValue::create()
325                   .setType(protocol::Runtime::WebDriverValue::TypeEnum::Weakset)
326                   .build();
327     return Response::Success();
328   }
329   if (value->IsNativeError()) {
330     *result = protocol::Runtime::WebDriverValue::create()
331                   .setType(protocol::Runtime::WebDriverValue::TypeEnum::Error)
332                   .build();
333     return Response::Success();
334   }
335   if (value->IsProxy()) {
336     *result = protocol::Runtime::WebDriverValue::create()
337                   .setType(protocol::Runtime::WebDriverValue::TypeEnum::Proxy)
338                   .build();
339     return Response::Success();
340   }
341   if (value->IsPromise()) {
342     *result = protocol::Runtime::WebDriverValue::create()
343                   .setType(protocol::Runtime::WebDriverValue::TypeEnum::Promise)
344                   .build();
345     return Response::Success();
346   }
347   if (value->IsTypedArray()) {
348     *result =
349         protocol::Runtime::WebDriverValue::create()
350             .setType(protocol::Runtime::WebDriverValue::TypeEnum::Typedarray)
351             .build();
352     return Response::Success();
353   }
354   if (value->IsArrayBuffer()) {
355     *result =
356         protocol::Runtime::WebDriverValue::create()
357             .setType(protocol::Runtime::WebDriverValue::TypeEnum::Arraybuffer)
358             .build();
359     return Response::Success();
360   }
361   if (value->IsFunction()) {
362     *result =
363         protocol::Runtime::WebDriverValue::create()
364             .setType(protocol::Runtime::WebDriverValue::TypeEnum::Function)
365             .build();
366     return Response::Success();
367   }
368 
369   // Serialize as an Object.
370   Response response =
371       _serializeObject(value.As<v8::Object>(), context, max_depth, result);
372   return response;
373 }
374 
375 }  // namespace v8_inspector
376