| 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 |