diff options
author | rafaelw@chromium.org <rafaelw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-31 02:48:12 +0000 |
---|---|---|
committer | rafaelw@chromium.org <rafaelw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-31 02:48:12 +0000 |
commit | 583d45c199e5af7a53bb0b15e5ef0e2d6f5ead90 (patch) | |
tree | 516825f2a3da3f33527e1e145af4c020c5d13bc2 /chrome/browser | |
parent | 3ad594ae4c38b057303eeb90d7e601a99d38a7c0 (diff) | |
download | chromium_src-583d45c199e5af7a53bb0b15e5ef0e2d6f5ead90.zip chromium_src-583d45c199e5af7a53bb0b15e5ef0e2d6f5ead90.tar.gz chromium_src-583d45c199e5af7a53bb0b15e5ef0e2d6f5ead90.tar.bz2 |
Reland r57788 - Expose Extension Bindings to Component Applications
This patch allows component (built-in) extension apps to have extension api bindings.
Note that this patch adds browser-side api permission checking for extension requests.
This is step two along the path to exposing an extension management api to the gallery (webstore).
Original Review: http://codereview.chromium.org/3163044
BUG=27431
TBR=mpcomplete
Review URL: http://codereview.chromium.org/3263007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@57941 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
20 files changed, 107 insertions, 53 deletions
diff --git a/chrome/browser/browser_url_handler.cc b/chrome/browser/browser_url_handler.cc index b209e04..6707606 100644 --- a/chrome/browser/browser_url_handler.cc +++ b/chrome/browser/browser_url_handler.cc @@ -60,7 +60,7 @@ static bool ReverseViewSource(GURL* url, Profile* profile) { // Handles rewriting DOM UI URLs. static bool HandleDOMUI(GURL* url, Profile* profile) { - if (!DOMUIFactory::UseDOMUIForURL(*url)) + if (!DOMUIFactory::UseDOMUIForURL(profile, *url)) return false; // Special case the new tab page. In older versions of Chrome, the new tab diff --git a/chrome/browser/dom_ui/dom_ui_factory.cc b/chrome/browser/dom_ui/dom_ui_factory.cc index 251f646..96f8b8a 100644 --- a/chrome/browser/dom_ui/dom_ui_factory.cc +++ b/chrome/browser/dom_ui/dom_ui_factory.cc @@ -55,14 +55,14 @@ DOMUI* NewDOMUI(TabContents* contents, const GURL& url) { // Special case for extensions. template<> DOMUI* NewDOMUI<ExtensionDOMUI>(TabContents* contents, const GURL& url) { - // Don't use a DOMUI for non-existent extensions or for incognito tabs. The - // latter restriction is because we require extensions to run within a single - // process. + // Don't use a DOMUI for incognito tabs because we require extensions to run + // within a single process. ExtensionsService* service = contents->profile()->GetExtensionsService(); - bool valid_extension = - (service && service->GetExtensionById(url.host(), false)); - if (valid_extension && !contents->profile()->IsOffTheRecord()) - return new ExtensionDOMUI(contents); + if (service && + service->ExtensionBindingsAllowed(url) && + !contents->profile()->IsOffTheRecord()) { + return new ExtensionDOMUI(contents, url); + } return NULL; } @@ -70,12 +70,14 @@ DOMUI* NewDOMUI<ExtensionDOMUI>(TabContents* contents, const GURL& url) { // tab, based on its URL. Returns NULL if the URL doesn't have DOMUI associated // with it. Even if the factory function is valid, it may yield a NULL DOMUI // when invoked for a particular tab - see NewDOMUI<ExtensionDOMUI>. -static DOMUIFactoryFunction GetDOMUIFactoryFunction(const GURL& url) { +static DOMUIFactoryFunction GetDOMUIFactoryFunction(Profile* profile, + const GURL& url) { // Currently, any gears: URL means an HTML dialog. if (url.SchemeIs(chrome::kGearsScheme)) return &NewDOMUI<HtmlDialogUI>; - if (url.SchemeIs(chrome::kExtensionScheme)) + ExtensionsService* service = profile->GetExtensionsService(); + if (service && service->ExtensionBindingsAllowed(url)) return &NewDOMUI<ExtensionDOMUI>; // All platform builds of Chrome will need to have a cloud printing @@ -159,8 +161,8 @@ static DOMUIFactoryFunction GetDOMUIFactoryFunction(const GURL& url) { } // static -DOMUITypeID DOMUIFactory::GetDOMUIType(const GURL& url) { - DOMUIFactoryFunction function = GetDOMUIFactoryFunction(url); +DOMUITypeID DOMUIFactory::GetDOMUIType(Profile* profile, const GURL& url) { + DOMUIFactoryFunction function = GetDOMUIFactoryFunction(profile, url); return function ? reinterpret_cast<DOMUITypeID>(function) : kNoDOMUI; } @@ -172,14 +174,15 @@ bool DOMUIFactory::HasDOMUIScheme(const GURL& url) { } // static -bool DOMUIFactory::UseDOMUIForURL(const GURL& url) { - return GetDOMUIFactoryFunction(url) != NULL; +bool DOMUIFactory::UseDOMUIForURL(Profile* profile, const GURL& url) { + return GetDOMUIFactoryFunction(profile, url) != NULL; } // static DOMUI* DOMUIFactory::CreateDOMUIForURL(TabContents* tab_contents, const GURL& url) { - DOMUIFactoryFunction function = GetDOMUIFactoryFunction(url); + DOMUIFactoryFunction function = GetDOMUIFactoryFunction( + tab_contents->profile(), url); if (!function) return NULL; return (*function)(tab_contents, url); diff --git a/chrome/browser/dom_ui/dom_ui_factory.h b/chrome/browser/dom_ui/dom_ui_factory.h index ba8dabe..3a7bfc6 100644 --- a/chrome/browser/dom_ui/dom_ui_factory.h +++ b/chrome/browser/dom_ui/dom_ui_factory.h @@ -27,7 +27,7 @@ class DOMUIFactory { // Returns a type identifier indicating what DOMUI we would use for the // given URL. This is useful for comparing the potential DOMUIs for two URLs. // Returns kNoDOMUI if the given URL will not use the DOM UI system. - static DOMUITypeID GetDOMUIType(const GURL& url); + static DOMUITypeID GetDOMUIType(Profile* profile, const GURL& url); // Returns true if the given URL's scheme would trigger the DOM UI system. // This is a less precise test than UseDONUIForURL, which tells you whether @@ -36,7 +36,7 @@ class DOMUIFactory { static bool HasDOMUIScheme(const GURL& url); // Returns true if the given URL will use the DOM UI system. - static bool UseDOMUIForURL(const GURL& url); + static bool UseDOMUIForURL(Profile* profile, const GURL& url); // Allocates a new DOMUI object for the given URL, and returns it. If the URL // is not a DOM UI URL, then it will return NULL. When non-NULL, ownership of diff --git a/chrome/browser/extensions/app_process_apitest.cc b/chrome/browser/extensions/app_process_apitest.cc index 1ca01cc..689a88c 100644 --- a/chrome/browser/extensions/app_process_apitest.cc +++ b/chrome/browser/extensions/app_process_apitest.cc @@ -86,10 +86,9 @@ IN_PROC_BROWSER_TEST_F(AppApiTest, AppProcess) { // The extension should have opened 3 new tabs. Including the original blank // tab, we now have 4 tabs. Two should be part of the extension app, and - // grouped in the extension process. + // grouped in the same process. ASSERT_EQ(4, browser()->tab_count()); RenderViewHost* host = browser()->GetTabContentsAt(1)->render_view_host(); - EXPECT_TRUE(host->is_extension_process()); EXPECT_EQ(host->process(), browser()->GetTabContentsAt(2)->render_view_host()->process()); diff --git a/chrome/browser/extensions/content_script_all_frames_apitest.cc b/chrome/browser/extensions/content_script_all_frames_apitest.cc index fac6362..3ed2f05 100644 --- a/chrome/browser/extensions/content_script_all_frames_apitest.cc +++ b/chrome/browser/extensions/content_script_all_frames_apitest.cc @@ -9,7 +9,10 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptAllFrames) { ASSERT_TRUE(RunExtensionTest("content_scripts/all_frames")) << message_; } -IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptExtensionIframe) { +// TODO(rafaelw): This test now fails because non-extension processes do not +// get extension bindings setup by scheme. Fixing crbug.com/53610 will fix this. +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, + DISABLED_ContentScriptExtensionIframe) { ASSERT_TRUE(test_server()->Start()); ASSERT_TRUE(RunExtensionTest("content_scripts/extension_iframe")) << message_; } diff --git a/chrome/browser/extensions/extension_dom_ui.cc b/chrome/browser/extensions/extension_dom_ui.cc index 1315330..62cfee0 100644 --- a/chrome/browser/extensions/extension_dom_ui.cc +++ b/chrome/browser/extensions/extension_dom_ui.cc @@ -120,18 +120,26 @@ class ExtensionDOMUIImageLoadingTracker : public ImageLoadingTracker::Observer { const char ExtensionDOMUI::kExtensionURLOverrides[] = "extensions.chrome_url_overrides"; -ExtensionDOMUI::ExtensionDOMUI(TabContents* tab_contents) +ExtensionDOMUI::ExtensionDOMUI(TabContents* tab_contents, GURL url) : DOMUI(tab_contents) { - should_hide_url_ = true; + ExtensionsService* service = tab_contents->profile()->GetExtensionsService(); + Extension* extension = service->GetExtensionByURL(url); + if (!extension) + extension = service->GetExtensionByWebExtent(url); + DCHECK(extension); + // Only hide the url for internal pages (e.g. chrome-extension or packaged + // component apps like bookmark manager. + should_hide_url_ = !extension->is_app(); + bindings_ = BindingsPolicy::EXTENSION; // Bind externalHost to Extension DOMUI loaded in Chrome Frame. const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); if (browser_command_line.HasSwitch(switches::kChromeFrame)) bindings_ |= BindingsPolicy::EXTERNAL_HOST; // For chrome:// overrides, some of the defaults are a little different. - GURL url = tab_contents->GetURL(); - if (url.SchemeIs(chrome::kChromeUIScheme) && - url.host() == chrome::kChromeUINewTabHost) { + GURL effective_url = tab_contents->GetURL(); + if (effective_url.SchemeIs(chrome::kChromeUIScheme) && + effective_url.host() == chrome::kChromeUINewTabHost) { focus_location_bar_by_default_ = true; } } diff --git a/chrome/browser/extensions/extension_dom_ui.h b/chrome/browser/extensions/extension_dom_ui.h index 56f1291..faa7836 100644 --- a/chrome/browser/extensions/extension_dom_ui.h +++ b/chrome/browser/extensions/extension_dom_ui.h @@ -15,6 +15,7 @@ #include "chrome/browser/favicon_service.h" #include "chrome/common/extensions/extension.h" +class GURL; class ListValue; class PrefService; class Profile; @@ -32,7 +33,7 @@ class ExtensionDOMUI public: static const char kExtensionURLOverrides[]; - explicit ExtensionDOMUI(TabContents* tab_contents); + explicit ExtensionDOMUI(TabContents* tab_contents, GURL url); ExtensionFunctionDispatcher* extension_function_dispatcher() const { return extension_function_dispatcher_.get(); diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc index 51cc8fe..a8253cf 100644 --- a/chrome/browser/extensions/extension_function_dispatcher.cc +++ b/chrome/browser/extensions/extension_function_dispatcher.cc @@ -333,7 +333,13 @@ ExtensionFunctionDispatcher* ExtensionFunctionDispatcher::Create( render_view_host->process()->profile()->GetExtensionsService(); DCHECK(service); + if (!service->ExtensionBindingsAllowed(url)) + return NULL; + Extension* extension = service->GetExtensionByURL(url); + if (!extension) + extension = service->GetExtensionByWebExtent(url); + if (extension) return new ExtensionFunctionDispatcher(render_view_host, delegate, extension, url); @@ -350,10 +356,12 @@ ExtensionFunctionDispatcher::ExtensionFunctionDispatcher( render_view_host_(render_view_host), delegate_(delegate), url_(url), + extension_id_(extension->id()), ALLOW_THIS_IN_INITIALIZER_LIST(peer_(new Peer(this))) { // TODO(erikkay) should we do something for these errors in Release? - DCHECK(url.SchemeIs(chrome::kExtensionScheme)); DCHECK(extension); + DCHECK(url.SchemeIs(chrome::kExtensionScheme) || + extension->location() == Extension::COMPONENT); // Notify the ExtensionProcessManager that the view was created. ExtensionProcessManager* epm = profile()->GetExtensionProcessManager(); @@ -448,6 +456,17 @@ void ExtensionFunctionDispatcher::HandleRequest( DCHECK(extension); function->set_include_incognito(service->IsIncognitoEnabled(extension)); + std::string permission_name = function->name(); + size_t separator = permission_name.find_first_of("./"); + if (separator != std::string::npos) + permission_name = permission_name.substr(0, separator); + + if (!service->ExtensionBindingsAllowed(function->source_url()) || + !extension->HasApiPermission(permission_name)) { + render_view_host_->BlockExtensionRequest(function->request_id()); + return; + } + ExtensionsQuotaService* quota = service->quota_service(); if (quota->Assess(extension_id(), function, ¶ms.arguments, base::TimeTicks::Now())) { diff --git a/chrome/browser/extensions/extension_function_dispatcher.h b/chrome/browser/extensions/extension_function_dispatcher.h index 9bddecf..2e8251f 100644 --- a/chrome/browser/extensions/extension_function_dispatcher.h +++ b/chrome/browser/extensions/extension_function_dispatcher.h @@ -114,7 +114,7 @@ class ExtensionFunctionDispatcher { const GURL& url() { return url_; } // Gets the ID for this extension. - const std::string extension_id() { return url_.host(); } + const std::string extension_id() { return extension_id_; } // The profile that this dispatcher is associated with. Profile* profile(); @@ -139,6 +139,8 @@ class ExtensionFunctionDispatcher { GURL url_; + std::string extension_id_; + scoped_refptr<Peer> peer_; // AutomationExtensionFunction requires access to the RenderViewHost diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc index 1c1a675..f43501b 100644 --- a/chrome/browser/extensions/extension_host.cc +++ b/chrome/browser/extensions/extension_host.cc @@ -513,7 +513,8 @@ void ExtensionHost::CreateNewWindow( route_id, render_view_host()->process()->profile(), site_instance(), - DOMUIFactory::GetDOMUIType(url_), + DOMUIFactory::GetDOMUIType(render_view_host()->process()->profile(), + url_), this, window_container_type, frame_name); diff --git a/chrome/browser/extensions/extension_messages_browsertest.cc b/chrome/browser/extensions/extension_messages_browsertest.cc index 3b3c273..5e78c79 100644 --- a/chrome/browser/extensions/extension_messages_browsertest.cc +++ b/chrome/browser/extensions/extension_messages_browsertest.cc @@ -16,8 +16,11 @@ static void DispatchOnConnect(int source_port_id, const std::string& name, args.Set(0, Value::CreateIntegerValue(source_port_id)); args.Set(1, Value::CreateStringValue(name)); args.Set(2, Value::CreateStringValue(tab_json)); - args.Set(3, Value::CreateStringValue("")); // extension ID is empty for tests - args.Set(4, Value::CreateStringValue("")); // extension ID is empty for tests + // Testing extensionId. Set in EventBindings::HandleContextCreated. + // We use the same id for source & target to similute an extension "talking + // to itself". + args.Set(3, Value::CreateStringValue(EventBindings::kTestingExtensionId)); + args.Set(4, Value::CreateStringValue(EventBindings::kTestingExtensionId)); RendererExtensionBindings::Invoke( ExtensionMessageService::kDispatchOnConnect, args, NULL, false, GURL()); } diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc index 5ea1ede..362ef22 100644 --- a/chrome/browser/extensions/extensions_service.cc +++ b/chrome/browser/extensions/extensions_service.cc @@ -1257,6 +1257,16 @@ Extension* ExtensionsService::GetExtensionByWebExtent(const GURL& url) { return NULL; } +bool ExtensionsService::ExtensionBindingsAllowed(const GURL& url) { + // Allow bindings for all packaged extension. + if (GetExtensionByURL(url)) + return true; + + // Allow bindings for all component, hosted apps. + Extension* extension = GetExtensionByWebExtent(url); + return (extension && extension->location() == Extension::COMPONENT); +} + Extension* ExtensionsService::GetExtensionByOverlappingWebExtent( const ExtensionExtent& extent) { for (size_t i = 0; i < extensions_.size(); ++i) { diff --git a/chrome/browser/extensions/extensions_service.h b/chrome/browser/extensions/extensions_service.h index 45110d4..efdc17b 100644 --- a/chrome/browser/extensions/extensions_service.h +++ b/chrome/browser/extensions/extensions_service.h @@ -288,6 +288,11 @@ class ExtensionsService // extent, if one exists. Extension* GetExtensionByOverlappingWebExtent(const ExtensionExtent& extent); + // Returns true if |url| should get extension api bindings and be permitted + // to make api calls. Note that this is independent of what extension + // permissions the given extension has been granted. + bool ExtensionBindingsAllowed(const GURL& url); + // Returns the icon to display in the omnibox for the given extension. const SkBitmap& GetOmniboxIcon(const std::string& extension_id); diff --git a/chrome/browser/notifications/balloon_host.cc b/chrome/browser/notifications/balloon_host.cc index 9e8f379..8e5b676 100644 --- a/chrome/browser/notifications/balloon_host.cc +++ b/chrome/browser/notifications/balloon_host.cc @@ -94,7 +94,8 @@ void BalloonHost::CreateNewWindow( route_id, balloon_->profile(), site_instance_.get(), - DOMUIFactory::GetDOMUIType(balloon_->notification().content_url()), + DOMUIFactory::GetDOMUIType(balloon_->profile(), + balloon_->notification().content_url()), this, window_container_type, frame_name); diff --git a/chrome/browser/renderer_host/browser_render_process_host.cc b/chrome/browser/renderer_host/browser_render_process_host.cc index 83d59f0..863362f 100644 --- a/chrome/browser/renderer_host/browser_render_process_host.cc +++ b/chrome/browser/renderer_host/browser_render_process_host.cc @@ -670,6 +670,7 @@ void BrowserRenderProcessHost::SendExtensionInfo() { info.id = extension->id(); info.web_extent = extension->web_extent(); info.name = extension->name(); + info.location = extension->location(); info.icon_url = extension->GetIconURLAllowLargerSize(Extension::EXTENSION_ICON_MEDIUM); params.extensions.push_back(info); diff --git a/chrome/browser/renderer_host/render_view_host.h b/chrome/browser/renderer_host/render_view_host.h index a2b4783..3010910 100644 --- a/chrome/browser/renderer_host/render_view_host.h +++ b/chrome/browser/renderer_host/render_view_host.h @@ -742,7 +742,7 @@ class RenderViewHost : public RenderWidgetHost { // The session storage namespace id to be used by the associated render view. int64 session_storage_namespace_id_; - // Whether this render view will be used for extensions. This controls + // Whether this render view will get extension api bindings. This controls // what process type we use. bool is_extension_process_; diff --git a/chrome/browser/tab_contents/background_contents.cc b/chrome/browser/tab_contents/background_contents.cc index 7b35bdc..b33ae32 100644 --- a/chrome/browser/tab_contents/background_contents.cc +++ b/chrome/browser/tab_contents/background_contents.cc @@ -166,13 +166,14 @@ void BackgroundContents::CreateNewWindow( int route_id, WindowContainerType window_container_type, const string16& frame_name) { - delegate_view_helper_.CreateNewWindow(route_id, - render_view_host_->process()->profile(), - render_view_host_->site_instance(), - DOMUIFactory::GetDOMUIType(url_), - this, - window_container_type, - frame_name); + delegate_view_helper_.CreateNewWindow( + route_id, + render_view_host_->process()->profile(), + render_view_host_->site_instance(), + DOMUIFactory::GetDOMUIType(render_view_host_->process()->profile(), url_), + this, + window_container_type, + frame_name); } void BackgroundContents::CreateNewWidget(int route_id, diff --git a/chrome/browser/tab_contents/render_view_host_manager.cc b/chrome/browser/tab_contents/render_view_host_manager.cc index e5f7426..d30b7d3 100644 --- a/chrome/browser/tab_contents/render_view_host_manager.cc +++ b/chrome/browser/tab_contents/render_view_host_manager.cc @@ -309,8 +309,9 @@ bool RenderViewHostManager::ShouldSwapProcessesForNavigation( // For security, we should transition between processes when one is a DOM UI // page and one isn't. - if (DOMUIFactory::UseDOMUIForURL(cur_entry->url()) != - DOMUIFactory::UseDOMUIForURL(new_entry->url())) + Profile* profile = delegate_->GetControllerForRenderManager().profile(); + if (DOMUIFactory::UseDOMUIForURL(profile, cur_entry->url()) != + DOMUIFactory::UseDOMUIForURL(profile, new_entry->url())) return true; // Also, we must switch if one is an extension and the other is not the exact @@ -472,14 +473,8 @@ bool RenderViewHostManager::InitRenderView(RenderViewHost* render_view_host, // Tell the RenderView whether it will be used for an extension process. Profile* profile = delegate_->GetControllerForRenderManager().profile(); - bool is_extension_process = false; - if (entry.url().SchemeIs(chrome::kExtensionScheme)) { - is_extension_process = true; - } else if (profile->GetExtensionsService() && - profile->GetExtensionsService()-> - GetExtensionByWebExtent(entry.url())) { - is_extension_process = true; - } + bool is_extension_process = profile->GetExtensionsService() && + profile->GetExtensionsService()->ExtensionBindingsAllowed(entry.url()); render_view_host->set_is_extension_process(is_extension_process); return delegate_->CreateRenderViewForRenderManager(render_view_host); diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc index 0bcaa84..ac2fe31 100644 --- a/chrome/browser/tab_contents/tab_contents.cc +++ b/chrome/browser/tab_contents/tab_contents.cc @@ -858,7 +858,7 @@ bool TabContents::NavigateToPendingEntry( // to a DOM UI renderer. Double check that here. int enabled_bindings = dest_render_view_host->enabled_bindings(); bool is_allowed_in_dom_ui_renderer = - DOMUIFactory::UseDOMUIForURL(entry.url()) || + DOMUIFactory::UseDOMUIForURL(profile(), entry.url()) || entry.url() == GURL(chrome::kAboutBlankURL); CHECK(!BindingsPolicy::is_dom_ui_enabled(enabled_bindings) || is_allowed_in_dom_ui_renderer); @@ -1604,7 +1604,8 @@ void TabContents::DidNavigateMainFramePostCommit( // If this is a window.open navigation, use the same DOMUI as the renderer // that opened the window, as long as both renderers have the same // privileges. - if (opener_dom_ui_type_ == DOMUIFactory::GetDOMUIType(GetURL())) { + if (opener_dom_ui_type_ == + DOMUIFactory::GetDOMUIType(profile(), GetURL())) { DOMUI* dom_ui = DOMUIFactory::CreateDOMUIForURL(this, GetURL()); // dom_ui might be NULL if the URL refers to a non-existent extension. if (dom_ui) { diff --git a/chrome/browser/tab_contents/tab_contents_view.cc b/chrome/browser/tab_contents/tab_contents_view.cc index 9c369d0..dd0242eb 100644 --- a/chrome/browser/tab_contents/tab_contents_view.cc +++ b/chrome/browser/tab_contents/tab_contents_view.cc @@ -34,7 +34,8 @@ void TabContentsView::CreateNewWindow( route_id, tab_contents_->profile(), tab_contents_->GetSiteInstance(), - DOMUIFactory::GetDOMUIType(tab_contents_->GetURL()), + DOMUIFactory::GetDOMUIType(tab_contents_->profile(), + tab_contents_->GetURL()), tab_contents_, window_container_type, frame_name); |