summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions/extension_function_dispatcher.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/extensions/extension_function_dispatcher.cc')
-rw-r--r--chrome/browser/extensions/extension_function_dispatcher.cc178
1 files changed, 119 insertions, 59 deletions
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc
index 8a27836..6a69d42 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.cc
+++ b/chrome/browser/extensions/extension_function_dispatcher.cc
@@ -30,6 +30,7 @@
#include "chrome/browser/extensions/extension_omnibox_api.h"
#include "chrome/browser/extensions/extension_page_actions_module.h"
#include "chrome/browser/extensions/extension_preference_api.h"
+#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/extensions/extension_processes_api.h"
#include "chrome/browser/extensions/extension_proxy_api.h"
#include "chrome/browser/extensions/extension_rlz_module.h"
@@ -51,6 +52,9 @@
#include "content/browser/child_process_security_policy.h"
#include "content/browser/renderer_host/render_process_host.h"
#include "content/browser/renderer_host/render_view_host.h"
+#include "content/browser/user_metrics.h"
+#include "content/common/notification_service.h"
+#include "content/common/result_codes.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_message_macros.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -381,19 +385,71 @@ void ExtensionFunctionDispatcher::ResetFunctions() {
FactoryRegistry::GetInstance()->ResetFunctions();
}
-ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(Profile* profile,
- Delegate* delegate)
- : profile_(profile),
+ExtensionFunctionDispatcher* ExtensionFunctionDispatcher::Create(
+ RenderViewHost* render_view_host,
+ Delegate* delegate,
+ const GURL& url) {
+ ExtensionService* service =
+ render_view_host->process()->profile()->GetExtensionService();
+ DCHECK(service);
+
+ if (!service->ExtensionBindingsAllowed(url))
+ return NULL;
+
+ const Extension* extension = service->GetExtensionByURL(url);
+ if (!extension)
+ extension = service->GetExtensionByWebExtent(url);
+
+ if (extension)
+ return new ExtensionFunctionDispatcher(render_view_host, delegate,
+ extension, url);
+ else
+ return NULL;
+}
+
+ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(
+ RenderViewHost* render_view_host,
+ Delegate* delegate,
+ const Extension* extension,
+ const GURL& url)
+ : profile_(render_view_host->process()->profile()),
+ render_view_host_(render_view_host),
delegate_(delegate),
+ url_(url),
+ extension_id_(extension->id()),
ALLOW_THIS_IN_INITIALIZER_LIST(peer_(new Peer(this))) {
+ // TODO(erikkay) should we do something for these errors in Release?
+ DCHECK(extension);
+ DCHECK(url.SchemeIs(chrome::kExtensionScheme) ||
+ extension->location() == Extension::COMPONENT);
+
+ // Notify the ExtensionProcessManager that the view was created.
+ ExtensionProcessManager* epm = profile()->GetExtensionProcessManager();
+ epm->RegisterExtensionProcess(extension_id(),
+ render_view_host->process()->id());
+
+ // Activate this extension in the renderer. This must be done before any
+ // extension JavaScript code runs because it controls some privileges the
+ // extension code has in the renderer.
+ render_view_host->Send(new ExtensionMsg_ActivateExtension(extension->id()));
+
+ NotificationService::current()->Notify(
+ NotificationType::EXTENSION_FUNCTION_DISPATCHER_CREATED,
+ Source<Profile>(profile_),
+ Details<ExtensionFunctionDispatcher>(this));
}
ExtensionFunctionDispatcher::~ExtensionFunctionDispatcher() {
peer_->dispatcher_ = NULL;
+
+ NotificationService::current()->Notify(
+ NotificationType::EXTENSION_FUNCTION_DISPATCHER_DESTROYED,
+ Source<Profile>(profile_),
+ Details<ExtensionFunctionDispatcher>(this));
}
Browser* ExtensionFunctionDispatcher::GetCurrentBrowser(
- RenderViewHost* render_view_host, bool include_incognito) {
+ bool include_incognito) {
Browser* browser = delegate_->GetBrowser();
// If the delegate has an associated browser, that is always the right answer.
@@ -405,7 +461,7 @@ Browser* ExtensionFunctionDispatcher::GetCurrentBrowser(
// profile. Note that the profile may already be incognito, in which case
// we will search the incognito version only, regardless of the value of
// |include_incognito|.
- Profile* profile = render_view_host->process()->profile();
+ Profile* profile = render_view_host()->process()->profile();
browser = BrowserList::FindTabbedBrowser(profile, include_incognito);
// NOTE(rafaelw): This can return NULL in some circumstances. In particular,
@@ -417,84 +473,88 @@ Browser* ExtensionFunctionDispatcher::GetCurrentBrowser(
return browser;
}
-void ExtensionFunctionDispatcher::Dispatch(
- const ExtensionHostMsg_Request_Params& params,
- RenderViewHost* render_view_host) {
- // TODO(aa): It would be cool to use ExtensionProcessManager to track which
- // processes are extension processes rather than ChildProcessSecurityPolicy.
- // EPM has richer information: it not only knows which processes contain
- // at least one extension, but it knows which extensions are inside and what
- // permissions the have. So we would be able to enforce permissions more
- // granularly.
- if (!ChildProcessSecurityPolicy::GetInstance()->HasExtensionBindings(
- render_view_host->process()->id())) {
- // TODO(aa): Allow content scripts access to low-threat extension APIs.
- // See: crbug.com/80308.
- LOG(ERROR) << "Extension API called from non-extension process.";
- SendAccessDenied(render_view_host, params.request_id);
- return;
- }
-
- ExtensionService* service = profile()->GetExtensionService();
- if (!service)
- return;
-
- if (!service->ExtensionBindingsAllowed(params.source_url)) {
- LOG(ERROR) << "Extension bindings not allowed for URL: "
- << params.source_url.spec();
- SendAccessDenied(render_view_host, params.request_id);
- return;
- }
-
- // TODO(aa): When we allow content scripts to call extension APIs, we will
- // have to pass the extension ID explicitly here, not use the source URL.
- const Extension* extension = service->GetExtensionByURL(params.source_url);
- if (!extension)
- extension = service->GetExtensionByWebExtent(params.source_url);
- if (!extension) {
- LOG(ERROR) << "Extension does not exist for URL: "
- << params.source_url.spec();
- SendAccessDenied(render_view_host, params.request_id);
- return;
- }
+bool ExtensionFunctionDispatcher::OnMessageReceived(
+ const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(ExtensionFunctionDispatcher, message)
+ IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
- if (!extension->HasApiPermission(params.name)) {
- LOG(ERROR) << "Extension " << extension->id() << " does not have "
- << "permission to function: " << params.name;
- SendAccessDenied(render_view_host, params.request_id);
+void ExtensionFunctionDispatcher::OnRequest(
+ const ExtensionHostMsg_Request_Params& params) {
+ if (!ChildProcessSecurityPolicy::GetInstance()->
+ HasExtensionBindings(render_view_host_->process()->id())) {
+ // This can happen if someone uses window.open() to open an extension URL
+ // from a non-extension context.
+ render_view_host_->Send(new ExtensionMsg_Response(
+ render_view_host_->routing_id(), params.request_id, false,
+ std::string(), "Access to extension API denied."));
return;
}
scoped_refptr<ExtensionFunction> function(
FactoryRegistry::GetInstance()->NewFunction(params.name));
- function->SetRenderViewHost(render_view_host);
function->set_dispatcher_peer(peer_);
function->set_profile(profile_);
- function->set_extension_id(extension->id());
+ function->set_extension_id(extension_id());
function->SetArgs(&params.arguments);
function->set_source_url(params.source_url);
function->set_request_id(params.request_id);
function->set_has_callback(params.has_callback);
function->set_user_gesture(params.user_gesture);
+ ExtensionService* service = profile()->GetExtensionService();
+ DCHECK(service);
+ const Extension* extension = service->GetExtensionById(extension_id(), false);
+ DCHECK(extension);
function->set_include_incognito(service->CanCrossIncognito(extension));
+ if (!service->ExtensionBindingsAllowed(function->source_url()) ||
+ !extension->HasApiPermission(function->name())) {
+ render_view_host_->Send(new ExtensionMsg_Response(
+ render_view_host_->routing_id(), function->request_id(), false,
+ std::string(), "Access to extension API denied."));
+ return;
+ }
+
ExtensionsQuotaService* quota = service->quota_service();
- if (quota->Assess(extension->id(), function, &params.arguments,
+ if (quota->Assess(extension_id(), function, &params.arguments,
base::TimeTicks::Now())) {
// See crbug.com/39178.
ExternalProtocolHandler::PermitLaunchUrl();
function->Run();
} else {
- render_view_host->Send(new ExtensionMsg_Response(
- render_view_host->routing_id(), function->request_id(), false,
+ render_view_host_->Send(new ExtensionMsg_Response(
+ render_view_host_->routing_id(), function->request_id(), false,
std::string(), QuotaLimitHeuristic::kGenericOverQuotaError));
}
}
-void ExtensionFunctionDispatcher::SendAccessDenied(
- RenderViewHost* render_view_host, int request_id) {
- render_view_host->Send(new ExtensionMsg_Response(
- render_view_host->routing_id(), request_id, false, std::string(),
- "Access to extension API denied."));
+void ExtensionFunctionDispatcher::SendResponse(ExtensionFunction* function,
+ bool success) {
+ render_view_host_->Send(new ExtensionMsg_Response(
+ render_view_host_->routing_id(), function->request_id(), success,
+ function->GetResult(), function->GetError()));
+}
+
+void ExtensionFunctionDispatcher::HandleBadMessage(ExtensionFunction* api) {
+ LOG(ERROR) << "bad extension message " <<
+ api->name() <<
+ " : terminating renderer.";
+ if (RenderProcessHost::run_renderer_in_process()) {
+ // In single process mode it is better if we don't suicide but just crash.
+ CHECK(false);
+ } else {
+ NOTREACHED();
+ UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_EFD"));
+ base::KillProcess(render_view_host_->process()->GetHandle(),
+ ResultCodes::KILLED_BAD_MESSAGE, false);
+ }
+}
+
+Profile* ExtensionFunctionDispatcher::profile() {
+ return profile_;
}