diff options
author | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-11 23:54:37 +0000 |
---|---|---|
committer | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-11 23:54:37 +0000 |
commit | 4bae577ea5e80c18d50cbfbd69892412a960a617 (patch) | |
tree | 73992b88d7a13ba00cf4e1ec5497116938b98228 /chrome/browser | |
parent | 7acf63cef0c03ed87b5f9f389a6b2b1828039b87 (diff) | |
download | chromium_src-4bae577ea5e80c18d50cbfbd69892412a960a617.zip chromium_src-4bae577ea5e80c18d50cbfbd69892412a960a617.tar.gz chromium_src-4bae577ea5e80c18d50cbfbd69892412a960a617.tar.bz2 |
Re-land r84928: Move ExtensionFunctionDispatcher to
ExtensionTabHelper.
This reverts commit 89a6b9d9232949a01b8263779fa819ed4d5b3089.
TBR=mpcomplete@chromium.org
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@85076 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
25 files changed, 404 insertions, 437 deletions
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index b7ce694..8efed98 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc @@ -26,13 +26,19 @@ #include "chrome/browser/ui/webui/chrome_web_ui_factory.h" #include "chrome/common/child_process_logging.h" #include "chrome/common/chrome_switches.h" +#include "chrome/common/extensions/extension_messages.h" #include "chrome/common/pref_names.h" +#include "chrome/common/url_constants.h" +#include "content/browser/browsing_instance.h" +#include "content/browser/child_process_security_policy.h" #include "content/browser/renderer_host/browser_render_process_host.h" #include "content/browser/renderer_host/render_view_host.h" #include "content/browser/renderer_host/render_view_host_notification_task.h" #include "content/browser/resource_context.h" +#include "content/browser/site_instance.h" #include "content/browser/tab_contents/tab_contents.h" #include "content/browser/worker_host/worker_process_host.h" +#include "content/common/bindings_policy.h" #include "net/base/cookie_monster.h" #include "net/base/cookie_options.h" #include "net/base/static_cookie_policy.h" @@ -42,6 +48,65 @@ #include "chrome/browser/crash_handler_host_linux.h" #endif // OS_LINUX +namespace { + +void InitRenderViewHostForExtensions(RenderViewHost* render_view_host) { + // Note that due to GetEffectiveURL(), even hosted apps will have a + // chrome-extension:// URL for their site, so we can ignore that wrinkle here. + SiteInstance* site_instance = render_view_host->site_instance(); + const GURL& site = site_instance->site(); + RenderProcessHost* process = render_view_host->process(); + + if (!site.SchemeIs(chrome::kExtensionScheme)) + return; + + Profile* profile = site_instance->browsing_instance()->profile(); + ExtensionService* service = profile->GetExtensionService(); + if (!service) + return; + + ExtensionProcessManager* process_manager = + profile->GetExtensionProcessManager(); + CHECK(process_manager); + + // This can happen if somebody typos a chrome-extension:// URL. + const Extension* extension = service->GetExtensionByURL(site); + if (!extension) + return; + + site_instance->GetProcess()->mark_is_extension_process(); + + // Register the association between extension and process with + // ExtensionProcessManager. + process_manager->RegisterExtensionProcess(extension->id(), process->id()); + + // Record which, if any, installed app is associated with this process. + // TODO(aa): Totally lame to store this state in a global map in extension + // service. Can we get it from EPM instead? + if (extension->is_app()) + service->SetInstalledAppForRenderer(process->id(), extension); + + // Some extensions use chrome:// URLs. + Extension::Type type = extension->GetType(); + if (type == Extension::TYPE_EXTENSION || + type == Extension::TYPE_PACKAGED_APP) { + ChildProcessSecurityPolicy::GetInstance()->GrantScheme( + process->id(), chrome::kChromeUIScheme); + } + + // Enable extension bindings for the renderer. Currently only extensions, + // packaged apps, and hosted component apps use extension bindings. + if (type == Extension::TYPE_EXTENSION || + type == Extension::TYPE_PACKAGED_APP || + (type == Extension::TYPE_HOSTED_APP && + extension->location() == Extension::COMPONENT)) { + render_view_host->Send(new ExtensionMsg_ActivateExtension(extension->id())); + render_view_host->AllowBindings(BindingsPolicy::EXTENSION); + } +} + +} + namespace chrome { void ChromeContentBrowserClient::RenderViewHostCreated( @@ -50,24 +115,8 @@ void ChromeContentBrowserClient::RenderViewHostCreated( new DesktopNotificationHandler(render_view_host); new DevToolsHandler(render_view_host); new ExtensionMessageHandler(render_view_host); -} -void ChromeContentBrowserClient::PreCreateRenderView( - RenderViewHost* render_view_host, - Profile* profile, - const GURL& url) { - // Tell the RenderViewHost whether it will be used for an extension process. - ExtensionService* service = profile->GetExtensionService(); - if (service) { - bool is_extension_process = service->ExtensionBindingsAllowed(url); - render_view_host->set_is_extension_process(is_extension_process); - - const Extension* installed_app = service->GetInstalledApp(url); - if (installed_app) { - service->SetInstalledAppForRenderer( - render_view_host->process()->id(), installed_app); - } - } + InitRenderViewHostForExtensions(render_view_host); } void ChromeContentBrowserClient::BrowserRenderProcessHostCreated( diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h index ee81fd3..2ba3e24 100644 --- a/chrome/browser/chrome_content_browser_client.h +++ b/chrome/browser/chrome_content_browser_client.h @@ -13,9 +13,6 @@ namespace chrome { class ChromeContentBrowserClient : public content::ContentBrowserClient { public: virtual void RenderViewHostCreated(RenderViewHost* render_view_host); - virtual void PreCreateRenderView(RenderViewHost* render_view_host, - Profile* profile, - const GURL& url); virtual void BrowserRenderProcessHostCreated(BrowserRenderProcessHost* host); virtual void WorkerProcessHostCreated(WorkerProcessHost* host); virtual content::WebUIFactory* GetWebUIFactory(); diff --git a/chrome/browser/extensions/extension_bookmark_manager_api.cc b/chrome/browser/extensions/extension_bookmark_manager_api.cc index 6f23fe8..6d89d373 100644 --- a/chrome/browser/extensions/extension_bookmark_manager_api.cc +++ b/chrome/browser/extensions/extension_bookmark_manager_api.cc @@ -365,12 +365,13 @@ bool StartDragBookmarkManagerFunction::RunImpl() { EXTENSION_FUNCTION_VALIDATE( GetNodesFromArguments(model, args_.get(), 0, &nodes)); - if (dispatcher()->render_view_host()->delegate()->GetRenderViewType() == + if (render_view_host_->delegate()->GetRenderViewType() == ViewType::TAB_CONTENTS) { - ExtensionWebUI* web_ui = - static_cast<ExtensionWebUI*>(dispatcher()->delegate()); - bookmark_utils::DragBookmarks( - profile(), nodes, web_ui->tab_contents()->GetNativeView()); + TabContents* tab_contents = + dispatcher()->delegate()->GetAssociatedTabContents(); + CHECK(tab_contents); + bookmark_utils::DragBookmarks(profile(), nodes, + tab_contents->GetNativeView()); return true; } else { @@ -406,10 +407,14 @@ bool DropBookmarkManagerFunction::RunImpl() { else drop_index = drop_parent->child_count(); - if (dispatcher()->render_view_host()->delegate()->GetRenderViewType() == + if (render_view_host_->delegate()->GetRenderViewType() == ViewType::TAB_CONTENTS) { + TabContents* tab_contents = + dispatcher()->delegate()->GetAssociatedTabContents(); + CHECK(tab_contents); ExtensionWebUI* web_ui = - static_cast<ExtensionWebUI*>(dispatcher()->delegate()); + static_cast<ExtensionWebUI*>(tab_contents->web_ui()); + CHECK(web_ui); ExtensionBookmarkManagerEventRouter* router = web_ui->extension_bookmark_manager_event_router(); diff --git a/chrome/browser/extensions/extension_bookmarks_module.cc b/chrome/browser/extensions/extension_bookmarks_module.cc index 1777e79..37a814f 100644 --- a/chrome/browser/extensions/extension_bookmarks_module.cc +++ b/chrome/browser/extensions/extension_bookmarks_module.cc @@ -856,7 +856,7 @@ void BookmarksIOFunction::ShowSelectFileDialog(SelectFileDialog::Type type, file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("html")); TabContents* tab_contents = dispatcher()->delegate()-> - associated_tab_contents(); + GetAssociatedTabContents(); // |tab_contents| can be NULL (for background pages), which is fine. In such // a case if file-selection dialogs are forbidden by policy, we will not diff --git a/chrome/browser/extensions/extension_file_browser_private_api.cc b/chrome/browser/extensions/extension_file_browser_private_api.cc index bff14a5..6063d3c 100644 --- a/chrome/browser/extensions/extension_file_browser_private_api.cc +++ b/chrome/browser/extensions/extension_file_browser_private_api.cc @@ -352,8 +352,7 @@ void RequestLocalFileSystemFunction::RequestOnFileThread( } bool RequestLocalFileSystemFunction::RunImpl() { - if (!dispatcher() || !dispatcher()->render_view_host() || - !dispatcher()->render_view_host()->process()) + if (!dispatcher() || !render_view_host() || !render_view_host()->process()) return false; BrowserThread::PostTask( @@ -361,7 +360,7 @@ bool RequestLocalFileSystemFunction::RunImpl() { NewRunnableMethod(this, &RequestLocalFileSystemFunction::RequestOnFileThread, source_url_, - dispatcher()->render_view_host()->process()->id())); + render_view_host()->process()->id())); // Will finish asynchronously. return true; } @@ -678,7 +677,7 @@ void ExecuteTasksFileBrowserFunction::RequestFileEntryOnFileThread( new ExecuteTasksFileSystemCallbackDispatcher( this, profile(), - dispatcher()->render_view_host()->process()->id(), + render_view_host()->process()->id(), source_url, GetExtension(), task_id, @@ -804,13 +803,13 @@ FileDialogFunction::Callback::Find(int32 tab_id) { int32 FileDialogFunction::GetTabId() const { - return dispatcher()->delegate()->associated_tab_contents()-> + return dispatcher()->delegate()->GetAssociatedTabContents()-> controller().session_id().id(); } const FileDialogFunction::Callback& FileDialogFunction::GetCallback() const { if (!dispatcher() || !dispatcher()->delegate() || - !dispatcher()->delegate()->associated_tab_contents()) { + !dispatcher()->delegate()->GetAssociatedTabContents()) { return Callback::null(); } return Callback::Find(GetTabId()); @@ -818,7 +817,7 @@ const FileDialogFunction::Callback& FileDialogFunction::GetCallback() const { void FileDialogFunction::CloseDialog(HtmlDialogView* dialog) { DCHECK(dialog); - TabContents* contents = dispatcher()->delegate()->associated_tab_contents(); + TabContents* contents = dispatcher()->delegate()->GetAssociatedTabContents(); if (contents) dialog->CloseContents(contents); } diff --git a/chrome/browser/extensions/extension_function.cc b/chrome/browser/extensions/extension_function.cc index 9f0d065..f390d72 100644 --- a/chrome/browser/extensions/extension_function.cc +++ b/chrome/browser/extensions/extension_function.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,6 +9,31 @@ #include "chrome/browser/extensions/extension_function_dispatcher.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/profiles/profile.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" +#include "content/browser/user_metrics.h" +#include "content/common/notification_source.h" +#include "content/common/notification_type.h" +#include "content/common/result_codes.h" + +ExtensionFunction::RenderViewHostTracker::RenderViewHostTracker( + ExtensionFunction* function) + : function_(function) { + registrar_.Add(this, + NotificationType::RENDER_VIEW_HOST_DELETED, + Source<RenderViewHost>(function->render_view_host())); +} + +void ExtensionFunction::RenderViewHostTracker::Observe( + NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + CHECK(type == NotificationType::RENDER_VIEW_HOST_DELETED); + CHECK(Source<RenderViewHost>(source).ptr() == + function_->render_view_host()); + function_->SetRenderViewHost(NULL); +} ExtensionFunction::ExtensionFunction() : request_id_(-1), @@ -21,6 +46,11 @@ ExtensionFunction::ExtensionFunction() ExtensionFunction::~ExtensionFunction() { } +void ExtensionFunction::SetRenderViewHost(RenderViewHost* render_view_host) { + render_view_host_ = render_view_host; + tracker_.reset(render_view_host ? new RenderViewHostTracker(this) : NULL); +} + const Extension* ExtensionFunction::GetExtension() { ExtensionService* service = profile_->GetExtensionService(); DCHECK(service); @@ -28,7 +58,7 @@ const Extension* ExtensionFunction::GetExtension() { } Browser* ExtensionFunction::GetCurrentBrowser() { - return dispatcher()->GetCurrentBrowser(include_incognito_); + return dispatcher()->GetCurrentBrowser(render_view_host_, include_incognito_); } AsyncExtensionFunction::AsyncExtensionFunction() @@ -61,12 +91,28 @@ void AsyncExtensionFunction::Run() { } void AsyncExtensionFunction::SendResponse(bool success) { - if (!dispatcher()) + if (!render_view_host_ || !dispatcher()) return; if (bad_message_) { - dispatcher()->HandleBadMessage(this); + HandleBadMessage(); + return; + } + + render_view_host_->Send(new ExtensionMsg_Response( + render_view_host_->routing_id(), request_id_, success, + GetResult(), GetError())); +} + +void AsyncExtensionFunction::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 { - dispatcher()->SendResponse(this, success); + NOTREACHED(); + UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_EFD")); + base::KillProcess(render_view_host_->process()->GetHandle(), + ResultCodes::KILLED_BAD_MESSAGE, false); } } diff --git a/chrome/browser/extensions/extension_function.h b/chrome/browser/extensions/extension_function.h index 7913703..9ec4ea8 100644 --- a/chrome/browser/extensions/extension_function.h +++ b/chrome/browser/extensions/extension_function.h @@ -12,6 +12,9 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "chrome/browser/extensions/extension_function_dispatcher.h" +#include "content/browser/browser_thread.h" +#include "content/common/notification_observer.h" +#include "content/common/notification_registrar.h" class ExtensionFunctionDispatcher; class ListValue; @@ -37,10 +40,14 @@ class Value; // Abstract base class for extension functions the ExtensionFunctionDispatcher // knows how to dispatch to. -class ExtensionFunction : public base::RefCountedThreadSafe<ExtensionFunction> { +class ExtensionFunction + : public base::RefCountedThreadSafe<ExtensionFunction, + BrowserThread::DeleteOnUIThread> { public: ExtensionFunction(); + virtual ~ExtensionFunction(); + // Specifies the name of the function. void set_name(const std::string& name) { name_ = name; } const std::string name() const { return name_; } @@ -56,6 +63,9 @@ class ExtensionFunction : public base::RefCountedThreadSafe<ExtensionFunction> { } std::string extension_id() const { return extension_id_; } + void SetRenderViewHost(RenderViewHost* render_view_host); + RenderViewHost* render_view_host() const { return render_view_host_; } + // Specifies the raw arguments to the function, as a JSON value. virtual void SetArgs(const ListValue* args) = 0; @@ -102,8 +112,6 @@ class ExtensionFunction : public base::RefCountedThreadSafe<ExtensionFunction> { protected: friend class base::RefCountedThreadSafe<ExtensionFunction>; - virtual ~ExtensionFunction(); - // Gets the extension that called this function. This can return NULL for // async functions, for example if the extension is unloaded while the // function is running. @@ -130,6 +138,9 @@ class ExtensionFunction : public base::RefCountedThreadSafe<ExtensionFunction> { // The peer to the dispatcher that will service this extension function call. scoped_refptr<ExtensionFunctionDispatcher::Peer> peer_; + // The RenderViewHost we will send responses too. + RenderViewHost* render_view_host_; + // Id of this request, used to map the response back to the caller. int request_id_; @@ -158,6 +169,26 @@ class ExtensionFunction : public base::RefCountedThreadSafe<ExtensionFunction> { // True if the call was made in response of user gesture. bool user_gesture_; + private: + // Helper class to track the lifetime of ExtensionFunction's RenderViewHost + // pointer and NULL it out when it dies. We use this separate class (instead + // of implementing NotificationObserver on ExtensionFunction) because it is + // common for subclasses of ExtensionFunction to be NotificationObservers, and + // it would be an easy error to forget to call the base class's Observe() + // method. + class RenderViewHostTracker : public NotificationObserver { + public: + explicit RenderViewHostTracker(ExtensionFunction* extension_function); + private: + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + ExtensionFunction* function_; + NotificationRegistrar registrar_; + }; + + scoped_ptr<RenderViewHostTracker> tracker_; + DISALLOW_COPY_AND_ASSIGN(ExtensionFunction); }; @@ -204,6 +235,13 @@ class AsyncExtensionFunction : public ExtensionFunction { // returning. The calling renderer process will be killed. bool bad_message_; + private: + // 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. + void HandleBadMessage(); + DISALLOW_COPY_AND_ASSIGN(AsyncExtensionFunction); }; diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc index 6a69d42..8a27836 100644 --- a/chrome/browser/extensions/extension_function_dispatcher.cc +++ b/chrome/browser/extensions/extension_function_dispatcher.cc @@ -30,7 +30,6 @@ #include "chrome/browser/extensions/extension_omnibox_api.h" #include "chrome/browser/extensions/extension_page_actions_module.h" #include "chrome/browser/extensions/extension_preference_api.h" -#include "chrome/browser/extensions/extension_process_manager.h" #include "chrome/browser/extensions/extension_processes_api.h" #include "chrome/browser/extensions/extension_proxy_api.h" #include "chrome/browser/extensions/extension_rlz_module.h" @@ -52,9 +51,6 @@ #include "content/browser/child_process_security_policy.h" #include "content/browser/renderer_host/render_process_host.h" #include "content/browser/renderer_host/render_view_host.h" -#include "content/browser/user_metrics.h" -#include "content/common/notification_service.h" -#include "content/common/result_codes.h" #include "ipc/ipc_message.h" #include "ipc/ipc_message_macros.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -385,71 +381,19 @@ void ExtensionFunctionDispatcher::ResetFunctions() { FactoryRegistry::GetInstance()->ResetFunctions(); } -ExtensionFunctionDispatcher* ExtensionFunctionDispatcher::Create( - RenderViewHost* render_view_host, - Delegate* delegate, - const GURL& url) { - ExtensionService* service = - render_view_host->process()->profile()->GetExtensionService(); - DCHECK(service); - - if (!service->ExtensionBindingsAllowed(url)) - return NULL; - - const Extension* extension = service->GetExtensionByURL(url); - if (!extension) - extension = service->GetExtensionByWebExtent(url); - - if (extension) - return new ExtensionFunctionDispatcher(render_view_host, delegate, - extension, url); - else - return NULL; -} - -ExtensionFunctionDispatcher::ExtensionFunctionDispatcher( - RenderViewHost* render_view_host, - Delegate* delegate, - const Extension* extension, - const GURL& url) - : profile_(render_view_host->process()->profile()), - render_view_host_(render_view_host), +ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(Profile* profile, + Delegate* delegate) + : profile_(profile), delegate_(delegate), - url_(url), - extension_id_(extension->id()), ALLOW_THIS_IN_INITIALIZER_LIST(peer_(new Peer(this))) { - // TODO(erikkay) should we do something for these errors in Release? - DCHECK(extension); - DCHECK(url.SchemeIs(chrome::kExtensionScheme) || - extension->location() == Extension::COMPONENT); - - // Notify the ExtensionProcessManager that the view was created. - ExtensionProcessManager* epm = profile()->GetExtensionProcessManager(); - epm->RegisterExtensionProcess(extension_id(), - render_view_host->process()->id()); - - // Activate this extension in the renderer. This must be done before any - // extension JavaScript code runs because it controls some privileges the - // extension code has in the renderer. - render_view_host->Send(new ExtensionMsg_ActivateExtension(extension->id())); - - NotificationService::current()->Notify( - NotificationType::EXTENSION_FUNCTION_DISPATCHER_CREATED, - Source<Profile>(profile_), - Details<ExtensionFunctionDispatcher>(this)); } ExtensionFunctionDispatcher::~ExtensionFunctionDispatcher() { peer_->dispatcher_ = NULL; - - NotificationService::current()->Notify( - NotificationType::EXTENSION_FUNCTION_DISPATCHER_DESTROYED, - Source<Profile>(profile_), - Details<ExtensionFunctionDispatcher>(this)); } Browser* ExtensionFunctionDispatcher::GetCurrentBrowser( - bool include_incognito) { + RenderViewHost* render_view_host, bool include_incognito) { Browser* browser = delegate_->GetBrowser(); // If the delegate has an associated browser, that is always the right answer. @@ -461,7 +405,7 @@ Browser* ExtensionFunctionDispatcher::GetCurrentBrowser( // profile. Note that the profile may already be incognito, in which case // we will search the incognito version only, regardless of the value of // |include_incognito|. - Profile* profile = render_view_host()->process()->profile(); + Profile* profile = render_view_host->process()->profile(); browser = BrowserList::FindTabbedBrowser(profile, include_incognito); // NOTE(rafaelw): This can return NULL in some circumstances. In particular, @@ -473,88 +417,84 @@ Browser* ExtensionFunctionDispatcher::GetCurrentBrowser( return browser; } -bool ExtensionFunctionDispatcher::OnMessageReceived( - const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(ExtensionFunctionDispatcher, message) - IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} +void ExtensionFunctionDispatcher::Dispatch( + const ExtensionHostMsg_Request_Params& params, + RenderViewHost* render_view_host) { + // TODO(aa): It would be cool to use ExtensionProcessManager to track which + // processes are extension processes rather than ChildProcessSecurityPolicy. + // EPM has richer information: it not only knows which processes contain + // at least one extension, but it knows which extensions are inside and what + // permissions the have. So we would be able to enforce permissions more + // granularly. + if (!ChildProcessSecurityPolicy::GetInstance()->HasExtensionBindings( + render_view_host->process()->id())) { + // TODO(aa): Allow content scripts access to low-threat extension APIs. + // See: crbug.com/80308. + LOG(ERROR) << "Extension API called from non-extension process."; + SendAccessDenied(render_view_host, params.request_id); + return; + } + + ExtensionService* service = profile()->GetExtensionService(); + if (!service) + return; + + if (!service->ExtensionBindingsAllowed(params.source_url)) { + LOG(ERROR) << "Extension bindings not allowed for URL: " + << params.source_url.spec(); + SendAccessDenied(render_view_host, params.request_id); + return; + } + + // TODO(aa): When we allow content scripts to call extension APIs, we will + // have to pass the extension ID explicitly here, not use the source URL. + const Extension* extension = service->GetExtensionByURL(params.source_url); + if (!extension) + extension = service->GetExtensionByWebExtent(params.source_url); + if (!extension) { + LOG(ERROR) << "Extension does not exist for URL: " + << params.source_url.spec(); + SendAccessDenied(render_view_host, params.request_id); + return; + } -void ExtensionFunctionDispatcher::OnRequest( - const ExtensionHostMsg_Request_Params& params) { - if (!ChildProcessSecurityPolicy::GetInstance()-> - HasExtensionBindings(render_view_host_->process()->id())) { - // This can happen if someone uses window.open() to open an extension URL - // from a non-extension context. - render_view_host_->Send(new ExtensionMsg_Response( - render_view_host_->routing_id(), params.request_id, false, - std::string(), "Access to extension API denied.")); + 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); return; } scoped_refptr<ExtensionFunction> function( FactoryRegistry::GetInstance()->NewFunction(params.name)); + function->SetRenderViewHost(render_view_host); function->set_dispatcher_peer(peer_); function->set_profile(profile_); - function->set_extension_id(extension_id()); + function->set_extension_id(extension->id()); function->SetArgs(¶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); - ExtensionService* service = profile()->GetExtensionService(); - DCHECK(service); - const Extension* extension = service->GetExtensionById(extension_id(), false); - DCHECK(extension); function->set_include_incognito(service->CanCrossIncognito(extension)); - if (!service->ExtensionBindingsAllowed(function->source_url()) || - !extension->HasApiPermission(function->name())) { - render_view_host_->Send(new ExtensionMsg_Response( - render_view_host_->routing_id(), function->request_id(), false, - std::string(), "Access to extension API denied.")); - return; - } - ExtensionsQuotaService* quota = service->quota_service(); - if (quota->Assess(extension_id(), function, ¶ms.arguments, + if (quota->Assess(extension->id(), function, ¶ms.arguments, base::TimeTicks::Now())) { // See crbug.com/39178. ExternalProtocolHandler::PermitLaunchUrl(); function->Run(); } else { - render_view_host_->Send(new ExtensionMsg_Response( - render_view_host_->routing_id(), function->request_id(), false, + render_view_host->Send(new ExtensionMsg_Response( + render_view_host->routing_id(), function->request_id(), false, std::string(), QuotaLimitHeuristic::kGenericOverQuotaError)); } } -void ExtensionFunctionDispatcher::SendResponse(ExtensionFunction* function, - bool success) { - render_view_host_->Send(new ExtensionMsg_Response( - render_view_host_->routing_id(), function->request_id(), success, - function->GetResult(), function->GetError())); -} - -void ExtensionFunctionDispatcher::HandleBadMessage(ExtensionFunction* api) { - LOG(ERROR) << "bad extension message " << - api->name() << - " : terminating renderer."; - if (RenderProcessHost::run_renderer_in_process()) { - // In single process mode it is better if we don't suicide but just crash. - CHECK(false); - } else { - NOTREACHED(); - UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_EFD")); - base::KillProcess(render_view_host_->process()->GetHandle(), - ResultCodes::KILLED_BAD_MESSAGE, false); - } -} - -Profile* ExtensionFunctionDispatcher::profile() { - return profile_; +void ExtensionFunctionDispatcher::SendAccessDenied( + RenderViewHost* render_view_host, int request_id) { + render_view_host->Send(new ExtensionMsg_Response( + render_view_host->routing_id(), request_id, false, std::string(), + "Access to extension API denied.")); } diff --git a/chrome/browser/extensions/extension_function_dispatcher.h b/chrome/browser/extensions/extension_function_dispatcher.h index 9f91d9d..d3b8d1c 100644 --- a/chrome/browser/extensions/extension_function_dispatcher.h +++ b/chrome/browser/extensions/extension_function_dispatcher.h @@ -11,7 +11,6 @@ #include "base/memory/ref_counted.h" #include "googleurl/src/gurl.h" -#include "ipc/ipc_channel.h" #include "ui/gfx/native_widget_types.h" class Browser; @@ -27,9 +26,19 @@ struct ExtensionHostMsg_Request_Params; typedef ExtensionFunction* (*ExtensionFunctionFactory)(); // ExtensionFunctionDispatcher receives requests to execute functions from -// Chromium extensions running in a RenderViewHost and dispatches them to the +// Chrome extensions running in a RenderViewHost and dispatches them to the // appropriate handler. It lives entirely on the UI thread. -class ExtensionFunctionDispatcher : public IPC::Channel::Listener { +// +// ExtensionFunctionDispatcher should be a member of some class that hosts +// RenderViewHosts and wants them to be able to display extension content. +// This class should also implement ExtensionFunctionDispatcher::Delegate. +// +// Note that a single ExtensionFunctionDispatcher does *not* correspond to a +// single RVH, a single extension, or a single URL. This is by design so that +// we can gracefully handle cases like TabContents, where the RVH, extension, +// and URL can all change over the lifetime of the tab. Instead, these items +// are all passed into each request. +class ExtensionFunctionDispatcher { public: class Delegate { public: @@ -45,7 +54,7 @@ class ExtensionFunctionDispatcher : public IPC::Channel::Listener { // context. For example, the TabContents in which an infobar or // chrome-extension://<id> URL are being shown. Callers must check for a // NULL return value (as in the case of a background page). - virtual TabContents* associated_tab_contents() const = 0; + virtual TabContents* GetAssociatedTabContents() const = 0; protected: virtual ~Delegate() {} @@ -76,21 +85,19 @@ class ExtensionFunctionDispatcher : public IPC::Channel::Listener { // Resets all functions to their initial implementation. static void ResetFunctions(); - // Creates an instance for the specified RenderViewHost and URL. If the URL - // does not contain a valid extension, returns NULL. - static ExtensionFunctionDispatcher* Create(RenderViewHost* render_view_host, - Delegate* delegate, - const GURL& url); + // Public constructor. Callers must ensure that: + // - |delegate| outlives this object. + // - This object outlives any RenderViewHost's passed to created + // ExtensionFunctions. + ExtensionFunctionDispatcher(Profile* profile, Delegate* delegate); ~ExtensionFunctionDispatcher(); Delegate* delegate() { return delegate_; } - // If |message| is an extension request, handle it. Returns true if handled. - virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; - - // Send a response to a function. - void SendResponse(ExtensionFunction* api, bool success); + // Message handlers. + void Dispatch(const ExtensionHostMsg_Request_Params& params, + RenderViewHost* sender); // Returns the current browser. Callers should generally prefer // ExtensionFunction::GetCurrentBrowser() over this method, as that one @@ -98,46 +105,20 @@ class ExtensionFunctionDispatcher : public IPC::Channel::Listener { // // See the comments for ExtensionFunction::GetCurrentBrowser() for more // details. - Browser* GetCurrentBrowser(bool include_incognito); - - // Handle a malformed message. Possibly the result of an attack, so kill - // the renderer. - void HandleBadMessage(ExtensionFunction* api); - - // Gets the URL for the view we're displaying. - const GURL& url() { return url_; } - - // Gets the ID for this extension. - const std::string extension_id() { return extension_id_; } + Browser* GetCurrentBrowser(RenderViewHost* render_view_host, + bool include_incognito); // The profile that this dispatcher is associated with. - Profile* profile(); - - // The RenderViewHost this dispatcher is associated with. - RenderViewHost* render_view_host() { return render_view_host_; } + Profile* profile() { return profile_; } private: - ExtensionFunctionDispatcher(RenderViewHost* render_view_host, - Delegate* delegate, - const Extension* extension, - const GURL& url); + // Helper to send an access denied error to the requesting render view. + void SendAccessDenied(RenderViewHost* render_view_host, int request_id); - // Message handlers. - void OnRequest(const ExtensionHostMsg_Request_Params& params); - - // We need to keep a pointer to the profile because we use it in the dtor - // in sending EXTENSION_FUNCTION_DISPATCHER_DESTROYED, but by that point - // the render_view_host_ has been deleted. Profile* profile_; - RenderViewHost* render_view_host_; - Delegate* delegate_; - GURL url_; - - std::string extension_id_; - scoped_refptr<Peer> peer_; }; diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc index 7badebf..318ca0b 100644 --- a/chrome/browser/extensions/extension_host.cc +++ b/chrome/browser/extensions/extension_host.cc @@ -28,6 +28,7 @@ #include "chrome/common/chrome_constants.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_constants.h" +#include "chrome/common/extensions/extension_messages.h" #include "chrome/common/render_messages.h" #include "chrome/common/url_constants.h" #include "chrome/common/view_types.h" @@ -131,17 +132,13 @@ ExtensionHost::ExtensionHost(const Extension* extension, did_stop_loading_(false), document_element_available_(false), url_(url), + ALLOW_THIS_IN_INITIALIZER_LIST( + extension_function_dispatcher_(profile_, this)), extension_host_type_(host_type), associated_tab_contents_(NULL), suppress_javascript_messages_(false) { render_view_host_ = new RenderViewHost(site_instance, this, MSG_ROUTING_NONE, NULL); - render_view_host_->set_is_extension_process(true); - if (extension->is_app()) { - profile()->GetExtensionService()->SetInstalledAppForRenderer( - render_view_host_->process()->id(), extension); - } - render_view_host_->AllowBindings(BindingsPolicy::EXTENSION); if (enable_dom_automation_) render_view_host_->AllowBindings(BindingsPolicy::DOM_AUTOMATION); @@ -182,7 +179,7 @@ void ExtensionHost::CreateView(Browser* browser) { #endif } -TabContents* ExtensionHost::associated_tab_contents() const { +TabContents* ExtensionHost::GetAssociatedTabContents() const { return associated_tab_contents_; } @@ -314,6 +311,9 @@ void ExtensionHost::RenderViewGone(RenderViewHost* render_view_host, if (!extension_) return; + // TODO(aa): This is suspicious. There can be multiple views in an extension, + // and they aren't all going to use ExtensionHost. This should be in someplace + // more central, like EPM maybe. DCHECK_EQ(render_view_host_, render_view_host); NotificationService::current()->Notify( NotificationType::EXTENSION_PROCESS_TERMINATED, @@ -327,29 +327,7 @@ void ExtensionHost::DidNavigate(RenderViewHost* render_view_host, if (!PageTransition::IsMainFrame(params.transition)) return; - if (!params.url.SchemeIs(chrome::kExtensionScheme)) { - extension_function_dispatcher_.reset(NULL); - url_ = params.url; - return; - } - - // This catches two bogus use cases: - // (1) URLs that look like chrome-extension://somethingbogus or - // chrome-extension://nosuchid/, in other words, no Extension would - // be found. - // (2) URLs that refer to a different extension than this one. - // In both cases, we preserve the old URL and reset the EFD to NULL. This - // will leave the host in kind of a bad state with poor UI and errors, but - // it's better than the alternative. - // TODO(erikkay) Perhaps we should display errors in developer mode. - if (params.url.host() != extension_id()) { - extension_function_dispatcher_.reset(NULL); - return; - } - url_ = params.url; - extension_function_dispatcher_.reset( - ExtensionFunctionDispatcher::Create(render_view_host_, this, url_)); } void ExtensionHost::InsertInfobarCSS() { @@ -465,7 +443,8 @@ gfx::NativeWindow ExtensionHost::GetMessageBoxRootWindow() { return platform_util::GetTopLevel(native_view); // Otherwise, try the active tab's view. - Browser* browser = extension_function_dispatcher_->GetCurrentBrowser(true); + Browser* browser = extension_function_dispatcher_.GetCurrentBrowser( + render_view_host_, true); if (browser) { TabContents* active_tab = browser->GetSelectedTabContents(); if (active_tab) @@ -507,7 +486,7 @@ void ExtensionHost::Close(RenderViewHost* render_view_host) { RendererPreferences ExtensionHost::GetRendererPrefs(Profile* profile) const { RendererPreferences preferences; - TabContents* associated_contents = associated_tab_contents(); + TabContents* associated_contents = GetAssociatedTabContents(); if (associated_contents) preferences = static_cast<RenderViewHostDelegate*>(associated_contents)-> @@ -561,7 +540,7 @@ void ExtensionHost::CreateNewWindow( params.window_container_type, params.frame_name); - TabContents* associated_contents = associated_tab_contents(); + TabContents* associated_contents = GetAssociatedTabContents(); if (associated_contents && associated_contents->delegate()) associated_contents->delegate()->TabContentsCreated(new_contents); } @@ -616,7 +595,7 @@ void ExtensionHost::ShowCreatedWindow(int route_id, // the case of extensions in 'spanning' incognito mode, they can mismatch. // We don't want to end up putting a normal tab into an incognito window, or // vice versa. - TabContents* associated_contents = associated_tab_contents(); + TabContents* associated_contents = GetAssociatedTabContents(); if (associated_contents && associated_contents->profile() == contents->profile()) { associated_contents->AddNewContents( @@ -774,19 +753,19 @@ ViewType::Type ExtensionHost::GetRenderViewType() const { } bool ExtensionHost::OnMessageReceived(const IPC::Message& message) { - if (extension_function_dispatcher_.get() && - extension_function_dispatcher_->OnMessageReceived(message)) { - return true; - } - bool handled = true; IPC_BEGIN_MESSAGE_MAP(ExtensionHost, message) IPC_MESSAGE_HANDLER(ViewHostMsg_RunFileChooser, OnRunFileChooser) + IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; } +void ExtensionHost::OnRequest(const ExtensionHostMsg_Request_Params& params) { + extension_function_dispatcher_.Dispatch(params, render_view_host_); +} + const GURL& ExtensionHost::GetURL() const { return url_; } @@ -795,13 +774,6 @@ void ExtensionHost::RenderViewCreated(RenderViewHost* render_view_host) { if (view_.get()) view_->RenderViewCreated(); - // TODO(mpcomplete): This is duplicated in DidNavigate, which means that - // we'll create 2 EFDs for the first navigation. We should try to find a - // better way to unify them. - // See http://code.google.com/p/chromium/issues/detail?id=18240 - extension_function_dispatcher_.reset( - ExtensionFunctionDispatcher::Create(render_view_host, this, url_)); - if (extension_host_type_ == ViewType::EXTENSION_POPUP || extension_host_type_ == ViewType::EXTENSION_INFOBAR) { render_view_host->EnablePreferredSizeChangedMode( @@ -832,5 +804,5 @@ void ExtensionHost::OnRunFileChooser( if (file_select_helper_.get() == NULL) file_select_helper_.reset(new FileSelectHelper(profile())); file_select_helper_->RunFileChooser(render_view_host_, - associated_tab_contents(), params); + GetAssociatedTabContents(), params); } diff --git a/chrome/browser/extensions/extension_host.h b/chrome/browser/extensions/extension_host.h index 311975d..87b691c 100644 --- a/chrome/browser/extensions/extension_host.h +++ b/chrome/browser/extensions/extension_host.h @@ -86,7 +86,7 @@ class ExtensionHost : public RenderViewHostDelegate, ViewType::Type extension_host_type() const { return extension_host_type_; } // ExtensionFunctionDispatcher::Delegate - virtual TabContents* associated_tab_contents() const; + virtual TabContents* GetAssociatedTabContents() const; void set_associated_tab_contents(TabContents* associated_tab_contents) { associated_tab_contents_ = associated_tab_contents; } @@ -229,6 +229,7 @@ class ExtensionHost : public RenderViewHostDelegate, // Message handlers. void OnRunFileChooser(const ViewHostMsg_RunFileChooser_Params& params); + void OnRequest(const ExtensionHostMsg_Request_Params& params); // Handles keyboard events that were not handled by HandleKeyboardEvent(). // Platform specific implementation may override this method to handle the @@ -274,7 +275,7 @@ class ExtensionHost : public RenderViewHostDelegate, NotificationRegistrar registrar_; - scoped_ptr<ExtensionFunctionDispatcher> extension_function_dispatcher_; + ExtensionFunctionDispatcher extension_function_dispatcher_; // Only EXTENSION_INFOBAR, EXTENSION_POPUP, and EXTENSION_BACKGROUND_PAGE // are used here, others are not hosted by ExtensionHost. diff --git a/chrome/browser/extensions/extension_tab_helper.cc b/chrome/browser/extensions/extension_tab_helper.cc index 6f44f6c..8a1caa5 100644 --- a/chrome/browser/extensions/extension_tab_helper.cc +++ b/chrome/browser/extensions/extension_tab_helper.cc @@ -6,12 +6,15 @@ #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" #include "chrome/browser/ui/tab_contents/tab_contents_wrapper_delegate.h" #include "chrome/common/extensions/extension_action.h" #include "chrome/common/extensions/extension_icon_set.h" #include "chrome/common/extensions/extension_messages.h" #include "chrome/common/extensions/extension_resource.h" +#include "content/browser/renderer_host/render_widget_host_view.h" #include "content/browser/tab_contents/tab_contents.h" #include "content/browser/tab_contents/navigation_controller.h" #include "content/common/notification_service.h" @@ -19,6 +22,8 @@ ExtensionTabHelper::ExtensionTabHelper(TabContentsWrapper* wrapper) : TabContentsObserver(wrapper->tab_contents()), extension_app_(NULL), + ALLOW_THIS_IN_INITIALIZER_LIST( + extension_function_dispatcher_(wrapper->profile(), this)), wrapper_(wrapper) { } @@ -113,6 +118,7 @@ bool ExtensionTabHelper::OnMessageReceived(const IPC::Message& message) { OnDidGetApplicationInfo) IPC_MESSAGE_HANDLER(ExtensionHostMsg_InstallApplication, OnInstallApplication) + IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; @@ -131,6 +137,12 @@ void ExtensionTabHelper::OnInstallApplication(const WebApplicationInfo& info) { wrapper_->delegate()->OnInstallApplication(wrapper_, info); } +void ExtensionTabHelper::OnRequest( + const ExtensionHostMsg_Request_Params& request) { + extension_function_dispatcher_.Dispatch(request, + tab_contents()->render_view_host()); +} + void ExtensionTabHelper::UpdateExtensionAppIcon(const Extension* extension) { extension_app_icon_.reset(); @@ -161,3 +173,37 @@ void ExtensionTabHelper::OnImageLoaded(SkBitmap* image, tab_contents()->NotifyNavigationStateChanged(TabContents::INVALIDATE_TAB); } } + +Browser* ExtensionTabHelper::GetBrowser() { + TabContents* contents = tab_contents(); + TabContentsIterator tab_iterator; + for (; !tab_iterator.done(); ++tab_iterator) { + if (contents == (*tab_iterator)->tab_contents()) + return tab_iterator.browser(); + } + + return NULL; +} + +TabContents* ExtensionTabHelper::GetAssociatedTabContents() const { + return tab_contents(); +} + +gfx::NativeWindow ExtensionTabHelper::GetCustomFrameNativeWindow() { + if (GetBrowser()) + return NULL; + + // If there was no browser associated with the function dispatcher delegate, + // then this WebUI may be hosted in an ExternalTabContainer, and a framing + // window will be accessible through the tab_contents. + TabContentsDelegate* tab_contents_delegate = tab_contents()->delegate(); + if (tab_contents_delegate) + return tab_contents_delegate->GetFrameNativeWindow(); + else + return NULL; +} + +gfx::NativeView ExtensionTabHelper::GetNativeViewOfHost() { + RenderWidgetHostView* rwhv = tab_contents()->GetRenderWidgetHostView(); + return rwhv ? rwhv->GetNativeView() : NULL; +} diff --git a/chrome/browser/extensions/extension_tab_helper.h b/chrome/browser/extensions/extension_tab_helper.h index 46b0348..8a4b51e 100644 --- a/chrome/browser/extensions/extension_tab_helper.h +++ b/chrome/browser/extensions/extension_tab_helper.h @@ -7,6 +7,7 @@ #pragma once #include "content/browser/tab_contents/tab_contents_observer.h" +#include "chrome/browser/extensions/extension_function_dispatcher.h" #include "chrome/browser/extensions/image_loading_tracker.h" #include "chrome/common/web_apps.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -17,6 +18,7 @@ struct WebApplicationInfo; // Per-tab extension helper. Also handles non-extension apps. class ExtensionTabHelper : public TabContentsObserver, + public ExtensionFunctionDispatcher::Delegate, public ImageLoadingTracker::Observer { public: explicit ExtensionTabHelper(TabContentsWrapper* wrapper); @@ -77,9 +79,16 @@ class ExtensionTabHelper : public TabContentsObserver, const ViewHostMsg_FrameNavigate_Params& params) OVERRIDE; virtual bool OnMessageReceived(const IPC::Message& message); + // ExtensionFunctionDispatcher::Delegate overrides. + virtual Browser* GetBrowser(); + virtual gfx::NativeView GetNativeViewOfHost(); + virtual gfx::NativeWindow GetCustomFrameNativeWindow(); + virtual TabContents* GetAssociatedTabContents() const; + // Message handlers. void OnDidGetApplicationInfo(int32 page_id, const WebApplicationInfo& info); void OnInstallApplication(const WebApplicationInfo& info); + void OnRequest(const ExtensionHostMsg_Request_Params& params); // App extensions related methods: @@ -101,6 +110,9 @@ class ExtensionTabHelper : public TabContentsObserver, // non-extension apps. SkBitmap extension_app_icon_; + // Process any extension messages coming from the tab. + ExtensionFunctionDispatcher extension_function_dispatcher_; + // Used for loading extension_app_icon_. scoped_ptr<ImageLoadingTracker> extension_app_image_loader_; diff --git a/chrome/browser/extensions/extension_tabs_module.cc b/chrome/browser/extensions/extension_tabs_module.cc index a43d894..97654bf 100644 --- a/chrome/browser/extensions/extension_tabs_module.cc +++ b/chrome/browser/extensions/extension_tabs_module.cc @@ -793,7 +793,7 @@ bool GetTabFunction::RunImpl() { bool GetCurrentTabFunction::RunImpl() { DCHECK(dispatcher()); - TabContents* contents = dispatcher()->delegate()->associated_tab_contents(); + TabContents* contents = dispatcher()->delegate()->GetAssociatedTabContents(); if (contents) result_.reset(ExtensionTabUtil::CreateTabValue(contents)); diff --git a/chrome/browser/extensions/extension_web_ui.cc b/chrome/browser/extensions/extension_web_ui.cc index e398c46..a816c76 100644 --- a/chrome/browser/extensions/extension_web_ui.cc +++ b/chrome/browser/extensions/extension_web_ui.cc @@ -24,11 +24,9 @@ #include "chrome/common/extensions/extension_icon_set.h" #include "chrome/common/extensions/extension_resource.h" #include "chrome/common/url_constants.h" -#include "content/browser/renderer_host/render_widget_host_view.h" #include "content/browser/tab_contents/tab_contents.h" #include "content/common/bindings_policy.h" #include "content/common/page_transition_types.h" -#include "ipc/ipc_message.h" #include "net/base/file_stream.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/gfx/codec/png_codec.h" @@ -140,7 +138,6 @@ ExtensionWebUI::ExtensionWebUI(TabContents* tab_contents, const GURL& url) // component apps like bookmark manager. should_hide_url_ = !extension->is_hosted_app(); - bindings_ = BindingsPolicy::EXTENSION; // Bind externalHost to Extension WebUI loaded in Chrome Frame. const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); if (browser_command_line.HasSwitch(switches::kChromeFrame)) @@ -155,86 +152,23 @@ ExtensionWebUI::ExtensionWebUI(TabContents* tab_contents, const GURL& url) should_hide_url_ = false; } } -} - -ExtensionWebUI::~ExtensionWebUI() {} -void ExtensionWebUI::ResetExtensionFunctionDispatcher( - RenderViewHost* render_view_host) { - // TODO(jcivelli): http://crbug.com/60608 we should get the URL out of the - // active entry of the navigation controller. - extension_function_dispatcher_.reset( - ExtensionFunctionDispatcher::Create(render_view_host, this, url_)); - DCHECK(extension_function_dispatcher_.get()); -} - -void ExtensionWebUI::ResetExtensionBookmarkManagerEventRouter() { // Hack: A few things we specialize just for the bookmark manager. - if (extension_function_dispatcher_->extension_id() == - extension_misc::kBookmarkManagerId) { + if (extension->id() == extension_misc::kBookmarkManagerId) { extension_bookmark_manager_event_router_.reset( - new ExtensionBookmarkManagerEventRouter(GetProfile(), tab_contents())); + new ExtensionBookmarkManagerEventRouter(GetProfile(), tab_contents)); link_transition_type_ = PageTransition::AUTO_BOOKMARK; } } -void ExtensionWebUI::RenderViewCreated(RenderViewHost* render_view_host) { - ResetExtensionFunctionDispatcher(render_view_host); - ResetExtensionBookmarkManagerEventRouter(); -} - -void ExtensionWebUI::RenderViewReused(RenderViewHost* render_view_host) { - ResetExtensionFunctionDispatcher(render_view_host); - ResetExtensionBookmarkManagerEventRouter(); -} - -bool ExtensionWebUI::OnMessageReceived(const IPC::Message& message) { - if (extension_function_dispatcher_.get()) - return extension_function_dispatcher_->OnMessageReceived(message); - - return false; -} - -Browser* ExtensionWebUI::GetBrowser() { - TabContents* contents = tab_contents(); - TabContentsIterator tab_iterator; - for (; !tab_iterator.done(); ++tab_iterator) { - if (contents == (*tab_iterator)->tab_contents()) - return tab_iterator.browser(); - } - - return NULL; -} - -TabContents* ExtensionWebUI::associated_tab_contents() const { - return tab_contents(); -} +ExtensionWebUI::~ExtensionWebUI() {} ExtensionBookmarkManagerEventRouter* ExtensionWebUI::extension_bookmark_manager_event_router() { return extension_bookmark_manager_event_router_.get(); } -gfx::NativeWindow ExtensionWebUI::GetCustomFrameNativeWindow() { - if (GetBrowser()) - return NULL; - - // If there was no browser associated with the function dispatcher delegate, - // then this WebUI may be hosted in an ExternalTabContainer, and a framing - // window will be accessible through the tab_contents. - TabContentsDelegate* tab_contents_delegate = tab_contents()->delegate(); - if (tab_contents_delegate) - return tab_contents_delegate->GetFrameNativeWindow(); - else - return NULL; -} - -gfx::NativeView ExtensionWebUI::GetNativeViewOfHost() { - RenderWidgetHostView* rwhv = tab_contents()->GetRenderWidgetHostView(); - return rwhv ? rwhv->GetNativeView() : NULL; -} - //////////////////////////////////////////////////////////////////////////////// // chrome:// URL overrides diff --git a/chrome/browser/extensions/extension_web_ui.h b/chrome/browser/extensions/extension_web_ui.h index 3a3a80b..4aad170 100644 --- a/chrome/browser/extensions/extension_web_ui.h +++ b/chrome/browser/extensions/extension_web_ui.h @@ -10,11 +10,9 @@ #include "base/memory/scoped_ptr.h" #include "chrome/browser/extensions/extension_bookmark_manager_api.h" -#include "chrome/browser/extensions/extension_function_dispatcher.h" #include "chrome/browser/favicon/favicon_service.h" #include "chrome/common/extensions/extension.h" #include "content/browser/webui/web_ui.h" -#include "ipc/ipc_channel.h" class GURL; class ListValue; @@ -22,15 +20,12 @@ class PrefService; class Profile; class RenderViewHost; class TabContents; -struct ExtensionHostMsg_Request_Params; // This class implements WebUI for extensions and allows extensions to put UI in // the main tab contents area. For example, each extension can specify an // "options_page", and that page is displayed in the tab contents area and is // hosted by this class. -class ExtensionWebUI - : public WebUI, - public ExtensionFunctionDispatcher::Delegate { +class ExtensionWebUI : public WebUI { public: static const char kExtensionURLOverrides[]; @@ -38,21 +33,6 @@ class ExtensionWebUI virtual ~ExtensionWebUI(); - ExtensionFunctionDispatcher* extension_function_dispatcher() const { - return extension_function_dispatcher_.get(); - } - - // WebUI - virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; - virtual void RenderViewCreated(RenderViewHost* render_view_host); - virtual void RenderViewReused(RenderViewHost* render_view_host); - - // ExtensionFunctionDispatcher::Delegate - virtual Browser* GetBrowser(); - virtual gfx::NativeView GetNativeViewOfHost(); - virtual gfx::NativeWindow GetCustomFrameNativeWindow(); - virtual TabContents* associated_tab_contents() const; - virtual ExtensionBookmarkManagerEventRouter* extension_bookmark_manager_event_router(); @@ -87,15 +67,6 @@ class ExtensionWebUI ListValue* list, Value* override); - // When the RenderViewHost changes (RenderViewCreated and RenderViewReused), - // we need to reset the ExtensionFunctionDispatcher so it's talking to the - // right one, as well as being linked to the correct URL. - void ResetExtensionFunctionDispatcher(RenderViewHost* render_view_host); - - void ResetExtensionBookmarkManagerEventRouter(); - - scoped_ptr<ExtensionFunctionDispatcher> extension_function_dispatcher_; - // TODO(aa): This seems out of place. Why is it not with the event routers for // the other extension APIs? scoped_ptr<ExtensionBookmarkManagerEventRouter> diff --git a/chrome/browser/extensions/extension_webstore_private_api.cc b/chrome/browser/extensions/extension_webstore_private_api.cc index 8dbf650..7c46cff 100644 --- a/chrome/browser/extensions/extension_webstore_private_api.cc +++ b/chrome/browser/extensions/extension_webstore_private_api.cc @@ -461,7 +461,7 @@ bool CompleteInstallFunction::RunImpl() { // install flow. The above call to SetWhitelistedInstallId will bypass the // normal permissions install dialog. NavigationController& controller = - dispatcher()->delegate()->associated_tab_contents()->controller(); + dispatcher()->delegate()->GetAssociatedTabContents()->controller(); controller.LoadURL(url, source_url(), PageTransition::LINK); return true; @@ -519,7 +519,7 @@ bool PromptBrowserLoginFunction::RunImpl() { // Login can currently only be invoked tab-modal. Since this is // coming from the webstore, we should always have a tab, but check // just in case. - TabContents* tab = dispatcher()->delegate()->associated_tab_contents(); + TabContents* tab = dispatcher()->delegate()->GetAssociatedTabContents(); if (!tab) return false; diff --git a/chrome/browser/extensions/extensions_quota_service_unittest.cc b/chrome/browser/extensions/extensions_quota_service_unittest.cc index 72958a9..63eedb1 100644 --- a/chrome/browser/extensions/extensions_quota_service_unittest.cc +++ b/chrome/browser/extensions/extensions_quota_service_unittest.cc @@ -95,11 +95,17 @@ class FrozenMockFunction : public MockFunction { class ExtensionsQuotaServiceTest : public testing::Test { public: ExtensionsQuotaServiceTest() - : extension_a_("a"), extension_b_("b"), extension_c_("c") {} + : extension_a_("a"), + extension_b_("b"), + extension_c_("c"), + loop_(), + ui_thread_(BrowserThread::UI, &loop_) { + } virtual void SetUp() { service_.reset(new ExtensionsQuotaService()); } virtual void TearDown() { + loop_.RunAllPending(); service_.reset(); } protected: @@ -107,6 +113,8 @@ class ExtensionsQuotaServiceTest : public testing::Test { std::string extension_b_; std::string extension_c_; scoped_ptr<ExtensionsQuotaService> service_; + MessageLoop loop_; + BrowserThread ui_thread_; }; class QuotaLimitHeuristicTest : public testing::Test { diff --git a/chrome/browser/extensions/extensions_ui.cc b/chrome/browser/extensions/extensions_ui.cc index 8022dc4..37e4fd9 100644 --- a/chrome/browser/extensions/extensions_ui.cc +++ b/chrome/browser/extensions/extensions_ui.cc @@ -20,7 +20,6 @@ #include "chrome/browser/extensions/crx_installer.h" #include "chrome/browser/extensions/extension_disabled_infobar_delegate.h" #include "chrome/browser/extensions/extension_error_reporter.h" -#include "chrome/browser/extensions/extension_function_dispatcher.h" #include "chrome/browser/extensions/extension_host.h" #include "chrome/browser/extensions/extension_message_service.h" #include "chrome/browser/extensions/extension_service.h" @@ -300,13 +299,11 @@ void ExtensionsDOMHandler::RegisterForNotifications() { NotificationService::AllSources()); registrar_.Add(this, NotificationType::EXTENSION_UPDATE_DISABLED, NotificationService::AllSources()); - registrar_.Add(this, NotificationType::EXTENSION_FUNCTION_DISPATCHER_CREATED, - NotificationService::AllSources()); registrar_.Add(this, - NotificationType::EXTENSION_FUNCTION_DISPATCHER_DESTROYED, + NotificationType::NAV_ENTRY_COMMITTED, NotificationService::AllSources()); registrar_.Add(this, - NotificationType::NAV_ENTRY_COMMITTED, + NotificationType::RENDER_VIEW_HOST_CREATED, NotificationService::AllSources()); registrar_.Add(this, NotificationType::RENDER_VIEW_HOST_DELETED, @@ -631,9 +628,11 @@ void ExtensionsDOMHandler::Observe(NotificationType type, // we don't know about the views for an extension at EXTENSION_LOADED, but // if we only listen to EXTENSION_PROCESS_CREATED, we'll miss extensions // that don't have a process at startup. Similarly, NAV_ENTRY_COMMITTED & - // EXTENSION_FUNCTION_DISPATCHER_CREATED because we want to handle both - // the case of live app pages (which don't have an EFD) and - // chrome-extension:// urls which are served in a TabContents. + // RENDER_VIEW_HOST_CREATED because we want to handle both + // the case of navigating from a non-extension page to an extension page in + // a TabContents (which will generate NAV_ENTRY_COMMITTED) as well as + // extension content being shown in popups and balloons (which will generate + // RENDER_VIEW_HOST_CREATED but no NAV_ENTRY_COMMITTED). // // Doing it this way gets everything but causes the page to be rendered // more than we need. It doesn't seem to result in any noticeable flicker. @@ -649,8 +648,7 @@ void ExtensionsDOMHandler::Observe(NotificationType type, case NotificationType::EXTENSION_PROCESS_CREATED: case NotificationType::EXTENSION_UNLOADED: case NotificationType::EXTENSION_UPDATE_DISABLED: - case NotificationType::EXTENSION_FUNCTION_DISPATCHER_CREATED: - case NotificationType::EXTENSION_FUNCTION_DISPATCHER_DESTROYED: + case NotificationType::RENDER_VIEW_HOST_CREATED: case NotificationType::NAV_ENTRY_COMMITTED: case NotificationType::BACKGROUND_CONTENTS_NAVIGATED: case NotificationType::EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED: diff --git a/chrome/browser/memory_details.cc b/chrome/browser/memory_details.cc index ea1c834..074e42d 100644 --- a/chrome/browser/memory_details.cc +++ b/chrome/browser/memory_details.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -171,7 +171,7 @@ void MemoryDetails::CollectChildInfoOnUIThread() { } TabContents* contents = host_delegate->GetAsTabContents(); if (!contents) { - if (host->is_extension_process()) { + if (host->process()->is_extension_process()) { const Extension* extension = extension_service->GetExtensionByURL(url); if (extension) { diff --git a/chrome/browser/notifications/balloon_host.cc b/chrome/browser/notifications/balloon_host.cc index 3d600a0..7219be0 100644 --- a/chrome/browser/notifications/balloon_host.cc +++ b/chrome/browser/notifications/balloon_host.cc @@ -3,14 +3,13 @@ // found in the LICENSE file. #include "chrome/browser/notifications/balloon_host.h" -#include "chrome/browser/extensions/extension_process_manager.h" -#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/notifications/balloon.h" #include "chrome/browser/notifications/notification.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/renderer_preferences_util.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/webui/chrome_web_ui_factory.h" +#include "chrome/common/extensions/extension_messages.h" #include "chrome/common/render_messages.h" #include "chrome/common/url_constants.h" #include "content/browser/renderer_host/browser_render_process_host.h" @@ -30,20 +29,12 @@ BalloonHost::BalloonHost(Balloon* balloon) balloon_(balloon), initialized_(false), should_notify_on_disconnect_(false), - enable_web_ui_(false) { - DCHECK(balloon_); - - // If the notification is for an extension URL, make sure to use the extension - // process to render it, so that it can communicate with other views in the - // extension. - const GURL& balloon_url = balloon_->notification().content_url(); - if (balloon_url.SchemeIs(chrome::kExtensionScheme)) { - site_instance_ = - balloon_->profile()->GetExtensionProcessManager()->GetSiteInstanceForURL( - balloon_url); - } else { - site_instance_ = SiteInstance::CreateSiteInstance(balloon_->profile()); - } + enable_web_ui_(false), + ALLOW_THIS_IN_INITIALIZER_LIST( + extension_function_dispatcher_(GetProfile(), this)) { + CHECK(balloon_); + site_instance_ = SiteInstance::CreateSiteInstanceForURL(balloon_->profile(), + GetURL()); } void BalloonHost::Shutdown() { @@ -64,7 +55,9 @@ gfx::NativeView BalloonHost::GetNativeViewOfHost() { return NULL; } -TabContents* BalloonHost::associated_tab_contents() const { return NULL; } +TabContents* BalloonHost::GetAssociatedTabContents() const { + return NULL; +} const string16& BalloonHost::GetSource() const { return balloon_->notification().display_source(); @@ -133,10 +126,16 @@ RenderViewHostDelegate::View* BalloonHost::GetViewDelegate() { } bool BalloonHost::OnMessageReceived(const IPC::Message& message) { - if (extension_function_dispatcher_.get()) - return extension_function_dispatcher_->OnMessageReceived(message); + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(BalloonHost, message) + IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} - return false; +void BalloonHost::OnRequest(const ExtensionHostMsg_Request_Params& params) { + extension_function_dispatcher_.Dispatch(params, render_view_host_); } // RenderViewHostDelegate::View methods implemented to allow links to @@ -196,24 +195,8 @@ void BalloonHost::Init() { DCHECK(!render_view_host_) << "BalloonViewHost already initialized."; RenderViewHost* rvh = new RenderViewHost( site_instance_.get(), this, MSG_ROUTING_NONE, NULL); - if (GetProfile()->GetExtensionService()) { - extension_function_dispatcher_.reset( - ExtensionFunctionDispatcher::Create( - rvh, this, balloon_->notification().content_url())); - } - if (extension_function_dispatcher_.get()) { - rvh->AllowBindings(BindingsPolicy::EXTENSION); - rvh->set_is_extension_process(true); - const Extension* installed_app = - GetProfile()->GetExtensionService()->GetInstalledApp( - balloon_->notification().content_url()); - if (installed_app) { - GetProfile()->GetExtensionService()->SetInstalledAppForRenderer( - rvh->process()->id(), installed_app); - } - } else if (enable_web_ui_) { + if (enable_web_ui_) rvh->AllowBindings(BindingsPolicy::WEB_UI); - } // Do platform-specific initialization. render_view_host_ = rvh; diff --git a/chrome/browser/notifications/balloon_host.h b/chrome/browser/notifications/balloon_host.h index 9a70e61..2a03506 100644 --- a/chrome/browser/notifications/balloon_host.h +++ b/chrome/browser/notifications/balloon_host.h @@ -44,7 +44,7 @@ class BalloonHost : public RenderViewHostDelegate, // ExtensionFunctionDispatcher::Delegate overrides. virtual Browser* GetBrowser(); virtual gfx::NativeView GetNativeViewOfHost(); - virtual TabContents* associated_tab_contents() const; + virtual TabContents* GetAssociatedTabContents() const; RenderViewHost* render_view_host() const { return render_view_host_; } @@ -137,6 +137,9 @@ class BalloonHost : public RenderViewHostDelegate, // RenderViewHostDelegate virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + // Message handlers + void OnRequest(const ExtensionHostMsg_Request_Params& params); + // Called to send an event that the balloon has been disconnected from // a renderer (if should_notify_on_disconnect_ is true). void NotifyDisconnect(); @@ -158,14 +161,12 @@ class BalloonHost : public RenderViewHostDelegate, // Common implementations of some RenderViewHostDelegate::View methods. RenderViewHostDelegateViewHelper delegate_view_helper_; - // Handles requests to extension APIs. Will only be non-NULL if we are - // rendering a page from an extension. - scoped_ptr<ExtensionFunctionDispatcher> extension_function_dispatcher_; - // A flag to enable Web UI. bool enable_web_ui_; NotificationRegistrar registrar_; + + ExtensionFunctionDispatcher extension_function_dispatcher_; }; #endif // CHROME_BROWSER_NOTIFICATIONS_BALLOON_HOST_H_ diff --git a/chrome/browser/sidebar/sidebar_container.cc b/chrome/browser/sidebar/sidebar_container.cc index 99c69a5..d1e4a33 100644 --- a/chrome/browser/sidebar/sidebar_container.cc +++ b/chrome/browser/sidebar/sidebar_container.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -16,7 +16,6 @@ #include "content/browser/tab_contents/navigation_entry.h" #include "content/browser/tab_contents/tab_contents.h" #include "content/browser/tab_contents/tab_contents_view.h" -#include "content/common/bindings_policy.h" #include "googleurl/src/gurl.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -32,17 +31,6 @@ SidebarContainer::SidebarContainer(TabContents* tab, // Create TabContents for sidebar. sidebar_contents_.reset( new TabContents(tab->profile(), NULL, MSG_ROUTING_NONE, NULL, NULL)); - sidebar_contents_->render_view_host()->set_is_extension_process(true); - const Extension* extension = GetExtension(); - if (extension && extension->is_app()) { - ExtensionService* service = tab->profile()->GetExtensionService(); - if (service) { - service->SetInstalledAppForRenderer( - sidebar_contents_->render_view_host()->process()->id(), extension); - } - } - sidebar_contents_->render_view_host()->AllowBindings( - BindingsPolicy::EXTENSION); sidebar_contents_->set_delegate(this); } diff --git a/chrome/browser/ui/webui/options/extension_settings_handler.cc b/chrome/browser/ui/webui/options/extension_settings_handler.cc index 0aa8434..c1760b7 100644 --- a/chrome/browser/ui/webui/options/extension_settings_handler.cc +++ b/chrome/browser/ui/webui/options/extension_settings_handler.cc @@ -20,7 +20,6 @@ #include "chrome/browser/extensions/crx_installer.h" #include "chrome/browser/extensions/extension_disabled_infobar_delegate.h" #include "chrome/browser/extensions/extension_error_reporter.h" -#include "chrome/browser/extensions/extension_function_dispatcher.h" #include "chrome/browser/extensions/extension_host.h" #include "chrome/browser/extensions/extension_message_service.h" #include "chrome/browser/extensions/extension_service.h" @@ -407,13 +406,11 @@ void ExtensionsDOMHandler::OnIconsLoaded(DictionaryValue* json) { NotificationService::AllSources()); registrar_.Add(this, NotificationType::EXTENSION_UPDATE_DISABLED, NotificationService::AllSources()); - registrar_.Add(this, NotificationType::EXTENSION_FUNCTION_DISPATCHER_CREATED, - NotificationService::AllSources()); registrar_.Add(this, - NotificationType::EXTENSION_FUNCTION_DISPATCHER_DESTROYED, + NotificationType::NAV_ENTRY_COMMITTED, NotificationService::AllSources()); registrar_.Add(this, - NotificationType::NAV_ENTRY_COMMITTED, + NotificationType::RENDER_VIEW_HOST_CREATED, NotificationService::AllSources()); registrar_.Add(this, NotificationType::RENDER_VIEW_HOST_DELETED, @@ -724,9 +721,11 @@ void ExtensionsDOMHandler::Observe(NotificationType type, // we don't know about the views for an extension at EXTENSION_LOADED, but // if we only listen to EXTENSION_PROCESS_CREATED, we'll miss extensions // that don't have a process at startup. Similarly, NAV_ENTRY_COMMITTED & - // EXTENSION_FUNCTION_DISPATCHER_CREATED because we want to handle both - // the case of live app pages (which don't have an EFD) and - // chrome-extension:// urls which are served in a TabContents. + // RENDER_VIEW_HOST_CREATED because we want to handle both + // the case of navigating from a non-extension page to an extension page in + // a TabContents (which will generate NAV_ENTRY_COMMITTED) as well as + // extension content being shown in popups and balloons (which will generate + // RENDER_VIEW_CREATED but no NAV_ENTRY_COMMITTED). // // Doing it this way gets everything but causes the page to be rendered // more than we need. It doesn't seem to result in any noticeable flicker. @@ -742,8 +741,7 @@ void ExtensionsDOMHandler::Observe(NotificationType type, case NotificationType::EXTENSION_PROCESS_CREATED: case NotificationType::EXTENSION_UNLOADED: case NotificationType::EXTENSION_UPDATE_DISABLED: - case NotificationType::EXTENSION_FUNCTION_DISPATCHER_CREATED: - case NotificationType::EXTENSION_FUNCTION_DISPATCHER_DESTROYED: + case NotificationType::RENDER_VIEW_HOST_CREATED: case NotificationType::NAV_ENTRY_COMMITTED: case NotificationType::BACKGROUND_CONTENTS_NAVIGATED: case NotificationType::EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED: diff --git a/chrome/browser/visitedlink/visitedlink_unittest.cc b/chrome/browser/visitedlink/visitedlink_unittest.cc index 6f58ad7..96bcd31 100644 --- a/chrome/browser/visitedlink/visitedlink_unittest.cc +++ b/chrome/browser/visitedlink/visitedlink_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -505,7 +505,7 @@ class VisitRelayingRenderProcessHost : public BrowserRenderProcessHost { Source<RenderProcessHost>(this), NotificationService::NoDetails()); } - virtual bool Init(bool is_accessibility_enabled, bool is_extension_process) { + virtual bool Init(bool is_accessibility_enabled) { return true; } |