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