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