Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(242)

Unified Diff: chrome/renderer/extensions/extension_dispatcher.cc

Issue 9386001: Implement a module system for the extension bindings JS. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/renderer/extensions/extension_dispatcher.cc
diff --git a/chrome/renderer/extensions/extension_dispatcher.cc b/chrome/renderer/extensions/extension_dispatcher.cc
index 88ba39b0dfaf6e1455252b19273b875896d5bf31..5bbadbbe601ef8fc12c439fd2c471a2cb4278ace 100644
--- a/chrome/renderer/extensions/extension_dispatcher.cc
+++ b/chrome/renderer/extensions/extension_dispatcher.cc
@@ -34,11 +34,103 @@
#include "ui/base/resource/resource_bundle.h"
#include "v8/include/v8.h"
+#include <iostream>
+using namespace std;
+
namespace {
+
static const int64 kInitialExtensionIdleHandlerDelayMs = 5*1000;
static const int64 kMaxExtensionIdleHandlerDelayMs = 5*60*1000;
+
+v8::Local<v8::Value> Run(v8::Handle<v8::String> code) {
+ return v8::Script::New(code)->Run();
+}
+
+const char* GetResource(int resourceId) {
+ const ResourceBundle& resource_bundle = ResourceBundle::GetSharedInstance();
+ return resource_bundle.GetRawDataResource(resourceId).as_string().c_str();
+}
+
+v8::Local<v8::Value> Run(int resourceId) {
+ return Run(v8::String::New(GetResource(resourceId)));
}
+v8::Handle<v8::Value> Execute(const v8::Arguments& args) {
+ v8::Handle<v8::String> code = v8::Handle<v8::String>::Cast(args[0]);
+ return Run(code);
+}
+
+v8::Handle<v8::Value> GetSource(const v8::Arguments& args) {
+ static std::map<std::string, std::string>* js_source_map = NULL;
+ if (js_source_map == NULL) {
+ js_source_map = new std::map<std::string, std::string>();
+
+ (*js_source_map)["app"] = GetResource(IDR_APP_BINDINGS_JS);
+ (*js_source_map)["webstore"] = GetResource(IDR_WEBSTORE_BINDINGS_JS);
+
+ (*js_source_map)["json_schema"] = GetResource(IDR_JSON_SCHEMA_JS);
+ (*js_source_map)["event_bindings"] = GetResource(IDR_EVENT_BINDINGS_JS);
+ (*js_source_map)["miscellaneous_bindings"] =
+ GetResource(IDR_MISCELLANEOUS_BINDINGS_JS);
+ (*js_source_map)["schema_generated_bindings"] =
+ GetResource(IDR_SCHEMA_GENERATED_BINDINGS_JS);
+ (*js_source_map)["apitest"] =
+ GetResource(IDR_EXTENSION_APITEST_JS);
+
+ // Custom hooks.
+ (*js_source_map)["custom/browserAction"] =
+ GetResource(IDR_BROWSER_ACTION_CUSTOM_BINDINGS_JS);
+ (*js_source_map)["custom/chromePrivate"] =
+ GetResource(IDR_CHROME_PRIVATE_CUSTOM_BINDINGS_JS);
+ (*js_source_map)["custom/contentSettings"] =
+ GetResource(IDR_CONTENT_SETTINGS_CUSTOM_BINDINGS_JS);
+ (*js_source_map)["custom/contextMenus"] =
+ GetResource(IDR_CONTEXT_MENUS_CUSTOM_BINDINGS_JS);
+ (*js_source_map)["custom/devtools"] =
+ GetResource(IDR_DEVTOOLS_CUSTOM_BINDINGS_JS);
+ (*js_source_map)["custom/extension"] =
+ GetResource(IDR_EXTENSION_CUSTOM_BINDINGS_JS);
+ (*js_source_map)["custom/fileBrowserHandler"] =
+ GetResource(IDR_FILE_BROWSER_HANDLER_CUSTOM_BINDINGS_JS);
+ (*js_source_map)["custom/fileBrowserPrivateHandler"] =
+ GetResource(IDR_FILE_BROWSER_PRIVATE_CUSTOM_BINDINGS_JS);
+ (*js_source_map)["custom/input.ime"] =
+ GetResource(IDR_INPUT_IME_CUSTOM_BINDINGS_JS);
+ (*js_source_map)["custom/omnibox"] =
+ GetResource(IDR_OMNIBOX_CUSTOM_BINDINGS_JS);
+ (*js_source_map)["custom/pageAction"] =
+ GetResource(IDR_PAGE_ACTION_CUSTOM_BINDINGS_JS);
+ (*js_source_map)["custom/pageActions"] =
+ GetResource(IDR_PAGE_ACTIONS_CUSTOM_BINDINGS_JS);
+ (*js_source_map)["custom/pageCapture"] =
+ GetResource(IDR_PAGE_CAPTURE_CUSTOM_BINDINGS_JS);
+ (*js_source_map)["custom/socket"] =
+ GetResource(IDR_EXPERIMENTAL_SOCKET_CUSTOM_BINDINGS_JS);
+ (*js_source_map)["custom/storage"] =
+ GetResource(IDR_STORAGE_CUSTOM_BINDINGS_JS);
+ (*js_source_map)["custom/tabs"] =
+ GetResource(IDR_TABS_CUSTOM_BINDINGS_JS);
+ (*js_source_map)["custom/tts"] =
+ GetResource(IDR_TTS_CUSTOM_BINDINGS_JS);
+ (*js_source_map)["custom/ttsEngine"] =
+ GetResource(IDR_TTS_ENGINE_CUSTOM_BINDINGS_JS);
+ (*js_source_map)["custom/types"] =
+ GetResource(IDR_TYPES_CUSTOM_BINDINGS_JS);
+ (*js_source_map)["custom/webRequest"] =
+ GetResource(IDR_WEB_REQUEST_CUSTOM_BINDINGS_JS);
+ (*js_source_map)["custom/windows"] =
+ GetResource(IDR_WINDOWS_CUSTOM_BINDINGS_JS);
+ }
+ std::string module_name = *v8::String::Utf8Value(args[0]->ToString());
+ if (js_source_map->count(module_name) == 0) {
+ return v8::Undefined();
+ }
+ v8::HandleScope scope;
+ return scope.Close(v8::String::New((*js_source_map)[module_name].c_str()));
+}
+
+} // namespace
+
using namespace extensions;
using WebKit::WebDataSource;
@@ -102,25 +194,6 @@ void ExtensionDispatcher::WebKitInitialized() {
RenderThread::Get(), &RenderThread::IdleHandler);
}
- RegisterExtension(new AppBindings(this), false);
- RegisterExtension(ChromeWebstoreExtension::Get(), false);
-
- // Add v8 extensions related to chrome extensions.
- RegisterExtension(new ChromeV8Extension(
- "extensions/json_schema.js", IDR_JSON_SCHEMA_JS, NULL), true);
- RegisterExtension(EventBindings::Get(this), true);
- RegisterExtension(MiscellaneousBindings::Get(this), true);
- RegisterExtension(SchemaGeneratedBindings::Get(this), true);
- RegisterExtension(new ChromeV8Extension(
- "extensions/apitest.js", IDR_EXTENSION_APITEST_JS, NULL), true);
-
- std::vector<v8::Extension*> custom_bindings =
- custom_bindings_util::GetAll(this);
- for (std::vector<v8::Extension*>::iterator it = custom_bindings.begin();
- it != custom_bindings.end(); ++it) {
- RegisterExtension(*it, true);
- }
-
// Initialize host permissions for any extensions that were activated before
// WebKit was initialized.
for (std::set<std::string>::iterator iter = active_extension_ids_.begin();
@@ -277,18 +350,17 @@ bool ExtensionDispatcher::AllowScriptExtension(
const std::string& v8_extension_name,
int extension_group,
int world_id) {
- // NULL in unit tests.
- if (!RenderThread::Get())
- return true;
-
- // If we don't know about it, it was added by WebCore, so we should allow it.
- if (!RenderThread::Get()->IsRegisteredExtension(v8_extension_name))
- return true;
-
- // If the V8 extension is not restricted, allow it to run anywhere.
- if (!restricted_v8_extensions_.count(v8_extension_name))
- return true;
+ // We haven't registered any extensions, so this must have been added by
+ // WebCore.
+ // TODO(koz): Have WebCore not ask us and delete this function.
+ return true;
+}
+bool ExtensionDispatcher::AllowAPI(
+ WebFrame* frame,
+ const std::string& module_name,
+ int extension_group,
+ int world_id) {
// Extension-only bindings should be restricted to content scripts and
// extension-blessed URLs.
if (extension_group == EXTENSION_GROUP_CONTENT_SCRIPTS ||
@@ -297,50 +369,162 @@ bool ExtensionDispatcher::AllowScriptExtension(
UserScriptSlave::GetDataSourceURLForFrame(frame)))) {
// If the extension is a custom API binding, only allow if the extension
// has permission to use the API.
- std::string custom_binding_api_name =
- custom_bindings_util::GetAPIName(v8_extension_name);
- if (!custom_binding_api_name.empty()) {
- std::string extension_id = GetExtensionID(frame, world_id);
- const Extension* extension = extensions_.GetByID(extension_id);
- if (!extension) {
- // This can happen when a resource is blocked due to CSP; a valid
- // chrome-extension:// URL is navigated to, so it passes the initial
- // checks, but the URL gets changed to "chrome-extension://invalid"
- // afterwards (see chrome_content_renderer_client.cc). An extension
- // page still gets loaded, just for the extension with ID "invalid",
- // which of course isn't found so GetById extension will be NULL.
- //
- // Reference: http://crbug.com/111614.
- CHECK_EQ("invalid", extension_id);
- return false;
- }
- return custom_bindings_util::AllowAPIInjection(
- custom_binding_api_name, *extension);
+ std::string extension_id = GetExtensionID(frame, world_id);
+ const Extension* extension = extensions_.GetByID(extension_id);
+ if (!extension) {
+ // This can happen when a resource is blocked due to CSP; a valid
+ // chrome-extension:// URL is navigated to, so it passes the initial
+ // checks, but the URL gets changed to "chrome-extension://invalid"
+ // afterwards (see chrome_content_renderer_client.cc). An extension
+ // page still gets loaded, just for the extension with ID "invalid",
+ // which of course isn't found so GetById extension will be NULL.
+ //
+ // Reference: http://crbug.com/111614.
+ CHECK_EQ("invalid", extension_id);
+ return false;
}
-
- return true;
+ return custom_bindings_util::AllowAPIInjection(
+ module_name, *extension);
}
return false;
}
+class GlobalFunctions : public ChromeV8Extension {
+ public:
+ GlobalFunctions(ExtensionDispatcher* dispatcher,
+ WebFrame* frame,
+ int extension_group,
+ int world_id)
+ : ChromeV8Extension("blah", 0, dispatcher),
+ frame_(frame),
+ extension_group_(extension_group),
+ world_id_(world_id) {}
+
+ // ChromeV8Extension
+ virtual void SetNativeFunctions(v8::Handle<v8::Object> object) OVERRIDE {
+ RouteFunctionHere("AllowAPI", object);
+ RouteFunctionToStatic("GetChromeHidden", GetChromeHidden, object);
+ RouteFunctionToStatic("Print", Print, object);
+ }
+
+ v8::Handle<v8::Value> HandleNativeFunction(const std::string& name,
+ const v8::Arguments& args) OVERRIDE {
+ CHECK(!name.empty());
+ if (name == "AllowAPI") {
+ return AllowAPI(args);
+ } else {
+ CHECK(false) << "Unknown native function: '" << name << "'" << endl;
+ }
+ return v8::Undefined();
+ }
+
+ v8::Handle<v8::Value> AllowAPI(const v8::Arguments& args) {
+ std::string api_name = *v8::String::AsciiValue(args[0]);
+ return v8::Boolean::New(extension_dispatcher_->AllowAPI(frame_,
+ api_name, extension_group_, world_id_));
+ }
+
+ static v8::Handle<v8::Value> GetChromeHidden(const v8::Arguments& args) {
+ return ChromeV8Context::GetOrCreateChromeHidden(v8::Context::GetCurrent());
+ }
+
+ static v8::Handle<v8::Value> Print(const v8::Arguments& args) {
+ if (args.Length() < 1)
+ return v8::Undefined();
+
+ std::vector<std::string> components;
+ for (int i = 0; i < args.Length(); ++i)
+ components.push_back(*v8::String::Utf8Value(args[i]->ToString()));
+
+ LOG(ERROR) << JoinString(components, ',');
+ return v8::Undefined();
+ }
+
+ private:
+ WebFrame* frame_;
+ int extension_group_;
+ int world_id_;
+};
+
+v8::Handle<v8::Object> ExtensionDispatcher::BuildBrowserObject(
+ ChromeV8Context* context) {
+ v8::Persistent<v8::Object> browser =
+ v8::Persistent<v8::Object>::New(v8::Object::New());
+
+ browser->Set(v8::String::NewSymbol("Execute"),
+ v8::FunctionTemplate::New(Execute)->GetFunction());
+ browser->Set(v8::String::NewSymbol("GetSource"),
+ v8::FunctionTemplate::New(GetSource)->GetFunction());
+ browser->Set(v8::String::NewSymbol("natives"), context->natives());
+ RegisterExtensions(context);
+ return browser;
+}
+
+void ExtensionDispatcher::RegisterExtensions(ChromeV8Context* context) {
+ context->RegisterExtension(new AppBindings(this, context));
+ context->RegisterExtension(ChromeWebstoreExtension::Get(this));
+ context->RegisterExtension(EventBindings::Get(this));
+ context->RegisterExtension(MiscellaneousBindings::Get(this));
+ context->RegisterExtension(SchemaGeneratedBindings::Get(this));
+
+ std::vector<ChromeV8Extension*> extensions =
+ custom_bindings_util::GetAll(this);
+ for (std::vector<ChromeV8Extension*>::iterator i = extensions.begin();
+ i != extensions.end(); i++) {
+ context->RegisterExtension(*i);
+ }
+}
+
void ExtensionDispatcher::DidCreateScriptContext(
- WebFrame* frame, v8::Handle<v8::Context> v8_context, int world_id) {
+ WebFrame* frame, v8::Handle<v8::Context> v8_context, int extension_group,
+ int world_id) {
+ ExtensionURLInfo thing(
+ frame->document().securityOrigin(),
+ UserScriptSlave::GetDataSourceURLForFrame(frame));
+ std::string extension_id = GetExtensionID(frame, world_id);
ChromeV8Context* context =
- new ChromeV8Context(v8_context, frame, GetExtensionID(frame, world_id));
+ new ChromeV8Context(v8_context, frame, extension_id);
v8_context_set_.Add(context);
+ SetupAPIBindings(context, frame, extension_group, world_id);
+
+ VLOG(1) << "Num tracked contexts: " << v8_context_set_.size();
+}
+
+void ExtensionDispatcher::SetupAPIBindings(ChromeV8Context* context,
+ WebFrame* frame,
+ int extension_group,
+ int world_id) {
+ context->RegisterExtension(new GlobalFunctions(this, context->web_frame(),
+ extension_group, world_id));
const Extension* extension = extensions_.GetByID(context->extension_id());
int manifest_version = 1;
if (extension)
manifest_version = extension->manifest_version();
- context->DispatchOnLoadEvent(
- is_extension_process_,
- ChromeRenderProcessObserver::is_incognito_process(),
- manifest_version);
+ Run(v8::String::New("var chrome = {};"));
+ v8::Local<v8::Value> result = Run(IDR_BOOTSTRAP_JS);
+ v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(result);
- VLOG(1) << "Num tracked contexts: " << v8_context_set_.size();
+ v8::Handle<v8::Object> browser = BuildBrowserObject(context);
+
+ bool allow_extension_apis =
+ extension_group == EXTENSION_GROUP_CONTENT_SCRIPTS ||
+ extensions_.ExtensionBindingsAllowed(ExtensionURLInfo(
+ frame->document().securityOrigin(),
+ UserScriptSlave::GetDataSourceURLForFrame(frame)));
+
+ v8::Handle<v8::Value> argv[] = {
+ v8::Local<v8::Value>::New(browser),
+ v8::String::New(context->extension_id().c_str()),
+ v8::Boolean::New(is_extension_process_),
+ v8::Boolean::New(ChromeRenderProcessObserver::is_incognito_process()),
+ v8::Integer::New(manifest_version),
+ v8::Boolean::New(allow_extension_apis)
+ };
+
+ f->Call(v8::Context::GetCurrent()->Global(), arraysize(argv), argv);
}
std::string ExtensionDispatcher::GetExtensionID(WebFrame* frame, int world_id) {

Powered by Google App Engine
This is Rietveld 408576698