diff options
Diffstat (limited to 'chrome/renderer/extensions')
-rw-r--r-- | chrome/renderer/extensions/bindings_utils.cc | 20 | ||||
-rw-r--r-- | chrome/renderer/extensions/bindings_utils.h | 10 | ||||
-rw-r--r-- | chrome/renderer/extensions/event_bindings.cc | 13 | ||||
-rw-r--r-- | chrome/renderer/extensions/event_bindings.h | 2 | ||||
-rw-r--r-- | chrome/renderer/extensions/extension_api_client_unittest.cc | 7 | ||||
-rw-r--r-- | chrome/renderer/extensions/extension_process_bindings.cc | 10 |
6 files changed, 49 insertions, 13 deletions
diff --git a/chrome/renderer/extensions/bindings_utils.cc b/chrome/renderer/extensions/bindings_utils.cc index 13deb2a..d96f8d7 100644 --- a/chrome/renderer/extensions/bindings_utils.cc +++ b/chrome/renderer/extensions/bindings_utils.cc @@ -13,6 +13,7 @@ using WebKit::WebFrame; namespace bindings_utils { const char* kChromeHidden = "chromeHidden"; +const char* kValidateCallbacks = "validateCallbacks"; struct SingletonData { ContextList contexts; @@ -40,6 +41,13 @@ v8::Handle<v8::Value> ExtensionBase::GetChromeHidden( if (hidden.IsEmpty() || hidden->IsUndefined()) { hidden = v8::Object::New(); global->SetHiddenValue(v8::String::New(kChromeHidden), hidden); + +#ifdef _DEBUG + // Tell extension_process_bindings.js to validate callbacks and events + // against their schema definitions in api/extension_api.json. + v8::Local<v8::Object>::Cast(hidden) + ->Set(v8::String::New(kValidateCallbacks), v8::True()); +#endif } DCHECK(hidden->IsObject()); @@ -94,9 +102,9 @@ RenderView* GetRenderViewForCurrentContext() { return renderview; } -void CallFunctionInContext(v8::Handle<v8::Context> context, - const std::string& function_name, int argc, - v8::Handle<v8::Value>* argv) { +v8::Handle<v8::Value> CallFunctionInContext(v8::Handle<v8::Context> context, + const std::string& function_name, int argc, + v8::Handle<v8::Value>* argv) { v8::Context::Scope context_scope(context); // Look up the function name, which may be a sub-property like @@ -111,12 +119,14 @@ void CallFunctionInContext(v8::Handle<v8::Context> context, } if (value.IsEmpty() || !value->IsFunction()) { NOTREACHED(); - return; + return v8::Undefined(); } v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(value); if (!function.IsEmpty()) - function->Call(v8::Object::New(), argc, argv); + return function->Call(v8::Object::New(), argc, argv); + + return v8::Undefined(); } } // namespace bindings_utils diff --git a/chrome/renderer/extensions/bindings_utils.h b/chrome/renderer/extensions/bindings_utils.h index 604cb2c..7354c72 100644 --- a/chrome/renderer/extensions/bindings_utils.h +++ b/chrome/renderer/extensions/bindings_utils.h @@ -106,10 +106,12 @@ RenderView* GetRenderViewForCurrentContext(); // Call the named javascript function with the given arguments in a context. // The function name should be reachable from the chromeHidden object, and can -// be a sub-property like "Port.dispatchOnMessage". -void CallFunctionInContext(v8::Handle<v8::Context> context, - const std::string& function_name, int argc, - v8::Handle<v8::Value>* argv); +// be a sub-property like "Port.dispatchOnMessage". Returns the result of +// the function call. If an exception is thrown an empty Handle will be +// returned. +v8::Handle<v8::Value> CallFunctionInContext(v8::Handle<v8::Context> context, + const std::string& function_name, int argc, + v8::Handle<v8::Value>* argv); } // namespace bindings_utils diff --git a/chrome/renderer/extensions/event_bindings.cc b/chrome/renderer/extensions/event_bindings.cc index 5003b82..b2cecdc 100644 --- a/chrome/renderer/extensions/event_bindings.cc +++ b/chrome/renderer/extensions/event_bindings.cc @@ -287,6 +287,17 @@ void EventBindings::CallFunction(const std::string& function_name, it != GetContexts().end(); ++it) { if (render_view && render_view != (*it)->render_view) continue; - CallFunctionInContext((*it)->context, function_name, argc, argv); + v8::Handle<v8::Value> retval = CallFunctionInContext((*it)->context, + function_name, argc, argv); + // In debug, the js will validate the event parameters and return a + // string if a validation error has occured. + // TODO(rafaelw): Consider only doing this check if function_name == + // "Event.dispatchJSON". +#ifdef _DEBUG + if (!retval.IsEmpty() && !retval->IsUndefined()) { + std::string error = *v8::String::AsciiValue(retval); + DCHECK(false) << error; + } +#endif } } diff --git a/chrome/renderer/extensions/event_bindings.h b/chrome/renderer/extensions/event_bindings.h index 022fe09..736cb8a 100644 --- a/chrome/renderer/extensions/event_bindings.h +++ b/chrome/renderer/extensions/event_bindings.h @@ -35,6 +35,8 @@ class EventBindings { // events. If render_view is non-NULL, only call the function in contexts // belonging to that view. See comments on // bindings_utils::CallFunctionInContext for more details. + // The called javascript function should not return a value other than + // v8::Undefined(). A DCHECK is setup to break if it is otherwise. static void CallFunction(const std::string& function_name, int argc, v8::Handle<v8::Value>* argv, RenderView* render_view); diff --git a/chrome/renderer/extensions/extension_api_client_unittest.cc b/chrome/renderer/extensions/extension_api_client_unittest.cc index 49136c5..d5f73bb 100644 --- a/chrome/renderer/extensions/extension_api_client_unittest.cc +++ b/chrome/renderer/extensions/extension_api_client_unittest.cc @@ -71,7 +71,9 @@ TEST_F(ExtensionAPIClientTest, CallbackDispatching) { "}" "function callback(result) {" " assert(typeof result == 'object', 'result not object');" - " assert(JSON.stringify(result) == '{\"foo\":\"bar\"}', " + " assert(JSON.stringify(result) == '{\"id\":1,\"index\":1,\"windowId\":1," + "\"selected\":true," + "\"url\":\"http://www.google.com/\"}'," " 'incorrect result');" " console.log('pass')" "}" @@ -92,7 +94,8 @@ TEST_F(ExtensionAPIClientTest, CallbackDispatching) { // Now send the callback a response ExtensionProcessBindings::HandleResponse( - callback_id, true, "{\"foo\":\"bar\"}", ""); + callback_id, true, "{\"id\":1,\"index\":1,\"windowId\":1,\"selected\":true," + "\"url\":\"http://www.google.com/\"}", ""); // And verify that it worked ASSERT_EQ("pass", GetConsoleMessage()); diff --git a/chrome/renderer/extensions/extension_process_bindings.cc b/chrome/renderer/extensions/extension_process_bindings.cc index 8d07d82..d28adb0 100644 --- a/chrome/renderer/extensions/extension_process_bindings.cc +++ b/chrome/renderer/extensions/extension_process_bindings.cc @@ -298,8 +298,16 @@ void ExtensionProcessBindings::HandleResponse(int request_id, bool success, argv[2] = v8::Boolean::New(success); argv[3] = v8::String::New(response.c_str()); argv[4] = v8::String::New(error.c_str()); - bindings_utils::CallFunctionInContext( + v8::Handle<v8::Value> retval = bindings_utils::CallFunctionInContext( request->second->context, "handleResponse", arraysize(argv), argv); + // In debug, the js will validate the callback parameters and return a + // string if a validation error has occured. +#ifdef _DEBUG + if (!retval.IsEmpty() && !retval->IsUndefined()) { + std::string error = *v8::String::AsciiValue(retval); + DCHECK(false) << error; + } +#endif pending_requests.erase(request); } |