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

Side by Side Diff: extensions/browser/extension_navigation_throttle.cc

Issue 2830893002: Refactor of ExtensionNavigationThrottle (Closed)
Patch Set: One more comment 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 unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "extensions/browser/extension_navigation_throttle.h" 5 #include "extensions/browser/extension_navigation_throttle.h"
6 6
7 #include "components/guest_view/browser/guest_view_base.h" 7 #include "components/guest_view/browser/guest_view_base.h"
8 #include "content/public/browser/browser_thread.h" 8 #include "content/public/browser/browser_thread.h"
9 #include "content/public/browser/navigation_handle.h" 9 #include "content/public/browser/navigation_handle.h"
10 #include "content/public/browser/render_frame_host.h" 10 #include "content/public/browser/render_frame_host.h"
(...skipping 16 matching lines...) Expand all
27 27
28 ExtensionNavigationThrottle::ExtensionNavigationThrottle( 28 ExtensionNavigationThrottle::ExtensionNavigationThrottle(
29 content::NavigationHandle* navigation_handle) 29 content::NavigationHandle* navigation_handle)
30 : content::NavigationThrottle(navigation_handle) {} 30 : content::NavigationThrottle(navigation_handle) {}
31 31
32 ExtensionNavigationThrottle::~ExtensionNavigationThrottle() {} 32 ExtensionNavigationThrottle::~ExtensionNavigationThrottle() {}
33 33
34 content::NavigationThrottle::ThrottleCheckResult 34 content::NavigationThrottle::ThrottleCheckResult
35 ExtensionNavigationThrottle::WillStartRequest() { 35 ExtensionNavigationThrottle::WillStartRequest() {
36 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 36 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
37 GURL url(navigation_handle()->GetURL());
38 content::WebContents* web_contents = navigation_handle()->GetWebContents(); 37 content::WebContents* web_contents = navigation_handle()->GetWebContents();
39 ExtensionRegistry* registry = 38 ExtensionRegistry* registry =
40 ExtensionRegistry::Get(web_contents->GetBrowserContext()); 39 ExtensionRegistry::Get(web_contents->GetBrowserContext());
41 40
41 // Is this navigation targeting an extension resource?
42 const GURL& url = navigation_handle()->GetURL();
43 bool url_has_extension_scheme = url.SchemeIs(kExtensionScheme);
44 url::Origin target_origin(url);
45 const Extension* target_extension = nullptr;
46 if (url_has_extension_scheme) {
47 // "chrome-extension://" URL.
48 target_extension =
49 registry->enabled_extensions().GetExtensionOrAppByURL(url);
50 } else if (target_origin.scheme() == kExtensionScheme) {
51 // "blob:chrome-extension://" or "filesystem:chrome-extension://" URL.
52 DCHECK(url.SchemeIsFileSystem() || url.SchemeIsBlob());
53 target_extension =
54 registry->enabled_extensions().GetByID(target_origin.host());
55 } else {
56 // If the navigation is not to a chrome-extension resource, no need to
57 // perform any more checks; it's outside of the purview of this throttle.
58 return content::NavigationThrottle::PROCEED;
59 }
60
61 // If the navigation is to an unknown or disabled extension, block it.
62 if (!target_extension) {
63 if (url_has_extension_scheme) {
64 // Proceed in this case; the protocol handler will surface an error.
65 return content::NavigationThrottle::PROCEED;
ncarter (slow) 2017/05/01 21:50:37 Note that this PROCEED case is new vs. the previou
Devlin 2017/05/01 22:04:28 Hmm... is there no way we could surface a useful e
ncarter (slow) 2017/05/02 20:14:15 Note that the PROCEED logic just matches the origi
ncarter (slow) 2017/05/02 23:53:15 My prev comment was incorrect (since the PROCEED i
66 }
67 // Explicitly block blob: and filesystem: URLs with unknown extensions.
68 // Nothing good can come of those.
69 return content::NavigationThrottle::BLOCK_REQUEST;
70 }
71
42 if (navigation_handle()->IsInMainFrame()) { 72 if (navigation_handle()->IsInMainFrame()) {
43 // Block top-level navigations to blob: or filesystem: URLs with extension 73 // Block top-level navigations to blob: or filesystem: URLs with extension
44 // origin from non-extension processes. See https://crbug.com/645028. 74 // origin from non-extension processes. See https://crbug.com/645028.
45 bool is_nested_url = url.SchemeIsFileSystem() || url.SchemeIsBlob(); 75 bool current_frame_is_extension_process =
46 bool is_extension = false; 76 !!registry->enabled_extensions().GetExtensionOrAppByURL(
47 if (registry) { 77 navigation_handle()->GetStartingSiteInstance()->GetSiteURL());
48 is_extension = !!registry->enabled_extensions().GetExtensionOrAppByURL(
49 navigation_handle()->GetStartingSiteInstance()->GetSiteURL());
50 }
51 78
52 url::Origin origin(url); 79 if (!url_has_extension_scheme && !current_frame_is_extension_process) {
53 if (is_nested_url && origin.scheme() == extensions::kExtensionScheme &&
54 !is_extension) {
55 // Relax this restriction for apps that use <webview>. See 80 // Relax this restriction for apps that use <webview>. See
56 // https://crbug.com/652077. 81 // https://crbug.com/652077.
57 const extensions::Extension* extension =
58 registry->enabled_extensions().GetByID(origin.host());
59 bool has_webview_permission = 82 bool has_webview_permission =
60 extension && 83 target_extension->permissions_data()->HasAPIPermission(
61 extension->permissions_data()->HasAPIPermission( 84 APIPermission::kWebView);
62 extensions::APIPermission::kWebView);
63 if (!has_webview_permission) 85 if (!has_webview_permission)
64 return content::NavigationThrottle::CANCEL; 86 return content::NavigationThrottle::CANCEL;
65 } 87 }
66 88
67 if (content::IsBrowserSideNavigationEnabled() && 89 guest_view::GuestViewBase* guest =
68 url.scheme() == extensions::kExtensionScheme) { 90 guest_view::GuestViewBase::FromWebContents(web_contents);
69 // This logic is performed for PlzNavigate sub-resources and for 91 if (content::IsBrowserSideNavigationEnabled() && url_has_extension_scheme &&
70 // non-PlzNavigate in 92 guest) {
71 // extensions::url_request_util::AllowCrossRendererResourceLoad. 93 // This variant of this logic applies to PlzNavigate top-level
72 const Extension* extension = 94 // navigations. It is performed for subresources, and for non-PlzNavigate
73 registry->enabled_extensions().GetExtensionOrAppByURL(url); 95 // top navigations, in url_request_util::AllowCrossRendererResourceLoad.
74 guest_view::GuestViewBase* guest = 96 const std::string& owner_extension_id = guest->owner_host();
75 guest_view::GuestViewBase::FromWebContents(web_contents); 97 const Extension* owner_extension =
76 if (guest) { 98 registry->enabled_extensions().GetByID(owner_extension_id);
77 std::string owner_extension_id = guest->owner_host();
78 const Extension* owner_extension =
79 registry->enabled_extensions().GetByID(owner_extension_id);
80 99
81 std::string partition_domain, partition_id; 100 std::string partition_domain;
82 bool in_memory; 101 std::string partition_id;
83 std::string resource_path = url.path(); 102 bool in_memory = false;
84 bool is_guest = WebViewGuest::GetGuestPartitionConfigForSite( 103 bool is_guest = WebViewGuest::GetGuestPartitionConfigForSite(
85 navigation_handle()->GetStartingSiteInstance()->GetSiteURL(), 104 navigation_handle()->GetStartingSiteInstance()->GetSiteURL(),
86 &partition_domain, &partition_id, &in_memory); 105 &partition_domain, &partition_id, &in_memory);
87 106
88 bool allowed = true; 107 bool allowed = true;
89 url_request_util::AllowCrossRendererResourceLoadHelper( 108 url_request_util::AllowCrossRendererResourceLoadHelper(
90 is_guest, extension, owner_extension, partition_id, resource_path, 109 is_guest, target_extension, owner_extension, partition_id, url.path(),
91 navigation_handle()->GetPageTransition(), &allowed); 110 navigation_handle()->GetPageTransition(), &allowed);
92 if (!allowed) 111 if (!allowed)
93 return content::NavigationThrottle::BLOCK_REQUEST; 112 return content::NavigationThrottle::BLOCK_REQUEST;
94 }
95 } 113 }
96 114
97 return content::NavigationThrottle::PROCEED; 115 return content::NavigationThrottle::PROCEED;
98 } 116 }
99 117
100 // Now enforce web_accessible_resources for navigations. Top-level navigations 118 // This is a subframe navigation to a |target_extension| resource.
101 // should always be allowed. 119 // Enforce the web_accessible_resources restriction.
120 content::RenderFrameHost* parent = web_contents->FindFrameByFrameTreeNodeId(
121 navigation_handle()->GetParentFrameTreeNodeId());
102 122
103 // If the navigation is not to a chrome-extension:// URL, no need to perform 123 // Look to see if all ancestors belong to |target_extension|. If not,
104 // any more checks. 124 // then the web_accessible_resource restriction applies.
105 if (!url.SchemeIs(extensions::kExtensionScheme)) 125 bool external_ancestor = false;
106 return content::NavigationThrottle::PROCEED; 126 for (auto* ancestor = parent; ancestor; ancestor = ancestor->GetParent()) {
127 // Look for a match on the last committed origin. This handles the
128 // common case, and the about:blank case.
129 if (ancestor->GetLastCommittedOrigin() == target_origin)
130 continue;
131 // Look for an origin match with the last committed URL. This handles the
132 // case of sandboxed extension resources, which commit with a null origin,
133 // but are permitted to load non-webaccessible extension resources in
134 // subframes.
135 if (url::Origin(ancestor->GetLastCommittedURL()) == target_origin)
136 continue;
137 // Ignore DevTools, as it is allowed to embed extension pages.
138 if (ancestor->GetLastCommittedURL().SchemeIs(
139 content::kChromeDevToolsScheme))
140 continue;
107 141
108 // The subframe which is navigated needs to have all of its ancestors be 142 // Otherwise, we have an external ancestor.
109 // at the same origin, otherwise the resource needs to be explicitly listed 143 external_ancestor = true;
110 // in web_accessible_resources. 144 break;
111 // Since the RenderFrameHost is not known until navigation has committed,
112 // we can't get it from NavigationHandle. However, this code only cares about
113 // the ancestor chain, so find the current RenderFrameHost and use it to
114 // traverse up to the main frame.
115 content::RenderFrameHost* navigating_frame = nullptr;
116 for (auto* frame : web_contents->GetAllFrames()) {
117 if (frame->GetFrameTreeNodeId() ==
118 navigation_handle()->GetFrameTreeNodeId()) {
119 navigating_frame = frame;
120 break;
121 }
122 }
123 DCHECK(navigating_frame);
124
125 // Traverse the chain of parent frames, checking if they are the same origin
126 // as the URL of this navigation.
127 content::RenderFrameHost* ancestor = navigating_frame->GetParent();
128 bool external_ancestor = false;
129 while (ancestor) {
130 if (ancestor->GetLastCommittedURL().GetOrigin() != url.GetOrigin()) {
131 // Ignore DevTools, as it is allowed to embed extension pages.
132 if (!ancestor->GetLastCommittedURL().SchemeIs(
133 content::kChromeDevToolsScheme)) {
134 external_ancestor = true;
135 break;
136 }
137 }
138 ancestor = ancestor->GetParent();
139 } 145 }
140 146
141 if (!external_ancestor) 147 if (external_ancestor) {
142 return content::NavigationThrottle::PROCEED; 148 // Cancel navigations to nested URLs, to match the main frame behavior.
Devlin 2017/05/01 22:04:28 Is this difference (CANCEL vs BLOCK_REQUEST) visib
ncarter (slow) 2017/05/01 22:42:53 Nested URLs (blob and filesystem) are classified a
Devlin 2017/05/02 01:52:09 Okay, I think that makes sense, as long as there's
149 if (!url_has_extension_scheme)
150 return content::NavigationThrottle::CANCEL;
143 151
144 // Since there was at least one origin different than the navigation URL, 152 // |url| must be in the manifest's "web_accessible_resources" section.
145 // explicitly check for the resource in web_accessible_resources. 153 if (!WebAccessibleResourcesInfo::IsResourceWebAccessible(target_extension,
146 std::string resource_path = url.path(); 154 url.path()))
147 if (!registry) 155 return content::NavigationThrottle::BLOCK_REQUEST;
148 return content::NavigationThrottle::BLOCK_REQUEST;
149
150 const extensions::Extension* extension =
151 registry->enabled_extensions().GetByID(url.host());
152 if (!extension)
153 return content::NavigationThrottle::BLOCK_REQUEST;
154
155 if (WebAccessibleResourcesInfo::IsResourceWebAccessible(extension,
156 resource_path)) {
157 return content::NavigationThrottle::PROCEED;
158 } 156 }
159 157
160 return content::NavigationThrottle::BLOCK_REQUEST; 158 return content::NavigationThrottle::PROCEED;
161 } 159 }
162 160
163 } // namespace extensions 161 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698