| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "chrome/renderer/extensions/chrome_extensions_renderer_client.h" | 5 #include "chrome/renderer/extensions/chrome_extensions_renderer_client.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| 11 #include "base/lazy_instance.h" | 11 #include "base/lazy_instance.h" |
| 12 #include "chrome/common/chrome_isolated_world_ids.h" | 12 #include "chrome/common/chrome_isolated_world_ids.h" |
| 13 #include "chrome/common/chrome_switches.h" | 13 #include "chrome/common/chrome_switches.h" |
| 14 #include "chrome/common/extensions/extension_constants.h" | 14 #include "chrome/common/extensions/extension_constants.h" |
| 15 #include "chrome/common/extensions/extension_metrics.h" | 15 #include "chrome/common/extensions/extension_metrics.h" |
| 16 #include "chrome/common/extensions/extension_process_policy.h" | |
| 17 #include "chrome/common/url_constants.h" | 16 #include "chrome/common/url_constants.h" |
| 18 #include "chrome/renderer/chrome_render_thread_observer.h" | 17 #include "chrome/renderer/chrome_render_thread_observer.h" |
| 19 #include "chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.h" | 18 #include "chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.h" |
| 20 #include "chrome/renderer/extensions/renderer_permissions_policy_delegate.h" | 19 #include "chrome/renderer/extensions/renderer_permissions_policy_delegate.h" |
| 21 #include "chrome/renderer/extensions/resource_request_policy.h" | 20 #include "chrome/renderer/extensions/resource_request_policy.h" |
| 22 #include "chrome/renderer/media/cast_ipc_dispatcher.h" | 21 #include "chrome/renderer/media/cast_ipc_dispatcher.h" |
| 23 #include "content/public/common/content_constants.h" | 22 #include "content/public/common/content_constants.h" |
| 24 #include "content/public/common/content_switches.h" | 23 #include "content/public/common/content_switches.h" |
| 25 #include "content/public/renderer/render_thread.h" | 24 #include "content/public/renderer/render_thread.h" |
| 26 #include "extensions/common/constants.h" | 25 #include "extensions/common/constants.h" |
| 27 #include "extensions/common/extension.h" | 26 #include "extensions/common/extension.h" |
| 28 #include "extensions/common/extension_set.h" | 27 #include "extensions/common/extension_set.h" |
| 28 #include "extensions/common/manifest_handlers/app_isolation_info.h" |
| 29 #include "extensions/common/switches.h" | 29 #include "extensions/common/switches.h" |
| 30 #include "extensions/renderer/dispatcher.h" | 30 #include "extensions/renderer/dispatcher.h" |
| 31 #include "extensions/renderer/extension_frame_helper.h" | 31 #include "extensions/renderer/extension_frame_helper.h" |
| 32 #include "extensions/renderer/extension_helper.h" | 32 #include "extensions/renderer/extension_helper.h" |
| 33 #include "extensions/renderer/extensions_render_frame_observer.h" | 33 #include "extensions/renderer/extensions_render_frame_observer.h" |
| 34 #include "extensions/renderer/guest_view/extensions_guest_view_container.h" | 34 #include "extensions/renderer/guest_view/extensions_guest_view_container.h" |
| 35 #include "extensions/renderer/guest_view/extensions_guest_view_container_dispatc
her.h" | 35 #include "extensions/renderer/guest_view/extensions_guest_view_container_dispatc
her.h" |
| 36 #include "extensions/renderer/guest_view/mime_handler_view/mime_handler_view_con
tainer.h" | 36 #include "extensions/renderer/guest_view/mime_handler_view/mime_handler_view_con
tainer.h" |
| 37 #include "extensions/renderer/script_context.h" | 37 #include "extensions/renderer/script_context.h" |
| 38 #include "third_party/WebKit/public/platform/WebURL.h" | 38 #include "third_party/WebKit/public/platform/WebURL.h" |
| 39 #include "third_party/WebKit/public/web/WebDocument.h" | 39 #include "third_party/WebKit/public/web/WebDocument.h" |
| 40 #include "third_party/WebKit/public/web/WebLocalFrame.h" | 40 #include "third_party/WebKit/public/web/WebLocalFrame.h" |
| 41 #include "third_party/WebKit/public/web/WebPluginParams.h" | 41 #include "third_party/WebKit/public/web/WebPluginParams.h" |
| 42 #include "url/gurl.h" |
| 42 | 43 |
| 43 using extensions::Extension; | 44 using extensions::Extension; |
| 44 | 45 |
| 45 namespace { | 46 namespace { |
| 46 | 47 |
| 47 bool IsStandaloneExtensionProcess() { | 48 bool IsStandaloneExtensionProcess() { |
| 48 return base::CommandLine::ForCurrentProcess()->HasSwitch( | 49 return base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 49 extensions::switches::kExtensionProcess); | 50 extensions::switches::kExtensionProcess); |
| 50 } | 51 } |
| 51 | 52 |
| 52 void IsGuestViewApiAvailableToScriptContext( | 53 void IsGuestViewApiAvailableToScriptContext( |
| 53 bool* api_is_available, | 54 bool* api_is_available, |
| 54 extensions::ScriptContext* context) { | 55 extensions::ScriptContext* context) { |
| 55 if (context->GetAvailability("guestViewInternal").is_available()) { | 56 if (context->GetAvailability("guestViewInternal").is_available()) { |
| 56 *api_is_available = true; | 57 *api_is_available = true; |
| 57 } | 58 } |
| 58 } | 59 } |
| 59 | 60 |
| 61 // Returns the extension for the given URL. Excludes extension objects for |
| 62 // bookmark apps, which do not use the app process model. |
| 63 const Extension* GetNonBookmarkAppExtension( |
| 64 const extensions::ExtensionSet& extensions, |
| 65 const GURL& url) { |
| 66 // Exclude bookmark apps, which do not use the app process model. |
| 67 const Extension* extension = extensions.GetExtensionOrAppByURL(url); |
| 68 if (extension && extension->from_bookmark()) |
| 69 extension = NULL; |
| 70 return extension; |
| 71 } |
| 72 |
| 73 bool IsHostedApp(const extensions::ExtensionSet& extensions, const GURL& url) { |
| 74 const extensions::Extension* extension = |
| 75 GetNonBookmarkAppExtension(extensions, url); |
| 76 return extension && extension->is_app(); |
| 77 } |
| 78 |
| 79 // Check if navigating a toplevel page from |old_url| to |new_url| would cross |
| 80 // an extension process boundary (e.g. navigating from a web URL into an |
| 81 // extension URL). |
| 82 // We temporarily consider a workaround where we will keep non-app URLs in |
| 83 // an app process, but only if |should_consider_workaround| is true. See |
| 84 // http://crbug.com/59285. |
| 85 bool CrossesExtensionProcessBoundary(const extensions::ExtensionSet& extensions, |
| 86 const GURL& old_url, |
| 87 const GURL& new_url, |
| 88 bool should_consider_workaround) { |
| 89 const extensions::Extension* old_url_extension = |
| 90 GetNonBookmarkAppExtension(extensions, old_url); |
| 91 const extensions::Extension* new_url_extension = |
| 92 GetNonBookmarkAppExtension(extensions, new_url); |
| 93 |
| 94 // TODO(creis): Temporary workaround for crbug.com/59285: Do not swap process |
| 95 // to navigate from a hosted app to a normal page or another hosted app |
| 96 // (unless either is the web store). This is because some OAuth providers |
| 97 // use non-app popups that communicate with non-app iframes inside the app |
| 98 // (e.g., Facebook). This would require out-of-process iframes to support. |
| 99 // See http://crbug.com/99379. |
| 100 // Note that we skip this exception for isolated apps, which require strict |
| 101 // process separation from non-app pages. |
| 102 if (should_consider_workaround) { |
| 103 bool old_url_is_hosted_app = |
| 104 old_url_extension && !old_url_extension->web_extent().is_empty() && |
| 105 !extensions::AppIsolationInfo::HasIsolatedStorage(old_url_extension); |
| 106 bool new_url_is_normal_or_hosted = |
| 107 !new_url_extension || |
| 108 (!new_url_extension->web_extent().is_empty() && |
| 109 !extensions::AppIsolationInfo::HasIsolatedStorage(new_url_extension)); |
| 110 bool either_is_web_store = |
| 111 (old_url_extension && |
| 112 old_url_extension->id() == extensions::kWebStoreAppId) || |
| 113 (new_url_extension && |
| 114 new_url_extension->id() == extensions::kWebStoreAppId); |
| 115 if (old_url_is_hosted_app && new_url_is_normal_or_hosted && |
| 116 !either_is_web_store) |
| 117 return false; |
| 118 } |
| 119 |
| 120 return old_url_extension != new_url_extension; |
| 121 } |
| 122 |
| 60 // Returns true if the frame is navigating to an URL either into or out of an | 123 // Returns true if the frame is navigating to an URL either into or out of an |
| 61 // extension app's extent. | 124 // extension app's extent. |
| 62 bool CrossesExtensionExtents(blink::WebLocalFrame* frame, | 125 bool CrossesHostedAppExtents(blink::WebLocalFrame* frame, |
| 63 const GURL& new_url, | 126 const GURL& new_url, |
| 64 bool is_extension_url, | 127 bool is_extension_url, |
| 65 bool is_initial_navigation) { | 128 bool is_initial_navigation) { |
| 66 DCHECK(!frame->Parent()); | 129 DCHECK(!frame->Parent()); |
| 67 GURL old_url(frame->GetDocument().Url()); | 130 GURL old_url(frame->GetDocument().Url()); |
| 68 | 131 |
| 69 extensions::RendererExtensionRegistry* extension_registry = | 132 extensions::RendererExtensionRegistry* extension_registry = |
| 70 extensions::RendererExtensionRegistry::Get(); | 133 extensions::RendererExtensionRegistry::Get(); |
| 134 const extensions::ExtensionSet& main_thread_extensions = |
| 135 *extension_registry->GetMainThreadExtensionSet(); |
| 71 | 136 |
| 72 // If old_url is still empty and this is an initial navigation, then this is | 137 // If old_url is still empty and this is an initial navigation, then this is |
| 73 // a window.open operation. We should look at the opener URL. Note that the | 138 // a window.open operation. We should look at the opener URL. Note that the |
| 74 // opener is a local frame in this case. | 139 // opener is a local frame in this case. |
| 75 if (is_initial_navigation && old_url.is_empty() && frame->Opener()) { | 140 if (is_initial_navigation && old_url.is_empty() && frame->Opener()) { |
| 76 blink::WebLocalFrame* opener_frame = frame->Opener()->ToWebLocalFrame(); | 141 blink::WebLocalFrame* opener_frame = frame->Opener()->ToWebLocalFrame(); |
| 77 | 142 |
| 78 // We want to compare against the URL that determines the type of | 143 // We want to compare against the URL that determines the type of |
| 79 // process. Use the URL of the opener's local frame root, which will | 144 // process. Use the URL of the opener's local frame root, which will |
| 80 // correctly handle any site isolation modes (e.g. --site-per-process). | 145 // correctly handle any site isolation modes (e.g. --site-per-process). |
| (...skipping 13 matching lines...) Expand all Loading... |
| 94 extension_registry->GetExtensionOrAppByURL(old_url); | 159 extension_registry->GetExtensionOrAppByURL(old_url); |
| 95 bool opener_is_web_store = | 160 bool opener_is_web_store = |
| 96 opener_top_extension && | 161 opener_top_extension && |
| 97 opener_top_extension->id() == extensions::kWebStoreAppId; | 162 opener_top_extension->id() == extensions::kWebStoreAppId; |
| 98 if (!is_extension_url && !opener_is_extension_url && !opener_is_web_store && | 163 if (!is_extension_url && !opener_is_extension_url && !opener_is_web_store && |
| 99 IsStandaloneExtensionProcess() && | 164 IsStandaloneExtensionProcess() && |
| 100 opener_origin.CanRequest(blink::WebURL(new_url))) | 165 opener_origin.CanRequest(blink::WebURL(new_url))) |
| 101 return false; | 166 return false; |
| 102 } | 167 } |
| 103 | 168 |
| 169 // With --isolate-extensions, forking is no longer needed to isolate |
| 170 // extensions into separate renderer processes (i.e. isolation should |
| 171 // be enforced by the transfer logic). |
| 172 bool old_or_new_is_hosted_app = |
| 173 IsHostedApp(main_thread_extensions, old_url) || |
| 174 IsHostedApp(main_thread_extensions, new_url); |
| 175 if (!old_or_new_is_hosted_app) |
| 176 return false; |
| 177 |
| 104 // Only consider keeping non-app URLs in an app process if this window | 178 // Only consider keeping non-app URLs in an app process if this window |
| 105 // has an opener (in which case it might be an OAuth popup that tries to | 179 // has an opener (in which case it might be an OAuth popup that tries to |
| 106 // script an iframe within the app). | 180 // script an iframe within the app). |
| 107 bool should_consider_workaround = !!frame->Opener(); | 181 bool should_consider_workaround = !!frame->Opener(); |
| 108 | 182 |
| 109 return extensions::CrossesExtensionProcessBoundary( | 183 return CrossesExtensionProcessBoundary(main_thread_extensions, old_url, |
| 110 *extension_registry->GetMainThreadExtensionSet(), old_url, new_url, | 184 new_url, should_consider_workaround); |
| 111 should_consider_workaround); | |
| 112 } | 185 } |
| 113 | 186 |
| 114 } // namespace | 187 } // namespace |
| 115 | 188 |
| 116 ChromeExtensionsRendererClient::ChromeExtensionsRendererClient() {} | 189 ChromeExtensionsRendererClient::ChromeExtensionsRendererClient() {} |
| 117 | 190 |
| 118 ChromeExtensionsRendererClient::~ChromeExtensionsRendererClient() {} | 191 ChromeExtensionsRendererClient::~ChromeExtensionsRendererClient() {} |
| 119 | 192 |
| 120 // static | 193 // static |
| 121 ChromeExtensionsRendererClient* ChromeExtensionsRendererClient::GetInstance() { | 194 ChromeExtensionsRendererClient* ChromeExtensionsRendererClient::GetInstance() { |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 239 // static | 312 // static |
| 240 bool ChromeExtensionsRendererClient::ShouldFork(blink::WebLocalFrame* frame, | 313 bool ChromeExtensionsRendererClient::ShouldFork(blink::WebLocalFrame* frame, |
| 241 const GURL& url, | 314 const GURL& url, |
| 242 bool is_initial_navigation, | 315 bool is_initial_navigation, |
| 243 bool is_server_redirect, | 316 bool is_server_redirect, |
| 244 bool* send_referrer) { | 317 bool* send_referrer) { |
| 245 const extensions::RendererExtensionRegistry* extension_registry = | 318 const extensions::RendererExtensionRegistry* extension_registry = |
| 246 extensions::RendererExtensionRegistry::Get(); | 319 extensions::RendererExtensionRegistry::Get(); |
| 247 | 320 |
| 248 // Determine if the new URL is an extension (excluding bookmark apps). | 321 // Determine if the new URL is an extension (excluding bookmark apps). |
| 249 const Extension* new_url_extension = extensions::GetNonBookmarkAppExtension( | 322 const Extension* new_url_extension = GetNonBookmarkAppExtension( |
| 250 *extension_registry->GetMainThreadExtensionSet(), url); | 323 *extension_registry->GetMainThreadExtensionSet(), url); |
| 251 bool is_extension_url = !!new_url_extension; | 324 bool is_extension_url = !!new_url_extension; |
| 252 | 325 |
| 253 // If the navigation would cross an app extent boundary, we also need | 326 // If the navigation would cross an app extent boundary, we also need |
| 254 // to defer to the browser to ensure process isolation. This is not necessary | 327 // to defer to the browser to ensure process isolation. This is not necessary |
| 255 // for server redirects, which will be transferred to a new process by the | 328 // for server redirects, which will be transferred to a new process by the |
| 256 // browser process when they are ready to commit. It is necessary for client | 329 // browser process when they are ready to commit. It is necessary for client |
| 257 // redirects, which won't be transferred in the same way. | 330 // redirects, which won't be transferred in the same way. |
| 258 if (!is_server_redirect && | 331 if (!is_server_redirect && |
| 259 CrossesExtensionExtents(frame, url, is_extension_url, | 332 CrossesHostedAppExtents(frame, url, is_extension_url, |
| 260 is_initial_navigation)) { | 333 is_initial_navigation)) { |
| 261 // Include the referrer in this case since we're going from a hosted web | 334 // Include the referrer in this case since we're going from a hosted web |
| 262 // page. (the packaged case is handled previously by the extension | 335 // page. (the packaged case is handled previously by the extension |
| 263 // navigation test) | 336 // navigation test) |
| 264 *send_referrer = true; | 337 *send_referrer = true; |
| 265 | 338 |
| 266 const Extension* extension = | 339 const Extension* extension = |
| 267 extension_registry->GetExtensionOrAppByURL(url); | 340 extension_registry->GetExtensionOrAppByURL(url); |
| 268 if (extension && extension->is_app()) { | 341 if (extension && extension->is_app()) { |
| 269 extensions::RecordAppLaunchType( | 342 extensions::RecordAppLaunchType( |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 305 | 378 |
| 306 void ChromeExtensionsRendererClient::RunScriptsAtDocumentEnd( | 379 void ChromeExtensionsRendererClient::RunScriptsAtDocumentEnd( |
| 307 content::RenderFrame* render_frame) { | 380 content::RenderFrame* render_frame) { |
| 308 extension_dispatcher_->RunScriptsAtDocumentEnd(render_frame); | 381 extension_dispatcher_->RunScriptsAtDocumentEnd(render_frame); |
| 309 } | 382 } |
| 310 | 383 |
| 311 void ChromeExtensionsRendererClient::RunScriptsAtDocumentIdle( | 384 void ChromeExtensionsRendererClient::RunScriptsAtDocumentIdle( |
| 312 content::RenderFrame* render_frame) { | 385 content::RenderFrame* render_frame) { |
| 313 extension_dispatcher_->RunScriptsAtDocumentIdle(render_frame); | 386 extension_dispatcher_->RunScriptsAtDocumentIdle(render_frame); |
| 314 } | 387 } |
| OLD | NEW |