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
15namespace v8_inspector {
16
17using protocol::Response;
18// private
19protocol::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
43String16 descriptionForObject(v8::Isolate* isolate,
44                              v8::Local<v8::Object> object) {
45  return toProtocolString(isolate, object->GetConstructorName());
46}
47
48String16 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
59String16 _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
73protocol::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
96protocol::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
108protocol::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
130protocol::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
148protocol::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
201protocol::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
219protocol::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
271protocol::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
289protocol::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