diff options
author | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-11 04:32:28 +0000 |
---|---|---|
committer | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-11 04:32:28 +0000 |
commit | 52836b694190e9deae90e4bfce2cced4545849f4 (patch) | |
tree | 48bbaa88a7533bd0d1c4699c92dec918a545a70b | |
parent | 8164ae1c8061f04a3da53ee01e7134ab540db66a (diff) | |
download | chromium_src-52836b694190e9deae90e4bfce2cced4545849f4.zip chromium_src-52836b694190e9deae90e4bfce2cced4545849f4.tar.gz chromium_src-52836b694190e9deae90e4bfce2cced4545849f4.tar.bz2 |
Move ExtensionFunctionDispatcher to ExtensionTabHelper. This
sets the stage for us to expose certain extension functions
to content scripts and normal web pages.
This required two major structural changes:
1. Made EFD stateless, except for the pointer to its
delegate. This is important to gracefully handle the case
of a RVH navigating between different extensions or even
to normal web content. Especially in the case of
TabContents, where the entire RVH can be torn down and
replaced during navigation.
2. Centralize all per-(extension, RVH) setup in
ChromeContentBrowserClient::RenderViewCreated(). In
particular, responsibility for enabling extension bindings
was very spread out before, making it hard to follow when
exactly they were enabled.
BUG=80308
Review URL: http://codereview.chromium.org/6927076
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@84928 0039d316-1c4b-4281-b951-d872f2087c98
38 files changed, 459 insertions, 514 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..a6857544 100644 --- a/chrome/browser/extensions/extension_file_browser_private_api.cc +++ b/chrome/browser/extensions/extension_file_browser_private_api.cc @@ -804,13 +804,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 +818,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..517719fe 100644 --- a/chrome/browser/extensions/extension_function.h +++ b/chrome/browser/extensions/extension_function.h @@ -11,6 +11,9 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include "content/browser/browser_thread.h" +#include "content/common/notification_observer.h" +#include "content/common/notification_registrar.h" #include "chrome/browser/extensions/extension_function_dispatcher.h" class ExtensionFunctionDispatcher; @@ -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: + 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_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; } diff --git a/chrome/renderer/extensions/extension_dispatcher.cc b/chrome/renderer/extensions/extension_dispatcher.cc index a2bb8c0..13339c3 100644 --- a/chrome/renderer/extensions/extension_dispatcher.cc +++ b/chrome/renderer/extensions/extension_dispatcher.cc @@ -35,7 +35,8 @@ using WebKit::WebFrame; using WebKit::WebSecurityPolicy; using WebKit::WebString; -ExtensionDispatcher::ExtensionDispatcher() { +ExtensionDispatcher::ExtensionDispatcher() + : is_webkit_initialized_(false) { std::string type_str = CommandLine::ForCurrentProcess()->GetSwitchValueASCII( switches::kProcessType); is_extension_process_ = type_str == switches::kExtensionProcess || @@ -88,6 +89,17 @@ void ExtensionDispatcher::WebKitInitialized() { RegisterExtension(EventBindings::Get(this), true); RegisterExtension(RendererExtensionBindings::Get(this), true); RegisterExtension(ExtensionApiTestV8Extension::Get(), true); + + // Initialize host permissions for any extensions that were activated before + // WebKit was initialized. + for (std::set<std::string>::iterator iter = active_extension_ids_.begin(); + iter != active_extension_ids_.end(); ++iter) { + const Extension* extension = extensions_.GetByID(*iter); + if (extension) + InitHostPermissions(extension); + } + + is_webkit_initialized_ = true; } void ExtensionDispatcher::IdleNotification() { @@ -202,6 +214,11 @@ void ExtensionDispatcher::OnActivateExtension( if (!extension) return; + if (is_webkit_initialized_) + InitHostPermissions(extension); +} + +void ExtensionDispatcher::InitHostPermissions(const Extension* extension) { if (extension->HasApiPermission(Extension::kManagementPermission)) { WebSecurityPolicy::addOriginAccessWhitelistEntry( extension->url(), @@ -210,13 +227,7 @@ void ExtensionDispatcher::OnActivateExtension( false); } - SetHostPermissions(extension->url(), - extension->host_permissions()); -} - -void ExtensionDispatcher::SetHostPermissions( - const GURL& extension_url, - const std::vector<URLPattern>& permissions) { + const URLPatternList& permissions = extension->host_permissions(); for (size_t i = 0; i < permissions.size(); ++i) { const char* schemes[] = { chrome::kHttpScheme, @@ -227,7 +238,7 @@ void ExtensionDispatcher::SetHostPermissions( for (size_t j = 0; j < arraysize(schemes); ++j) { if (permissions[i].MatchesScheme(schemes[j])) { WebSecurityPolicy::addOriginAccessWhitelistEntry( - extension_url, + extension->url(), WebString::fromUTF8(schemes[j]), WebString::fromUTF8(permissions[i].host()), permissions[i].match_subdomains()); diff --git a/chrome/renderer/extensions/extension_dispatcher.h b/chrome/renderer/extensions/extension_dispatcher.h index c966d37..bce3c0f 100644 --- a/chrome/renderer/extensions/extension_dispatcher.h +++ b/chrome/renderer/extensions/extension_dispatcher.h @@ -81,9 +81,8 @@ class ExtensionDispatcher : public RenderProcessObserver { // extension is for Chrome Extensions only. void RegisterExtension(v8::Extension* extension, bool restrict_to_extensions); - // Sets the host permissions for a particular extension. - void SetHostPermissions(const GURL& extension_url, - const std::vector<URLPattern>& permissions); + // Sets up the host permissions for |extension|. + void InitHostPermissions(const Extension* extension); // True if this renderer is running extensions. bool is_extension_process_; @@ -108,6 +107,9 @@ class ExtensionDispatcher : public RenderProcessObserver { // The extensions that are active in this process. std::set<std::string> active_extension_ids_; + // True once WebKit has been initialized (and it is therefore safe to poke). + bool is_webkit_initialized_; + DISALLOW_COPY_AND_ASSIGN(ExtensionDispatcher); }; diff --git a/content/browser/content_browser_client.cc b/content/browser/content_browser_client.cc index 84603af..901097e 100644 --- a/content/browser/content_browser_client.cc +++ b/content/browser/content_browser_client.cc @@ -14,11 +14,6 @@ void ContentBrowserClient::RenderViewHostCreated( RenderViewHost* render_view_host) { } -void ContentBrowserClient::PreCreateRenderView(RenderViewHost* render_view_host, - Profile* profile, - const GURL& url) { -} - void ContentBrowserClient::BrowserRenderProcessHostCreated( BrowserRenderProcessHost* host) { } diff --git a/content/browser/content_browser_client.h b/content/browser/content_browser_client.h index 2de7751..7772188 100644 --- a/content/browser/content_browser_client.h +++ b/content/browser/content_browser_client.h @@ -34,14 +34,7 @@ class ContentBrowserClient { // Notifies that a new RenderHostView has been created. virtual void RenderViewHostCreated(RenderViewHost* render_view_host); - // Initialize a RenderViewHost before its CreateRenderView method is called. - virtual void PreCreateRenderView(RenderViewHost* render_view_host, - Profile* profile, - const GURL& url); - - // Notifies that a BrowserRenderProcessHost has been created. This is called - // before the content layer adds its own BrowserMessageFilters, so that the - // embedder's IPC filters have priority. + // Notifies that a BrowserRenderProcessHost has been created. virtual void BrowserRenderProcessHostCreated(BrowserRenderProcessHost* host); // Notifies that a WorkerProcessHost has been created. diff --git a/content/browser/renderer_host/browser_render_process_host.cc b/content/browser/renderer_host/browser_render_process_host.cc index 5874e57..2bbfadd 100644 --- a/content/browser/renderer_host/browser_render_process_host.cc +++ b/content/browser/renderer_host/browser_render_process_host.cc @@ -192,7 +192,7 @@ BrowserRenderProcessHost::BrowserRenderProcessHost(Profile* profile) base::TimeDelta::FromSeconds(5), this, &BrowserRenderProcessHost::ClearTransportDIBCache)), accessibility_enabled_(false), - extension_process_(false) { + is_initialized_(false) { widget_helper_ = new RenderWidgetHelper(); WebCacheManager::GetInstance()->Add(id()); @@ -239,8 +239,7 @@ BrowserRenderProcessHost::~BrowserRenderProcessHost() { ClearTransportDIBCache(); } -bool BrowserRenderProcessHost::Init( - bool is_accessibility_enabled, bool is_extensions_process) { +bool BrowserRenderProcessHost::Init(bool is_accessibility_enabled) { // calling Init() more than once does nothing, this makes it more convenient // for the view host which may not be sure in some cases if (channel_.get()) @@ -248,10 +247,6 @@ bool BrowserRenderProcessHost::Init( accessibility_enabled_ = is_accessibility_enabled; - // It is possible for an extension process to be reused for non-extension - // content, e.g. if an extension calls window.open. - extension_process_ = extension_process_ || is_extensions_process; - CommandLine::StringType renderer_prefix; #if defined(OS_POSIX) // A command prefix is something prepended to the command line of the spawned @@ -332,6 +327,7 @@ bool BrowserRenderProcessHost::Init( fast_shutdown_started_ = false; } + is_initialized_ = true; return true; } @@ -470,8 +466,8 @@ void BrowserRenderProcessHost::AppendRendererCommandLine( // Extensions use a special pseudo-process type to make them distinguishable, // even though they're just renderers. command_line->AppendSwitchASCII(switches::kProcessType, - extension_process_ ? switches::kExtensionProcess : - switches::kRendererProcess); + is_extension_process_ ? switches::kExtensionProcess : + switches::kRendererProcess); if (logging::DialogsAreSuppressed()) command_line->AppendSwitch(switches::kNoErrorDialogs); @@ -762,8 +758,13 @@ void BrowserRenderProcessHost::ClearTransportDIBCache() { bool BrowserRenderProcessHost::Send(IPC::Message* msg) { if (!channel_.get()) { - delete msg; - return false; + if (!is_initialized_) { + queued_messages_.push(msg); + return true; + } else { + delete msg; + return false; + } } if (child_process_launcher_.get() && child_process_launcher_->IsStarting()) { @@ -846,15 +847,15 @@ void BrowserRenderProcessHost::OnChannelError() { if (status == base::TERMINATION_STATUS_PROCESS_CRASHED || status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION) { UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildCrashes", - extension_process_ ? 2 : 1); + is_extension_process_ ? 2 : 1); } if (status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED) { UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildKills", - extension_process_ ? 2 : 1); + is_extension_process_ ? 2 : 1); } - RendererClosedDetails details(status, exit_code, extension_process_); + RendererClosedDetails details(status, exit_code, is_extension_process_); NotificationService::current()->Notify( NotificationType::RENDERER_PROCESS_CLOSED, Source<RenderProcessHost>(this), diff --git a/content/browser/renderer_host/browser_render_process_host.h b/content/browser/renderer_host/browser_render_process_host.h index d3eee33..c97648c 100644 --- a/content/browser/renderer_host/browser_render_process_host.h +++ b/content/browser/renderer_host/browser_render_process_host.h @@ -47,7 +47,7 @@ class BrowserRenderProcessHost : public RenderProcessHost, ~BrowserRenderProcessHost(); // RenderProcessHost implementation (public portion). - virtual bool Init(bool is_accessibility_enabled, bool is_extensions_process); + virtual bool Init(bool is_accessibility_enabled); virtual int GetNextRoutingID(); virtual void CancelResourceRequests(int render_widget_id); virtual void CrossSiteClosePageACK(const ViewMsg_ClosePage_Params& params); @@ -130,9 +130,9 @@ class BrowserRenderProcessHost : public RenderProcessHost, // True if this prcoess should have accessibility enabled; bool accessibility_enabled_; - // True iff this process is being used as an extension process. Not valid - // when running in single-process mode. - bool extension_process_; + // True after Init() has been called. We can't just check channel_ because we + // also reset that in the case of process termination. + bool is_initialized_; // Used to launch and terminate the process without blocking the UI thread. scoped_ptr<ChildProcessLauncher> child_process_launcher_; diff --git a/content/browser/renderer_host/mock_render_process_host.cc b/content/browser/renderer_host/mock_render_process_host.cc index 104395f..dec107a 100644 --- a/content/browser/renderer_host/mock_render_process_host.cc +++ b/content/browser/renderer_host/mock_render_process_host.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 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. @@ -23,8 +23,7 @@ MockRenderProcessHost::~MockRenderProcessHost() { factory_->Remove(this); } -bool MockRenderProcessHost::Init( - bool is_accessibility_enabled, bool is_extensions_process) { +bool MockRenderProcessHost::Init(bool is_accessibility_enabled) { return true; } diff --git a/content/browser/renderer_host/mock_render_process_host.h b/content/browser/renderer_host/mock_render_process_host.h index 0e7656c..a6804a1 100644 --- a/content/browser/renderer_host/mock_render_process_host.h +++ b/content/browser/renderer_host/mock_render_process_host.h @@ -36,7 +36,7 @@ class MockRenderProcessHost : public RenderProcessHost { int bad_msg_count() const { return bad_msg_count_; } // RenderProcessHost implementation (public portion). - virtual bool Init(bool is_accessibility_enabled, bool is_extensions_process); + virtual bool Init(bool is_accessibility_enabled); virtual int GetNextRoutingID(); virtual void CancelResourceRequests(int render_widget_id); virtual void CrossSiteClosePageACK(const ViewMsg_ClosePage_Params& params); diff --git a/content/browser/renderer_host/render_process_host.cc b/content/browser/renderer_host/render_process_host.cc index cf380ab..f435e7c 100644 --- a/content/browser/renderer_host/render_process_host.cc +++ b/content/browser/renderer_host/render_process_host.cc @@ -94,6 +94,7 @@ RenderProcessHost::RenderProcessHost(Profile* profile) : max_page_id_(-1), fast_shutdown_started_(false), deleting_soon_(false), + is_extension_process_(false), id_(ChildProcessInfo::GenerateChildProcessUniqueId()), profile_(profile), sudden_termination_allowed_(true), diff --git a/content/browser/renderer_host/render_process_host.h b/content/browser/renderer_host/render_process_host.h index b384026..4a76d1f 100644 --- a/content/browser/renderer_host/render_process_host.h +++ b/content/browser/renderer_host/render_process_host.h @@ -88,6 +88,9 @@ class RenderProcessHost : public IPC::Channel::Sender, sudden_termination_allowed_ = enabled; } + bool is_extension_process() const { return is_extension_process_; } + void mark_is_extension_process() { is_extension_process_ = true; } + // Used for refcounting, each holder of this object must Attach and Release // just like it would for a COM object. This object should be allocated on // the heap; when no listeners own it any more, it will delete itself. @@ -157,8 +160,7 @@ class RenderProcessHost : public IPC::Channel::Sender, // be called once before the object can be used, but can be called after // that with no effect. Therefore, if the caller isn't sure about whether // the process has been created, it should just call Init(). - virtual bool Init( - bool is_accessibility_enabled, bool is_extensions_process) = 0; + virtual bool Init(bool is_accessibility_enabled) = 0; // Gets the next available routing id. virtual int GetNextRoutingID() = 0; @@ -276,6 +278,10 @@ class RenderProcessHost : public IPC::Channel::Sender, // True if we've posted a DeleteTask and will be deleted soon. bool deleting_soon_; + // True iff this process is being used as an extension process. Not valid + // when running in single-process mode. + bool is_extension_process_; + private: // The globally-unique identifier for this RPH. int id_; diff --git a/content/browser/renderer_host/render_view_host.cc b/content/browser/renderer_host/render_view_host.cc index 47e5457..c74ac5e 100644 --- a/content/browser/renderer_host/render_view_host.cc +++ b/content/browser/renderer_host/render_view_host.cc @@ -102,7 +102,6 @@ RenderViewHost::RenderViewHost(SiteInstance* instance, are_javascript_messages_suppressed_(false), sudden_termination_allowed_(false), session_storage_namespace_(session_storage), - is_extension_process_(false), save_accessibility_tree_for_testing_(false), render_view_termination_status_(base::TERMINATION_STATUS_STILL_RUNNING) { if (!session_storage_namespace_) { @@ -114,6 +113,11 @@ RenderViewHost::RenderViewHost(SiteInstance* instance, DCHECK(delegate_); content::GetContentClient()->browser()->RenderViewHostCreated(this); + + NotificationService::current()->Notify( + NotificationType::RENDER_VIEW_HOST_CREATED, + Source<RenderViewHost>(this), + NotificationService::NoDetails()); } RenderViewHost::~RenderViewHost() { @@ -139,7 +143,7 @@ bool RenderViewHost::CreateRenderView(const string16& frame_name) { // initialized it) or may not (we have our own process or the old process // crashed) have been initialized. Calling Init multiple times will be // ignored, so this is safe. - if (!process()->Init(renderer_accessible(), is_extension_process_)) + if (!process()->Init(renderer_accessible())) return false; DCHECK(process()->HasConnection()); DCHECK(process()->profile()); @@ -152,10 +156,6 @@ bool RenderViewHost::CreateRenderView(const string16& frame_name) { if (BindingsPolicy::is_extension_enabled(enabled_bindings_)) { ChildProcessSecurityPolicy::GetInstance()->GrantExtensionBindings( process()->id()); - - // Extensions may have permission to access chrome:// URLs. - ChildProcessSecurityPolicy::GetInstance()->GrantScheme( - process()->id(), chrome::kChromeUIScheme); } renderer_initialized_ = true; diff --git a/content/browser/renderer_host/render_view_host.h b/content/browser/renderer_host/render_view_host.h index bfd7bf85..b29f2ed 100644 --- a/content/browser/renderer_host/render_view_host.h +++ b/content/browser/renderer_host/render_view_host.h @@ -314,12 +314,6 @@ class RenderViewHost : public RenderWidgetHost { // RenderView. See BindingsPolicy for details. int enabled_bindings() const { return enabled_bindings_; } - // See variable comment. - bool is_extension_process() const { return is_extension_process_; } - void set_is_extension_process(bool is_extension_process) { - is_extension_process_ = is_extension_process; - } - // Sets a property with the given name and value on the Web UI binding object. // Must call AllowWebUIBindings() on this renderer first. void SetWebUIProperty(const std::string& name, const std::string& value); @@ -599,10 +593,6 @@ class RenderViewHost : public RenderWidgetHost { // The session storage namespace to be used by the associated render view. scoped_refptr<SessionStorageNamespace> session_storage_namespace_; - // Whether this render view will get extension api bindings. This controls - // what process type we use. - bool is_extension_process_; - // Whether the accessibility tree should be saved, for unit testing. bool save_accessibility_tree_for_testing_; diff --git a/content/browser/tab_contents/render_view_host_manager.cc b/content/browser/tab_contents/render_view_host_manager.cc index d08f6ab..7effc09 100644 --- a/content/browser/tab_contents/render_view_host_manager.cc +++ b/content/browser/tab_contents/render_view_host_manager.cc @@ -480,11 +480,6 @@ bool RenderViewHostManager::InitRenderView(RenderViewHost* render_view_host, if (pending_web_ui_.get()) render_view_host->AllowBindings(pending_web_ui_->bindings()); - // Give the embedder a chance to initialize the render view. - Profile* profile = delegate_->GetControllerForRenderManager().profile(); - content::GetContentClient()->browser()->PreCreateRenderView( - render_view_host, profile, entry.url()); - return delegate_->CreateRenderViewForRenderManager(render_view_host); } diff --git a/content/common/notification_type.h b/content/common/notification_type.h index 021f5ba..e19e01c 100644 --- a/content/common/notification_type.h +++ b/content/common/notification_type.h @@ -460,6 +460,10 @@ class NotificationType { // Used only in testing. RENDER_WIDGET_HOST_DID_RECEIVE_INPUT_EVENT_ACK, + // Sent from RenderViewHost constructor. The source is the RenderViewHost, + // the details unused. + RENDER_VIEW_HOST_CREATED, + // Sent from ~RenderViewHost. The source is the RenderViewHost, the details // unused. RENDER_VIEW_HOST_DELETED, @@ -866,18 +870,6 @@ class NotificationType { // Extension, and the source is a Profile. EXTENSION_USER_SCRIPTS_UPDATED, - // Sent after a new ExtensionFunctionDispatcher is created. The details are - // an ExtensionFunctionDispatcher* and the source is a Profile*. This is - // similar in timing to EXTENSION_HOST_CREATED, but also fires when an - // extension view which is hosted in TabContents* is created. - EXTENSION_FUNCTION_DISPATCHER_CREATED, - - // Sent before an ExtensionHost is destroyed. The details are - // an ExtensionFunctionDispatcher* and the source is a Profile*. This is - // similar in timing to EXTENSION_HOST_DESTROYED, but also fires when an - // extension view which is hosted in TabContents* is destroyed. - EXTENSION_FUNCTION_DISPATCHER_DESTROYED, - // Sent after a new ExtensionHost is created. The details are // an ExtensionHost* and the source is an ExtensionProcessManager*. EXTENSION_HOST_CREATED, |