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

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

Issue 2830893002: Refactor of ExtensionNavigationThrottle (Closed)
Patch Set: Blockage. 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()); 37 const GURL& url = navigation_handle()->GetURL();
38 bool url_has_extension_scheme = url.SchemeIs(kExtensionScheme);
38 content::WebContents* web_contents = navigation_handle()->GetWebContents(); 39 content::WebContents* web_contents = navigation_handle()->GetWebContents();
39 ExtensionRegistry* registry = 40 ExtensionRegistry* registry =
40 ExtensionRegistry::Get(web_contents->GetBrowserContext()); 41 ExtensionRegistry::Get(web_contents->GetBrowserContext());
41 42
43 // Is this navigation targeting an extension resource?
44 bool is_nested_url = url.SchemeIsFileSystem() || url.SchemeIsBlob();
45 url::Origin target_origin(url);
46 const Extension* target_extension = nullptr;
47 if (url_has_extension_scheme) {
48 target_extension =
49 registry->enabled_extensions().GetExtensionOrAppByURL(url);
50 } else if (is_nested_url && target_origin.scheme() == kExtensionScheme) {
51 target_extension =
52 registry->enabled_extensions().GetByID(target_origin.host());
53 } else {
54 // If the navigation is not to a chrome-extension resource, no need to
55 // perform any more checks; it's outside of the purview of this throttle.
56 return content::NavigationThrottle::PROCEED;
57 }
58
59 // If the navigation is to an unknown or disabled extension, block it.
60 if (!target_extension)
61 return content::NavigationThrottle::BLOCK_REQUEST;
62
42 if (navigation_handle()->IsInMainFrame()) { 63 if (navigation_handle()->IsInMainFrame()) {
43 // Block top-level navigations to blob: or filesystem: URLs with extension 64 // Block top-level navigations to blob: or filesystem: URLs with extension
44 // origin from non-extension processes. See https://crbug.com/645028. 65 // origin from non-extension processes. See https://crbug.com/645028.
45 bool is_nested_url = url.SchemeIsFileSystem() || url.SchemeIsBlob(); 66 bool current_frame_is_extension_process =
46 bool is_extension = false; 67 !!registry->enabled_extensions().GetExtensionOrAppByURL(
47 if (registry) { 68 navigation_handle()->GetStartingSiteInstance()->GetSiteURL());
48 is_extension = !!registry->enabled_extensions().GetExtensionOrAppByURL(
49 navigation_handle()->GetStartingSiteInstance()->GetSiteURL());
50 }
51 69
52 url::Origin origin(url); 70 if (is_nested_url && !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 71 // Relax this restriction for apps that use <webview>. See
56 // https://crbug.com/652077. 72 // https://crbug.com/652077.
57 const extensions::Extension* extension =
58 registry->enabled_extensions().GetByID(origin.host());
59 bool has_webview_permission = 73 bool has_webview_permission =
60 extension && 74 target_extension->permissions_data()->HasAPIPermission(
61 extension->permissions_data()->HasAPIPermission( 75 APIPermission::kWebView);
62 extensions::APIPermission::kWebView);
63 if (!has_webview_permission) 76 if (!has_webview_permission)
64 return content::NavigationThrottle::CANCEL; 77 return content::NavigationThrottle::CANCEL;
65 } 78 }
66 79
67 if (content::IsBrowserSideNavigationEnabled() && 80 guest_view::GuestViewBase* guest =
68 url.scheme() == extensions::kExtensionScheme) { 81 guest_view::GuestViewBase::FromWebContents(web_contents);
69 // This logic is performed for PlzNavigate sub-resources and for 82 if (content::IsBrowserSideNavigationEnabled() && url_has_extension_scheme &&
70 // non-PlzNavigate in 83 guest) {
71 // extensions::url_request_util::AllowCrossRendererResourceLoad. 84 // This logic is performed for PlzNavigate sub-resources and for non-
72 const Extension* extension = 85 // PlzNavigate in url_request_util::AllowCrossRendererResourceLoad.
73 registry->enabled_extensions().GetExtensionOrAppByURL(url); 86 std::string owner_extension_id = guest->owner_host();
74 guest_view::GuestViewBase* guest = 87 const Extension* owner_extension =
75 guest_view::GuestViewBase::FromWebContents(web_contents); 88 registry->enabled_extensions().GetByID(owner_extension_id);
76 if (guest) {
77 std::string owner_extension_id = guest->owner_host();
78 const Extension* owner_extension =
79 registry->enabled_extensions().GetByID(owner_extension_id);
80 89
81 std::string partition_domain, partition_id; 90 std::string partition_domain, partition_id;
82 bool in_memory; 91 bool in_memory;
83 std::string resource_path = url.path(); 92 std::string resource_path = url.path();
nasko 2017/04/27 23:14:06 nit: We can skip the local variable here, as it se
ncarter (slow) 2017/04/27 23:19:41 Done.
84 bool is_guest = WebViewGuest::GetGuestPartitionConfigForSite( 93 bool is_guest = WebViewGuest::GetGuestPartitionConfigForSite(
85 navigation_handle()->GetStartingSiteInstance()->GetSiteURL(), 94 navigation_handle()->GetStartingSiteInstance()->GetSiteURL(),
86 &partition_domain, &partition_id, &in_memory); 95 &partition_domain, &partition_id, &in_memory);
87 96
88 bool allowed = true; 97 bool allowed = true;
89 url_request_util::AllowCrossRendererResourceLoadHelper( 98 url_request_util::AllowCrossRendererResourceLoadHelper(
90 is_guest, extension, owner_extension, partition_id, resource_path, 99 is_guest, target_extension, owner_extension, partition_id,
91 navigation_handle()->GetPageTransition(), &allowed); 100 resource_path, navigation_handle()->GetPageTransition(), &allowed);
92 if (!allowed) 101 if (!allowed)
93 return content::NavigationThrottle::BLOCK_REQUEST; 102 return content::NavigationThrottle::BLOCK_REQUEST;
94 }
95 } 103 }
96 104
97 return content::NavigationThrottle::PROCEED; 105 return content::NavigationThrottle::PROCEED;
98 } 106 }
99 107
100 // Now enforce web_accessible_resources for navigations. Top-level navigations 108 // This is a subframe navigation to a |target_extension| resource.
101 // should always be allowed. 109 // Enforce the web_accessible_resources restriction.
110 content::RenderFrameHost* parent = web_contents->FindFrameByFrameTreeNodeId(
111 navigation_handle()->GetParentFrameTreeNodeId());
102 112
103 // If the navigation is not to a chrome-extension:// URL, no need to perform 113 // Look to see if all ancestors belong to |target_extension|. If not,
104 // any more checks. 114 // then the web_accessible_resource restriction applies.
105 if (!url.SchemeIs(extensions::kExtensionScheme)) 115 bool external_ancestor = false;
106 return content::NavigationThrottle::PROCEED; 116 for (auto* ancestor = parent; ancestor; ancestor = ancestor->GetParent()) {
117 // Look for a match on the last committed origin. This handles the
118 // common case, and the about:blank case.
119 if (ancestor->GetLastCommittedOrigin().IsSameOriginWith(target_origin))
120 continue;
121 // Look for an origin match with the last committed URL. This handles the
122 // case of sandboxed extension resources.
123 if (url::Origin(ancestor->GetLastCommittedURL()) == target_origin)
124 continue;
125 // Ignore DevTools, as it is allowed to embed extension pages.
126 if (ancestor->GetLastCommittedURL().SchemeIs(
127 content::kChromeDevToolsScheme))
128 continue;
107 129
108 // The subframe which is navigated needs to have all of its ancestors be 130 // Otherwise, we have an external ancestor.
109 // at the same origin, otherwise the resource needs to be explicitly listed 131 external_ancestor = true;
110 // in web_accessible_resources. 132 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 } 133 }
140 134
141 if (!external_ancestor) 135 if (external_ancestor) {
142 return content::NavigationThrottle::PROCEED; 136 // Cancel navigations to nested URLs, to match the main frame behavior.
137 if (!url_has_extension_scheme)
138 return content::NavigationThrottle::CANCEL;
143 139
144 // Since there was at least one origin different than the navigation URL, 140 // |url| must be in the manifest's "web_accessible_resources" section.
145 // explicitly check for the resource in web_accessible_resources. 141 if (!WebAccessibleResourcesInfo::IsResourceWebAccessible(target_extension,
146 std::string resource_path = url.path(); 142 url.path()))
147 if (!registry) 143 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 } 144 }
159 145
160 return content::NavigationThrottle::BLOCK_REQUEST; 146 return content::NavigationThrottle::PROCEED;
161 } 147 }
162 148
163 } // namespace extensions 149 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698