summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
Diffstat (limited to 'content')
-rw-r--r--content/renderer/v8_value_converter_impl.cc67
-rw-r--r--content/renderer/v8_value_converter_impl.h11
-rw-r--r--content/renderer/v8_value_converter_impl_unittest.cc72
-rw-r--r--content/test/unittest_test_suite.cc3
4 files changed, 129 insertions, 24 deletions
diff --git a/content/renderer/v8_value_converter_impl.cc b/content/renderer/v8_value_converter_impl.cc
index 993ee37..20923cc 100644
--- a/content/renderer/v8_value_converter_impl.cc
+++ b/content/renderer/v8_value_converter_impl.cc
@@ -19,14 +19,12 @@ using base::ListValue;
using base::StringValue;
using base::Value;
-
namespace content {
V8ValueConverter* V8ValueConverter::create() {
return new V8ValueConverterImpl();
}
-
-}
+} // namespace content
V8ValueConverterImpl::V8ValueConverterImpl()
: undefined_allowed_(false),
@@ -79,7 +77,8 @@ Value* V8ValueConverterImpl::FromV8Value(
v8::Handle<v8::Context> context) const {
v8::Context::Scope context_scope(context);
v8::HandleScope handle_scope;
- return FromV8ValueImpl(val);
+ std::set<int> unique_set;
+ return FromV8ValueImpl(val, &unique_set);
}
v8::Handle<v8::Value> V8ValueConverterImpl::ToV8ValueImpl(
@@ -180,7 +179,8 @@ v8::Handle<v8::Value> V8ValueConverterImpl::ToArrayBuffer(
return buffer.toV8Value();
}
-Value* V8ValueConverterImpl::FromV8ValueImpl(v8::Handle<v8::Value> val) const {
+Value* V8ValueConverterImpl::FromV8ValueImpl(v8::Handle<v8::Value> val,
+ std::set<int>* unique_set) const {
CHECK(!val.IsEmpty());
if (val->IsNull())
@@ -215,22 +215,37 @@ Value* V8ValueConverterImpl::FromV8ValueImpl(v8::Handle<v8::Value> val) const {
// v8::Value doesn't have a ToArray() method for some reason.
if (val->IsArray())
- return FromV8Array(val.As<v8::Array>());
+ return FromV8Array(val.As<v8::Array>(), unique_set);
if (val->IsObject()) {
BinaryValue* binary_value = FromV8Buffer(val);
if (binary_value) {
return binary_value;
} else {
- return FromV8Object(val->ToObject());
+ return FromV8Object(val->ToObject(), unique_set);
}
}
LOG(ERROR) << "Unexpected v8 value type encountered.";
return Value::CreateNullValue();
}
-ListValue* V8ValueConverterImpl::FromV8Array(v8::Handle<v8::Array> val) const {
+Value* V8ValueConverterImpl::FromV8Array(v8::Handle<v8::Array> val,
+ std::set<int>* unique_set) const {
+ if (unique_set && unique_set->count(val->GetIdentityHash()))
+ return Value::CreateNullValue();
+
+ scoped_ptr<v8::Context::Scope> scope;
+ // If val was created in a different context than our current one, change to
+ // that context, but change back after val is converted.
+ if (!val->CreationContext().IsEmpty() &&
+ val->CreationContext() != v8::Context::GetCurrent())
+ scope.reset(new v8::Context::Scope(val->CreationContext()));
+
ListValue* result = new ListValue();
+
+ if (unique_set)
+ unique_set->insert(val->GetIdentityHash());
+ // Only fields with integer keys are carried over to the ListValue.
for (uint32 i = 0; i < val->Length(); ++i) {
v8::TryCatch try_catch;
v8::Handle<v8::Value> child_v8 = val->Get(i);
@@ -239,12 +254,10 @@ ListValue* V8ValueConverterImpl::FromV8Array(v8::Handle<v8::Array> val) const {
child_v8 = v8::Null();
}
- // TODO(aa): It would be nice to support getters, but we need
- // http://code.google.com/p/v8/issues/detail?id=1342 to do it properly.
if (!val->HasRealIndexedProperty(i))
continue;
- Value* child = FromV8ValueImpl(child_v8);
+ Value* child = FromV8ValueImpl(child_v8, unique_set);
CHECK(child);
result->Append(child);
@@ -277,29 +290,42 @@ base::BinaryValue* V8ValueConverterImpl::FromV8Buffer(
return NULL;
}
-DictionaryValue* V8ValueConverterImpl::FromV8Object(
- v8::Handle<v8::Object> val) const {
+Value* V8ValueConverterImpl::FromV8Object(
+ v8::Handle<v8::Object> val,
+ std::set<int>* unique_set) const {
+ if (unique_set && unique_set->count(val->GetIdentityHash()))
+ return Value::CreateNullValue();
+ scoped_ptr<v8::Context::Scope> scope;
+ // If val was created in a different context than our current one, change to
+ // that context, but change back after val is converted.
+ if (!val->CreationContext().IsEmpty() &&
+ val->CreationContext() != v8::Context::GetCurrent())
+ scope.reset(new v8::Context::Scope(val->CreationContext()));
+
scoped_ptr<DictionaryValue> result(new DictionaryValue());
v8::Handle<v8::Array> property_names(val->GetPropertyNames());
+
+ if (unique_set)
+ unique_set->insert(val->GetIdentityHash());
+
for (uint32 i = 0; i < property_names->Length(); ++i) {
- v8::Handle<v8::String> name(property_names->Get(i).As<v8::String>());
+ v8::Handle<v8::Value> key(property_names->Get(i));
- // TODO(aa): It would be nice to support getters, but we need
- // http://code.google.com/p/v8/issues/detail?id=1342 to do it properly.
- if (!val->HasRealNamedProperty(name))
+ if (!key->IsString() || !val->HasRealNamedProperty(key->ToString()))
continue;
- v8::String::Utf8Value name_utf8(name->ToString());
+ v8::String::Utf8Value name_utf8(key->ToString());
v8::TryCatch try_catch;
- v8::Handle<v8::Value> child_v8 = val->Get(name);
+ v8::Handle<v8::Value> child_v8 = val->Get(key);
+
if (try_catch.HasCaught()) {
LOG(ERROR) << "Getter for property " << *name_utf8
<< " threw an exception.";
child_v8 = v8::Null();
}
- scoped_ptr<Value> child(FromV8ValueImpl(child_v8));
+ scoped_ptr<Value> child(FromV8ValueImpl(child_v8, unique_set));
CHECK(child.get());
// Strip null if asked (and since undefined is turned into null, undefined
@@ -328,5 +354,6 @@ DictionaryValue* V8ValueConverterImpl::FromV8Object(
result->SetWithoutPathExpansion(std::string(*name_utf8, name_utf8.length()),
child.release());
}
+
return result.release();
}
diff --git a/content/renderer/v8_value_converter_impl.h b/content/renderer/v8_value_converter_impl.h
index 7f75899..baf061a 100644
--- a/content/renderer/v8_value_converter_impl.h
+++ b/content/renderer/v8_value_converter_impl.h
@@ -5,6 +5,8 @@
#ifndef CONTENT_RENDERER_V8_VALUE_CONVERTER_IMPL_H_
#define CONTENT_RENDERER_V8_VALUE_CONVERTER_IMPL_H_
+#include <set>
+
#include "base/compiler_specific.h"
#include "content/common/content_export.h"
#include "content/public/renderer/v8_value_converter.h"
@@ -43,15 +45,18 @@ class CONTENT_EXPORT V8ValueConverterImpl : public content::V8ValueConverter {
const base::DictionaryValue* dictionary) const;
v8::Handle<v8::Value> ToArrayBuffer(const base::BinaryValue* value) const;
- base::Value* FromV8ValueImpl(v8::Handle<v8::Value> value) const;
- base::ListValue* FromV8Array(v8::Handle<v8::Array> array) const;
+ base::Value* FromV8ValueImpl(v8::Handle<v8::Value> value,
+ std::set<int>* unique_set) const;
+ base::Value* FromV8Array(v8::Handle<v8::Array> array,
+ std::set<int>* unique_set) const;
// This will convert objects of type ArrayBuffer or any of the
// ArrayBufferView subclasses. The return value will be NULL if |value| is
// not one of these types.
base::BinaryValue* FromV8Buffer(v8::Handle<v8::Value> value) const;
- base::DictionaryValue* FromV8Object(v8::Handle<v8::Object> object) const;
+ base::Value* FromV8Object(v8::Handle<v8::Object> object,
+ std::set<int>* unique_set) const;
// If true, we will convert undefined JavaScript values to null.
bool undefined_allowed_;
diff --git a/content/renderer/v8_value_converter_impl_unittest.cc b/content/renderer/v8_value_converter_impl_unittest.cc
index a56941a..a4e461f 100644
--- a/content/renderer/v8_value_converter_impl_unittest.cc
+++ b/content/renderer/v8_value_converter_impl_unittest.cc
@@ -113,6 +113,7 @@ class V8ValueConverterImplTest : public testing::Test {
static_cast<DictionaryValue*>(
converter.FromV8Value(object, context_)));
ASSERT_TRUE(dictionary.get());
+
Value* temp = NULL;
ASSERT_TRUE(dictionary->Get("test", &temp));
EXPECT_EQ(expected_type, temp->GetType());
@@ -346,3 +347,74 @@ TEST_F(V8ValueConverterImplTest, StripNullFromObjects) {
ASSERT_TRUE(result.get());
EXPECT_EQ(0u, result->size());
}
+
+TEST_F(V8ValueConverterImplTest, RecursiveObjects) {
+ v8::Context::Scope context_scope(context_);
+ v8::HandleScope handle_scope;
+
+ V8ValueConverterImpl converter;
+
+ v8::Handle<v8::Object> object = v8::Object::New().As<v8::Object>();
+ ASSERT_FALSE(object.IsEmpty());
+ object->Set(v8::String::New("foo"), v8::String::New("bar"));
+ object->Set(v8::String::New("obj"), object);
+
+ scoped_ptr<DictionaryValue> object_result(
+ static_cast<DictionaryValue*>(converter.FromV8Value(object, context_)));
+ ASSERT_TRUE(object_result.get());
+ EXPECT_EQ(2u, object_result->size());
+ EXPECT_TRUE(IsNull(object_result.get(), "obj"));
+
+ v8::Handle<v8::Array> array = v8::Array::New().As<v8::Array>();
+ ASSERT_FALSE(array.IsEmpty());
+ array->Set(0, v8::String::New("1"));
+ array->Set(1, array);
+
+ scoped_ptr<ListValue> list_result(
+ static_cast<ListValue*>(converter.FromV8Value(array, context_)));
+ ASSERT_TRUE(list_result.get());
+ EXPECT_EQ(2u, list_result->GetSize());
+ EXPECT_TRUE(IsNull(list_result.get(), 1));
+}
+
+TEST_F(V8ValueConverterImplTest, ObjectGetters) {
+ v8::Context::Scope context_scope(context_);
+ v8::HandleScope handle_scope;
+
+ const char* source = "(function() {"
+ "var a = {};"
+ "a.__defineGetter__('foo', function() { return 'bar'; });"
+ "return a;"
+ "})();";
+
+ v8::Handle<v8::Script> script(v8::Script::New(v8::String::New(source)));
+ v8::Handle<v8::Object> object = script->Run().As<v8::Object>();
+ ASSERT_FALSE(object.IsEmpty());
+
+ V8ValueConverterImpl converter;
+ scoped_ptr<DictionaryValue> result(
+ static_cast<DictionaryValue*>(converter.FromV8Value(object, context_)));
+ ASSERT_TRUE(result.get());
+ EXPECT_EQ(1u, result->size());
+}
+
+TEST_F(V8ValueConverterImplTest, ArrayGetters) {
+ v8::Context::Scope context_scope(context_);
+ v8::HandleScope handle_scope;
+
+ const char* source = "(function() {"
+ "var a = [0];"
+ "a.__defineGetter__(1, function() { return 'bar'; });"
+ "return a;"
+ "})();";
+
+ v8::Handle<v8::Script> script(v8::Script::New(v8::String::New(source)));
+ v8::Handle<v8::Array> array = script->Run().As<v8::Array>();
+ ASSERT_FALSE(array.IsEmpty());
+
+ V8ValueConverterImpl converter;
+ scoped_ptr<ListValue> result(
+ static_cast<ListValue*>(converter.FromV8Value(array, context_)));
+ ASSERT_TRUE(result.get());
+ EXPECT_EQ(2u, result->GetSize());
+}
diff --git a/content/test/unittest_test_suite.cc b/content/test/unittest_test_suite.cc
index 85597d5..fdcd49a 100644
--- a/content/test/unittest_test_suite.cc
+++ b/content/test/unittest_test_suite.cc
@@ -5,6 +5,7 @@
#include "content/public/test/unittest_test_suite.h"
#include "base/logging.h"
+#include "base/rand_util.h"
#include "base/test/test_suite.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebKit.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebKitPlatformSupport.h"
@@ -19,7 +20,7 @@ class UnitTestTestSuite::UnitTestWebKitPlatformSupport
virtual ~UnitTestWebKitPlatformSupport() {}
virtual void cryptographicallyRandomValues(unsigned char* buffer,
size_t length) OVERRIDE {
- memset(buffer, 0, length);
+ base::RandBytes(buffer, length);
}
virtual const unsigned char* getTraceCategoryEnabledFlag(
const char* categoryName) {