Move CEF V8 internal attributes to hidden values and add a test to verify safety (issue #316).
git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@361 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
parent
53a2f21ba4
commit
ae5371dd09
|
@ -2508,7 +2508,6 @@ public:
|
|||
// OBJECT METHODS - These methods are only available on objects. Arrays and
|
||||
// functions are also objects. String- and integer-based keys can be used
|
||||
// interchangably with the framework converting between them as necessary.
|
||||
// Keys beginning with "Cef::" and "v8::" are reserved by the system.
|
||||
|
||||
///
|
||||
// Returns true if the object has a value with the specified identifier.
|
||||
|
|
|
@ -2226,7 +2226,6 @@ typedef struct _cef_v8value_t
|
|||
// OBJECT METHODS - These functions are only available on objects. Arrays and
|
||||
// functions are also objects. String- and integer-based keys can be used
|
||||
// interchangably with the framework converting between them as necessary.
|
||||
// Keys beginning with "Cef::" and "v8::" are reserved by the system.
|
||||
|
||||
///
|
||||
// Returns true (1) if the object has a value with the specified identifier.
|
||||
|
|
|
@ -13,13 +13,13 @@
|
|||
|
||||
#define CEF_REQUIRE_UI_THREAD(var) \
|
||||
if (!CefThread::CurrentlyOn(CefThread::UI)) { \
|
||||
NOTREACHED(); \
|
||||
NOTREACHED() << "called on invalid thread"; \
|
||||
return var; \
|
||||
}
|
||||
|
||||
#define CEF_REQUIRE_VALID_CONTEXT(var) \
|
||||
if (!CONTEXT_STATE_VALID()) { \
|
||||
NOTREACHED(); \
|
||||
NOTREACHED() << "context not valid"; \
|
||||
return var; \
|
||||
}
|
||||
|
||||
|
@ -29,9 +29,6 @@ namespace {
|
|||
static const char kCefAccessor[] = "Cef::Accessor";
|
||||
static const char kCefHandler[] = "Cef::Handler";
|
||||
static const char kCefUserData[] = "Cef::UserData";
|
||||
static const v8::PropertyAttribute kInternalAttributes =
|
||||
static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontEnum |
|
||||
v8::DontDelete);
|
||||
|
||||
// Memory manager.
|
||||
|
||||
|
@ -209,14 +206,8 @@ v8::Handle<v8::Value> AccessorGetterCallbackImpl(v8::Local<v8::String> property,
|
|||
v8::HandleScope handle_scope;
|
||||
|
||||
v8::Handle<v8::Object> obj = info.This();
|
||||
v8::Handle<v8::String> key = v8::String::New(kCefAccessor);
|
||||
|
||||
CefV8Accessor* accessorPtr = NULL;
|
||||
if (obj->Has(key)) {
|
||||
accessorPtr = static_cast<CefV8Accessor*>(v8::External::Unwrap(
|
||||
obj->Get(key)));
|
||||
}
|
||||
|
||||
CefV8Accessor* accessorPtr = CefV8ValueImpl::GetAccessor(obj);
|
||||
if (accessorPtr) {
|
||||
CefRefPtr<CefV8Value> retval;
|
||||
CefRefPtr<CefV8Value> object = new CefV8ValueImpl(obj);
|
||||
|
@ -244,14 +235,8 @@ void AccessorSetterCallbackImpl(v8::Local<v8::String> property,
|
|||
v8::HandleScope handle_scope;
|
||||
|
||||
v8::Handle<v8::Object> obj = info.This();
|
||||
v8::Handle<v8::String> key = v8::String::New(kCefAccessor);
|
||||
|
||||
CefV8Accessor* accessorPtr = NULL;
|
||||
if (obj->Has(key)) {
|
||||
accessorPtr = static_cast<CefV8Accessor*>(v8::External::Unwrap(
|
||||
obj->Get(key)));
|
||||
}
|
||||
|
||||
CefV8Accessor* accessorPtr = CefV8ValueImpl::GetAccessor(obj);
|
||||
if (accessorPtr) {
|
||||
CefRefPtr<CefV8Value> object = new CefV8ValueImpl(obj);
|
||||
CefRefPtr<CefV8Value> cefValue = new CefV8ValueImpl(value);
|
||||
|
@ -554,13 +539,13 @@ CefRefPtr<CefV8Value> CefV8Value::CreateObject(
|
|||
// Attach the user data to the V8 object.
|
||||
if (user_data.get()) {
|
||||
v8::Local<v8::Value> data = v8::External::Wrap(user_data.get());
|
||||
obj->Set(v8::String::New(kCefUserData), data, kInternalAttributes);
|
||||
obj->SetHiddenValue(v8::String::New(kCefUserData), data);
|
||||
}
|
||||
|
||||
// Attach the accessor to the V8 object.
|
||||
if (accessor.get()) {
|
||||
v8::Local<v8::Value> data = v8::External::Wrap(accessor.get());
|
||||
obj->Set(v8::String::New(kCefAccessor), data, kInternalAttributes);
|
||||
obj->SetHiddenValue(v8::String::New(kCefAccessor), data);
|
||||
}
|
||||
|
||||
return new CefV8ValueImpl(obj, tracker);
|
||||
|
@ -578,16 +563,21 @@ CefRefPtr<CefV8Value> CefV8Value::CreateArray()
|
|||
|
||||
// static
|
||||
CefRefPtr<CefV8Value> CefV8Value::CreateFunction(const CefString& name,
|
||||
CefRefPtr<CefV8Handler> handler)
|
||||
CefRefPtr<CefV8Handler> handler)
|
||||
{
|
||||
CEF_REQUIRE_VALID_CONTEXT(NULL);
|
||||
CEF_REQUIRE_UI_THREAD(NULL);
|
||||
|
||||
if (!handler.get()) {
|
||||
NOTREACHED() << "invalid parameter";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
v8::HandleScope handle_scope;
|
||||
|
||||
// Create a new V8 function template with one internal field.
|
||||
v8::Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
|
||||
|
||||
|
||||
v8::Local<v8::Value> data = v8::External::Wrap(handler.get());
|
||||
|
||||
// Set the function handler callback.
|
||||
|
@ -598,7 +588,7 @@ CefRefPtr<CefV8Value> CefV8Value::CreateFunction(const CefString& name,
|
|||
func->SetName(GetV8String(name));
|
||||
|
||||
// Attach the handler instance to the V8 object.
|
||||
func->Set(v8::String::New(kCefHandler), data, kInternalAttributes);
|
||||
func->SetHiddenValue(v8::String::New(kCefHandler), data);
|
||||
|
||||
// Create the CefV8ValueImpl and provide a tracker object that will cause
|
||||
// the handler reference to be released when the V8 object is destroyed.
|
||||
|
@ -746,8 +736,6 @@ CefString CefV8ValueImpl::GetStringValue()
|
|||
bool CefV8ValueImpl::HasValue(const CefString& key)
|
||||
{
|
||||
CEF_REQUIRE_UI_THREAD(false);
|
||||
if(IsReservedKey(key))
|
||||
return false;
|
||||
if(!GetHandle()->IsObject()) {
|
||||
NOTREACHED();
|
||||
return false;
|
||||
|
@ -774,8 +762,6 @@ bool CefV8ValueImpl::HasValue(int index)
|
|||
bool CefV8ValueImpl::DeleteValue(const CefString& key)
|
||||
{
|
||||
CEF_REQUIRE_UI_THREAD(false);
|
||||
if(IsReservedKey(key))
|
||||
return false;
|
||||
if(!GetHandle()->IsObject()) {
|
||||
NOTREACHED();
|
||||
return false;
|
||||
|
@ -802,8 +788,6 @@ bool CefV8ValueImpl::DeleteValue(int index)
|
|||
CefRefPtr<CefV8Value> CefV8ValueImpl::GetValue(const CefString& key)
|
||||
{
|
||||
CEF_REQUIRE_UI_THREAD(NULL);
|
||||
if(IsReservedKey(key))
|
||||
return NULL;
|
||||
if(!GetHandle()->IsObject()) {
|
||||
NOTREACHED();
|
||||
return NULL;
|
||||
|
@ -832,8 +816,6 @@ bool CefV8ValueImpl::SetValue(const CefString& key,
|
|||
PropertyAttribute attribute)
|
||||
{
|
||||
CEF_REQUIRE_UI_THREAD(false);
|
||||
if(IsReservedKey(key))
|
||||
return false;
|
||||
if(!GetHandle()->IsObject()) {
|
||||
NOTREACHED();
|
||||
return false;
|
||||
|
@ -886,6 +868,10 @@ bool CefV8ValueImpl::SetValue(const CefString& key, AccessControl settings,
|
|||
v8::HandleScope handle_scope;
|
||||
v8::Local<v8::Object> obj = GetHandle()->ToObject();
|
||||
|
||||
// Verify that an accessor exists for this object.
|
||||
if (!GetAccessor(obj))
|
||||
return false;
|
||||
|
||||
v8::AccessorGetter getter = AccessorGetterCallbackImpl;
|
||||
v8::AccessorSetter setter = (attribute & V8_PROPERTY_ATTRIBUTE_READONLY) ?
|
||||
NULL : AccessorSetterCallbackImpl;
|
||||
|
@ -912,8 +898,7 @@ bool CefV8ValueImpl::GetKeys(std::vector<CefString>& keys)
|
|||
v8::Local<v8::Value> value = arr_keys->Get(v8::Integer::New(i));
|
||||
CefString str;
|
||||
GetCefString(value->ToString(), str);
|
||||
if(!IsReservedKey(str))
|
||||
keys.push_back(str);
|
||||
keys.push_back(str);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -928,9 +913,12 @@ CefRefPtr<CefBase> CefV8ValueImpl::GetUserData()
|
|||
|
||||
v8::HandleScope handle_scope;
|
||||
v8::Local<v8::Object> obj = GetHandle()->ToObject();
|
||||
v8::Local<v8::String> key = v8::String::New(kCefUserData);
|
||||
if(obj->Has(key))
|
||||
return static_cast<CefBase*>(v8::External::Unwrap(obj->Get(key)));
|
||||
|
||||
v8::Local<v8::Value> value =
|
||||
obj->GetHiddenValue(v8::String::New(kCefUserData));
|
||||
if (!value.IsEmpty())
|
||||
return static_cast<CefBase*>(v8::External::Unwrap(value));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -974,9 +962,12 @@ CefRefPtr<CefV8Handler> CefV8ValueImpl::GetFunctionHandler()
|
|||
|
||||
v8::HandleScope handle_scope;
|
||||
v8::Local<v8::Object> obj = GetHandle()->ToObject();
|
||||
v8::Local<v8::String> key = v8::String::New(kCefHandler);
|
||||
if (obj->Has(key))
|
||||
return static_cast<CefV8Handler*>(v8::External::Unwrap(obj->Get(key)));
|
||||
|
||||
v8::Local<v8::Value> value =
|
||||
obj->GetHiddenValue(v8::String::New(kCefHandler));
|
||||
if (!value.IsEmpty())
|
||||
return static_cast<CefV8Handler*>(v8::External::Unwrap(value));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1052,8 +1043,13 @@ bool CefV8ValueImpl::ExecuteFunctionWithContext(
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CefV8ValueImpl::IsReservedKey(const CefString& key)
|
||||
// static
|
||||
CefV8Accessor* CefV8ValueImpl::GetAccessor(v8::Handle<v8::Object> object)
|
||||
{
|
||||
std::string str = key;
|
||||
return (str.find("Cef::") == 0 || str.find("v8::") == 0);
|
||||
v8::Local<v8::Value> value =
|
||||
object->GetHiddenValue(v8::String::New(kCefAccessor));
|
||||
if (!value.IsEmpty())
|
||||
return static_cast<CefV8Accessor*>(v8::External::Unwrap(value));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -158,7 +158,8 @@ public:
|
|||
return v8_value_->GetHandle();
|
||||
}
|
||||
|
||||
bool IsReservedKey(const CefString& key);
|
||||
// Returns the accessor assigned for the specified object, if any.
|
||||
static CefV8Accessor* GetAccessor(v8::Handle<v8::Object> object);
|
||||
|
||||
protected:
|
||||
scoped_refptr<CefV8ValueHandle> v8_value_;
|
||||
|
|
|
@ -935,3 +935,472 @@ TEST(V8Test, Context)
|
|||
EXPECT_TRUE(handler->got_navigation_);
|
||||
EXPECT_TRUE(handler->got_testcomplete_);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class TestInternalHandler : public TestHandler
|
||||
{
|
||||
public:
|
||||
class UserData : public CefBase
|
||||
{
|
||||
public:
|
||||
UserData(CefRefPtr<TestInternalHandler> test)
|
||||
: test_(test)
|
||||
{
|
||||
}
|
||||
|
||||
void Test(const std::string& name)
|
||||
{
|
||||
if (name == "obj1-before") {
|
||||
if (test_->nav_ == 0)
|
||||
test_->got_userdata_obj1_before_test1_fail_.yes();
|
||||
else
|
||||
test_->got_userdata_obj1_before_test2_fail_.yes();
|
||||
} else if (name == "obj2-before") {
|
||||
if (test_->nav_ == 0)
|
||||
test_->got_userdata_obj2_before_test1_.yes();
|
||||
else
|
||||
test_->got_userdata_obj2_before_test2_fail_.yes();
|
||||
}else if (name == "obj1-after") {
|
||||
if (test_->nav_ == 0)
|
||||
test_->got_userdata_obj1_after_test1_fail_.yes();
|
||||
else
|
||||
test_->got_userdata_obj1_after_test2_fail_.yes();
|
||||
} else if (name == "obj2-after") {
|
||||
if (test_->nav_ == 0)
|
||||
test_->got_userdata_obj2_after_test1_.yes();
|
||||
else
|
||||
test_->got_userdata_obj2_after_test2_fail_.yes();
|
||||
}
|
||||
}
|
||||
|
||||
CefRefPtr<TestInternalHandler> test_;
|
||||
|
||||
IMPLEMENT_REFCOUNTING(UserData);
|
||||
};
|
||||
|
||||
class Accessor : public CefV8Accessor
|
||||
{
|
||||
public:
|
||||
Accessor(CefRefPtr<TestInternalHandler> test)
|
||||
: test_(test)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool Get(const CefString& name,
|
||||
const CefRefPtr<CefV8Value> object,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception) OVERRIDE
|
||||
{
|
||||
if (test_->nav_ == 0)
|
||||
test_->got_accessor_get1_.yes();
|
||||
else
|
||||
test_->got_accessor_get2_fail_.yes();
|
||||
|
||||
retval = CefV8Value::CreateString("default2");
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool Set(const CefString& name,
|
||||
const CefRefPtr<CefV8Value> object,
|
||||
const CefRefPtr<CefV8Value> value,
|
||||
CefString& exception) OVERRIDE
|
||||
{
|
||||
if (test_->nav_ == 0)
|
||||
test_->got_accessor_set1_.yes();
|
||||
else
|
||||
test_->got_accessor_set2_fail_.yes();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CefRefPtr<TestInternalHandler> test_;
|
||||
|
||||
IMPLEMENT_REFCOUNTING(Accessor);
|
||||
};
|
||||
|
||||
class Handler : public CefV8Handler
|
||||
{
|
||||
public:
|
||||
Handler(CefRefPtr<TestInternalHandler> test)
|
||||
: test_(test),
|
||||
execute_ct_(0)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool Execute(const CefString& name,
|
||||
CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception) OVERRIDE
|
||||
{
|
||||
CefRefPtr<CefV8Handler> handler =
|
||||
object->GetValue("func")->GetFunctionHandler();
|
||||
|
||||
if (execute_ct_ == 0) {
|
||||
if (handler.get() == this)
|
||||
test_->got_execute1_.yes();
|
||||
else
|
||||
test_->got_execute1_fail_.yes();
|
||||
} else {
|
||||
if (handler.get() == this)
|
||||
test_->got_execute2_.yes();
|
||||
else
|
||||
test_->got_execute2_fail_.yes();
|
||||
}
|
||||
|
||||
execute_ct_++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CefRefPtr<TestInternalHandler> test_;
|
||||
int execute_ct_;
|
||||
|
||||
IMPLEMENT_REFCOUNTING(Accessor);
|
||||
};
|
||||
|
||||
class TestHandler : public CefV8Handler
|
||||
{
|
||||
public:
|
||||
TestHandler(CefRefPtr<TestInternalHandler> test)
|
||||
: test_(test)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool Execute(const CefString& name,
|
||||
CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception) OVERRIDE
|
||||
{
|
||||
if (name == "store") {
|
||||
// Store a JSON value.
|
||||
if (arguments.size() == 2 && arguments[0]->IsString() &&
|
||||
arguments[1]->IsString()) {
|
||||
std::string name = arguments[0]->GetStringValue();
|
||||
std::string val = arguments[1]->GetStringValue();
|
||||
if (name == "obj1") {
|
||||
test_->obj1_json_ = val;
|
||||
if (val == "{\"value\":\"testval1\",\"value2\":\"default1\"}")
|
||||
test_->got_obj1_json_.yes();
|
||||
} else if (name == "obj2") {
|
||||
test_->obj2_json_ = val;
|
||||
if (val == "{\"value\":\"testval2\",\"value2\":\"default2\"}")
|
||||
test_->got_obj2_json_.yes();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
retval = CefV8Value::CreateBool(true);
|
||||
return true;
|
||||
}
|
||||
} else if (name == "retrieve") {
|
||||
// Retrieve a JSON value.
|
||||
if (arguments.size() == 1 && arguments[0]->IsString()) {
|
||||
std::string name = arguments[0]->GetStringValue();
|
||||
std::string val;
|
||||
if (name == "obj1")
|
||||
val = test_->obj1_json_;
|
||||
else if (name == "obj2")
|
||||
val = test_->obj2_json_;
|
||||
if (!val.empty()) {
|
||||
retval = CefV8Value::CreateString(val);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if (name == "userdata") {
|
||||
if (arguments.size() == 2 && arguments[0]->IsString() &&
|
||||
arguments[1]->IsObject()) {
|
||||
std::string name = arguments[0]->GetStringValue();
|
||||
CefRefPtr<UserData> userData =
|
||||
reinterpret_cast<UserData*>(arguments[1]->GetUserData().get());
|
||||
if (!userData.get()) {
|
||||
// No UserData object.
|
||||
if (name == "obj1-before") {
|
||||
if (test_->nav_ == 0)
|
||||
test_->got_userdata_obj1_before_null1_.yes();
|
||||
else
|
||||
test_->got_userdata_obj1_before_null2_.yes();
|
||||
} else if (name == "obj2-before") {
|
||||
if (test_->nav_ == 0)
|
||||
test_->got_userdata_obj2_before_null1_fail_.yes();
|
||||
else
|
||||
test_->got_userdata_obj2_before_null2_.yes();
|
||||
} else if (name == "obj1-after") {
|
||||
if (test_->nav_ == 0)
|
||||
test_->got_userdata_obj1_after_null1_.yes();
|
||||
else
|
||||
test_->got_userdata_obj1_after_null2_.yes();
|
||||
} else if (name == "obj2-after") {
|
||||
if (test_->nav_ == 0)
|
||||
test_->got_userdata_obj2_after_null1_fail_.yes();
|
||||
else
|
||||
test_->got_userdata_obj2_after_null2_.yes();
|
||||
}
|
||||
} else {
|
||||
// Call the test function.
|
||||
userData->Test(name);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} else if (name == "record") {
|
||||
if (arguments.size() == 1 && arguments[0]->IsString()) {
|
||||
std::string name = arguments[0]->GetStringValue();
|
||||
if (name == "userdata-obj1-set-succeed") {
|
||||
if (test_->nav_ == 0)
|
||||
test_->got_userdata_obj1_set_succeed1_.yes();
|
||||
else
|
||||
test_->got_userdata_obj1_set_succeed2_.yes();
|
||||
} else if (name == "userdata-obj1-set-except") {
|
||||
if (test_->nav_ == 0)
|
||||
test_->got_userdata_obj1_set_except1_fail_.yes();
|
||||
else
|
||||
test_->got_userdata_obj1_set_except2_fail_.yes();
|
||||
} else if (name == "userdata-obj2-set-succeed") {
|
||||
if (test_->nav_ == 0)
|
||||
test_->got_userdata_obj2_set_succeed1_.yes();
|
||||
else
|
||||
test_->got_userdata_obj2_set_succeed2_.yes();
|
||||
} else if (name == "userdata-obj2-set-except") {
|
||||
if (test_->nav_ == 0)
|
||||
test_->got_userdata_obj2_set_except1_fail_.yes();
|
||||
else
|
||||
test_->got_userdata_obj2_set_except2_fail_.yes();
|
||||
} else if (name == "func-set-succeed") {
|
||||
test_->got_func_set_succeed_.yes();
|
||||
} else if (name == "func-set-except") {
|
||||
test_->got_func_set_except_fail_.yes();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
CefRefPtr<TestInternalHandler> test_;
|
||||
|
||||
IMPLEMENT_REFCOUNTING(Handler);
|
||||
};
|
||||
|
||||
TestInternalHandler()
|
||||
: nav_(0)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void RunTest() OVERRIDE
|
||||
{
|
||||
std::string tests =
|
||||
// Test userdata retrieval.
|
||||
"window.test.userdata('obj1-before', window.obj1);\n"
|
||||
"window.test.userdata('obj2-before', window.obj2);\n"
|
||||
// Test accessors.
|
||||
"window.obj1.value2 = 'newval1';\n"
|
||||
"window.obj2.value2 = 'newval2';\n"
|
||||
"val1 = window.obj1.value2;\n"
|
||||
"val2 = window.obj2.value2;\n"
|
||||
// Test setting the hidden internal values.
|
||||
"try { window.obj1['Cef::UserData'] = 1;\n"
|
||||
"window.obj1['Cef::Accessor'] = 1;\n"
|
||||
"window.test.record('userdata-obj1-set-succeed'); }\n"
|
||||
"catch(e) { window.test.record('userdata-obj1-set-except'); }\n"
|
||||
"try { window.obj2['Cef::UserData'] = 1;\n"
|
||||
"window.obj2['Cef::Accessor'] = 1;\n"
|
||||
"window.test.record('userdata-obj2-set-succeed'); }\n"
|
||||
"catch(e) { window.test.record('userdata-obj2-set-except'); }\n"
|
||||
// Test userdata retrieval after messing with the internal values.
|
||||
"window.test.userdata('obj1-after', window.obj1);\n"
|
||||
"window.test.userdata('obj2-after', window.obj2);\n"
|
||||
// Test accessors after messing with the internal values.
|
||||
"window.obj1.value2 = 'newval1';\n"
|
||||
"window.obj2.value2 = 'newval2';\n"
|
||||
"val1 = window.obj1.value2;\n"
|
||||
"val2 = window.obj2.value2;\n";
|
||||
|
||||
std::stringstream testHtml;
|
||||
|
||||
testHtml <<
|
||||
"<html><body>\n"
|
||||
"<script language=\"JavaScript\">\n"
|
||||
// Serialize the bound values.
|
||||
"window.test.store('obj1', JSON.stringify(window.obj1));\n"
|
||||
"window.test.store('obj2', JSON.stringify(window.obj2));\n"
|
||||
// Run the tests.
|
||||
<< tests.c_str() <<
|
||||
// Test function call.
|
||||
"window.func();\n"
|
||||
// Test setting the hidden internal values.
|
||||
"try { window.func['Cef::Handler'] = 1;\n"
|
||||
"window.test.record('func-set-succeed'); }\n"
|
||||
"catch(e) { window.test.record('func-set-except'); }\n"
|
||||
// Test function call after messing with internal values.
|
||||
"window.func();\n"
|
||||
"</script>\n"
|
||||
"</body></html>";
|
||||
AddResource("http://tests/run1.html", testHtml.str(), "text/html");
|
||||
testHtml.str("");
|
||||
|
||||
testHtml <<
|
||||
"<html><body>\n"
|
||||
"<script language=\"JavaScript\">\n"
|
||||
// Deserialize the bound values.
|
||||
"window.obj1 = JSON.parse(window.test.retrieve('obj1'));\n"
|
||||
"window.obj2 = JSON.parse(window.test.retrieve('obj2'));\n"
|
||||
// Run the tests.
|
||||
<< tests.c_str() <<
|
||||
"</script>\n"
|
||||
"</body></html>";
|
||||
AddResource("http://tests/run2.html", testHtml.str(), "text/html");
|
||||
testHtml.str("");
|
||||
|
||||
CreateBrowser("http://tests/run1.html");
|
||||
}
|
||||
|
||||
virtual void OnLoadEnd(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int httpStatusCode) OVERRIDE
|
||||
{
|
||||
if (nav_ == 0) {
|
||||
// Navigate to the next page.
|
||||
frame->LoadURL("http://tests/run2.html");
|
||||
} else {
|
||||
DestroyTest();
|
||||
}
|
||||
|
||||
nav_++;
|
||||
}
|
||||
|
||||
virtual void OnJSBinding(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefV8Value> object) OVERRIDE
|
||||
{
|
||||
if (nav_ == 0) {
|
||||
// Create an object without any internal values.
|
||||
CefRefPtr<CefV8Value> obj1 = CefV8Value::CreateObject(NULL, NULL);
|
||||
obj1->SetValue("value", CefV8Value::CreateString("testval1"),
|
||||
V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
obj1->SetValue("value2", CefV8Value::CreateString("default1"),
|
||||
V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
object->SetValue("obj1", obj1, V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
|
||||
// Create an object with Cef::Accessor and Cef::UserData internal values.
|
||||
CefRefPtr<CefV8Value> obj2 =
|
||||
CefV8Value::CreateObject(new UserData(this), new Accessor(this));
|
||||
obj2->SetValue("value", CefV8Value::CreateString("testval2"),
|
||||
V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
obj2->SetValue("value2", V8_ACCESS_CONTROL_DEFAULT,
|
||||
V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
object->SetValue("obj2", obj2, V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
|
||||
// Create a function with Cef::Handler internal value.
|
||||
CefRefPtr<CefV8Value> func =
|
||||
CefV8Value::CreateFunction("func", new Handler(this));
|
||||
object->SetValue("func", func, V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
}
|
||||
|
||||
// Used for executing the test.
|
||||
CefRefPtr<CefV8Handler> handler = new TestHandler(this);
|
||||
CefRefPtr<CefV8Value> obj = CefV8Value::CreateObject(NULL, NULL);
|
||||
obj->SetValue("store", CefV8Value::CreateFunction("store", handler),
|
||||
V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
obj->SetValue("retrieve", CefV8Value::CreateFunction("retrieve", handler),
|
||||
V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
obj->SetValue("userdata", CefV8Value::CreateFunction("userdata", handler),
|
||||
V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
obj->SetValue("record", CefV8Value::CreateFunction("record", handler),
|
||||
V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
object->SetValue("test", obj, V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
}
|
||||
|
||||
int nav_;
|
||||
std::string obj1_json_, obj2_json_;
|
||||
|
||||
TrackCallback got_obj1_json_;
|
||||
TrackCallback got_obj2_json_;
|
||||
|
||||
TrackCallback got_userdata_obj1_before_null1_;
|
||||
TrackCallback got_userdata_obj2_before_null1_fail_;
|
||||
TrackCallback got_userdata_obj1_before_test1_fail_;
|
||||
TrackCallback got_userdata_obj2_before_test1_;
|
||||
TrackCallback got_userdata_obj1_set_succeed1_;
|
||||
TrackCallback got_userdata_obj1_set_except1_fail_;
|
||||
TrackCallback got_userdata_obj2_set_succeed1_;
|
||||
TrackCallback got_userdata_obj2_set_except1_fail_;
|
||||
TrackCallback got_userdata_obj1_after_null1_;
|
||||
TrackCallback got_userdata_obj2_after_null1_fail_;
|
||||
TrackCallback got_userdata_obj1_after_test1_fail_;
|
||||
TrackCallback got_userdata_obj2_after_test1_;
|
||||
|
||||
TrackCallback got_userdata_obj1_before_null2_;
|
||||
TrackCallback got_userdata_obj2_before_null2_;
|
||||
TrackCallback got_userdata_obj1_before_test2_fail_;
|
||||
TrackCallback got_userdata_obj2_before_test2_fail_;
|
||||
TrackCallback got_userdata_obj1_set_succeed2_;
|
||||
TrackCallback got_userdata_obj1_set_except2_fail_;
|
||||
TrackCallback got_userdata_obj2_set_succeed2_;
|
||||
TrackCallback got_userdata_obj2_set_except2_fail_;
|
||||
TrackCallback got_userdata_obj1_after_null2_;
|
||||
TrackCallback got_userdata_obj2_after_null2_;
|
||||
TrackCallback got_userdata_obj1_after_test2_fail_;
|
||||
TrackCallback got_userdata_obj2_after_test2_fail_;
|
||||
|
||||
TrackCallback got_accessor_get1_;
|
||||
TrackCallback got_accessor_get2_fail_;
|
||||
TrackCallback got_accessor_set1_;
|
||||
TrackCallback got_accessor_set2_fail_;
|
||||
|
||||
TrackCallback got_execute1_;
|
||||
TrackCallback got_execute1_fail_;
|
||||
TrackCallback got_func_set_succeed_;
|
||||
TrackCallback got_func_set_except_fail_;
|
||||
TrackCallback got_execute2_;
|
||||
TrackCallback got_execute2_fail_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// Test that messing around with CEF internal values doesn't cause crashes.
|
||||
TEST(V8Test, Internal)
|
||||
{
|
||||
CefRefPtr<TestInternalHandler> handler = new TestInternalHandler();
|
||||
handler->ExecuteTest();
|
||||
|
||||
EXPECT_TRUE(handler->got_obj1_json_.isSet());
|
||||
EXPECT_TRUE(handler->got_obj2_json_.isSet());
|
||||
|
||||
EXPECT_TRUE(handler->got_userdata_obj1_before_null1_.isSet());
|
||||
EXPECT_FALSE(handler->got_userdata_obj2_before_null1_fail_.isSet());
|
||||
EXPECT_FALSE(handler->got_userdata_obj1_before_test1_fail_.isSet());
|
||||
EXPECT_TRUE(handler->got_userdata_obj2_before_test1_.isSet());
|
||||
EXPECT_TRUE(handler->got_userdata_obj1_set_succeed1_.isSet());
|
||||
EXPECT_FALSE(handler->got_userdata_obj1_set_except1_fail_.isSet());
|
||||
EXPECT_TRUE(handler->got_userdata_obj2_set_succeed1_.isSet());
|
||||
EXPECT_FALSE(handler->got_userdata_obj2_set_except1_fail_.isSet());
|
||||
EXPECT_TRUE(handler->got_userdata_obj1_after_null1_.isSet());
|
||||
EXPECT_FALSE(handler->got_userdata_obj2_after_null1_fail_.isSet());
|
||||
EXPECT_FALSE(handler->got_userdata_obj1_after_test1_fail_.isSet());
|
||||
EXPECT_TRUE(handler->got_userdata_obj2_after_test1_.isSet());
|
||||
|
||||
EXPECT_TRUE(handler->got_userdata_obj1_before_null2_.isSet());
|
||||
EXPECT_TRUE(handler->got_userdata_obj2_before_null2_.isSet());
|
||||
EXPECT_FALSE(handler->got_userdata_obj1_before_test2_fail_.isSet());
|
||||
EXPECT_FALSE(handler->got_userdata_obj2_before_test2_fail_.isSet());
|
||||
EXPECT_TRUE(handler->got_userdata_obj1_set_succeed2_.isSet());
|
||||
EXPECT_FALSE(handler->got_userdata_obj1_set_except2_fail_.isSet());
|
||||
EXPECT_TRUE(handler->got_userdata_obj2_set_succeed2_.isSet());
|
||||
EXPECT_FALSE(handler->got_userdata_obj2_set_except2_fail_.isSet());
|
||||
EXPECT_TRUE(handler->got_userdata_obj1_after_null2_.isSet());
|
||||
EXPECT_TRUE(handler->got_userdata_obj2_after_null2_.isSet());
|
||||
EXPECT_FALSE(handler->got_userdata_obj1_after_test2_fail_.isSet());
|
||||
EXPECT_FALSE(handler->got_userdata_obj2_after_test2_fail_.isSet());
|
||||
|
||||
EXPECT_TRUE(handler->got_accessor_get1_.isSet());
|
||||
EXPECT_FALSE(handler->got_accessor_get2_fail_.isSet());
|
||||
EXPECT_TRUE(handler->got_accessor_set1_.isSet());
|
||||
EXPECT_FALSE(handler->got_accessor_set2_fail_.isSet());
|
||||
|
||||
EXPECT_TRUE(handler->got_execute1_.isSet());
|
||||
EXPECT_FALSE(handler->got_execute1_fail_.isSet());
|
||||
EXPECT_TRUE(handler->got_execute2_.isSet());
|
||||
EXPECT_FALSE(handler->got_execute2_fail_.isSet());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue