summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authormpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-09 20:52:42 +0000
committermpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-09 20:52:42 +0000
commitc357acb4058ca346d8e22d29a9d12c72f5d327b4 (patch)
tree8951ca281e3a73c14e5defc119a6ec8723bff67e /chrome/browser
parent34d38beaec22c3c958a477097df274669d023aa2 (diff)
downloadchromium_src-c357acb4058ca346d8e22d29a9d12c72f5d327b4.zip
chromium_src-c357acb4058ca346d8e22d29a9d12c72f5d327b4.tar.gz
chromium_src-c357acb4058ca346d8e22d29a9d12c72f5d327b4.tar.bz2
Handle extension webrequest API on the IO thread. This speeds up blocking event
dispatch and handling. BUG=no TEST=should not change functionality Review URL: http://codereview.chromium.org/7024056 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@88583 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/extensions/extension_event_router.cc38
-rw-r--r--chrome/browser/extensions/extension_event_router.h13
-rw-r--r--chrome/browser/extensions/extension_function.cc91
-rw-r--r--chrome/browser/extensions/extension_function.h70
-rw-r--r--chrome/browser/extensions/extension_function_dispatcher.cc131
-rw-r--r--chrome/browser/extensions/extension_function_dispatcher.h31
-rw-r--r--chrome/browser/extensions/extension_info_map.cc59
-rw-r--r--chrome/browser/extensions/extension_info_map.h26
-rw-r--r--chrome/browser/extensions/extension_info_map_unittest.cc14
-rw-r--r--chrome/browser/extensions/extension_webrequest_api.cc205
-rw-r--r--chrome/browser/extensions/extension_webrequest_api.h55
-rw-r--r--chrome/browser/extensions/extension_webrequest_api_unittest.cc43
-rw-r--r--chrome/browser/io_thread.cc1
-rw-r--r--chrome/browser/net/chrome_network_delegate.cc18
-rw-r--r--chrome/browser/net/chrome_network_delegate.h4
-rw-r--r--chrome/browser/profiles/profile.cc24
-rw-r--r--chrome/browser/profiles/profile_impl.cc10
-rw-r--r--chrome/browser/profiles/profile_io_data.cc1
-rw-r--r--chrome/browser/renderer_host/chrome_render_message_filter.cc23
-rw-r--r--chrome/browser/renderer_host/chrome_render_message_filter.h9
-rw-r--r--chrome/browser/ui/panels/panel_browser_view_browsertest.cc6
21 files changed, 622 insertions, 250 deletions
diff --git a/chrome/browser/extensions/extension_event_router.cc b/chrome/browser/extensions/extension_event_router.cc
index a86bf1c..a5e617a 100644
--- a/chrome/browser/extensions/extension_event_router.cc
+++ b/chrome/browser/extensions/extension_event_router.cc
@@ -22,18 +22,6 @@ namespace {
const char kDispatchEvent[] = "Event.dispatchJSON";
-static void DispatchEvent(RenderProcessHost* renderer,
- const std::string& extension_id,
- const std::string& event_name,
- const std::string& event_args,
- const GURL& event_url) {
- ListValue args;
- args.Set(0, Value::CreateStringValue(event_name));
- args.Set(1, Value::CreateStringValue(event_args));
- renderer->Send(new ExtensionMsg_MessageInvoke(MSG_ROUTING_CONTROL,
- extension_id, kDispatchEvent, args, event_url));
-}
-
static void NotifyEventListenerRemovedOnIOThread(
ProfileId profile_id,
const std::string& extension_id,
@@ -62,22 +50,16 @@ struct ExtensionEventRouter::EventListener {
};
// static
-bool ExtensionEventRouter::CanCrossIncognito(Profile* profile,
- const std::string& extension_id) {
- const Extension* extension =
- profile->GetExtensionService()->GetExtensionById(extension_id, false);
- return CanCrossIncognito(profile, extension);
-}
-
-// static
-bool ExtensionEventRouter::CanCrossIncognito(Profile* profile,
- const Extension* extension) {
- // We allow the extension to see events and data from another profile iff it
- // uses "spanning" behavior and it has incognito access. "split" mode
- // extensions only see events for a matching profile.
- return
- (profile->GetExtensionService()->IsIncognitoEnabled(extension->id()) &&
- !extension->incognito_split_mode());
+void ExtensionEventRouter::DispatchEvent(IPC::Message::Sender* ipc_sender,
+ const std::string& extension_id,
+ const std::string& event_name,
+ const std::string& event_args,
+ const GURL& event_url) {
+ ListValue args;
+ args.Set(0, Value::CreateStringValue(event_name));
+ args.Set(1, Value::CreateStringValue(event_args));
+ ipc_sender->Send(new ExtensionMsg_MessageInvoke(MSG_ROUTING_CONTROL,
+ extension_id, kDispatchEvent, args, event_url));
}
ExtensionEventRouter::ExtensionEventRouter(Profile* profile)
diff --git a/chrome/browser/extensions/extension_event_router.h b/chrome/browser/extensions/extension_event_router.h
index 4ebae0c..2e5597b 100644
--- a/chrome/browser/extensions/extension_event_router.h
+++ b/chrome/browser/extensions/extension_event_router.h
@@ -13,6 +13,7 @@
#include "base/memory/ref_counted.h"
#include "content/common/notification_observer.h"
#include "content/common/notification_registrar.h"
+#include "ipc/ipc_message.h"
class GURL;
class Extension;
@@ -22,11 +23,13 @@ class RenderProcessHost;
class ExtensionEventRouter : public NotificationObserver {
public:
- // Returns true if the given extension can see events and data from another
- // sub-profile (incognito to original profile, or vice versa).
- static bool CanCrossIncognito(Profile* profile,
- const std::string& extension_id);
- static bool CanCrossIncognito(Profile* profile, const Extension* extension);
+ // Sends an event via ipc_sender to the given extension. Can be called on
+ // any thread.
+ static void DispatchEvent(IPC::Message::Sender* ipc_sender,
+ const std::string& extension_id,
+ const std::string& event_name,
+ const std::string& event_args,
+ const GURL& event_url);
explicit ExtensionEventRouter(Profile* profile);
virtual ~ExtensionEventRouter();
diff --git a/chrome/browser/extensions/extension_function.cc b/chrome/browser/extensions/extension_function.cc
index ef9d048..fbb6c03a 100644
--- a/chrome/browser/extensions/extension_function.cc
+++ b/chrome/browser/extensions/extension_function.cc
@@ -9,6 +9,7 @@
#include "chrome/browser/extensions/extension_function_dispatcher.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_host/chrome_render_message_filter.h"
#include "chrome/common/extensions/extension_messages.h"
#include "content/browser/renderer_host/render_process_host.h"
#include "content/browser/renderer_host/render_view_host.h"
@@ -42,7 +43,7 @@ void UIThreadExtensionFunction::RenderViewHostTracker::Observe(
ExtensionFunction::ExtensionFunction()
: request_id_(-1),
- profile_id_(0),
+ profile_id_(Profile::kInvalidProfileId),
has_callback_(false),
include_incognito_(false),
user_gesture_(false),
@@ -57,6 +58,10 @@ UIThreadExtensionFunction* ExtensionFunction::AsUIThreadExtensionFunction() {
return NULL;
}
+IOThreadExtensionFunction* ExtensionFunction::AsIOThreadExtensionFunction() {
+ return NULL;
+}
+
void ExtensionFunction::SetArgs(const ListValue* args) {
DCHECK(!args_.get()); // Should only be called once.
args_.reset(args->DeepCopy());
@@ -84,8 +89,34 @@ bool ExtensionFunction::HasOptionalArgument(size_t index) {
return args_->Get(index, &value) && !value->IsType(Value::TYPE_NULL);
}
+void ExtensionFunction::SendResponseImpl(base::ProcessHandle process,
+ IPC::Message::Sender* ipc_sender,
+ int routing_id,
+ bool success) {
+ DCHECK(ipc_sender);
+ if (bad_message_) {
+ HandleBadMessage(process);
+ return;
+ }
+
+ ipc_sender->Send(new ExtensionMsg_Response(
+ routing_id, request_id_, success, GetResult(), GetError()));
+}
+
+void ExtensionFunction::HandleBadMessage(base::ProcessHandle process) {
+ LOG(ERROR) << "bad extension message " << 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"));
+ if (process)
+ base::KillProcess(process, ResultCodes::KILLED_BAD_MESSAGE, false);
+ }
+}
UIThreadExtensionFunction::UIThreadExtensionFunction()
- : profile_(NULL) {
+ : render_view_host_(NULL), profile_(NULL) {
}
UIThreadExtensionFunction::~UIThreadExtensionFunction() {
@@ -113,29 +144,35 @@ Browser* UIThreadExtensionFunction::GetCurrentBrowser() {
void UIThreadExtensionFunction::SendResponse(bool success) {
if (!render_view_host_ || !dispatcher())
return;
- if (bad_message_) {
- HandleBadMessage();
- return;
- }
- render_view_host_->Send(new ExtensionMsg_Response(
- render_view_host_->routing_id(), request_id_, success,
- GetResult(), GetError()));
+ SendResponseImpl(render_view_host_->process()->GetHandle(),
+ render_view_host_,
+ render_view_host_->routing_id(),
+ success);
}
-void UIThreadExtensionFunction::HandleBadMessage() {
- LOG(ERROR) << "bad extension message " << 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"));
- if (render_view_host_) {
- base::KillProcess(render_view_host_->process()->GetHandle(),
- ResultCodes::KILLED_BAD_MESSAGE, false);
- }
- }
+IOThreadExtensionFunction::IOThreadExtensionFunction()
+ : routing_id_(-1) {
+}
+
+IOThreadExtensionFunction::~IOThreadExtensionFunction() {
+}
+
+IOThreadExtensionFunction*
+IOThreadExtensionFunction::AsIOThreadExtensionFunction() {
+ return this;
+}
+
+void IOThreadExtensionFunction::Destruct() const {
+ BrowserThread::DeleteOnIOThread::Destruct(this);
+}
+
+void IOThreadExtensionFunction::SendResponse(bool success) {
+ if (!ipc_sender())
+ return;
+
+ SendResponseImpl(ipc_sender()->peer_handle(),
+ ipc_sender(), routing_id_, success);
}
AsyncExtensionFunction::AsyncExtensionFunction() {
@@ -153,3 +190,13 @@ SyncExtensionFunction::~SyncExtensionFunction() {
void SyncExtensionFunction::Run() {
SendResponse(RunImpl());
}
+
+SyncIOThreadExtensionFunction::SyncIOThreadExtensionFunction() {
+}
+
+SyncIOThreadExtensionFunction::~SyncIOThreadExtensionFunction() {
+}
+
+void SyncIOThreadExtensionFunction::Run() {
+ SendResponse(RunImpl());
+}
diff --git a/chrome/browser/extensions/extension_function.h b/chrome/browser/extensions/extension_function.h
index f000bf1..c57f0b1 100644
--- a/chrome/browser/extensions/extension_function.h
+++ b/chrome/browser/extensions/extension_function.h
@@ -11,16 +11,22 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/process.h"
+#include "chrome/browser/extensions/extension_info_map.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/extension.h"
#include "content/browser/browser_thread.h"
#include "content/common/notification_observer.h"
#include "content/common/notification_registrar.h"
+#include "ipc/ipc_message.h"
class Browser;
+class ChromeRenderMessageFilter;
class ExtensionFunction;
class ExtensionFunctionDispatcher;
class UIThreadExtensionFunction;
+class IOThreadExtensionFunction;
class ListValue;
class QuotaLimitHeuristic;
class RenderViewHost;
@@ -59,6 +65,7 @@ class ExtensionFunction
ExtensionFunction();
virtual UIThreadExtensionFunction* AsUIThreadExtensionFunction();
+ virtual IOThreadExtensionFunction* AsIOThreadExtensionFunction();
// Execute the API. Clients should initialize the ExtensionFunction using
// SetArgs(), set_request_id(), and the other setters before calling this
@@ -124,11 +131,17 @@ class ExtensionFunction
// Sends the result back to the extension.
virtual void SendResponse(bool success) = 0;
+ // Common implementation for SenderResponse.
+ void SendResponseImpl(base::ProcessHandle process,
+ IPC::Message::Sender* ipc_sender,
+ int routing_id,
+ bool success);
+
// Called when we receive an extension api request that is invalid in a way
// that JSON validation in the renderer should have caught. This should never
// happen and could be an attacker trying to exploit the browser, so we crash
// the renderer instead.
- virtual void HandleBadMessage() = 0;
+ void HandleBadMessage(base::ProcessHandle process);
// Return true if the argument to this function at |index| was provided and
// is non-null.
@@ -257,12 +270,52 @@ class UIThreadExtensionFunction : public ExtensionFunction {
NotificationRegistrar registrar_;
};
- virtual void HandleBadMessage();
-
virtual void Destruct() const;
scoped_ptr<RenderViewHostTracker> tracker_;
+};
+
+// Extension functions that run on the IO thread.
+class IOThreadExtensionFunction : public ExtensionFunction {
+ public:
+ IOThreadExtensionFunction();
+
+ virtual IOThreadExtensionFunction* AsIOThreadExtensionFunction() OVERRIDE;
+
+ void set_ipc_sender(base::WeakPtr<ChromeRenderMessageFilter> ipc_sender,
+ int routing_id) {
+ ipc_sender_ = ipc_sender;
+ routing_id_ = routing_id;
+ }
+ ChromeRenderMessageFilter* ipc_sender() const { return ipc_sender_.get(); }
+ int routing_id() const { return routing_id_; }
+
+ base::WeakPtr<ChromeRenderMessageFilter> ipc_sender_weak() const {
+ return ipc_sender_;
+ }
+
+ void set_extension_info_map(const ExtensionInfoMap* extension_info_map) {
+ extension_info_map_ = extension_info_map;
+ }
+ const ExtensionInfoMap* extension_info_map() const {
+ return extension_info_map_.get();
+ }
+
+ protected:
+ friend struct BrowserThread::DeleteOnThread<BrowserThread::IO>;
+ friend class DeleteTask<IOThreadExtensionFunction>;
+ virtual ~IOThreadExtensionFunction();
+
+ virtual void Destruct() const;
+
+ virtual void SendResponse(bool success);
+
+ private:
+ base::WeakPtr<ChromeRenderMessageFilter> ipc_sender_;
+ int routing_id_;
+
+ scoped_refptr<const ExtensionInfoMap> extension_info_map_;
};
// Base class for an extension function that runs asynchronously *relative to
@@ -290,9 +343,16 @@ class SyncExtensionFunction : public UIThreadExtensionFunction {
protected:
virtual ~SyncExtensionFunction();
+};
- private:
- DISALLOW_COPY_AND_ASSIGN(SyncExtensionFunction);
+class SyncIOThreadExtensionFunction : public IOThreadExtensionFunction {
+ public:
+ SyncIOThreadExtensionFunction();
+
+ virtual void Run() OVERRIDE;
+
+ protected:
+ virtual ~SyncIOThreadExtensionFunction();
};
#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_FUNCTION_H_
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc
index 0eb742a..3e1a761 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.cc
+++ b/chrome/browser/extensions/extension_function_dispatcher.cc
@@ -46,6 +46,7 @@
#include "chrome/browser/extensions/extensions_quota_service.h"
#include "chrome/browser/external_protocol/external_protocol_handler.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_host/chrome_render_message_filter.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/common/extensions/extension_messages.h"
@@ -411,6 +412,36 @@ void ExtensionFunctionDispatcher::ResetFunctions() {
FactoryRegistry::GetInstance()->ResetFunctions();
}
+// static
+void ExtensionFunctionDispatcher::DispatchOnIOThread(
+ const ExtensionInfoMap* extension_info_map,
+ ProfileId profile_id,
+ int render_process_id,
+ base::WeakPtr<ChromeRenderMessageFilter> ipc_sender,
+ int routing_id,
+ const ExtensionHostMsg_Request_Params& params) {
+ const Extension* extension =
+ extension_info_map->extensions().GetByURL(params.source_url);
+
+ scoped_refptr<ExtensionFunction> function(
+ CreateExtensionFunction(params, extension, profile_id, render_process_id,
+ ipc_sender, routing_id));
+ if (!function)
+ return;
+
+ IOThreadExtensionFunction* function_io =
+ function->AsIOThreadExtensionFunction();
+ if (!function_io) {
+ NOTREACHED();
+ return;
+ }
+ function_io->set_ipc_sender(ipc_sender, routing_id);
+ function_io->set_extension_info_map(extension_info_map);
+ function->set_include_incognito(
+ extension_info_map->IsIncognitoEnabled(extension->id()));
+ function->Run();
+}
+
ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(Profile* profile,
Delegate* delegate)
: profile_(profile),
@@ -448,21 +479,6 @@ Browser* ExtensionFunctionDispatcher::GetCurrentBrowser(
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;
@@ -470,7 +486,8 @@ void ExtensionFunctionDispatcher::Dispatch(
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);
+ SendAccessDenied(render_view_host, render_view_host->routing_id(),
+ params.request_id);
return;
}
@@ -479,22 +496,14 @@ void ExtensionFunctionDispatcher::Dispatch(
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;
- }
- 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);
+ scoped_refptr<ExtensionFunction> function(CreateExtensionFunction(
+ params, extension, profile_->GetRuntimeId(),
+ render_view_host->process()->id(),
+ render_view_host, render_view_host->routing_id()));
+ if (!function)
return;
- }
- scoped_refptr<ExtensionFunction> function(
- FactoryRegistry::GetInstance()->NewFunction(params.name));
UIThreadExtensionFunction* function_ui =
function->AsUIThreadExtensionFunction();
if (!function_ui) {
@@ -504,14 +513,6 @@ void ExtensionFunctionDispatcher::Dispatch(
function_ui->SetRenderViewHost(render_view_host);
function_ui->set_dispatcher(AsWeakPtr());
function_ui->set_profile(profile_);
-
- function->set_profile_id(profile_->GetRuntimeId());
- function->set_extension(extension);
- 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);
function->set_include_incognito(service->CanCrossIncognito(extension));
ExtensionsQuotaService* quota = service->quota_service();
@@ -528,9 +529,59 @@ void ExtensionFunctionDispatcher::Dispatch(
}
}
+// static
+ExtensionFunction* ExtensionFunctionDispatcher::CreateExtensionFunction(
+ const ExtensionHostMsg_Request_Params& params,
+ const Extension* extension,
+ ProfileId profile_id,
+ int render_process_id,
+ IPC::Message::Sender* ipc_sender,
+ int routing_id) {
+ // 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_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(ipc_sender, routing_id, params.request_id);
+ return NULL;
+ }
+
+ if (!extension) {
+ LOG(ERROR) << "Extension does not exist for URL: "
+ << params.source_url.spec();
+ SendAccessDenied(ipc_sender, routing_id, params.request_id);
+ return NULL;
+ }
+
+ if (!extension->HasApiPermission(params.name)) {
+ LOG(ERROR) << "Extension " << extension->id() << " does not have "
+ << "permission to function: " << params.name;
+ SendAccessDenied(ipc_sender, routing_id, params.request_id);
+ return NULL;
+ }
+
+ ExtensionFunction* function =
+ FactoryRegistry::GetInstance()->NewFunction(params.name);
+ 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);
+ function->set_extension(extension);
+ function->set_profile_id(profile_id);
+ return function;
+}
+
+// static
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(),
+ IPC::Message::Sender* ipc_sender, int routing_id, int request_id) {
+ ipc_sender->Send(new ExtensionMsg_Response(
+ routing_id, request_id, false, std::string(),
"Access to extension API denied."));
}
diff --git a/chrome/browser/extensions/extension_function_dispatcher.h b/chrome/browser/extensions/extension_function_dispatcher.h
index a59890e..5ebd6a2 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.h
+++ b/chrome/browser/extensions/extension_function_dispatcher.h
@@ -10,10 +10,13 @@
#include <vector>
#include "base/memory/weak_ptr.h"
+#include "chrome/browser/profiles/profile.h"
+#include "ipc/ipc_message.h"
#include "googleurl/src/gurl.h"
#include "ui/gfx/native_widget_types.h"
class Browser;
+class ChromeRenderMessageFilter;
class Extension;
class ExtensionFunction;
class ListValue;
@@ -72,6 +75,16 @@ class ExtensionFunctionDispatcher
// Resets all functions to their initial implementation.
static void ResetFunctions();
+ // Dispatches an IO-thread extension function. Only used for specific
+ // functions that must be handled on the IO-thread.
+ static void DispatchOnIOThread(
+ const ExtensionInfoMap* extension_info_map,
+ ProfileId profile_id,
+ int render_process_id,
+ base::WeakPtr<ChromeRenderMessageFilter> ipc_sender,
+ int routing_id,
+ const ExtensionHostMsg_Request_Params& params);
+
// Public constructor. Callers must ensure that:
// - |delegate| outlives this object.
// - This object outlives any RenderViewHost's passed to created
@@ -99,8 +112,22 @@ class ExtensionFunctionDispatcher
Profile* profile() { return profile_; }
private:
- // Helper to send an access denied error to the requesting render view.
- void SendAccessDenied(RenderViewHost* render_view_host, int request_id);
+ // Helper to create an ExtensionFunction to handle the function given by
+ // |params|. Can be called on any thread.
+ // Does not set subclass properties, or include_incognito.
+ static ExtensionFunction* CreateExtensionFunction(
+ const ExtensionHostMsg_Request_Params& params,
+ const Extension* extension,
+ ProfileId profile_id,
+ int render_process_id,
+ IPC::Message::Sender* ipc_sender,
+ int routing_id);
+
+ // Helper to send an access denied error to the requesting renderer. Can be
+ // called on any thread.
+ static void SendAccessDenied(IPC::Message::Sender* ipc_sender,
+ int routing_id,
+ int request_id);
Profile* profile_;
diff --git a/chrome/browser/extensions/extension_info_map.cc b/chrome/browser/extensions/extension_info_map.cc
index c812237..4e16420 100644
--- a/chrome/browser/extensions/extension_info_map.cc
+++ b/chrome/browser/extensions/extension_info_map.cc
@@ -15,35 +15,82 @@ static void CheckOnValidThread() {
} // namespace
+
+struct ExtensionInfoMap::ExtraData {
+ // When the extension was installed.
+ base::Time install_time;
+
+ // True if the user has allowed this extension to run in incognito mode.
+ bool incognito_enabled;
+
+ ExtraData();
+ ~ExtraData();
+};
+
+ExtensionInfoMap::ExtraData::ExtraData() : incognito_enabled(false) {
+}
+
+ExtensionInfoMap::ExtraData::~ExtraData() {
+}
+
+
ExtensionInfoMap::ExtensionInfoMap() {
}
ExtensionInfoMap::~ExtensionInfoMap() {
}
-void ExtensionInfoMap::AddExtension(const Extension* extension) {
+void ExtensionInfoMap::AddExtension(const Extension* extension,
+ base::Time install_time,
+ bool incognito_enabled) {
CheckOnValidThread();
extensions_.Insert(extension);
disabled_extensions_.Remove(extension->id());
+
+ extra_data_[extension->id()].install_time = install_time;
+ extra_data_[extension->id()].incognito_enabled = incognito_enabled;
}
-void ExtensionInfoMap::RemoveExtension(const std::string& id,
+void ExtensionInfoMap::RemoveExtension(const std::string& extension_id,
const UnloadedExtensionInfo::Reason reason) {
CheckOnValidThread();
- const Extension* extension = extensions_.GetByID(id);
+ const Extension* extension = extensions_.GetByID(extension_id);
+ extra_data_.erase(extension_id); // we don't care about disabled extra data
if (extension) {
if (reason == UnloadedExtensionInfo::DISABLE)
disabled_extensions_.Insert(extension);
- extensions_.Remove(id);
+ extensions_.Remove(extension_id);
} else if (reason != UnloadedExtensionInfo::DISABLE) {
// If the extension was uninstalled, make sure it's removed from the map of
// disabled extensions.
- disabled_extensions_.Remove(id);
+ disabled_extensions_.Remove(extension_id);
} else {
// NOTE: This can currently happen if we receive multiple unload
// notifications, e.g. setting incognito-enabled state for a
// disabled extension (e.g., via sync). See
// http://code.google.com/p/chromium/issues/detail?id=50582 .
- NOTREACHED() << id;
+ NOTREACHED() << extension_id;
}
}
+
+base::Time ExtensionInfoMap::GetInstallTime(
+ const std::string& extension_id) const {
+ ExtraDataMap::const_iterator iter = extra_data_.find(extension_id);
+ if (iter != extra_data_.end())
+ return iter->second.install_time;
+ return base::Time();
+}
+
+bool ExtensionInfoMap::IsIncognitoEnabled(
+ const std::string& extension_id) const {
+ ExtraDataMap::const_iterator iter = extra_data_.find(extension_id);
+ if (iter != extra_data_.end())
+ return iter->second.incognito_enabled;
+ return false;
+}
+
+bool ExtensionInfoMap::CanCrossIncognito(const Extension* extension) {
+ // This is duplicated from ExtensionService :(.
+ return IsIncognitoEnabled(extension->id()) &&
+ !extension->incognito_split_mode();
+}
diff --git a/chrome/browser/extensions/extension_info_map.h b/chrome/browser/extensions/extension_info_map.h
index 1c1edb0..63a6346 100644
--- a/chrome/browser/extensions/extension_info_map.h
+++ b/chrome/browser/extensions/extension_info_map.h
@@ -9,6 +9,7 @@
#include <string>
#include "base/basictypes.h"
+#include "base/time.h"
#include "base/memory/ref_counted.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_set.h"
@@ -29,15 +30,36 @@ class ExtensionInfoMap : public base::RefCountedThreadSafe<ExtensionInfoMap> {
}
// Callback for when new extensions are loaded.
- void AddExtension(const Extension* extension);
+ void AddExtension(const Extension* extension,
+ base::Time install_time,
+ bool incognito_enabled);
// Callback for when an extension is unloaded.
- void RemoveExtension(const std::string& id,
+ void RemoveExtension(const std::string& extension_id,
const UnloadedExtensionInfo::Reason reason);
+ // Returns the time the extension was installed, or base::Time() if not found.
+ base::Time GetInstallTime(const std::string& extension_id) const;
+
+ // Returns true if the user has allowed this extension to run in incognito
+ // mode.
+ bool IsIncognitoEnabled(const std::string& extension_id) const;
+
+ // Returns true if the given extension can see events and data from another
+ // sub-profile (incognito to original profile, or vice versa).
+ bool CanCrossIncognito(const Extension* extension);
+
private:
+ // Extra dynamic data related to an extension.
+ struct ExtraData;
+ // Map of extension_id to ExtraData.
+ typedef std::map<std::string, ExtraData> ExtraDataMap;
+
ExtensionSet extensions_;
ExtensionSet disabled_extensions_;
+
+ // Extra data associated with enabled extensions.
+ ExtraDataMap extra_data_;
};
#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_INFO_MAP_H_
diff --git a/chrome/browser/extensions/extension_info_map_unittest.cc b/chrome/browser/extensions/extension_info_map_unittest.cc
index 66dcb7c..a355673 100644
--- a/chrome/browser/extensions/extension_info_map_unittest.cc
+++ b/chrome/browser/extensions/extension_info_map_unittest.cc
@@ -84,9 +84,9 @@ TEST_F(ExtensionInfoMapTest, RefCounting) {
EXPECT_TRUE(extension3->HasOneRef());
// Add a ref to each extension and give it to the info map.
- info_map->AddExtension(extension1);
- info_map->AddExtension(extension2);
- info_map->AddExtension(extension3);
+ info_map->AddExtension(extension1, base::Time(), false);
+ info_map->AddExtension(extension2, base::Time(), false);
+ info_map->AddExtension(extension3, base::Time(), false);
// Release extension1, and the info map should have the only ref.
const Extension* weak_extension1 = extension1;
@@ -109,8 +109,8 @@ TEST_F(ExtensionInfoMapTest, Properties) {
scoped_refptr<Extension> extension1(CreateExtension("extension1"));
scoped_refptr<Extension> extension2(CreateExtension("extension2"));
- info_map->AddExtension(extension1);
- info_map->AddExtension(extension2);
+ info_map->AddExtension(extension1, base::Time(), false);
+ info_map->AddExtension(extension2, base::Time(), false);
EXPECT_EQ(2u, info_map->extensions().size());
EXPECT_EQ(extension1.get(), info_map->extensions().GetByID(extension1->id()));
@@ -130,8 +130,8 @@ TEST_F(ExtensionInfoMapTest, CheckPermissions) {
ASSERT_TRUE(app->is_app());
ASSERT_TRUE(app->web_extent().MatchesURL(app_url));
- info_map->AddExtension(app);
- info_map->AddExtension(extension);
+ info_map->AddExtension(app, base::Time(), false);
+ info_map->AddExtension(extension, base::Time(), false);
// The app should have the notifications permission, either from a
// chrome-extension URL or from its web extent.
diff --git a/chrome/browser/extensions/extension_webrequest_api.cc b/chrome/browser/extensions/extension_webrequest_api.cc
index 983bdfe..46929fe 100644
--- a/chrome/browser/extensions/extension_webrequest_api.cc
+++ b/chrome/browser/extensions/extension_webrequest_api.cc
@@ -10,16 +10,19 @@
#include "base/metrics/histogram.h"
#include "base/string_number_conversions.h"
#include "base/values.h"
-#include "chrome/browser/extensions/extension_event_router_forwarder.h"
+#include "chrome/browser/extensions/extension_event_router.h"
+#include "chrome/browser/extensions/extension_info_map.h"
#include "chrome/browser/extensions/extension_prefs.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_tab_id_map.h"
#include "chrome/browser/extensions/extension_webrequest_api_constants.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_host/chrome_render_message_filter.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_error_utils.h"
#include "chrome/common/extensions/url_pattern.h"
#include "chrome/common/url_constants.h"
+#include "content/browser/browser_message_filter.h"
#include "content/browser/browser_thread.h"
#include "content/browser/renderer_host/resource_dispatcher_host.h"
#include "content/browser/renderer_host/resource_dispatcher_host_request_info.h"
@@ -84,7 +87,7 @@ const char* ResourceTypeToString(ResourceType::Type type) {
}
bool ParseResourceType(const std::string& type_str,
- ResourceType::Type* type) {
+ ResourceType::Type* type) {
const char** iter =
std::find(kResourceTypeStrings, ARRAYEND(kResourceTypeStrings), type_str);
if (iter == ARRAYEND(kResourceTypeStrings))
@@ -94,9 +97,9 @@ bool ParseResourceType(const std::string& type_str,
}
void ExtractRequestInfo(net::URLRequest* request,
- int* tab_id,
- int* window_id,
- ResourceType::Type* resource_type) {
+ int* tab_id,
+ int* window_id,
+ ResourceType::Type* resource_type) {
if (!request->GetUserData(NULL))
return;
@@ -113,30 +116,6 @@ void ExtractRequestInfo(net::URLRequest* request,
*iter : ResourceType::LAST_TYPE;
}
-void AddEventListenerOnIOThread(
- ProfileId profile_id,
- const std::string& extension_id,
- const std::string& event_name,
- const std::string& sub_event_name,
- const ExtensionWebRequestEventRouter::RequestFilter& filter,
- int extra_info_spec) {
- ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
- profile_id, extension_id, event_name, sub_event_name, filter,
- extra_info_spec);
-}
-
-void EventHandledOnIOThread(
- ProfileId profile_id,
- const std::string& extension_id,
- const std::string& event_name,
- const std::string& sub_event_name,
- uint64 request_id,
- ExtensionWebRequestEventRouter::EventResponse* response) {
- ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
- profile_id, extension_id, event_name, sub_event_name, request_id,
- response);
-}
-
// Creates a list of HttpHeaders (see extension_api.json). If |headers| is
// NULL, the list is empty. Ownership is passed to the caller.
ListValue* GetResponseHeadersList(const net::HttpResponseHeaders* headers) {
@@ -184,6 +163,7 @@ struct ExtensionWebRequestEventRouter::EventListener {
std::string sub_event_name;
RequestFilter filter;
int extra_info_spec;
+ base::WeakPtr<IPC::Message::Sender> ipc_sender;
mutable std::set<uint64> blocked_requests;
// Comparator to work with std::set.
@@ -341,7 +321,7 @@ ExtensionWebRequestEventRouter::~ExtensionWebRequestEventRouter() {
int ExtensionWebRequestEventRouter::OnBeforeRequest(
ProfileId profile_id,
- ExtensionEventRouterForwarder* event_router,
+ ExtensionInfoMap* extension_info_map,
net::URLRequest* request,
net::CompletionCallback* callback,
GURL* new_url) {
@@ -366,7 +346,8 @@ int ExtensionWebRequestEventRouter::OnBeforeRequest(
int extra_info_spec = 0;
std::vector<const EventListener*> listeners =
- GetMatchingListeners(profile_id, keys::kOnBeforeRequest, request->url(),
+ GetMatchingListeners(profile_id, extension_info_map,
+ keys::kOnBeforeRequest, request->url(),
tab_id, window_id, resource_type, &extra_info_spec);
if (listeners.empty())
return net::OK;
@@ -385,7 +366,7 @@ int ExtensionWebRequestEventRouter::OnBeforeRequest(
dict->SetDouble(keys::kTimeStampKey, base::Time::Now().ToDoubleT() * 1000);
args.Append(dict);
- if (DispatchEvent(profile_id, event_router, request, listeners, args)) {
+ if (DispatchEvent(profile_id, request, listeners, args)) {
blocked_requests_[request->identifier()].event = kOnBeforeRequest;
blocked_requests_[request->identifier()].callback = callback;
blocked_requests_[request->identifier()].new_url = new_url;
@@ -396,7 +377,7 @@ int ExtensionWebRequestEventRouter::OnBeforeRequest(
int ExtensionWebRequestEventRouter::OnBeforeSendHeaders(
ProfileId profile_id,
- ExtensionEventRouterForwarder* event_router,
+ ExtensionInfoMap* extension_info_map,
uint64 request_id,
net::CompletionCallback* callback,
net::HttpRequestHeaders* headers) {
@@ -415,7 +396,8 @@ int ExtensionWebRequestEventRouter::OnBeforeSendHeaders(
int extra_info_spec = 0;
std::vector<const EventListener*> listeners =
- GetMatchingListeners(profile_id, keys::kOnBeforeSendHeaders, request,
+ GetMatchingListeners(profile_id, extension_info_map,
+ keys::kOnBeforeSendHeaders, request,
&extra_info_spec);
if (listeners.empty())
return net::OK;
@@ -433,7 +415,7 @@ int ExtensionWebRequestEventRouter::OnBeforeSendHeaders(
args.Append(dict);
- if (DispatchEvent(profile_id, event_router, request, listeners, args)) {
+ if (DispatchEvent(profile_id, request, listeners, args)) {
blocked_requests_[request->identifier()].event = kOnBeforeSendHeaders;
blocked_requests_[request->identifier()].callback = callback;
blocked_requests_[request->identifier()].request_headers = headers;
@@ -444,7 +426,7 @@ int ExtensionWebRequestEventRouter::OnBeforeSendHeaders(
void ExtensionWebRequestEventRouter::OnRequestSent(
ProfileId profile_id,
- ExtensionEventRouterForwarder* event_router,
+ ExtensionInfoMap* extension_info_map,
uint64 request_id,
const net::HostPortPair& socket_address,
const net::HttpRequestHeaders& headers) {
@@ -465,8 +447,8 @@ void ExtensionWebRequestEventRouter::OnRequestSent(
int extra_info_spec = 0;
std::vector<const EventListener*> listeners =
- GetMatchingListeners(profile_id, keys::kOnRequestSent, request,
- &extra_info_spec);
+ GetMatchingListeners(profile_id, extension_info_map,
+ keys::kOnRequestSent, request, &extra_info_spec);
if (listeners.empty())
return;
@@ -482,12 +464,12 @@ void ExtensionWebRequestEventRouter::OnRequestSent(
// TODO(battre): support "request line".
args.Append(dict);
- DispatchEvent(profile_id, event_router, request, listeners, args);
+ DispatchEvent(profile_id, request, listeners, args);
}
void ExtensionWebRequestEventRouter::OnBeforeRedirect(
ProfileId profile_id,
- ExtensionEventRouterForwarder* event_router,
+ ExtensionInfoMap* extension_info_map,
net::URLRequest* request,
const GURL& new_location) {
if (profile_id == Profile::kInvalidProfileId)
@@ -503,8 +485,8 @@ void ExtensionWebRequestEventRouter::OnBeforeRedirect(
int extra_info_spec = 0;
std::vector<const EventListener*> listeners =
- GetMatchingListeners(profile_id, keys::kOnBeforeRedirect, request,
- &extra_info_spec);
+ GetMatchingListeners(profile_id, extension_info_map,
+ keys::kOnBeforeRedirect, request, &extra_info_spec);
if (listeners.empty())
return;
@@ -526,12 +508,12 @@ void ExtensionWebRequestEventRouter::OnBeforeRedirect(
dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
args.Append(dict);
- DispatchEvent(profile_id, event_router, request, listeners, args);
+ DispatchEvent(profile_id, request, listeners, args);
}
void ExtensionWebRequestEventRouter::OnResponseStarted(
ProfileId profile_id,
- ExtensionEventRouterForwarder* event_router,
+ ExtensionInfoMap* extension_info_map,
net::URLRequest* request) {
if (profile_id == Profile::kInvalidProfileId)
return;
@@ -544,8 +526,8 @@ void ExtensionWebRequestEventRouter::OnResponseStarted(
int extra_info_spec = 0;
std::vector<const EventListener*> listeners =
- GetMatchingListeners(profile_id, keys::kOnResponseStarted, request,
- &extra_info_spec);
+ GetMatchingListeners(profile_id, extension_info_map,
+ keys::kOnResponseStarted, request, &extra_info_spec);
if (listeners.empty())
return;
@@ -569,12 +551,12 @@ void ExtensionWebRequestEventRouter::OnResponseStarted(
dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
args.Append(dict);
- DispatchEvent(profile_id, event_router, request, listeners, args);
+ DispatchEvent(profile_id, request, listeners, args);
}
void ExtensionWebRequestEventRouter::OnCompleted(
ProfileId profile_id,
- ExtensionEventRouterForwarder* event_router,
+ ExtensionInfoMap* extension_info_map,
net::URLRequest* request) {
if (profile_id == Profile::kInvalidProfileId)
return;
@@ -587,8 +569,8 @@ void ExtensionWebRequestEventRouter::OnCompleted(
int extra_info_spec = 0;
std::vector<const EventListener*> listeners =
- GetMatchingListeners(profile_id, keys::kOnCompleted, request,
- &extra_info_spec);
+ GetMatchingListeners(profile_id, extension_info_map,
+ keys::kOnCompleted, request, &extra_info_spec);
if (listeners.empty())
return;
@@ -612,12 +594,12 @@ void ExtensionWebRequestEventRouter::OnCompleted(
dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
args.Append(dict);
- DispatchEvent(profile_id, event_router, request, listeners, args);
+ DispatchEvent(profile_id, request, listeners, args);
}
void ExtensionWebRequestEventRouter::OnErrorOccurred(
ProfileId profile_id,
- ExtensionEventRouterForwarder* event_router,
+ ExtensionInfoMap* extension_info_map,
net::URLRequest* request) {
if (profile_id == Profile::kInvalidProfileId)
return;
@@ -630,8 +612,8 @@ void ExtensionWebRequestEventRouter::OnErrorOccurred(
int extra_info_spec = 0;
std::vector<const EventListener*> listeners =
- GetMatchingListeners(profile_id, keys::kOnErrorOccurred, request,
- &extra_info_spec);
+ GetMatchingListeners(profile_id, extension_info_map,
+ keys::kOnErrorOccurred, request, &extra_info_spec);
if (listeners.empty())
return;
@@ -645,7 +627,7 @@ void ExtensionWebRequestEventRouter::OnErrorOccurred(
dict->SetDouble(keys::kTimeStampKey, time.ToDoubleT() * 1000);
args.Append(dict);
- DispatchEvent(profile_id, event_router, request, listeners, args);
+ DispatchEvent(profile_id, request, listeners, args);
}
void ExtensionWebRequestEventRouter::OnURLRequestDestroyed(
@@ -667,7 +649,6 @@ void ExtensionWebRequestEventRouter::OnHttpTransactionDestroyed(
bool ExtensionWebRequestEventRouter::DispatchEvent(
ProfileId profile_id,
- ExtensionEventRouterForwarder* event_router,
net::URLRequest* request,
const std::vector<const EventListener*>& listeners,
const ListValue& args) {
@@ -690,9 +671,10 @@ bool ExtensionWebRequestEventRouter::DispatchEvent(
dict->Remove(keys::kStatusLineKey, NULL);
base::JSONWriter::Write(args_filtered.get(), false, &json_args);
- event_router->DispatchEventToExtension(
- (*it)->extension_id, (*it)->sub_event_name, json_args,
- profile_id, true, GURL());
+
+ ExtensionEventRouter::DispatchEvent(
+ (*it)->ipc_sender.get(), (*it)->extension_id, (*it)->sub_event_name,
+ json_args, GURL());
if ((*it)->extra_info_spec & ExtraInfoSpec::BLOCKING) {
(*it)->blocked_requests.insert(request->identifier());
++num_handlers_blocking;
@@ -739,7 +721,8 @@ void ExtensionWebRequestEventRouter::AddEventListener(
const std::string& event_name,
const std::string& sub_event_name,
const RequestFilter& filter,
- int extra_info_spec) {
+ int extra_info_spec,
+ base::WeakPtr<IPC::Message::Sender> ipc_sender) {
if (!IsWebRequestEvent(event_name))
return;
@@ -748,6 +731,7 @@ void ExtensionWebRequestEventRouter::AddEventListener(
listener.sub_event_name = sub_event_name;
listener.filter = filter;
listener.extra_info_spec = extra_info_spec;
+ listener.ipc_sender = ipc_sender;
CHECK_EQ(listeners_[profile_id][event_name].count(listener), 0u) <<
"extension=" << extension_id << " event=" << event_name;
@@ -788,23 +772,39 @@ void ExtensionWebRequestEventRouter::RemoveEventListener(
listeners_[profile_id][event_name].erase(listener);
}
-std::vector<const ExtensionWebRequestEventRouter::EventListener*>
-ExtensionWebRequestEventRouter::GetMatchingListeners(
+void ExtensionWebRequestEventRouter::OnOTRProfileCreated(
+ ProfileId original_profile_id, ProfileId otr_profile_id) {
+ cross_profile_map_[original_profile_id] = otr_profile_id;
+ cross_profile_map_[otr_profile_id] = original_profile_id;
+}
+
+void ExtensionWebRequestEventRouter::OnOTRProfileDestroyed(
+ ProfileId original_profile_id, ProfileId otr_profile_id) {
+ cross_profile_map_.erase(otr_profile_id);
+ cross_profile_map_.erase(original_profile_id);
+}
+
+void ExtensionWebRequestEventRouter::GetMatchingListenersImpl(
ProfileId profile_id,
+ ExtensionInfoMap* extension_info_map,
+ bool crosses_incognito,
const std::string& event_name,
const GURL& url,
int tab_id,
int window_id,
ResourceType::Type resource_type,
- int* extra_info_spec) {
- // TODO(mpcomplete): handle profile_id == invalid (should collect all
- // listeners).
- *extra_info_spec = 0;
-
- std::vector<const EventListener*> matching_listeners;
+ int* extra_info_spec,
+ std::vector<const ExtensionWebRequestEventRouter::EventListener*>*
+ matching_listeners) {
std::set<EventListener>& listeners = listeners_[profile_id][event_name];
for (std::set<EventListener>::iterator it = listeners.begin();
it != listeners.end(); ++it) {
+ if (!it->ipc_sender.get()) {
+ // The IPC sender has been deleted. This listener will be removed soon
+ // via a call to RemoveEventListener. For now, just skip it.
+ continue;
+ }
+
if (!it->filter.urls.is_empty() && !it->filter.urls.MatchesURL(url))
continue;
if (it->filter.tab_id != -1 && tab_id != it->filter.tab_id)
@@ -816,15 +816,57 @@ ExtensionWebRequestEventRouter::GetMatchingListeners(
resource_type) == it->filter.types.end())
continue;
- matching_listeners.push_back(&(*it));
+ // Check if this event crosses incognito boundaries when it shouldn't.
+ // extension_info_map can be NULL if this is a system-level request.
+ if (extension_info_map) {
+ const Extension* extension =
+ extension_info_map->extensions().GetByID(it->extension_id);
+ if (!extension ||
+ (crosses_incognito &&
+ !extension_info_map->CanCrossIncognito(extension)))
+ continue;
+ }
+
+ matching_listeners->push_back(&(*it));
*extra_info_spec |= it->extra_info_spec;
}
+}
+
+std::vector<const ExtensionWebRequestEventRouter::EventListener*>
+ExtensionWebRequestEventRouter::GetMatchingListeners(
+ ProfileId profile_id,
+ ExtensionInfoMap* extension_info_map,
+ const std::string& event_name,
+ const GURL& url,
+ int tab_id,
+ int window_id,
+ ResourceType::Type resource_type,
+ int* extra_info_spec) {
+ // TODO(mpcomplete): handle profile_id == invalid (should collect all
+ // listeners).
+ *extra_info_spec = 0;
+
+ std::vector<const ExtensionWebRequestEventRouter::EventListener*>
+ matching_listeners;
+
+ GetMatchingListenersImpl(
+ profile_id, extension_info_map, false, event_name, url,
+ tab_id, window_id, resource_type, extra_info_spec, &matching_listeners);
+ CrossProfileMap::const_iterator cross_profile_id =
+ cross_profile_map_.find(profile_id);
+ if (cross_profile_id != cross_profile_map_.end()) {
+ GetMatchingListenersImpl(
+ cross_profile_id->second, extension_info_map, true, event_name, url,
+ tab_id, window_id, resource_type, extra_info_spec, &matching_listeners);
+ }
+
return matching_listeners;
}
std::vector<const ExtensionWebRequestEventRouter::EventListener*>
ExtensionWebRequestEventRouter::GetMatchingListeners(
ProfileId profile_id,
+ ExtensionInfoMap* extension_info_map,
const std::string& event_name,
net::URLRequest* request,
int* extra_info_spec) {
@@ -834,8 +876,8 @@ ExtensionWebRequestEventRouter::GetMatchingListeners(
ExtractRequestInfo(request, &tab_id, &window_id, &resource_type);
return GetMatchingListeners(
- profile_id, event_name, request->url(), tab_id, window_id, resource_type,
- extra_info_spec);
+ profile_id, extension_info_map, event_name, request->url(),
+ tab_id, window_id, resource_type, extra_info_spec);
}
void ExtensionWebRequestEventRouter::DecrementBlockCount(
@@ -955,12 +997,9 @@ bool WebRequestAddEventListener::RunImpl() {
std::string sub_event_name;
EXTENSION_FUNCTION_VALIDATE(args_->GetString(4, &sub_event_name));
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableFunction(
- &AddEventListenerOnIOThread,
- profile()->GetRuntimeId(), extension_id(),
- event_name, sub_event_name, filter, extra_info_spec));
+ ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
+ profile_id(), extension_id(), event_name, sub_event_name, filter,
+ extra_info_spec, ipc_sender_weak());
return true;
}
@@ -985,8 +1024,7 @@ bool WebRequestEventHandled::RunImpl() {
if (!value->empty()) {
base::Time install_time =
- profile()->GetExtensionService()->extension_prefs()->
- GetInstallTime(extension_id());
+ extension_info_map()->GetInstallTime(extension_id());
response.reset(new ExtensionWebRequestEventRouter::EventResponse(
extension_id(), install_time));
}
@@ -1036,12 +1074,9 @@ bool WebRequestEventHandled::RunImpl() {
}
}
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- NewRunnableFunction(
- &EventHandledOnIOThread,
- profile()->GetRuntimeId(), extension_id(),
- event_name, sub_event_name, request_id, response.release()));
+ ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
+ profile_id(), extension_id(), event_name, sub_event_name, request_id,
+ response.release());
return true;
}
diff --git a/chrome/browser/extensions/extension_webrequest_api.h b/chrome/browser/extensions/extension_webrequest_api.h
index 8913702..161643a 100644
--- a/chrome/browser/extensions/extension_webrequest_api.h
+++ b/chrome/browser/extensions/extension_webrequest_api.h
@@ -21,7 +21,7 @@
#include "webkit/glue/resource_type.h"
class DictionaryValue;
-class ExtensionEventRouterForwarder;
+class ExtensionInfoMap;
class GURL;
class ListValue;
class StringValue;
@@ -109,7 +109,7 @@ class ExtensionWebRequestEventRouter {
// the given request. Returns net::ERR_IO_PENDING if an extension is
// intercepting the request, OK otherwise.
int OnBeforeRequest(ProfileId profile_id,
- ExtensionEventRouterForwarder* event_router,
+ ExtensionInfoMap* extension_info_map,
net::URLRequest* request,
net::CompletionCallback* callback,
GURL* new_url);
@@ -119,7 +119,7 @@ class ExtensionWebRequestEventRouter {
// Returns net::ERR_IO_PENDING if an extension is intercepting the request, OK
// otherwise.
int OnBeforeSendHeaders(ProfileId profile_id,
- ExtensionEventRouterForwarder* event_router,
+ ExtensionInfoMap* extension_info_map,
uint64 request_id,
net::CompletionCallback* callback,
net::HttpRequestHeaders* headers);
@@ -127,7 +127,7 @@ class ExtensionWebRequestEventRouter {
// Dispatches the onRequestSent event. This is fired for HTTP(s) requests
// only.
void OnRequestSent(ProfileId profile_id,
- ExtensionEventRouterForwarder* event_router,
+ ExtensionInfoMap* extension_info_map,
uint64 request_id,
const net::HostPortPair& socket_address,
const net::HttpRequestHeaders& headers);
@@ -135,24 +135,24 @@ class ExtensionWebRequestEventRouter {
// Dispatches the onBeforeRedirect event. This is fired for HTTP(s) requests
// only.
void OnBeforeRedirect(ProfileId profile_id,
- ExtensionEventRouterForwarder* event_router,
+ ExtensionInfoMap* extension_info_map,
net::URLRequest* request,
const GURL& new_location);
// Dispatches the onResponseStarted event indicating that the first bytes of
// the response have arrived.
void OnResponseStarted(ProfileId profile_id,
- ExtensionEventRouterForwarder* event_router,
+ ExtensionInfoMap* extension_info_map,
net::URLRequest* request);
// Dispatches the onComplete event.
void OnCompleted(ProfileId profile_id,
- ExtensionEventRouterForwarder* event_router,
+ ExtensionInfoMap* extension_info_map,
net::URLRequest* request);
// Dispatches an onErrorOccurred event.
void OnErrorOccurred(ProfileId profile_id,
- ExtensionEventRouterForwarder* event_router,
+ ExtensionInfoMap* extension_info_map,
net::URLRequest* request);
// Notifications when objects are going away.
@@ -178,7 +178,8 @@ class ExtensionWebRequestEventRouter {
const std::string& event_name,
const std::string& sub_event_name,
const RequestFilter& filter,
- int extra_info_spec);
+ int extra_info_spec,
+ base::WeakPtr<IPC::Message::Sender> ipc_sender);
// Removes the listener for the given sub-event.
void RemoveEventListener(
@@ -186,6 +187,12 @@ class ExtensionWebRequestEventRouter {
const std::string& extension_id,
const std::string& sub_event_name);
+ // Called when an incognito profile is created or destroyed.
+ void OnOTRProfileCreated(ProfileId original_profile_id,
+ ProfileId otr_profile_id);
+ void OnOTRProfileDestroyed(ProfileId original_profile_id,
+ ProfileId otr_profile_id);
+
private:
friend struct DefaultSingletonTraits<ExtensionWebRequestEventRouter>;
struct EventListener;
@@ -196,13 +203,13 @@ class ExtensionWebRequestEventRouter {
typedef std::map<uint64, net::URLRequest*> HttpRequestMap;
// Map of request_id -> bit vector of EventTypes already signaled
typedef std::map<uint64, int> SignaledRequestMap;
+ typedef std::map<ProfileId, ProfileId> CrossProfileMap;
ExtensionWebRequestEventRouter();
~ExtensionWebRequestEventRouter();
bool DispatchEvent(
ProfileId profile_id,
- ExtensionEventRouterForwarder* event_router,
net::URLRequest* request,
const std::vector<const EventListener*>& listeners,
const ListValue& args);
@@ -212,6 +219,7 @@ class ExtensionWebRequestEventRouter {
// set of extra_info_spec flags that every matching listener asked for.
std::vector<const EventListener*> GetMatchingListeners(
ProfileId profile_id,
+ ExtensionInfoMap* extension_info_map,
const std::string& event_name,
const GURL& url,
int tab_id,
@@ -222,10 +230,27 @@ class ExtensionWebRequestEventRouter {
// Same as above, but retrieves the filter parameters from the request.
std::vector<const EventListener*> GetMatchingListeners(
ProfileId profile_id,
+ ExtensionInfoMap* extension_info_map,
const std::string& event_name,
net::URLRequest* request,
int* extra_info_spec);
+ // Helper for the above functions. This is called twice: once for the profile
+ // of the event, the next time for the "cross" profile (i.e. the incognito
+ // profile if the event is originally for the normal profile, or vice versa).
+ void GetMatchingListenersImpl(
+ ProfileId profile_id,
+ ExtensionInfoMap* extension_info_map,
+ bool crosses_incognito,
+ const std::string& event_name,
+ const GURL& url,
+ int tab_id,
+ int window_id,
+ ResourceType::Type resource_type,
+ int* extra_info_spec,
+ std::vector<const ExtensionWebRequestEventRouter::EventListener*>*
+ matching_listeners);
+
// Decrements the count of event handlers blocking the given request. When the
// count reaches 0, we stop blocking the request and proceed it using the
// method requested by the extension with the highest precedence. Precedence
@@ -233,8 +258,6 @@ class ExtensionWebRequestEventRouter {
// method assumes ownership.
void DecrementBlockCount(uint64 request_id, EventResponse* response);
- void OnRequestDeleted(net::URLRequest* request);
-
// Sets the flag that |event_type| has been signaled for |request_id|.
// Returns the value of the flag before setting it.
bool GetAndSetSignaled(uint64 request_id, EventTypes event_type);
@@ -258,16 +281,20 @@ class ExtensionWebRequestEventRouter {
// signaled and should not be sent again.
SignaledRequestMap signaled_requests_;
+ // A map of original profile -> corresponding incognito profile (and vice
+ // versa).
+ CrossProfileMap cross_profile_map_;
+
DISALLOW_COPY_AND_ASSIGN(ExtensionWebRequestEventRouter);
};
-class WebRequestAddEventListener : public SyncExtensionFunction {
+class WebRequestAddEventListener : public SyncIOThreadExtensionFunction {
public:
virtual bool RunImpl();
DECLARE_EXTENSION_FUNCTION_NAME("experimental.webRequest.addEventListener");
};
-class WebRequestEventHandled : public SyncExtensionFunction {
+class WebRequestEventHandled : public SyncIOThreadExtensionFunction {
public:
virtual bool RunImpl();
DECLARE_EXTENSION_FUNCTION_NAME("experimental.webRequest.eventHandled");
diff --git a/chrome/browser/extensions/extension_webrequest_api_unittest.cc b/chrome/browser/extensions/extension_webrequest_api_unittest.cc
index e2ace67..67ff804 100644
--- a/chrome/browser/extensions/extension_webrequest_api_unittest.cc
+++ b/chrome/browser/extensions/extension_webrequest_api_unittest.cc
@@ -12,6 +12,7 @@
#include "chrome/browser/extensions/extension_webrequest_api_constants.h"
#include "chrome/browser/net/chrome_network_delegate.h"
#include "chrome/browser/prefs/pref_member.h"
+#include "chrome/common/extensions/extension_messages.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/testing_pref_service.h"
#include "chrome/test/testing_profile.h"
@@ -37,7 +38,7 @@ static void EventHandledOnIOThread(
// A mock event router that responds to events with a pre-arranged queue of
// Tasks.
-class TestEventRouter : public ExtensionEventRouterForwarder {
+class TestIPCSender : public IPC::Message::Sender {
public:
// Adds a Task to the queue. We will fire these in order as events are
// dispatched.
@@ -48,16 +49,15 @@ public:
size_t GetNumTasks() { return task_queue_.size(); }
private:
- // ExtensionEventRouterForwarder:
- virtual void HandleEvent(const std::string& extension_id,
- const std::string& event_name,
- const std::string& event_args,
- ProfileId profile_id,
- bool use_profile_to_restrict_events,
- const GURL& event_url) {
- ASSERT_FALSE(task_queue_.empty());
+ // IPC::Message::Sender
+ virtual bool Send(IPC::Message* message) {
+ EXPECT_EQ(ExtensionMsg_MessageInvoke::ID, message->type());
+
+ EXPECT_FALSE(task_queue_.empty());
MessageLoop::current()->PostTask(FROM_HERE, task_queue_.front());
task_queue_.pop();
+
+ return false;
}
std::queue<Task*> task_queue_;
@@ -66,11 +66,11 @@ private:
class ExtensionWebRequestTest : public testing::Test {
protected:
virtual void SetUp() {
- event_router_ = new TestEventRouter();
+ event_router_ = new ExtensionEventRouterForwarder();
enable_referrers_.Init(
prefs::kEnableReferrers, profile_.GetTestingPrefService(), NULL);
network_delegate_.reset(new ChromeNetworkDelegate(
- event_router_.get(), profile_.GetRuntimeId(),
+ event_router_.get(), NULL, profile_.GetRuntimeId(),
&enable_referrers_));
context_ = new TestURLRequestContext();
context_->set_network_delegate(network_delegate_.get());
@@ -80,7 +80,9 @@ protected:
TestingProfile profile_;
TestDelegate delegate_;
BooleanPrefMember enable_referrers_;
- scoped_refptr<TestEventRouter> event_router_;
+ TestIPCSender ipc_sender_;
+ scoped_refptr<ExtensionEventRouterForwarder> event_router_;
+ scoped_refptr<ExtensionInfoMap> extension_info_map_;
scoped_ptr<ChromeNetworkDelegate> network_delegate_;
scoped_refptr<TestURLRequestContext> context_;
};
@@ -93,14 +95,17 @@ TEST_F(ExtensionWebRequestTest, BlockingEventPrecedence) {
std::string extension2_id("2");
ExtensionWebRequestEventRouter::RequestFilter filter;
const std::string kEventName(keys::kOnBeforeRequest);
+ base::WeakPtrFactory<TestIPCSender> ipc_sender_factory(&ipc_sender_);
ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
profile_.GetRuntimeId(), extension1_id, kEventName,
kEventName + "/1", filter,
- ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING);
+ ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING,
+ ipc_sender_factory.GetWeakPtr());
ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
profile_.GetRuntimeId(), extension2_id, kEventName,
kEventName + "/2", filter,
- ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING);
+ ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING,
+ ipc_sender_factory.GetWeakPtr());
net::URLRequest request(GURL("about:blank"), &delegate_);
request.set_context(context_);
@@ -117,7 +122,7 @@ TEST_F(ExtensionWebRequestTest, BlockingEventPrecedence) {
response = new ExtensionWebRequestEventRouter::EventResponse(
extension1_id, base::Time::FromDoubleT(1));
response->cancel = true;
- event_router_->PushTask(
+ ipc_sender_.PushTask(
NewRunnableFunction(&EventHandledOnIOThread,
profile_.GetRuntimeId(), extension1_id,
kEventName, kEventName + "/1", request.identifier(), response));
@@ -126,7 +131,7 @@ TEST_F(ExtensionWebRequestTest, BlockingEventPrecedence) {
response = new ExtensionWebRequestEventRouter::EventResponse(
extension2_id, base::Time::FromDoubleT(2));
response->new_url = redirect_url;
- event_router_->PushTask(
+ ipc_sender_.PushTask(
NewRunnableFunction(&EventHandledOnIOThread,
profile_.GetRuntimeId(), extension2_id,
kEventName, kEventName + "/2", request.identifier(), response));
@@ -134,7 +139,7 @@ TEST_F(ExtensionWebRequestTest, BlockingEventPrecedence) {
// Extension2 response to the redirected URL. Arrives first, and chosen.
response = new ExtensionWebRequestEventRouter::EventResponse(
extension2_id, base::Time::FromDoubleT(2));
- event_router_->PushTask(
+ ipc_sender_.PushTask(
NewRunnableFunction(&EventHandledOnIOThread,
profile_.GetRuntimeId(), extension2_id,
kEventName, kEventName + "/2", request.identifier(), response));
@@ -143,7 +148,7 @@ TEST_F(ExtensionWebRequestTest, BlockingEventPrecedence) {
response = new ExtensionWebRequestEventRouter::EventResponse(
extension1_id, base::Time::FromDoubleT(1));
response->cancel = true;
- event_router_->PushTask(
+ ipc_sender_.PushTask(
NewRunnableFunction(&EventHandledOnIOThread,
profile_.GetRuntimeId(), extension1_id,
kEventName, kEventName + "/1", request.identifier(), response));
@@ -156,6 +161,6 @@ TEST_F(ExtensionWebRequestTest, BlockingEventPrecedence) {
EXPECT_EQ(0, request.status().os_error());
EXPECT_EQ(redirect_url, request.url());
EXPECT_EQ(2U, request.url_chain().size());
- EXPECT_EQ(0U, event_router_->GetNumTasks());
+ EXPECT_EQ(0U, ipc_sender_.GetNumTasks());
}
}
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index 0561bff..fba8719 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -456,6 +456,7 @@ void IOThread::Init() {
extension_event_router_forwarder_;
globals_->system_network_delegate.reset(new ChromeNetworkDelegate(
extension_event_router_forwarder_,
+ NULL,
Profile::kInvalidProfileId,
&system_enable_referrers_));
globals_->host_resolver.reset(
diff --git a/chrome/browser/net/chrome_network_delegate.cc b/chrome/browser/net/chrome_network_delegate.cc
index 0058ca5..91b76d3 100644
--- a/chrome/browser/net/chrome_network_delegate.cc
+++ b/chrome/browser/net/chrome_network_delegate.cc
@@ -7,6 +7,7 @@
#include "base/logging.h"
#include "chrome/browser/custom_handlers/protocol_handler_registry.h"
#include "chrome/browser/extensions/extension_event_router_forwarder.h"
+#include "chrome/browser/extensions/extension_info_map.h"
#include "chrome/browser/extensions/extension_proxy_api.h"
#include "chrome/browser/extensions/extension_webrequest_api.h"
#include "chrome/browser/prefs/pref_member.h"
@@ -41,10 +42,12 @@ void ForwardProxyErrors(net::URLRequest* request,
ChromeNetworkDelegate::ChromeNetworkDelegate(
ExtensionEventRouterForwarder* event_router,
+ ExtensionInfoMap* extension_info_map,
ProfileId profile_id,
BooleanPrefMember* enable_referrers)
: event_router_(event_router),
profile_id_(profile_id),
+ extension_info_map_(extension_info_map),
enable_referrers_(enable_referrers) {
DCHECK(event_router);
DCHECK(enable_referrers);
@@ -68,7 +71,7 @@ int ChromeNetworkDelegate::OnBeforeURLRequest(
if (!enable_referrers_->GetValue())
request->set_referrer(std::string());
return ExtensionWebRequestEventRouter::GetInstance()->OnBeforeRequest(
- profile_id_, event_router_.get(), request, callback, new_url);
+ profile_id_, extension_info_map_.get(), request, callback, new_url);
}
int ChromeNetworkDelegate::OnBeforeSendHeaders(
@@ -76,7 +79,7 @@ int ChromeNetworkDelegate::OnBeforeSendHeaders(
net::CompletionCallback* callback,
net::HttpRequestHeaders* headers) {
return ExtensionWebRequestEventRouter::GetInstance()->OnBeforeSendHeaders(
- profile_id_, event_router_.get(), request_id, callback, headers);
+ profile_id_, extension_info_map_.get(), request_id, callback, headers);
}
void ChromeNetworkDelegate::OnRequestSent(
@@ -84,19 +87,20 @@ void ChromeNetworkDelegate::OnRequestSent(
const net::HostPortPair& socket_address,
const net::HttpRequestHeaders& headers) {
ExtensionWebRequestEventRouter::GetInstance()->OnRequestSent(
- profile_id_, event_router_.get(), request_id, socket_address, headers);
+ profile_id_, extension_info_map_.get(), request_id,
+ socket_address, headers);
}
void ChromeNetworkDelegate::OnBeforeRedirect(net::URLRequest* request,
const GURL& new_location) {
ExtensionWebRequestEventRouter::GetInstance()->OnBeforeRedirect(
- profile_id_, event_router_.get(), request, new_location);
+ profile_id_, extension_info_map_.get(), request, new_location);
}
void ChromeNetworkDelegate::OnResponseStarted(net::URLRequest* request) {
ExtensionWebRequestEventRouter::GetInstance()->OnResponseStarted(
- profile_id_, event_router_.get(), request);
+ profile_id_, extension_info_map_.get(), request);
ForwardProxyErrors(request, event_router_.get(), profile_id_);
}
@@ -112,11 +116,11 @@ void ChromeNetworkDelegate::OnCompleted(net::URLRequest* request) {
request->response_headers()->response_code());
if (!is_redirect) {
ExtensionWebRequestEventRouter::GetInstance()->OnCompleted(
- profile_id_, event_router_.get(), request);
+ profile_id_, extension_info_map_.get(), request);
}
} else if (request->status().status() == net::URLRequestStatus::FAILED) {
ExtensionWebRequestEventRouter::GetInstance()->OnErrorOccurred(
- profile_id_, event_router_.get(), request);
+ profile_id_, extension_info_map_.get(), request);
}
ForwardProxyErrors(request, event_router_.get(), profile_id_);
}
diff --git a/chrome/browser/net/chrome_network_delegate.h b/chrome/browser/net/chrome_network_delegate.h
index 797ab35..113e0fe 100644
--- a/chrome/browser/net/chrome_network_delegate.h
+++ b/chrome/browser/net/chrome_network_delegate.h
@@ -13,6 +13,7 @@
#include "net/base/network_delegate.h"
class ExtensionEventRouterForwarder;
+class ExtensionInfoMap;
template<class T> class PrefMember;
typedef PrefMember<bool> BooleanPrefMember;
@@ -28,6 +29,7 @@ class ChromeNetworkDelegate : public net::NetworkDelegate {
// at shutdown.
ChromeNetworkDelegate(
ExtensionEventRouterForwarder* event_router,
+ ExtensionInfoMap* extension_info_map,
ProfileId profile_id,
BooleanPrefMember* enable_referrers);
virtual ~ChromeNetworkDelegate();
@@ -60,6 +62,8 @@ class ChromeNetworkDelegate : public net::NetworkDelegate {
scoped_refptr<ExtensionEventRouterForwarder> event_router_;
const ProfileId profile_id_;
+ scoped_refptr<ExtensionInfoMap> extension_info_map_;
+
// Weak, owned by our owner.
BooleanPrefMember* enable_referrers_;
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc
index 03f0113..b61febd 100644
--- a/chrome/browser/profiles/profile.cc
+++ b/chrome/browser/profiles/profile.cc
@@ -81,6 +81,18 @@ net::URLRequestContextGetter* Profile::default_request_context_;
namespace {
+void NotifyOTRProfileCreatedOnIOThread(ProfileId original_profile_id,
+ ProfileId otr_profile_id) {
+ ExtensionWebRequestEventRouter::GetInstance()->OnOTRProfileCreated(
+ original_profile_id, otr_profile_id);
+}
+
+void NotifyOTRProfileDestroyedOnIOThread(ProfileId original_profile_id,
+ ProfileId otr_profile_id) {
+ ExtensionWebRequestEventRouter::GetInstance()->OnOTRProfileDestroyed(
+ original_profile_id, otr_profile_id);
+}
+
} // namespace
Profile::Profile()
@@ -231,6 +243,12 @@ class OffTheRecordProfileImpl : public Profile,
// Make the chrome//extension-icon/ resource available.
ExtensionIconSource* icon_source = new ExtensionIconSource(real_profile);
GetChromeURLDataManager()->AddDataSource(icon_source);
+
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableFunction(
+ &NotifyOTRProfileCreatedOnIOThread,
+ profile_->GetRuntimeId(), GetRuntimeId()));
}
virtual ~OffTheRecordProfileImpl() {
@@ -240,6 +258,12 @@ class OffTheRecordProfileImpl : public Profile,
ProfileDependencyManager::GetInstance()->DestroyProfileServices(this);
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableFunction(
+ &NotifyOTRProfileDestroyedOnIOThread,
+ profile_->GetRuntimeId(), GetRuntimeId()));
+
// Clean up all DB files/directories
if (db_tracker_)
BrowserThread::PostTask(
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index ddf8906..a87fec7 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -909,11 +909,19 @@ net::URLRequestContextGetter* ProfileImpl::GetRequestContextForIsolatedApp(
void ProfileImpl::RegisterExtensionWithRequestContexts(
const Extension* extension) {
+ base::Time install_time;
+ if (extension->location() != Extension::COMPONENT) {
+ install_time = GetExtensionService()->extension_prefs()->
+ GetInstallTime(extension->id());
+ }
+ bool incognito_enabled =
+ GetExtensionService()->IsIncognitoEnabled(extension->id());
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableMethod(extension_info_map_.get(),
&ExtensionInfoMap::AddExtension,
- make_scoped_refptr(extension)));
+ make_scoped_refptr(extension),
+ install_time, incognito_enabled));
}
void ProfileImpl::UnregisterExtensionWithRequestContexts(
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index 9247f26..61260b1 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -406,6 +406,7 @@ void ProfileIOData::LazyInitialize() const {
network_delegate_.reset(new ChromeNetworkDelegate(
io_thread_globals->extension_event_router_forwarder.get(),
+ profile_params_->extension_info_map,
profile_params_->profile_id,
&enable_referrers_));
diff --git a/chrome/browser/renderer_host/chrome_render_message_filter.cc b/chrome/browser/renderer_host/chrome_render_message_filter.cc
index e91e8c8..d7393aa 100644
--- a/chrome/browser/renderer_host/chrome_render_message_filter.cc
+++ b/chrome/browser/renderer_host/chrome_render_message_filter.cc
@@ -11,6 +11,7 @@
#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/browser/content_settings/tab_specific_content_settings.h"
#include "chrome/browser/extensions/extension_event_router.h"
+#include "chrome/browser/extensions/extension_function_dispatcher.h"
#include "chrome/browser/extensions/extension_message_service.h"
#include "chrome/browser/metrics/histogram_synchronizer.h"
#include "chrome/browser/nacl_host/nacl_process_host.h"
@@ -44,8 +45,10 @@ ChromeRenderMessageFilter::ChromeRenderMessageFilter(
Profile* profile,
net::URLRequestContextGetter* request_context)
: render_process_id_(render_process_id),
+ profile_id_(profile->GetRuntimeId()),
profile_(profile),
- request_context_(request_context) {
+ request_context_(request_context),
+ weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
allow_outdated_plugins_.Init(prefs::kPluginsAllowOutdated,
profile_->GetPrefs(), NULL);
allow_outdated_plugins_.MoveToThread(BrowserThread::IO);
@@ -78,6 +81,8 @@ bool ChromeRenderMessageFilter::OnMessageReceived(const IPC::Message& message,
IPC_MESSAGE_HANDLER(ExtensionHostMsg_RemoveListener,
OnExtensionRemoveListener)
IPC_MESSAGE_HANDLER(ExtensionHostMsg_CloseChannel, OnExtensionCloseChannel)
+ IPC_MESSAGE_HANDLER(ExtensionHostMsg_RequestForIOThread,
+ OnExtensionRequestForIOThread)
#if defined(USE_TCMALLOC)
IPC_MESSAGE_HANDLER(ViewHostMsg_RendererTcmalloc, OnRendererTcmalloc)
#endif
@@ -113,6 +118,11 @@ bool ChromeRenderMessageFilter::OnMessageReceived(const IPC::Message& message,
}
void ChromeRenderMessageFilter::OnDestruct() const {
+ const_cast<ChromeRenderMessageFilter*>(this)->
+ weak_ptr_factory_.DetachFromThread();
+ const_cast<ChromeRenderMessageFilter*>(this)->
+ weak_ptr_factory_.InvalidateWeakPtrs();
+
// Destroy on the UI thread because we contain a PrefMember.
BrowserThread::DeleteOnUIThread::Destruct(this);
}
@@ -331,6 +341,17 @@ void ChromeRenderMessageFilter::OnExtensionCloseChannel(int port_id) {
profile_->GetExtensionMessageService()->CloseChannel(port_id);
}
+void ChromeRenderMessageFilter::OnExtensionRequestForIOThread(
+ int routing_id,
+ const ExtensionHostMsg_Request_Params& params) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ ChromeURLRequestContext* context = static_cast<ChromeURLRequestContext*>(
+ request_context_->GetURLRequestContext());
+ ExtensionFunctionDispatcher::DispatchOnIOThread(
+ context->extension_info_map(), profile_id_, render_process_id_,
+ weak_ptr_factory_.GetWeakPtr(), routing_id, params);
+}
#if defined(USE_TCMALLOC)
void ChromeRenderMessageFilter::OnRendererTcmalloc(base::ProcessId pid,
diff --git a/chrome/browser/renderer_host/chrome_render_message_filter.h b/chrome/browser/renderer_host/chrome_render_message_filter.h
index 1110517..867b824 100644
--- a/chrome/browser/renderer_host/chrome_render_message_filter.h
+++ b/chrome/browser/renderer_host/chrome_render_message_filter.h
@@ -6,8 +6,10 @@
#define CHROME_BROWSER_RENDERER_HOST_CHROME_RENDER_MESSAGE_FILTER_H_
#pragma once
+#include "base/memory/weak_ptr.h"
#include "chrome/common/content_settings.h"
#include "chrome/browser/prefs/pref_member.h"
+#include "chrome/browser/profiles/profile.h"
#include "content/browser/browser_message_filter.h"
#include "content/common/dom_storage_common.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebCache.h"
@@ -16,7 +18,6 @@ struct ExtensionHostMsg_Request_Params;
class FilePath;
class GURL;
class HostContentSettingsMap;
-class Profile;
namespace net {
class URLRequestContextGetter;
@@ -82,6 +83,9 @@ class ChromeRenderMessageFilter : public BrowserMessageFilter {
void OnExtensionRemoveListener(const std::string& extension_id,
const std::string& event_name);
void OnExtensionCloseChannel(int port_id);
+ void OnExtensionRequestForIOThread(
+ int routing_id,
+ const ExtensionHostMsg_Request_Params& params);
#if defined(USE_TCMALLOC)
void OnRendererTcmalloc(base::ProcessId pid, const std::string& output);
#endif
@@ -122,6 +126,7 @@ class ChromeRenderMessageFilter : public BrowserMessageFilter {
const std::string& cookie);
int render_process_id_;
+ ProfileId profile_id_;
// The Profile associated with our renderer process. This should only be
// accessed on the UI thread!
@@ -133,6 +138,8 @@ class ChromeRenderMessageFilter : public BrowserMessageFilter {
BooleanPrefMember allow_outdated_plugins_;
BooleanPrefMember always_authorize_plugins_;
+ base::WeakPtrFactory<ChromeRenderMessageFilter> weak_ptr_factory_;
+
DISALLOW_COPY_AND_ASSIGN(ChromeRenderMessageFilter);
};
diff --git a/chrome/browser/ui/panels/panel_browser_view_browsertest.cc b/chrome/browser/ui/panels/panel_browser_view_browsertest.cc
index a35620f..863f992 100644
--- a/chrome/browser/ui/panels/panel_browser_view_browsertest.cc
+++ b/chrome/browser/ui/panels/panel_browser_view_browsertest.cc
@@ -215,13 +215,9 @@ class PanelBrowserViewTest : public InProcessBrowserTest {
&error);
ASSERT_TRUE(extension.get());
EXPECT_STREQ("", error.c_str());
- browser()->GetProfile()->GetExtensionService()->AddExtension(
+ browser()->GetProfile()->GetExtensionService()->OnLoadSingleExtension(
extension.get());
- // Makes sure that async task ExtensionPrefs::OnExtensionInstalled gets a
- // chance to be procesed.
- MessageLoop::current()->RunAllPending();
-
// Creates a panel with the app name that comes from the extension ID.
PanelBrowserView* browser_view = CreatePanelBrowserView(
web_app::GenerateApplicationNameFromExtensionId(extension->id()));