| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/child/v8_value_converter_impl.h" | 5 #include "content/child/v8_value_converter_impl.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 | 9 |
| 10 #include <cmath> | 10 #include <cmath> |
| 11 #include <memory> | 11 #include <memory> |
| 12 #include <string> | 12 #include <string> |
| 13 #include <utility> |
| 13 | 14 |
| 14 #include "base/bind.h" | 15 #include "base/bind.h" |
| 15 #include "base/bind_helpers.h" | 16 #include "base/bind_helpers.h" |
| 16 #include "base/logging.h" | 17 #include "base/logging.h" |
| 18 #include "base/memory/ptr_util.h" |
| 17 #include "base/values.h" | 19 #include "base/values.h" |
| 18 #include "third_party/WebKit/public/web/WebArrayBuffer.h" | 20 #include "third_party/WebKit/public/web/WebArrayBuffer.h" |
| 19 #include "third_party/WebKit/public/web/WebArrayBufferConverter.h" | 21 #include "third_party/WebKit/public/web/WebArrayBufferConverter.h" |
| 20 #include "third_party/WebKit/public/web/WebArrayBufferView.h" | 22 #include "third_party/WebKit/public/web/WebArrayBufferView.h" |
| 21 #include "v8/include/v8.h" | 23 #include "v8/include/v8.h" |
| 22 | 24 |
| 23 namespace content { | 25 namespace content { |
| 24 | 26 |
| 25 // Default implementation of V8ValueConverter::Strategy | 27 // Default implementation of V8ValueConverter::Strategy |
| 26 | 28 |
| 27 bool V8ValueConverter::Strategy::FromV8Object( | 29 bool V8ValueConverter::Strategy::FromV8Object( |
| 28 v8::Local<v8::Object> value, | 30 v8::Local<v8::Object> value, |
| 29 base::Value** out, | 31 std::unique_ptr<base::Value>* out, |
| 30 v8::Isolate* isolate, | 32 v8::Isolate* isolate, |
| 31 const FromV8ValueCallback& callback) const { | 33 const FromV8ValueCallback& callback) const { |
| 32 return false; | 34 return false; |
| 33 } | 35 } |
| 34 | 36 |
| 35 bool V8ValueConverter::Strategy::FromV8Array( | 37 bool V8ValueConverter::Strategy::FromV8Array( |
| 36 v8::Local<v8::Array> value, | 38 v8::Local<v8::Array> value, |
| 37 base::Value** out, | 39 std::unique_ptr<base::Value>* out, |
| 38 v8::Isolate* isolate, | 40 v8::Isolate* isolate, |
| 39 const FromV8ValueCallback& callback) const { | 41 const FromV8ValueCallback& callback) const { |
| 40 return false; | 42 return false; |
| 41 } | 43 } |
| 42 | 44 |
| 43 bool V8ValueConverter::Strategy::FromV8ArrayBuffer(v8::Local<v8::Object> value, | 45 bool V8ValueConverter::Strategy::FromV8ArrayBuffer( |
| 44 base::Value** out, | 46 v8::Local<v8::Object> value, |
| 45 v8::Isolate* isolate) const { | 47 std::unique_ptr<base::Value>* out, |
| 48 v8::Isolate* isolate) const { |
| 46 return false; | 49 return false; |
| 47 } | 50 } |
| 48 | 51 |
| 49 bool V8ValueConverter::Strategy::FromV8Number(v8::Local<v8::Number> value, | 52 bool V8ValueConverter::Strategy::FromV8Number( |
| 50 base::Value** out) const { | 53 v8::Local<v8::Number> value, |
| 54 std::unique_ptr<base::Value>* out) const { |
| 51 return false; | 55 return false; |
| 52 } | 56 } |
| 53 | 57 |
| 54 bool V8ValueConverter::Strategy::FromV8Undefined(base::Value** out) const { | 58 bool V8ValueConverter::Strategy::FromV8Undefined( |
| 59 std::unique_ptr<base::Value>* out) const { |
| 55 return false; | 60 return false; |
| 56 } | 61 } |
| 57 | 62 |
| 58 | 63 |
| 59 namespace { | 64 namespace { |
| 60 | 65 |
| 61 // For the sake of the storage API, make this quite large. | 66 // For the sake of the storage API, make this quite large. |
| 62 const int kMaxRecursionDepth = 100; | 67 const int kMaxRecursionDepth = 100; |
| 63 | 68 |
| 64 } // namespace | 69 } // namespace |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 205 } | 210 } |
| 206 | 211 |
| 207 v8::Local<v8::Value> V8ValueConverterImpl::ToV8Value( | 212 v8::Local<v8::Value> V8ValueConverterImpl::ToV8Value( |
| 208 const base::Value* value, v8::Local<v8::Context> context) const { | 213 const base::Value* value, v8::Local<v8::Context> context) const { |
| 209 v8::Context::Scope context_scope(context); | 214 v8::Context::Scope context_scope(context); |
| 210 v8::EscapableHandleScope handle_scope(context->GetIsolate()); | 215 v8::EscapableHandleScope handle_scope(context->GetIsolate()); |
| 211 return handle_scope.Escape( | 216 return handle_scope.Escape( |
| 212 ToV8ValueImpl(context->GetIsolate(), context->Global(), value)); | 217 ToV8ValueImpl(context->GetIsolate(), context->Global(), value)); |
| 213 } | 218 } |
| 214 | 219 |
| 215 base::Value* V8ValueConverterImpl::FromV8Value( | 220 std::unique_ptr<base::Value> V8ValueConverterImpl::FromV8Value( |
| 216 v8::Local<v8::Value> val, | 221 v8::Local<v8::Value> val, |
| 217 v8::Local<v8::Context> context) const { | 222 v8::Local<v8::Context> context) const { |
| 218 v8::Context::Scope context_scope(context); | 223 v8::Context::Scope context_scope(context); |
| 219 v8::HandleScope handle_scope(context->GetIsolate()); | 224 v8::HandleScope handle_scope(context->GetIsolate()); |
| 220 FromV8ValueState state(avoid_identity_hash_for_testing_); | 225 FromV8ValueState state(avoid_identity_hash_for_testing_); |
| 221 return FromV8ValueImpl(&state, val, context->GetIsolate()); | 226 return FromV8ValueImpl(&state, val, context->GetIsolate()); |
| 222 } | 227 } |
| 223 | 228 |
| 224 v8::Local<v8::Value> V8ValueConverterImpl::ToV8ValueImpl( | 229 v8::Local<v8::Value> V8ValueConverterImpl::ToV8ValueImpl( |
| 225 v8::Isolate* isolate, | 230 v8::Isolate* isolate, |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 334 v8::Isolate* isolate, | 339 v8::Isolate* isolate, |
| 335 v8::Local<v8::Object> creation_context, | 340 v8::Local<v8::Object> creation_context, |
| 336 const base::BinaryValue* value) const { | 341 const base::BinaryValue* value) const { |
| 337 blink::WebArrayBuffer buffer = | 342 blink::WebArrayBuffer buffer = |
| 338 blink::WebArrayBuffer::create(value->GetSize(), 1); | 343 blink::WebArrayBuffer::create(value->GetSize(), 1); |
| 339 memcpy(buffer.data(), value->GetBuffer(), value->GetSize()); | 344 memcpy(buffer.data(), value->GetBuffer(), value->GetSize()); |
| 340 return blink::WebArrayBufferConverter::toV8Value( | 345 return blink::WebArrayBufferConverter::toV8Value( |
| 341 &buffer, creation_context, isolate); | 346 &buffer, creation_context, isolate); |
| 342 } | 347 } |
| 343 | 348 |
| 344 base::Value* V8ValueConverterImpl::FromV8ValueImpl( | 349 std::unique_ptr<base::Value> V8ValueConverterImpl::FromV8ValueImpl( |
| 345 FromV8ValueState* state, | 350 FromV8ValueState* state, |
| 346 v8::Local<v8::Value> val, | 351 v8::Local<v8::Value> val, |
| 347 v8::Isolate* isolate) const { | 352 v8::Isolate* isolate) const { |
| 348 CHECK(!val.IsEmpty()); | 353 CHECK(!val.IsEmpty()); |
| 349 | 354 |
| 350 FromV8ValueState::Level state_level(state); | 355 FromV8ValueState::Level state_level(state); |
| 351 if (state->HasReachedMaxRecursionDepth()) | 356 if (state->HasReachedMaxRecursionDepth()) |
| 352 return NULL; | 357 return nullptr; |
| 353 | 358 |
| 354 if (val->IsNull()) | 359 if (val->IsNull()) |
| 355 return base::Value::CreateNullValue().release(); | 360 return base::Value::CreateNullValue(); |
| 356 | 361 |
| 357 if (val->IsBoolean()) | 362 if (val->IsBoolean()) |
| 358 return new base::FundamentalValue(val->ToBoolean(isolate)->Value()); | 363 return base::MakeUnique<base::FundamentalValue>( |
| 364 val->ToBoolean(isolate)->Value()); |
| 359 | 365 |
| 360 if (val->IsNumber() && strategy_) { | 366 if (val->IsNumber() && strategy_) { |
| 361 base::Value* out = NULL; | 367 std::unique_ptr<base::Value> out; |
| 362 if (strategy_->FromV8Number(val.As<v8::Number>(), &out)) | 368 if (strategy_->FromV8Number(val.As<v8::Number>(), &out)) |
| 363 return out; | 369 return out; |
| 364 } | 370 } |
| 365 | 371 |
| 366 if (val->IsInt32()) | 372 if (val->IsInt32()) |
| 367 return new base::FundamentalValue(val->ToInt32(isolate)->Value()); | 373 return base::MakeUnique<base::FundamentalValue>( |
| 374 val->ToInt32(isolate)->Value()); |
| 368 | 375 |
| 369 if (val->IsNumber()) { | 376 if (val->IsNumber()) { |
| 370 double val_as_double = val.As<v8::Number>()->Value(); | 377 double val_as_double = val.As<v8::Number>()->Value(); |
| 371 if (!std::isfinite(val_as_double)) | 378 if (!std::isfinite(val_as_double)) |
| 372 return NULL; | 379 return nullptr; |
| 373 return new base::FundamentalValue(val_as_double); | 380 return base::MakeUnique<base::FundamentalValue>(val_as_double); |
| 374 } | 381 } |
| 375 | 382 |
| 376 if (val->IsString()) { | 383 if (val->IsString()) { |
| 377 v8::String::Utf8Value utf8(val); | 384 v8::String::Utf8Value utf8(val); |
| 378 return new base::StringValue(std::string(*utf8, utf8.length())); | 385 return base::MakeUnique<base::StringValue>( |
| 386 std::string(*utf8, utf8.length())); |
| 379 } | 387 } |
| 380 | 388 |
| 381 if (val->IsUndefined()) { | 389 if (val->IsUndefined()) { |
| 382 if (strategy_) { | 390 if (strategy_) { |
| 383 base::Value* out = NULL; | 391 std::unique_ptr<base::Value> out; |
| 384 if (strategy_->FromV8Undefined(&out)) | 392 if (strategy_->FromV8Undefined(&out)) |
| 385 return out; | 393 return out; |
| 386 } | 394 } |
| 387 // JSON.stringify ignores undefined. | 395 // JSON.stringify ignores undefined. |
| 388 return NULL; | 396 return nullptr; |
| 389 } | 397 } |
| 390 | 398 |
| 391 if (val->IsDate()) { | 399 if (val->IsDate()) { |
| 392 if (!date_allowed_) | 400 if (!date_allowed_) |
| 393 // JSON.stringify would convert this to a string, but an object is more | 401 // JSON.stringify would convert this to a string, but an object is more |
| 394 // consistent within this class. | 402 // consistent within this class. |
| 395 return FromV8Object(val->ToObject(isolate), state, isolate); | 403 return FromV8Object(val->ToObject(isolate), state, isolate); |
| 396 v8::Date* date = v8::Date::Cast(*val); | 404 v8::Date* date = v8::Date::Cast(*val); |
| 397 return new base::FundamentalValue(date->ValueOf() / 1000.0); | 405 return base::MakeUnique<base::FundamentalValue>(date->ValueOf() / 1000.0); |
| 398 } | 406 } |
| 399 | 407 |
| 400 if (val->IsRegExp()) { | 408 if (val->IsRegExp()) { |
| 401 if (!reg_exp_allowed_) | 409 if (!reg_exp_allowed_) |
| 402 // JSON.stringify converts to an object. | 410 // JSON.stringify converts to an object. |
| 403 return FromV8Object(val.As<v8::Object>(), state, isolate); | 411 return FromV8Object(val.As<v8::Object>(), state, isolate); |
| 404 return new base::StringValue(*v8::String::Utf8Value(val)); | 412 return base::MakeUnique<base::StringValue>(*v8::String::Utf8Value(val)); |
| 405 } | 413 } |
| 406 | 414 |
| 407 // v8::Value doesn't have a ToArray() method for some reason. | 415 // v8::Value doesn't have a ToArray() method for some reason. |
| 408 if (val->IsArray()) | 416 if (val->IsArray()) |
| 409 return FromV8Array(val.As<v8::Array>(), state, isolate); | 417 return FromV8Array(val.As<v8::Array>(), state, isolate); |
| 410 | 418 |
| 411 if (val->IsFunction()) { | 419 if (val->IsFunction()) { |
| 412 if (!function_allowed_) | 420 if (!function_allowed_) |
| 413 // JSON.stringify refuses to convert function(){}. | 421 // JSON.stringify refuses to convert function(){}. |
| 414 return NULL; | 422 return nullptr; |
| 415 return FromV8Object(val.As<v8::Object>(), state, isolate); | 423 return FromV8Object(val.As<v8::Object>(), state, isolate); |
| 416 } | 424 } |
| 417 | 425 |
| 418 if (val->IsArrayBuffer() || val->IsArrayBufferView()) | 426 if (val->IsArrayBuffer() || val->IsArrayBufferView()) |
| 419 return FromV8ArrayBuffer(val.As<v8::Object>(), isolate); | 427 return FromV8ArrayBuffer(val.As<v8::Object>(), isolate); |
| 420 | 428 |
| 421 if (val->IsObject()) | 429 if (val->IsObject()) |
| 422 return FromV8Object(val.As<v8::Object>(), state, isolate); | 430 return FromV8Object(val.As<v8::Object>(), state, isolate); |
| 423 | 431 |
| 424 LOG(ERROR) << "Unexpected v8 value type encountered."; | 432 LOG(ERROR) << "Unexpected v8 value type encountered."; |
| 425 return NULL; | 433 return nullptr; |
| 426 } | 434 } |
| 427 | 435 |
| 428 base::Value* V8ValueConverterImpl::FromV8Array( | 436 std::unique_ptr<base::Value> V8ValueConverterImpl::FromV8Array( |
| 429 v8::Local<v8::Array> val, | 437 v8::Local<v8::Array> val, |
| 430 FromV8ValueState* state, | 438 FromV8ValueState* state, |
| 431 v8::Isolate* isolate) const { | 439 v8::Isolate* isolate) const { |
| 432 ScopedUniquenessGuard uniqueness_guard(state, val); | 440 ScopedUniquenessGuard uniqueness_guard(state, val); |
| 433 if (!uniqueness_guard.is_valid()) | 441 if (!uniqueness_guard.is_valid()) |
| 434 return base::Value::CreateNullValue().release(); | 442 return base::Value::CreateNullValue(); |
| 435 | 443 |
| 436 std::unique_ptr<v8::Context::Scope> scope; | 444 std::unique_ptr<v8::Context::Scope> scope; |
| 437 // If val was created in a different context than our current one, change to | 445 // If val was created in a different context than our current one, change to |
| 438 // that context, but change back after val is converted. | 446 // that context, but change back after val is converted. |
| 439 if (!val->CreationContext().IsEmpty() && | 447 if (!val->CreationContext().IsEmpty() && |
| 440 val->CreationContext() != isolate->GetCurrentContext()) | 448 val->CreationContext() != isolate->GetCurrentContext()) |
| 441 scope.reset(new v8::Context::Scope(val->CreationContext())); | 449 scope.reset(new v8::Context::Scope(val->CreationContext())); |
| 442 | 450 |
| 443 if (strategy_) { | 451 if (strategy_) { |
| 444 // These base::Unretained's are safe, because Strategy::FromV8Value should | 452 // These base::Unretained's are safe, because Strategy::FromV8Value should |
| 445 // be synchronous, so this object can't be out of scope. | 453 // be synchronous, so this object can't be out of scope. |
| 446 V8ValueConverter::Strategy::FromV8ValueCallback callback = | 454 V8ValueConverter::Strategy::FromV8ValueCallback callback = |
| 447 base::Bind(&V8ValueConverterImpl::FromV8ValueImpl, | 455 base::Bind(&V8ValueConverterImpl::FromV8ValueImpl, |
| 448 base::Unretained(this), | 456 base::Unretained(this), |
| 449 base::Unretained(state)); | 457 base::Unretained(state)); |
| 450 base::Value* out = NULL; | 458 std::unique_ptr<base::Value> out; |
| 451 if (strategy_->FromV8Array(val, &out, isolate, callback)) | 459 if (strategy_->FromV8Array(val, &out, isolate, callback)) |
| 452 return out; | 460 return out; |
| 453 } | 461 } |
| 454 | 462 |
| 455 base::ListValue* result = new base::ListValue(); | 463 std::unique_ptr<base::ListValue> result(new base::ListValue()); |
| 456 | 464 |
| 457 // Only fields with integer keys are carried over to the ListValue. | 465 // Only fields with integer keys are carried over to the ListValue. |
| 458 for (uint32_t i = 0; i < val->Length(); ++i) { | 466 for (uint32_t i = 0; i < val->Length(); ++i) { |
| 459 v8::TryCatch try_catch(isolate); | 467 v8::TryCatch try_catch(isolate); |
| 460 v8::Local<v8::Value> child_v8 = val->Get(i); | 468 v8::Local<v8::Value> child_v8 = val->Get(i); |
| 461 if (try_catch.HasCaught()) { | 469 if (try_catch.HasCaught()) { |
| 462 LOG(ERROR) << "Getter for index " << i << " threw an exception."; | 470 LOG(ERROR) << "Getter for index " << i << " threw an exception."; |
| 463 child_v8 = v8::Null(isolate); | 471 child_v8 = v8::Null(isolate); |
| 464 } | 472 } |
| 465 | 473 |
| 466 if (!val->HasRealIndexedProperty(i)) { | 474 if (!val->HasRealIndexedProperty(i)) { |
| 467 result->Append(base::Value::CreateNullValue()); | 475 result->Append(base::Value::CreateNullValue()); |
| 468 continue; | 476 continue; |
| 469 } | 477 } |
| 470 | 478 |
| 471 base::Value* child = FromV8ValueImpl(state, child_v8, isolate); | 479 std::unique_ptr<base::Value> child = |
| 480 FromV8ValueImpl(state, child_v8, isolate); |
| 472 if (child) | 481 if (child) |
| 473 result->Append(child); | 482 result->Append(std::move(child)); |
| 474 else | 483 else |
| 475 // JSON.stringify puts null in places where values don't serialize, for | 484 // JSON.stringify puts null in places where values don't serialize, for |
| 476 // example undefined and functions. Emulate that behavior. | 485 // example undefined and functions. Emulate that behavior. |
| 477 result->Append(base::Value::CreateNullValue()); | 486 result->Append(base::Value::CreateNullValue()); |
| 478 } | 487 } |
| 479 return result; | 488 return std::move(result); |
| 480 } | 489 } |
| 481 | 490 |
| 482 base::Value* V8ValueConverterImpl::FromV8ArrayBuffer( | 491 std::unique_ptr<base::Value> V8ValueConverterImpl::FromV8ArrayBuffer( |
| 483 v8::Local<v8::Object> val, | 492 v8::Local<v8::Object> val, |
| 484 v8::Isolate* isolate) const { | 493 v8::Isolate* isolate) const { |
| 485 if (strategy_) { | 494 if (strategy_) { |
| 486 base::Value* out = NULL; | 495 std::unique_ptr<base::Value> out; |
| 487 if (strategy_->FromV8ArrayBuffer(val, &out, isolate)) | 496 if (strategy_->FromV8ArrayBuffer(val, &out, isolate)) |
| 488 return out; | 497 return out; |
| 489 } | 498 } |
| 490 | 499 |
| 491 char* data = NULL; | 500 char* data = NULL; |
| 492 size_t length = 0; | 501 size_t length = 0; |
| 493 | 502 |
| 494 std::unique_ptr<blink::WebArrayBuffer> array_buffer( | 503 std::unique_ptr<blink::WebArrayBuffer> array_buffer( |
| 495 blink::WebArrayBufferConverter::createFromV8Value(val, isolate)); | 504 blink::WebArrayBufferConverter::createFromV8Value(val, isolate)); |
| 496 std::unique_ptr<blink::WebArrayBufferView> view; | 505 std::unique_ptr<blink::WebArrayBufferView> view; |
| 497 if (array_buffer) { | 506 if (array_buffer) { |
| 498 data = reinterpret_cast<char*>(array_buffer->data()); | 507 data = reinterpret_cast<char*>(array_buffer->data()); |
| 499 length = array_buffer->byteLength(); | 508 length = array_buffer->byteLength(); |
| 500 } else { | 509 } else { |
| 501 view.reset(blink::WebArrayBufferView::createFromV8Value(val)); | 510 view.reset(blink::WebArrayBufferView::createFromV8Value(val)); |
| 502 if (view) { | 511 if (view) { |
| 503 data = reinterpret_cast<char*>(view->baseAddress()) + view->byteOffset(); | 512 data = reinterpret_cast<char*>(view->baseAddress()) + view->byteOffset(); |
| 504 length = view->byteLength(); | 513 length = view->byteLength(); |
| 505 } | 514 } |
| 506 } | 515 } |
| 507 | 516 |
| 508 if (data) | 517 if (data) |
| 509 return base::BinaryValue::CreateWithCopiedBuffer(data, length); | 518 return base::WrapUnique( |
| 519 base::BinaryValue::CreateWithCopiedBuffer(data, length)); |
| 510 else | 520 else |
| 511 return NULL; | 521 return nullptr; |
| 512 } | 522 } |
| 513 | 523 |
| 514 base::Value* V8ValueConverterImpl::FromV8Object( | 524 std::unique_ptr<base::Value> V8ValueConverterImpl::FromV8Object( |
| 515 v8::Local<v8::Object> val, | 525 v8::Local<v8::Object> val, |
| 516 FromV8ValueState* state, | 526 FromV8ValueState* state, |
| 517 v8::Isolate* isolate) const { | 527 v8::Isolate* isolate) const { |
| 518 ScopedUniquenessGuard uniqueness_guard(state, val); | 528 ScopedUniquenessGuard uniqueness_guard(state, val); |
| 519 if (!uniqueness_guard.is_valid()) | 529 if (!uniqueness_guard.is_valid()) |
| 520 return base::Value::CreateNullValue().release(); | 530 return base::Value::CreateNullValue(); |
| 521 | 531 |
| 522 std::unique_ptr<v8::Context::Scope> scope; | 532 std::unique_ptr<v8::Context::Scope> scope; |
| 523 // If val was created in a different context than our current one, change to | 533 // If val was created in a different context than our current one, change to |
| 524 // that context, but change back after val is converted. | 534 // that context, but change back after val is converted. |
| 525 if (!val->CreationContext().IsEmpty() && | 535 if (!val->CreationContext().IsEmpty() && |
| 526 val->CreationContext() != isolate->GetCurrentContext()) | 536 val->CreationContext() != isolate->GetCurrentContext()) |
| 527 scope.reset(new v8::Context::Scope(val->CreationContext())); | 537 scope.reset(new v8::Context::Scope(val->CreationContext())); |
| 528 | 538 |
| 529 if (strategy_) { | 539 if (strategy_) { |
| 530 // These base::Unretained's are safe, because Strategy::FromV8Value should | 540 // These base::Unretained's are safe, because Strategy::FromV8Value should |
| 531 // be synchronous, so this object can't be out of scope. | 541 // be synchronous, so this object can't be out of scope. |
| 532 V8ValueConverter::Strategy::FromV8ValueCallback callback = | 542 V8ValueConverter::Strategy::FromV8ValueCallback callback = |
| 533 base::Bind(&V8ValueConverterImpl::FromV8ValueImpl, | 543 base::Bind(&V8ValueConverterImpl::FromV8ValueImpl, |
| 534 base::Unretained(this), | 544 base::Unretained(this), |
| 535 base::Unretained(state)); | 545 base::Unretained(state)); |
| 536 base::Value* out = NULL; | 546 std::unique_ptr<base::Value> out; |
| 537 if (strategy_->FromV8Object(val, &out, isolate, callback)) | 547 if (strategy_->FromV8Object(val, &out, isolate, callback)) |
| 538 return out; | 548 return out; |
| 539 } | 549 } |
| 540 | 550 |
| 541 // Don't consider DOM objects. This check matches isHostObject() in Blink's | 551 // Don't consider DOM objects. This check matches isHostObject() in Blink's |
| 542 // bindings/v8/V8Binding.h used in structured cloning. It reads: | 552 // bindings/v8/V8Binding.h used in structured cloning. It reads: |
| 543 // | 553 // |
| 544 // If the object has any internal fields, then we won't be able to serialize | 554 // If the object has any internal fields, then we won't be able to serialize |
| 545 // or deserialize them; conveniently, this is also a quick way to detect DOM | 555 // or deserialize them; conveniently, this is also a quick way to detect DOM |
| 546 // wrapper objects, because the mechanism for these relies on data stored in | 556 // wrapper objects, because the mechanism for these relies on data stored in |
| 547 // these fields. | 557 // these fields. |
| 548 // | 558 // |
| 549 // NOTE: check this after |strategy_| so that callers have a chance to | 559 // NOTE: check this after |strategy_| so that callers have a chance to |
| 550 // do something else, such as convert to the node's name rather than NULL. | 560 // do something else, such as convert to the node's name rather than NULL. |
| 551 // | 561 // |
| 552 // ANOTHER NOTE: returning an empty dictionary here to minimise surprise. | 562 // ANOTHER NOTE: returning an empty dictionary here to minimise surprise. |
| 553 // See also http://crbug.com/330559. | 563 // See also http://crbug.com/330559. |
| 554 if (val->InternalFieldCount()) | 564 if (val->InternalFieldCount()) |
| 555 return new base::DictionaryValue(); | 565 return base::MakeUnique<base::DictionaryValue>(); |
| 556 | 566 |
| 557 std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue()); | 567 std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue()); |
| 558 v8::Local<v8::Array> property_names(val->GetOwnPropertyNames()); | 568 v8::Local<v8::Array> property_names(val->GetOwnPropertyNames()); |
| 559 | 569 |
| 560 for (uint32_t i = 0; i < property_names->Length(); ++i) { | 570 for (uint32_t i = 0; i < property_names->Length(); ++i) { |
| 561 v8::Local<v8::Value> key(property_names->Get(i)); | 571 v8::Local<v8::Value> key(property_names->Get(i)); |
| 562 | 572 |
| 563 // Extend this test to cover more types as necessary and if sensible. | 573 // Extend this test to cover more types as necessary and if sensible. |
| 564 if (!key->IsString() && | 574 if (!key->IsString() && |
| 565 !key->IsNumber()) { | 575 !key->IsNumber()) { |
| 566 NOTREACHED() << "Key \"" << *v8::String::Utf8Value(key) << "\" " | 576 NOTREACHED() << "Key \"" << *v8::String::Utf8Value(key) << "\" " |
| 567 "is neither a string nor a number"; | 577 "is neither a string nor a number"; |
| 568 continue; | 578 continue; |
| 569 } | 579 } |
| 570 | 580 |
| 571 v8::String::Utf8Value name_utf8(key); | 581 v8::String::Utf8Value name_utf8(key); |
| 572 | 582 |
| 573 v8::TryCatch try_catch(isolate); | 583 v8::TryCatch try_catch(isolate); |
| 574 v8::Local<v8::Value> child_v8 = val->Get(key); | 584 v8::Local<v8::Value> child_v8 = val->Get(key); |
| 575 | 585 |
| 576 if (try_catch.HasCaught()) { | 586 if (try_catch.HasCaught()) { |
| 577 LOG(WARNING) << "Getter for property " << *name_utf8 | 587 LOG(WARNING) << "Getter for property " << *name_utf8 |
| 578 << " threw an exception."; | 588 << " threw an exception."; |
| 579 child_v8 = v8::Null(isolate); | 589 child_v8 = v8::Null(isolate); |
| 580 } | 590 } |
| 581 | 591 |
| 582 std::unique_ptr<base::Value> child( | 592 std::unique_ptr<base::Value> child = |
| 583 FromV8ValueImpl(state, child_v8, isolate)); | 593 FromV8ValueImpl(state, child_v8, isolate); |
| 584 if (!child) | 594 if (!child) |
| 585 // JSON.stringify skips properties whose values don't serialize, for | 595 // JSON.stringify skips properties whose values don't serialize, for |
| 586 // example undefined and functions. Emulate that behavior. | 596 // example undefined and functions. Emulate that behavior. |
| 587 continue; | 597 continue; |
| 588 | 598 |
| 589 // Strip null if asked (and since undefined is turned into null, undefined | 599 // Strip null if asked (and since undefined is turned into null, undefined |
| 590 // too). The use case for supporting this is JSON-schema support, | 600 // too). The use case for supporting this is JSON-schema support, |
| 591 // specifically for extensions, where "optional" JSON properties may be | 601 // specifically for extensions, where "optional" JSON properties may be |
| 592 // represented as null, yet due to buggy legacy code elsewhere isn't | 602 // represented as null, yet due to buggy legacy code elsewhere isn't |
| 593 // treated as such (potentially causing crashes). For example, the | 603 // treated as such (potentially causing crashes). For example, the |
| 594 // "tabs.create" function takes an object as its first argument with an | 604 // "tabs.create" function takes an object as its first argument with an |
| 595 // optional "windowId" property. | 605 // optional "windowId" property. |
| 596 // | 606 // |
| 597 // Given just | 607 // Given just |
| 598 // | 608 // |
| 599 // tabs.create({}) | 609 // tabs.create({}) |
| 600 // | 610 // |
| 601 // this will work as expected on code that only checks for the existence of | 611 // this will work as expected on code that only checks for the existence of |
| 602 // a "windowId" property (such as that legacy code). However given | 612 // a "windowId" property (such as that legacy code). However given |
| 603 // | 613 // |
| 604 // tabs.create({windowId: null}) | 614 // tabs.create({windowId: null}) |
| 605 // | 615 // |
| 606 // there *is* a "windowId" property, but since it should be an int, code | 616 // there *is* a "windowId" property, but since it should be an int, code |
| 607 // on the browser which doesn't additionally check for null will fail. | 617 // on the browser which doesn't additionally check for null will fail. |
| 608 // We can avoid all bugs related to this by stripping null. | 618 // We can avoid all bugs related to this by stripping null. |
| 609 if (strip_null_from_objects_ && child->IsType(base::Value::TYPE_NULL)) | 619 if (strip_null_from_objects_ && child->IsType(base::Value::TYPE_NULL)) |
| 610 continue; | 620 continue; |
| 611 | 621 |
| 612 result->SetWithoutPathExpansion(std::string(*name_utf8, name_utf8.length()), | 622 result->SetWithoutPathExpansion(std::string(*name_utf8, name_utf8.length()), |
| 613 child.release()); | 623 std::move(child)); |
| 614 } | 624 } |
| 615 | 625 |
| 616 return result.release(); | 626 return std::move(result); |
| 617 } | 627 } |
| 618 | 628 |
| 619 } // namespace content | 629 } // namespace content |
| OLD | NEW |