Index: chrome/renderer/extensions/extension_dispatcher.cc |
diff --git a/chrome/renderer/extensions/extension_dispatcher.cc b/chrome/renderer/extensions/extension_dispatcher.cc |
index 23c57e46c3f9e365fbdd7f291a281bea697cb7b0..4d187bb295513a57c5802683623c61e561d873eb 100644 |
--- a/chrome/renderer/extensions/extension_dispatcher.cc |
+++ b/chrome/renderer/extensions/extension_dispatcher.cc |
@@ -4,7 +4,10 @@ |
#include "chrome/renderer/extensions/extension_dispatcher.h" |
+#include "base/callback.h" |
#include "base/command_line.h" |
+#include "base/memory/scoped_ptr.h" |
+#include "base/string_piece.h" |
#include "chrome/common/child_process_logging.h" |
#include "chrome/common/chrome_switches.h" |
#include "chrome/common/extensions/extension.h" |
@@ -22,6 +25,9 @@ |
#include "chrome/renderer/extensions/schema_generated_bindings.h" |
#include "chrome/renderer/extensions/user_script_slave.h" |
#include "chrome/renderer/extensions/webstore_bindings.h" |
+#include "chrome/renderer/module_system.h" |
+#include "chrome/renderer/native_handler.h" |
+#include "chrome/renderer/resource_bundle_source_map.h" |
#include "content/public/renderer/render_thread.h" |
#include "grit/renderer_resources.h" |
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDataSource.h" |
@@ -35,9 +41,34 @@ |
#include "ui/base/resource/resource_bundle.h" |
#include "v8/include/v8.h" |
+#include "chrome/renderer/extensions/chrome_private_custom_bindings.h" |
+#include "chrome/renderer/extensions/context_menus_custom_bindings.h" |
+#include "chrome/renderer/extensions/experimental.socket_custom_bindings.h" |
+#include "chrome/renderer/extensions/extension_custom_bindings.h" |
+#include "chrome/renderer/extensions/file_browser_handler_custom_bindings.h" |
+#include "chrome/renderer/extensions/file_browser_private_custom_bindings.h" |
+#include "chrome/renderer/extensions/i18n_custom_bindings.h" |
+#include "chrome/renderer/extensions/page_actions_custom_bindings.h" |
+#include "chrome/renderer/extensions/page_capture_custom_bindings.h" |
+#include "chrome/renderer/extensions/tabs_custom_bindings.h" |
+#include "chrome/renderer/extensions/tts_custom_bindings.h" |
+#include "chrome/renderer/extensions/web_request_custom_bindings.h" |
+ |
using content::RenderThread; |
+using extensions::ChromePrivateCustomBindings; |
+using extensions::ContextMenusCustomBindings; |
+using extensions::ExperimentalSocketCustomBindings; |
+using extensions::ExtensionCustomBindings; |
+using extensions::FileBrowserHandlerCustomBindings; |
+using extensions::FileBrowserPrivateCustomBindings; |
+using extensions::I18NCustomBindings; |
using extensions::MiscellaneousBindings; |
+using extensions::PageActionsCustomBindings; |
+using extensions::PageCaptureCustomBindings; |
using extensions::SchemaGeneratedBindings; |
+using extensions::TTSCustomBindings; |
+using extensions::TabsCustomBindings; |
+using extensions::WebRequestCustomBindings; |
using WebKit::WebDataSource; |
using WebKit::WebDocument; |
using WebKit::WebFrame; |
@@ -60,13 +91,83 @@ ChromeV8Context::ContextType ExtensionGroupToContextType(int extension_group) { |
return ChromeV8Context::OTHER; |
} |
+class ChromeHiddenNativeHandler : public NativeHandler { |
+ public: |
+ ChromeHiddenNativeHandler() { |
+ RouteFunction("GetChromeHidden", |
+ base::Bind(&ChromeHiddenNativeHandler::GetChromeHidden, |
+ base::Unretained(this))); |
+ } |
+ |
+ v8::Handle<v8::Value> GetChromeHidden(const v8::Arguments& args) { |
+ return ChromeV8Context::GetOrCreateChromeHidden(v8::Context::GetCurrent()); |
+ } |
+}; |
+ |
+class PrintNativeHandler : public NativeHandler { |
+ public: |
+ PrintNativeHandler() { |
+ RouteFunction("Print", |
+ base::Bind(&PrintNativeHandler::Print, |
+ base::Unretained(this))); |
+ } |
+ |
+ 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(); |
+ } |
+}; |
+ |
+class ContextInfoNativeHandler : public NativeHandler { |
+ public: |
+ explicit ContextInfoNativeHandler(ExtensionDispatcher* extension_dispatcher, |
+ bool is_bindings_allowed, |
+ WebKit::WebFrame* frame, |
+ int world_id) |
+ : extension_dispatcher_(extension_dispatcher), |
+ is_bindings_allowed_(is_bindings_allowed), |
+ frame_(frame), |
+ world_id_(world_id) { |
+ RouteFunction("IsBindingsAllowed", |
+ base::Bind(&ContextInfoNativeHandler::IsBindingsAllowed, |
+ base::Unretained(this))); |
+ RouteFunction("IsAPIAllowed", |
+ base::Bind(&ContextInfoNativeHandler::IsAPIAllowed, |
+ base::Unretained(this))); |
+ } |
+ |
+ v8::Handle<v8::Value> IsBindingsAllowed(const v8::Arguments& args) { |
+ return v8::Boolean::New(is_bindings_allowed_); |
+ } |
+ |
+ v8::Handle<v8::Value> IsAPIAllowed(const v8::Arguments& args) { |
+ std::string custom_api_name = *v8::String::AsciiValue(args[0]->ToString()); |
+ return v8::Boolean::New(extension_dispatcher_->AllowCustomAPI( |
+ frame_, custom_api_name, world_id_)); |
+ } |
+ |
+ private: |
+ ExtensionDispatcher* extension_dispatcher_; |
+ bool is_bindings_allowed_; |
+ WebKit::WebFrame* frame_; |
+ int world_id_; |
+}; |
+ |
} |
ExtensionDispatcher::ExtensionDispatcher() |
: is_webkit_initialized_(false), |
webrequest_adblock_(false), |
webrequest_adblock_plus_(false), |
- webrequest_other_(false) { |
+ webrequest_other_(false), |
+ source_map_(&ResourceBundle::GetSharedInstance()) { |
const CommandLine& command_line = *(CommandLine::ForCurrentProcess()); |
is_extension_process_ = |
command_line.HasSwitch(switches::kExtensionProcess) || |
@@ -78,6 +179,7 @@ ExtensionDispatcher::ExtensionDispatcher() |
} |
user_script_slave_.reset(new UserScriptSlave(&extensions_)); |
+ PopulateSourceMap(); |
} |
ExtensionDispatcher::~ExtensionDispatcher() { |
@@ -115,24 +217,6 @@ void ExtensionDispatcher::WebKitInitialized() { |
RenderThread::Get(), &RenderThread::IdleHandler); |
} |
- RegisterExtension(new AppBindings(this), false); |
- RegisterExtension(new WebstoreBindings(this), 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 = 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(); |
@@ -300,53 +384,121 @@ bool ExtensionDispatcher::AllowScriptExtension( |
int extension_group, |
int world_id) { |
g_hack_extension_group = extension_group; |
+ return true; |
+} |
- // 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; |
- |
- // Extension-only bindings should be restricted to content scripts and |
- // extension-blessed URLs. |
- ChromeV8Context::ContextType context_type = |
- ExtensionGroupToContextType(extension_group); |
- |
- if (context_type == ChromeV8Context::CONTENT_SCRIPT || |
- extensions_.ExtensionBindingsAllowed(ExtensionURLInfo( |
- frame->document().securityOrigin(), |
- 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 = 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 util::AllowAPIInjection(custom_binding_api_name, *extension, this); |
- } |
- |
+bool ExtensionDispatcher::AllowCustomAPI( |
+ WebFrame* frame, |
+ const std::string& custom_binding_api_name, |
+ int world_id) { |
+ std::string extension_id = GetExtensionID(frame, world_id); |
+ if (IsTestExtensionId(extension_id)) |
return true; |
+ 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 false; |
+ return util::AllowAPIInjection( |
+ custom_binding_api_name, *extension, this); |
+} |
+ |
+void ExtensionDispatcher::RegisterNativeHandlers(ModuleSystem* module_system, |
+ ChromeV8Context* context) { |
+ module_system->RegisterNativeHandler("app", |
+ scoped_ptr<NativeHandler>(new AppBindings(this, context))); |
+ module_system->RegisterNativeHandler("webstore", |
+ scoped_ptr<NativeHandler>(new WebstoreBindings(this, context))); |
+ module_system->RegisterNativeHandler("event_bindings", |
+ scoped_ptr<NativeHandler>(EventBindings::Get(this))); |
+ module_system->RegisterNativeHandler("miscellaneous_bindings", |
+ scoped_ptr<NativeHandler>(MiscellaneousBindings::Get(this))); |
+ module_system->RegisterNativeHandler("schema_generated_bindings", |
+ scoped_ptr<NativeHandler>(SchemaGeneratedBindings::Get(this))); |
+ |
+ // Custom bindings. |
+ module_system->RegisterNativeHandler("chrome_private", |
+ scoped_ptr<NativeHandler>( |
+ new ChromePrivateCustomBindings(this))); |
+ module_system->RegisterNativeHandler("context_menus", |
+ scoped_ptr<NativeHandler>(new ContextMenusCustomBindings())); |
+ module_system->RegisterNativeHandler("extension", |
+ scoped_ptr<NativeHandler>( |
+ new ExtensionCustomBindings(this))); |
+ module_system->RegisterNativeHandler("experimental_socket", |
+ scoped_ptr<NativeHandler>(new ExperimentalSocketCustomBindings())); |
+ module_system->RegisterNativeHandler("file_browser_handler", |
+ scoped_ptr<NativeHandler>(new FileBrowserHandlerCustomBindings())); |
+ module_system->RegisterNativeHandler("file_browser_private", |
+ scoped_ptr<NativeHandler>(new FileBrowserPrivateCustomBindings())); |
+ module_system->RegisterNativeHandler("i18n", |
+ scoped_ptr<NativeHandler>(new I18NCustomBindings())); |
+ module_system->RegisterNativeHandler("page_actions", |
+ scoped_ptr<NativeHandler>( |
+ new PageActionsCustomBindings(this))); |
+ module_system->RegisterNativeHandler("page_capture", |
+ scoped_ptr<NativeHandler>(new PageCaptureCustomBindings())); |
+ module_system->RegisterNativeHandler("tabs", |
+ scoped_ptr<NativeHandler>(new TabsCustomBindings())); |
+ module_system->RegisterNativeHandler("tts", |
+ scoped_ptr<NativeHandler>(new TTSCustomBindings())); |
+ module_system->RegisterNativeHandler("web_request", |
+ scoped_ptr<NativeHandler>(new WebRequestCustomBindings())); |
+} |
+ |
+void ExtensionDispatcher::PopulateSourceMap() { |
+ source_map_.RegisterSource("app", IDR_APP_BINDINGS_JS); |
+ source_map_.RegisterSource("webstore", IDR_WEBSTORE_BINDINGS_JS); |
+ source_map_.RegisterSource("event_bindings", IDR_EVENT_BINDINGS_JS); |
+ source_map_.RegisterSource("miscellaneous_bindings", |
+ IDR_MISCELLANEOUS_BINDINGS_JS); |
+ source_map_.RegisterSource("schema_generated_bindings", |
+ IDR_SCHEMA_GENERATED_BINDINGS_JS); |
+ source_map_.RegisterSource("json_schema", IDR_JSON_SCHEMA_JS); |
+ source_map_.RegisterSource("apitest", IDR_EXTENSION_APITEST_JS); |
+ source_map_.RegisterSource("setup_bindings", IDR_SETUP_BINDINGS_JS); |
+ |
+ // Custom bindings. |
+ source_map_.RegisterSource("browserAction", |
+ IDR_BROWSER_ACTION_CUSTOM_BINDINGS_JS); |
+ source_map_.RegisterSource("chromePrivate", |
+ IDR_CHROME_PRIVATE_CUSTOM_BINDINGS_JS); |
+ source_map_.RegisterSource("contentSettings", |
+ IDR_CONTENT_SETTINGS_CUSTOM_BINDINGS_JS); |
+ source_map_.RegisterSource("contextMenus", |
+ IDR_CONTEXT_MENUS_CUSTOM_BINDINGS_JS); |
+ source_map_.RegisterSource("devtools", IDR_DEVTOOLS_CUSTOM_BINDINGS_JS); |
+ source_map_.RegisterSource("experimental.declarative", |
+ IDR_EXPERIMENTAL_DECLARATIVE_CUSTOM_BINDINGS_JS); |
+ source_map_.RegisterSource("experimental.socket", |
+ IDR_EXPERIMENTAL_SOCKET_CUSTOM_BINDINGS_JS); |
+ source_map_.RegisterSource("extension", IDR_EXTENSION_CUSTOM_BINDINGS_JS); |
+ source_map_.RegisterSource("fileBrowserHandler", |
+ IDR_FILE_BROWSER_HANDLER_CUSTOM_BINDINGS_JS); |
+ source_map_.RegisterSource("fileBrowserPrivate", |
+ IDR_FILE_BROWSER_PRIVATE_CUSTOM_BINDINGS_JS); |
+ source_map_.RegisterSource("i18n", IDR_I18N_CUSTOM_BINDINGS_JS); |
+ source_map_.RegisterSource("input.ime", IDR_INPUT_IME_CUSTOM_BINDINGS_JS); |
+ source_map_.RegisterSource("omnibox", IDR_OMNIBOX_CUSTOM_BINDINGS_JS); |
+ source_map_.RegisterSource("pageActions", |
+ IDR_PAGE_ACTIONS_CUSTOM_BINDINGS_JS); |
+ source_map_.RegisterSource("pageAction", IDR_PAGE_ACTION_CUSTOM_BINDINGS_JS); |
+ source_map_.RegisterSource("pageCapture", |
+ IDR_PAGE_CAPTURE_CUSTOM_BINDINGS_JS); |
+ source_map_.RegisterSource("storage", IDR_STORAGE_CUSTOM_BINDINGS_JS); |
+ source_map_.RegisterSource("tabs", IDR_TABS_CUSTOM_BINDINGS_JS); |
+ source_map_.RegisterSource("tts", IDR_TTS_CUSTOM_BINDINGS_JS); |
+ source_map_.RegisterSource("ttsEngine", IDR_TTS_ENGINE_CUSTOM_BINDINGS_JS); |
+ source_map_.RegisterSource("types", IDR_TYPES_CUSTOM_BINDINGS_JS); |
+ source_map_.RegisterSource("webRequest", IDR_WEB_REQUEST_CUSTOM_BINDINGS_JS); |
} |
void ExtensionDispatcher::DidCreateScriptContext( |
@@ -355,19 +507,59 @@ void ExtensionDispatcher::DidCreateScriptContext( |
// TODO(koz): If the caller didn't pass extension_group, use the last value. |
if (extension_group == -1) |
extension_group = g_hack_extension_group; |
+ |
+ std::string extension_id = GetExtensionID(frame, world_id); |
ChromeV8Context* context = |
new ChromeV8Context( |
v8_context, |
frame, |
- GetExtensionID(frame, world_id), |
+ extension_id, |
ExtensionGroupToContextType(extension_group)); |
v8_context_set_.Add(context); |
+ scoped_ptr<ModuleSystem> module_system(new ModuleSystem(&source_map_)); |
+ RegisterNativeHandlers(module_system.get(), context); |
+ |
+ bool is_bindings_allowed = |
+ IsTestExtensionId(extension_id) || |
+ context->context_type() == ChromeV8Context::CONTENT_SCRIPT || |
+ extensions_.ExtensionBindingsAllowed(ExtensionURLInfo( |
+ frame->document().securityOrigin(), |
+ UserScriptSlave::GetDataSourceURLForFrame(frame))); |
+ |
+ module_system->RegisterNativeHandler("chrome_hidden", |
+ scoped_ptr<NativeHandler>(new ChromeHiddenNativeHandler())); |
+ module_system->RegisterNativeHandler("context_info", |
+ scoped_ptr<NativeHandler>(new ContextInfoNativeHandler( |
+ this, |
+ is_bindings_allowed, |
+ frame, |
+ world_id))); |
+ module_system->RegisterNativeHandler("print", |
+ scoped_ptr<NativeHandler>(new PrintNativeHandler())); |
+ |
const Extension* extension = extensions_.GetByID(context->extension_id()); |
int manifest_version = 1; |
if (extension) |
manifest_version = extension->manifest_version(); |
+ // Create the 'chrome' variable if it doesn't already exist. |
+ { |
+ v8::HandleScope handle_scope; |
+ v8::Handle<v8::String> chrome_string(v8::String::New("chrome")); |
+ v8::Handle<v8::Object> global(v8::Context::GetCurrent()->Global()); |
+ if (global->Get(chrome_string)->IsUndefined()) |
+ global->Set(chrome_string, v8::Object::New()); |
+ } |
+ module_system->Require("app"); |
+ module_system->Require("webstore"); |
+ if (is_bindings_allowed) { |
+ module_system->Require("setup_bindings"); |
+ } |
+ module_system->set_natives_enabled(false); |
+ |
+ context->set_module_system(module_system.Pass()); |
+ |
context->DispatchOnLoadEvent( |
is_extension_process_, |
ChromeRenderProcessObserver::is_incognito_process(), |
@@ -398,12 +590,6 @@ void ExtensionDispatcher::WillReleaseScriptContext( |
context->DispatchOnUnloadEvent(); |
- ChromeV8Extension::InstanceSet extensions = ChromeV8Extension::GetAll(); |
- for (ChromeV8Extension::InstanceSet::const_iterator iter = extensions.begin(); |
- iter != extensions.end(); ++iter) { |
- (*iter)->ContextWillBeReleased(context); |
- } |
- |
v8_context_set_.Remove(context); |
VLOG(1) << "Num tracked contexts: " << v8_context_set_.size(); |
} |
@@ -413,7 +599,7 @@ void ExtensionDispatcher::SetTestExtensionId(const std::string& id) { |
} |
bool ExtensionDispatcher::IsTestExtensionId(const std::string& id) { |
- return id == test_extension_id_; |
+ return !test_extension_id_.empty() && id == test_extension_id_; |
} |
void ExtensionDispatcher::OnActivateApplication( |