OLD | NEW |
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 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
49 target_extension = | 49 target_extension = |
50 registry->enabled_extensions().GetExtensionOrAppByURL(url); | 50 registry->enabled_extensions().GetExtensionOrAppByURL(url); |
51 } else if (target_origin.scheme() == kExtensionScheme) { | 51 } else if (target_origin.scheme() == kExtensionScheme) { |
52 // "blob:chrome-extension://" or "filesystem:chrome-extension://" URL. | 52 // "blob:chrome-extension://" or "filesystem:chrome-extension://" URL. |
53 DCHECK(url.SchemeIsFileSystem() || url.SchemeIsBlob()); | 53 DCHECK(url.SchemeIsFileSystem() || url.SchemeIsBlob()); |
54 target_extension = | 54 target_extension = |
55 registry->enabled_extensions().GetByID(target_origin.host()); | 55 registry->enabled_extensions().GetByID(target_origin.host()); |
56 } else { | 56 } else { |
57 // If the navigation is not to a chrome-extension resource, no need to | 57 // If the navigation is not to a chrome-extension resource, no need to |
58 // perform any more checks; it's outside of the purview of this throttle. | 58 // perform any more checks; it's outside of the purview of this throttle. |
59 return content::NavigationThrottle::PROCEED; | 59 return {PROCEED}; |
60 } | 60 } |
61 | 61 |
62 // If the navigation is to an unknown or disabled extension, block it. | 62 // If the navigation is to an unknown or disabled extension, block it. |
63 if (!target_extension) { | 63 if (!target_extension) |
64 // TODO(nick): This yields an unsatisfying error page; use a different error | 64 return {BLOCK_REQUEST, net::ERR_FILE_NOT_FOUND}; |
65 // code once that's supported. https://crbug.com/649869 | |
66 return content::NavigationThrottle::BLOCK_REQUEST; | |
67 } | |
68 | 65 |
69 if (navigation_handle()->IsInMainFrame()) { | 66 if (navigation_handle()->IsInMainFrame()) { |
70 // Block top-level navigations to blob: or filesystem: URLs with extension | 67 // Block top-level navigations to blob: or filesystem: URLs with extension |
71 // origin from non-extension processes. See https://crbug.com/645028. | 68 // origin from non-extension processes. See https://crbug.com/645028. |
72 bool current_frame_is_extension_process = | 69 bool current_frame_is_extension_process = |
73 !!registry->enabled_extensions().GetExtensionOrAppByURL( | 70 !!registry->enabled_extensions().GetExtensionOrAppByURL( |
74 navigation_handle()->GetStartingSiteInstance()->GetSiteURL()); | 71 navigation_handle()->GetStartingSiteInstance()->GetSiteURL()); |
75 | 72 |
76 if (!url_has_extension_scheme && !current_frame_is_extension_process) { | 73 if (!url_has_extension_scheme && !current_frame_is_extension_process) { |
77 // Relax this restriction for apps that use <webview>. See | 74 // Relax this restriction for apps that use <webview>. See |
78 // https://crbug.com/652077. | 75 // https://crbug.com/652077. |
79 bool has_webview_permission = | 76 bool has_webview_permission = |
80 target_extension->permissions_data()->HasAPIPermission( | 77 target_extension->permissions_data()->HasAPIPermission( |
81 APIPermission::kWebView); | 78 APIPermission::kWebView); |
82 if (!has_webview_permission) | 79 if (!has_webview_permission) |
83 return content::NavigationThrottle::CANCEL; | 80 return {CANCEL}; |
84 } | 81 } |
85 | 82 |
86 guest_view::GuestViewBase* guest = | 83 guest_view::GuestViewBase* guest = |
87 guest_view::GuestViewBase::FromWebContents(web_contents); | 84 guest_view::GuestViewBase::FromWebContents(web_contents); |
88 if (content::IsBrowserSideNavigationEnabled() && url_has_extension_scheme && | 85 if (content::IsBrowserSideNavigationEnabled() && url_has_extension_scheme && |
89 guest) { | 86 guest) { |
90 // This variant of this logic applies to PlzNavigate top-level | 87 // This variant of this logic applies to PlzNavigate top-level |
91 // navigations. It is performed for subresources, and for non-PlzNavigate | 88 // navigations. It is performed for subresources, and for non-PlzNavigate |
92 // top navigations, in url_request_util::AllowCrossRendererResourceLoad. | 89 // top navigations, in url_request_util::AllowCrossRendererResourceLoad. |
93 const std::string& owner_extension_id = guest->owner_host(); | 90 const std::string& owner_extension_id = guest->owner_host(); |
94 const Extension* owner_extension = | 91 const Extension* owner_extension = |
95 registry->enabled_extensions().GetByID(owner_extension_id); | 92 registry->enabled_extensions().GetByID(owner_extension_id); |
96 | 93 |
97 std::string partition_domain; | 94 std::string partition_domain; |
98 std::string partition_id; | 95 std::string partition_id; |
99 bool in_memory = false; | 96 bool in_memory = false; |
100 bool is_guest = WebViewGuest::GetGuestPartitionConfigForSite( | 97 bool is_guest = WebViewGuest::GetGuestPartitionConfigForSite( |
101 navigation_handle()->GetStartingSiteInstance()->GetSiteURL(), | 98 navigation_handle()->GetStartingSiteInstance()->GetSiteURL(), |
102 &partition_domain, &partition_id, &in_memory); | 99 &partition_domain, &partition_id, &in_memory); |
103 | 100 |
104 bool allowed = true; | 101 bool allowed = true; |
105 url_request_util::AllowCrossRendererResourceLoadHelper( | 102 url_request_util::AllowCrossRendererResourceLoadHelper( |
106 is_guest, target_extension, owner_extension, partition_id, url.path(), | 103 is_guest, target_extension, owner_extension, partition_id, url.path(), |
107 navigation_handle()->GetPageTransition(), &allowed); | 104 navigation_handle()->GetPageTransition(), &allowed); |
108 if (!allowed) | 105 if (!allowed) |
109 return content::NavigationThrottle::BLOCK_REQUEST; | 106 return {BLOCK_REQUEST, net::ERR_ACCESS_DENIED}; |
110 } | 107 } |
111 | 108 |
112 // Platform apps should only load in app windows, or guest views; never in | 109 // Platform apps should only load in app windows, or guest views; never in |
113 // regular tabs. TODO(nick): Further restrict the !guest case below. | 110 // regular tabs. TODO(nick): Further restrict the !guest case below. |
114 if (target_extension->is_platform_app() && !guest) { | 111 if (target_extension->is_platform_app() && !guest) { |
115 switch (GetViewType(web_contents)) { | 112 switch (GetViewType(web_contents)) { |
116 case VIEW_TYPE_APP_WINDOW: | 113 case VIEW_TYPE_APP_WINDOW: |
117 case VIEW_TYPE_BACKGROUND_CONTENTS: | 114 case VIEW_TYPE_BACKGROUND_CONTENTS: |
118 case VIEW_TYPE_EXTENSION_BACKGROUND_PAGE: | 115 case VIEW_TYPE_EXTENSION_BACKGROUND_PAGE: |
119 case VIEW_TYPE_PANEL: | 116 case VIEW_TYPE_PANEL: |
120 break; | 117 break; |
121 default: | 118 default: |
122 return content::NavigationThrottle::CANCEL; | 119 return {CANCEL}; |
123 } | 120 } |
124 } | 121 } |
125 | 122 |
126 return content::NavigationThrottle::PROCEED; | 123 return {PROCEED}; |
127 } | 124 } |
128 | 125 |
129 // This is a subframe navigation to a |target_extension| resource. | 126 // This is a subframe navigation to a |target_extension| resource. |
130 // Enforce the web_accessible_resources restriction, and same-origin | 127 // Enforce the web_accessible_resources restriction, and same-origin |
131 // restrictions for platform apps. | 128 // restrictions for platform apps. |
132 content::RenderFrameHost* parent = navigation_handle()->GetParentFrame(); | 129 content::RenderFrameHost* parent = navigation_handle()->GetParentFrame(); |
133 | 130 |
134 // Look to see if all ancestors belong to |target_extension|. If not, | 131 // Look to see if all ancestors belong to |target_extension|. If not, |
135 // then the web_accessible_resource restriction applies. | 132 // then the web_accessible_resource restriction applies. |
136 bool external_ancestor = false; | 133 bool external_ancestor = false; |
(...skipping 14 matching lines...) Expand all Loading... |
151 continue; | 148 continue; |
152 | 149 |
153 // Otherwise, we have an external ancestor. | 150 // Otherwise, we have an external ancestor. |
154 external_ancestor = true; | 151 external_ancestor = true; |
155 break; | 152 break; |
156 } | 153 } |
157 | 154 |
158 if (external_ancestor) { | 155 if (external_ancestor) { |
159 // Cancel navigations to nested URLs, to match the main frame behavior. | 156 // Cancel navigations to nested URLs, to match the main frame behavior. |
160 if (!url_has_extension_scheme) | 157 if (!url_has_extension_scheme) |
161 return content::NavigationThrottle::CANCEL; | 158 return {CANCEL}; |
162 | 159 |
163 // |url| must be in the manifest's "web_accessible_resources" section. | 160 // |url| must be in the manifest's "web_accessible_resources" section. |
164 if (!WebAccessibleResourcesInfo::IsResourceWebAccessible(target_extension, | 161 if (!WebAccessibleResourcesInfo::IsResourceWebAccessible(target_extension, |
165 url.path())) | 162 url.path())) |
166 return content::NavigationThrottle::BLOCK_REQUEST; | 163 return {BLOCK_REQUEST, net::ERR_ACCESS_DENIED}; |
167 | 164 |
168 // A platform app may not be loaded in an <iframe> by another origin. | 165 // A platform app may not be loaded in an <iframe> by another origin. |
169 // | 166 // |
170 // In fact, platform apps may not have any cross-origin iframes at all; for | 167 // In fact, platform apps may not have any cross-origin iframes at all; for |
171 // non-extension origins of |url| this is enforced by means of a Content | 168 // non-extension origins of |url| this is enforced by means of a Content |
172 // Security Policy. But CSP is incapable of blocking the chrome-extension | 169 // Security Policy. But CSP is incapable of blocking the chrome-extension |
173 // scheme. Thus, this case must be handled specially here. | 170 // scheme. Thus, this case must be handled specially here. |
174 if (target_extension->is_platform_app()) | 171 if (target_extension->is_platform_app()) |
175 return content::NavigationThrottle::CANCEL; | 172 return {CANCEL}; |
176 | 173 |
177 // A platform app may not load another extension in an <iframe>. | 174 // A platform app may not load another extension in an <iframe>. |
178 const Extension* parent_extension = | 175 const Extension* parent_extension = |
179 registry->enabled_extensions().GetExtensionOrAppByURL( | 176 registry->enabled_extensions().GetExtensionOrAppByURL( |
180 parent->GetSiteInstance()->GetSiteURL()); | 177 parent->GetSiteInstance()->GetSiteURL()); |
181 if (parent_extension && parent_extension->is_platform_app()) | 178 if (parent_extension && parent_extension->is_platform_app()) |
182 return content::NavigationThrottle::BLOCK_REQUEST; | 179 return {BLOCK_REQUEST, net::ERR_BLOCKED_BY_CLIENT}; |
183 } | 180 } |
184 | 181 |
185 return content::NavigationThrottle::PROCEED; | 182 return {PROCEED}; |
186 } | 183 } |
187 | 184 |
188 content::NavigationThrottle::ThrottleCheckResult | 185 content::NavigationThrottle::ThrottleCheckResult |
189 ExtensionNavigationThrottle::WillStartRequest() { | 186 ExtensionNavigationThrottle::WillStartRequest() { |
190 return WillStartOrRedirectRequest(); | 187 return WillStartOrRedirectRequest(); |
191 } | 188 } |
192 | 189 |
193 content::NavigationThrottle::ThrottleCheckResult | 190 content::NavigationThrottle::ThrottleCheckResult |
194 ExtensionNavigationThrottle::WillRedirectRequest() { | 191 ExtensionNavigationThrottle::WillRedirectRequest() { |
195 ThrottleCheckResult result = WillStartOrRedirectRequest(); | 192 ThrottleCheckResult result = WillStartOrRedirectRequest(); |
196 if (result.action() == BLOCK_REQUEST) { | 193 if (result.action() == BLOCK_REQUEST) { |
197 // BLOCK_REQUEST is on redirect does not work without PlzNavigate, so | 194 // BLOCK_REQUEST is on redirect does not work without PlzNavigate, so |
198 // translate these errors into CANCEL. | 195 // translate these errors into CANCEL. |
199 return CANCEL; | 196 return {CANCEL}; |
200 } | 197 } |
201 return result; | 198 return result; |
202 } | 199 } |
203 | 200 |
204 const char* ExtensionNavigationThrottle::GetNameForLogging() { | 201 const char* ExtensionNavigationThrottle::GetNameForLogging() { |
205 return "ExtensionNavigationThrottle"; | 202 return "ExtensionNavigationThrottle"; |
206 } | 203 } |
207 | 204 |
208 } // namespace extensions | 205 } // namespace extensions |
OLD | NEW |