diff options
author | mpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-06-09 20:52:42 +0000 |
---|---|---|
committer | mpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-06-09 20:52:42 +0000 |
commit | c357acb4058ca346d8e22d29a9d12c72f5d327b4 (patch) | |
tree | 8951ca281e3a73c14e5defc119a6ec8723bff67e /chrome/browser | |
parent | 34d38beaec22c3c958a477097df274669d023aa2 (diff) | |
download | chromium_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')
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(¶ms.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(¶ms.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())); |