Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2203)

Unified Diff: extensions/browser/extension_navigation_throttle.cc

Issue 2830893002: Refactor of ExtensionNavigationThrottle (Closed)
Patch Set: \ Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/ui/toolbar/toolbar_model_unittest.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: extensions/browser/extension_navigation_throttle.cc
diff --git a/extensions/browser/extension_navigation_throttle.cc b/extensions/browser/extension_navigation_throttle.cc
index 5d026c5d7d649db24e2476ee38bb38b7353f9b26..37ead6b0182a5c7869ac4802805a5671b8542f09 100644
--- a/extensions/browser/extension_navigation_throttle.cc
+++ b/extensions/browser/extension_navigation_throttle.cc
@@ -34,114 +34,123 @@ ExtensionNavigationThrottle::~ExtensionNavigationThrottle() {}
content::NavigationThrottle::ThrottleCheckResult
ExtensionNavigationThrottle::WillStartRequest() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- GURL url(navigation_handle()->GetURL());
content::WebContents* web_contents = navigation_handle()->GetWebContents();
ExtensionRegistry* registry =
ExtensionRegistry::Get(web_contents->GetBrowserContext());
+ // Is this navigation targeting an extension resource?
+ const GURL& url = navigation_handle()->GetURL();
+ bool url_has_extension_scheme = url.SchemeIs(kExtensionScheme);
+ url::Origin target_origin(url);
+ const Extension* target_extension = nullptr;
+ if (url_has_extension_scheme) {
+ // "chrome-extension://" URL.
+ target_extension =
+ registry->enabled_extensions().GetExtensionOrAppByURL(url);
+ } else if (target_origin.scheme() == kExtensionScheme) {
+ // "blob:chrome-extension://" or "filesystem:chrome-extension://" URL.
+ DCHECK(url.SchemeIsFileSystem() || url.SchemeIsBlob());
+ target_extension =
+ registry->enabled_extensions().GetByID(target_origin.host());
+ } else {
+ // If the navigation is not to a chrome-extension resource, no need to
+ // perform any more checks; it's outside of the purview of this throttle.
+ return content::NavigationThrottle::PROCEED;
+ }
+
+ // If the navigation is to an unknown or disabled extension, block it.
+ if (!target_extension) {
+ // TODO(nick): This yields an unsatisfying error page; use a different error
+ // code once that's supported. https://crbug.com/649869
+ return content::NavigationThrottle::BLOCK_REQUEST;
+ }
+
if (navigation_handle()->IsInMainFrame()) {
// Block top-level navigations to blob: or filesystem: URLs with extension
// origin from non-extension processes. See https://crbug.com/645028.
- bool is_nested_url = url.SchemeIsFileSystem() || url.SchemeIsBlob();
- bool is_extension = false;
- if (registry) {
- is_extension = !!registry->enabled_extensions().GetExtensionOrAppByURL(
- navigation_handle()->GetStartingSiteInstance()->GetSiteURL());
- }
+ bool current_frame_is_extension_process =
+ !!registry->enabled_extensions().GetExtensionOrAppByURL(
+ navigation_handle()->GetStartingSiteInstance()->GetSiteURL());
- url::Origin origin(url);
- if (is_nested_url && origin.scheme() == extensions::kExtensionScheme &&
- !is_extension) {
+ if (!url_has_extension_scheme && !current_frame_is_extension_process) {
// Relax this restriction for apps that use <webview>. See
// https://crbug.com/652077.
- const extensions::Extension* extension =
- registry->enabled_extensions().GetByID(origin.host());
bool has_webview_permission =
- extension &&
- extension->permissions_data()->HasAPIPermission(
- extensions::APIPermission::kWebView);
+ target_extension->permissions_data()->HasAPIPermission(
+ APIPermission::kWebView);
if (!has_webview_permission)
return content::NavigationThrottle::CANCEL;
}
- if (content::IsBrowserSideNavigationEnabled() &&
- url.scheme() == extensions::kExtensionScheme) {
- // This logic is performed for PlzNavigate sub-resources and for
- // non-PlzNavigate in
- // extensions::url_request_util::AllowCrossRendererResourceLoad.
- const Extension* extension =
- registry->enabled_extensions().GetExtensionOrAppByURL(url);
- guest_view::GuestViewBase* guest =
- guest_view::GuestViewBase::FromWebContents(web_contents);
- if (guest) {
- std::string owner_extension_id = guest->owner_host();
- const Extension* owner_extension =
- registry->enabled_extensions().GetByID(owner_extension_id);
-
- std::string partition_domain, partition_id;
- bool in_memory;
- std::string resource_path = url.path();
- bool is_guest = WebViewGuest::GetGuestPartitionConfigForSite(
- navigation_handle()->GetStartingSiteInstance()->GetSiteURL(),
- &partition_domain, &partition_id, &in_memory);
-
- bool allowed = true;
- url_request_util::AllowCrossRendererResourceLoadHelper(
- is_guest, extension, owner_extension, partition_id, resource_path,
- navigation_handle()->GetPageTransition(), &allowed);
- if (!allowed)
- return content::NavigationThrottle::BLOCK_REQUEST;
- }
+ guest_view::GuestViewBase* guest =
+ guest_view::GuestViewBase::FromWebContents(web_contents);
+ if (content::IsBrowserSideNavigationEnabled() && url_has_extension_scheme &&
+ guest) {
+ // This variant of this logic applies to PlzNavigate top-level
+ // navigations. It is performed for subresources, and for non-PlzNavigate
+ // top navigations, in url_request_util::AllowCrossRendererResourceLoad.
+ const std::string& owner_extension_id = guest->owner_host();
+ const Extension* owner_extension =
+ registry->enabled_extensions().GetByID(owner_extension_id);
+
+ std::string partition_domain;
+ std::string partition_id;
+ bool in_memory = false;
+ bool is_guest = WebViewGuest::GetGuestPartitionConfigForSite(
+ navigation_handle()->GetStartingSiteInstance()->GetSiteURL(),
+ &partition_domain, &partition_id, &in_memory);
+
+ bool allowed = true;
+ url_request_util::AllowCrossRendererResourceLoadHelper(
+ is_guest, target_extension, owner_extension, partition_id, url.path(),
+ navigation_handle()->GetPageTransition(), &allowed);
+ if (!allowed)
+ return content::NavigationThrottle::BLOCK_REQUEST;
}
return content::NavigationThrottle::PROCEED;
}
- // Now enforce web_accessible_resources for navigations. Top-level navigations
- // should always be allowed.
-
- // If the navigation is not to a chrome-extension:// URL, no need to perform
- // any more checks.
- if (!url.SchemeIs(extensions::kExtensionScheme))
- return content::NavigationThrottle::PROCEED;
+ // This is a subframe navigation to a |target_extension| resource.
+ // Enforce the web_accessible_resources restriction.
+ content::RenderFrameHost* parent = navigation_handle()->GetParentFrame();
- // The subframe which is navigated needs to have all of its ancestors be
- // at the same origin, otherwise the resource needs to be explicitly listed
- // in web_accessible_resources.
- content::RenderFrameHost* ancestor = navigation_handle()->GetParentFrame();
+ // Look to see if all ancestors belong to |target_extension|. If not,
+ // then the web_accessible_resource restriction applies.
bool external_ancestor = false;
- while (ancestor) {
- if (ancestor->GetLastCommittedURL().GetOrigin() != url.GetOrigin()) {
- // Ignore DevTools, as it is allowed to embed extension pages.
- if (!ancestor->GetLastCommittedURL().SchemeIs(
- content::kChromeDevToolsScheme)) {
- external_ancestor = true;
- break;
- }
- }
- ancestor = ancestor->GetParent();
+ for (auto* ancestor = parent; ancestor; ancestor = ancestor->GetParent()) {
+ // Look for a match on the last committed origin. This handles the
+ // common case, and the about:blank case.
+ if (ancestor->GetLastCommittedOrigin() == target_origin)
+ continue;
+ // Look for an origin match with the last committed URL. This handles the
+ // case of sandboxed extension resources, which commit with a null origin,
+ // but are permitted to load non-webaccessible extension resources in
+ // subframes.
+ if (url::Origin(ancestor->GetLastCommittedURL()) == target_origin)
+ continue;
+ // Ignore DevTools, as it is allowed to embed extension pages.
+ if (ancestor->GetLastCommittedURL().SchemeIs(
+ content::kChromeDevToolsScheme))
+ continue;
+
+ // Otherwise, we have an external ancestor.
+ external_ancestor = true;
+ break;
}
- if (!external_ancestor)
- return content::NavigationThrottle::PROCEED;
-
- // Since there was at least one origin different than the navigation URL,
- // explicitly check for the resource in web_accessible_resources.
- std::string resource_path = url.path();
- if (!registry)
- return content::NavigationThrottle::BLOCK_REQUEST;
-
- const extensions::Extension* extension =
- registry->enabled_extensions().GetByID(url.host());
- if (!extension)
- return content::NavigationThrottle::BLOCK_REQUEST;
+ if (external_ancestor) {
+ // Cancel navigations to nested URLs, to match the main frame behavior.
+ if (!url_has_extension_scheme)
+ return content::NavigationThrottle::CANCEL;
- if (WebAccessibleResourcesInfo::IsResourceWebAccessible(extension,
- resource_path)) {
- return content::NavigationThrottle::PROCEED;
+ // |url| must be in the manifest's "web_accessible_resources" section.
+ if (!WebAccessibleResourcesInfo::IsResourceWebAccessible(target_extension,
+ url.path()))
+ return content::NavigationThrottle::BLOCK_REQUEST;
}
- return content::NavigationThrottle::BLOCK_REQUEST;
+ return content::NavigationThrottle::PROCEED;
}
const char* ExtensionNavigationThrottle::GetNameForLogging() {
« no previous file with comments | « chrome/browser/ui/toolbar/toolbar_model_unittest.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698