blob: f29c56f2aa5371464a5cdb9883223a63cda3d58f [file] [log] [blame] [edit]
// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/inspector/v8-webdriver-serializer.h"
#include "include/v8-container.h"
#include "include/v8-context.h"
#include "include/v8-date.h"
#include "include/v8-exception.h"
#include "include/v8-regexp.h"
#include "src/inspector/protocol/Forward.h"
#include "src/inspector/value-mirror.h"
namespace v8_inspector {
namespace {
using protocol::Response;
std::unique_ptr<protocol::Value> SerializeRecursively(
v8::Local<v8::Value> value, v8::Local<v8::Context> context, int max_depth) {
std::unique_ptr<ValueMirror> mirror = ValueMirror::create(context, value);
std::unique_ptr<protocol::Runtime::WebDriverValue> web_driver_value =
mirror->buildWebDriverValue(context, max_depth - 1);
DCHECK(web_driver_value);
std::unique_ptr<protocol::DictionaryValue> result_dict =
protocol::DictionaryValue::create();
result_dict->setValue(
protocol::String("type"),
protocol::StringValue::create(web_driver_value->getType()));
if (web_driver_value->hasValue()) {
result_dict->setValue(protocol::String("value"),
web_driver_value->getValue(nullptr)->clone());
}
return result_dict;
}
std::unique_ptr<protocol::Value> DescriptionForDate(
v8::Local<v8::Context> context, v8::Local<v8::Date> date) {
v8::Isolate* isolate = context->GetIsolate();
v8::TryCatch tryCatch(isolate);
v8::Local<v8::String> dateISOString = date->ToISOString();
return protocol::StringValue::create(
toProtocolString(isolate, dateISOString));
}
String16 _descriptionForRegExpFlags(v8::Local<v8::RegExp> value) {
String16Builder result_string_builder;
v8::RegExp::Flags flags = value->GetFlags();
if (flags & v8::RegExp::Flags::kHasIndices) result_string_builder.append('d');
if (flags & v8::RegExp::Flags::kGlobal) result_string_builder.append('g');
if (flags & v8::RegExp::Flags::kIgnoreCase) result_string_builder.append('i');
if (flags & v8::RegExp::Flags::kLinear) result_string_builder.append('l');
if (flags & v8::RegExp::Flags::kMultiline) result_string_builder.append('m');
if (flags & v8::RegExp::Flags::kDotAll) result_string_builder.append('s');
if (flags & v8::RegExp::Flags::kUnicode) result_string_builder.append('u');
if (flags & v8::RegExp::Flags::kSticky) result_string_builder.append('y');
return result_string_builder.toString();
}
std::unique_ptr<protocol::Runtime::WebDriverValue> SerializeRegexp(
v8::Local<v8::RegExp> value, v8::Local<v8::Context> context) {
std::unique_ptr<protocol::Runtime::WebDriverValue> result =
protocol::Runtime::WebDriverValue::create()
.setType(protocol::Runtime::WebDriverValue::TypeEnum::Regexp)
.build();
std::unique_ptr<protocol::DictionaryValue> result_value =
protocol::DictionaryValue::create();
result_value->setValue(protocol::String("pattern"),
protocol::StringValue::create(toProtocolString(
context->GetIsolate(), value->GetSource())));
String16 flags = _descriptionForRegExpFlags(value);
if (!flags.isEmpty()) {
result_value->setValue(protocol::String("flags"),
protocol::StringValue::create(flags));
}
result->setValue(std::move(result_value));
return result;
}
std::unique_ptr<protocol::Runtime::WebDriverValue> SerializeDate(
v8::Local<v8::Date> value, v8::Local<v8::Context> context) {
std::unique_ptr<protocol::Runtime::WebDriverValue> result =
protocol::Runtime::WebDriverValue::create()
.setType(protocol::Runtime::WebDriverValue::TypeEnum::Date)
.build();
std::unique_ptr<protocol::Value> date_description =
DescriptionForDate(context, value.As<v8::Date>());
result->setValue(std::move(date_description));
return result;
}
std::unique_ptr<protocol::Value> SerializeArrayValue(
v8::Local<v8::Array> value, v8::Local<v8::Context> context, int max_depth) {
std::unique_ptr<protocol::ListValue> result = protocol::ListValue::create();
uint32_t length = value->Length();
result->reserve(length);
for (uint32_t i = 0; i < length; i++) {
v8::Local<v8::Value> element_value;
bool success = value->Get(context, i).ToLocal(&element_value);
DCHECK(success);
USE(success);
std::unique_ptr<protocol::Value> element_protocol_value =
SerializeRecursively(element_value, context, max_depth);
result->pushValue(std::move(element_protocol_value));
}
return result;
}
std::unique_ptr<protocol::Runtime::WebDriverValue> SerializeArray(
v8::Local<v8::Array> value, v8::Local<v8::Context> context, int max_depth) {
std::unique_ptr<protocol::Runtime::WebDriverValue> result =
protocol::Runtime::WebDriverValue::create()
.setType(protocol::Runtime::WebDriverValue::TypeEnum::Array)
.build();
if (max_depth > 0) {
result->setValue(SerializeArrayValue(value, context, max_depth));
}
return result;
}
std::unique_ptr<protocol::Runtime::WebDriverValue> SerializeMap(
v8::Local<v8::Map> value, v8::Local<v8::Context> context, int max_depth) {
std::unique_ptr<protocol::Runtime::WebDriverValue> result =
protocol::Runtime::WebDriverValue::create()
.setType(protocol::Runtime::WebDriverValue::TypeEnum::Map)
.build();
if (max_depth > 0) {
std::unique_ptr<protocol::ListValue> result_value =
protocol::ListValue::create();
v8::Local<v8::Array> properties_and_values = value->AsArray();
uint32_t length = properties_and_values->Length();
result_value->reserve(length);
for (uint32_t i = 0; i < length; i += 2) {
v8::Local<v8::Value> key_value, property_value;
std::unique_ptr<protocol::Value> key_protocol_value,
property_protocol_value;
bool success = properties_and_values->Get(context, i).ToLocal(&key_value);
DCHECK(success);
success =
properties_and_values->Get(context, i + 1).ToLocal(&property_value);
DCHECK(success);
USE(success);
if (key_value->IsString()) {
key_protocol_value = protocol::StringValue::create(toProtocolString(
context->GetIsolate(), key_value.As<v8::String>()));
} else {
key_protocol_value =
SerializeRecursively(key_value, context, max_depth);
}
property_protocol_value =
SerializeRecursively(property_value, context, max_depth);
std::unique_ptr<protocol::ListValue> key_value_list =
protocol::ListValue::create();
key_value_list->pushValue(std::move(key_protocol_value));
key_value_list->pushValue(std::move(property_protocol_value));
result_value->pushValue(std::move(key_value_list));
}
result->setValue(std::move(result_value));
}
return result;
}
std::unique_ptr<protocol::Runtime::WebDriverValue> SerializeSet(
v8::Local<v8::Set> value, v8::Local<v8::Context> context, int max_depth) {
std::unique_ptr<protocol::Runtime::WebDriverValue> result =
protocol::Runtime::WebDriverValue::create()
.setType(protocol::Runtime::WebDriverValue::TypeEnum::Set)
.build();
if (max_depth > 0) {
result->setValue(SerializeArrayValue(value->AsArray(), context, max_depth));
}
return result;
}
std::unique_ptr<protocol::Value> SerializeObjectValue(
v8::Local<v8::Object> value, v8::Local<v8::Context> context,
int max_depth) {
std::unique_ptr<protocol::ListValue> result = protocol::ListValue::create();
// Iterate through object's properties.
v8::Local<v8::Array> property_names;
bool success = value->GetOwnPropertyNames(context).ToLocal(&property_names);
DCHECK(success);
uint32_t length = property_names->Length();
result->reserve(length);
for (uint32_t i = 0; i < length; i++) {
v8::Local<v8::Value> key_value, property_value;
std::unique_ptr<protocol::Value> key_protocol_value,
property_protocol_value;
success = property_names->Get(context, i).ToLocal(&key_value);
DCHECK(success);
if (key_value->IsString()) {
v8::Maybe<bool> hasRealNamedProperty =
value->HasRealNamedProperty(context, key_value.As<v8::String>());
// Don't access properties with interceptors.
if (hasRealNamedProperty.IsNothing() ||
!hasRealNamedProperty.FromJust()) {
continue;
}
key_protocol_value = protocol::StringValue::create(
toProtocolString(context->GetIsolate(), key_value.As<v8::String>()));
} else {
key_protocol_value = SerializeRecursively(key_value, context, max_depth);
}
success = value->Get(context, key_value).ToLocal(&property_value);
DCHECK(success);
USE(success);
property_protocol_value =
SerializeRecursively(property_value, context, max_depth);
std::unique_ptr<protocol::ListValue> key_value_list =
protocol::ListValue::create();
key_value_list->pushValue(std::move(key_protocol_value));
key_value_list->pushValue(std::move(property_protocol_value));
result->pushValue(std::move(key_value_list));
}
return result;
}
std::unique_ptr<protocol::Runtime::WebDriverValue> SerializeObject(
v8::Local<v8::Object> value, v8::Local<v8::Context> context,
int max_depth) {
std::unique_ptr<protocol::Runtime::WebDriverValue> result =
protocol::Runtime::WebDriverValue::create()
.setType(protocol::Runtime::WebDriverValue::TypeEnum::Object)
.build();
if (max_depth > 0) {
result->setValue(
SerializeObjectValue(value.As<v8::Object>(), context, max_depth));
}
return result;
}
} // namespace
std::unique_ptr<protocol::Runtime::WebDriverValue>
V8WebDriverSerializer::serializeV8Value(v8::Local<v8::Object> value,
v8::Local<v8::Context> context,
int max_depth) {
if (value->IsArray()) {
return SerializeArray(value.As<v8::Array>(), context, max_depth);
}
if (value->IsRegExp()) {
return SerializeRegexp(value.As<v8::RegExp>(), context);
}
if (value->IsDate()) {
return SerializeDate(value.As<v8::Date>(), context);
}
if (value->IsMap()) {
return SerializeMap(value.As<v8::Map>(), context, max_depth);
}
if (value->IsSet()) {
return SerializeSet(value.As<v8::Set>(), context, max_depth);
}
if (value->IsWeakMap()) {
return protocol::Runtime::WebDriverValue::create()
.setType(protocol::Runtime::WebDriverValue::TypeEnum::Weakmap)
.build();
}
if (value->IsWeakSet()) {
return protocol::Runtime::WebDriverValue::create()
.setType(protocol::Runtime::WebDriverValue::TypeEnum::Weakset)
.build();
}
if (value->IsNativeError()) {
return protocol::Runtime::WebDriverValue::create()
.setType(protocol::Runtime::WebDriverValue::TypeEnum::Error)
.build();
}
if (value->IsProxy()) {
return protocol::Runtime::WebDriverValue::create()
.setType(protocol::Runtime::WebDriverValue::TypeEnum::Proxy)
.build();
}
if (value->IsPromise()) {
return protocol::Runtime::WebDriverValue::create()
.setType(protocol::Runtime::WebDriverValue::TypeEnum::Promise)
.build();
}
if (value->IsTypedArray()) {
return protocol::Runtime::WebDriverValue::create()
.setType(protocol::Runtime::WebDriverValue::TypeEnum::Typedarray)
.build();
}
if (value->IsArrayBuffer()) {
return protocol::Runtime::WebDriverValue::create()
.setType(protocol::Runtime::WebDriverValue::TypeEnum::Arraybuffer)
.build();
}
if (value->IsFunction()) {
return protocol::Runtime::WebDriverValue::create()
.setType(protocol::Runtime::WebDriverValue::TypeEnum::Function)
.build();
}
// Serialize as an Object.
return SerializeObject(value.As<v8::Object>(), context, max_depth);
}
} // namespace v8_inspector