summaryrefslogtreecommitdiffstats
path: root/chrome/renderer/extensions
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/renderer/extensions')
-rw-r--r--chrome/renderer/extensions/bindings_utils.cc20
-rw-r--r--chrome/renderer/extensions/bindings_utils.h10
-rw-r--r--chrome/renderer/extensions/event_bindings.cc13
-rw-r--r--chrome/renderer/extensions/event_bindings.h2
-rw-r--r--chrome/renderer/extensions/extension_api_client_unittest.cc7
-rw-r--r--chrome/renderer/extensions/extension_process_bindings.cc10
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);
}