| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "content/browser/frame_host/render_frame_host_manager.h" | 5 #include "content/browser/frame_host/render_frame_host_manager.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <utility> | 10 #include <utility> |
| 11 | 11 |
| 12 #include "base/command_line.h" | 12 #include "base/command_line.h" |
| 13 #include "base/debug/crash_logging.h" | 13 #include "base/debug/crash_logging.h" |
| 14 #include "base/debug/dump_without_crashing.h" | 14 #include "base/debug/dump_without_crashing.h" |
| 15 #include "base/logging.h" | 15 #include "base/logging.h" |
| 16 #include "base/memory/ptr_util.h" | 16 #include "base/memory/ptr_util.h" |
| 17 #include "base/stl_util.h" | 17 #include "base/stl_util.h" |
| 18 #include "base/trace_event/trace_event.h" | 18 #include "base/trace_event/trace_event.h" |
| 19 #include "content/browser/child_process_security_policy_impl.h" | 19 #include "content/browser/child_process_security_policy_impl.h" |
| 20 #include "content/browser/devtools/render_frame_devtools_agent_host.h" | 20 #include "content/browser/devtools/render_frame_devtools_agent_host.h" |
| 21 #include "content/browser/frame_host/cross_site_transferring_request.h" |
| 21 #include "content/browser/frame_host/debug_urls.h" | 22 #include "content/browser/frame_host/debug_urls.h" |
| 22 #include "content/browser/frame_host/frame_navigation_entry.h" | 23 #include "content/browser/frame_host/frame_navigation_entry.h" |
| 23 #include "content/browser/frame_host/interstitial_page_impl.h" | 24 #include "content/browser/frame_host/interstitial_page_impl.h" |
| 24 #include "content/browser/frame_host/navigation_controller_impl.h" | 25 #include "content/browser/frame_host/navigation_controller_impl.h" |
| 25 #include "content/browser/frame_host/navigation_entry_impl.h" | 26 #include "content/browser/frame_host/navigation_entry_impl.h" |
| 26 #include "content/browser/frame_host/navigation_handle_impl.h" | 27 #include "content/browser/frame_host/navigation_handle_impl.h" |
| 27 #include "content/browser/frame_host/navigation_request.h" | 28 #include "content/browser/frame_host/navigation_request.h" |
| 28 #include "content/browser/frame_host/navigator.h" | 29 #include "content/browser/frame_host/navigator.h" |
| 29 #include "content/browser/frame_host/render_frame_host_factory.h" | 30 #include "content/browser/frame_host/render_frame_host_factory.h" |
| 30 #include "content/browser/frame_host/render_frame_host_impl.h" | 31 #include "content/browser/frame_host/render_frame_host_impl.h" |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 272 // RenderFrameHostManager are completely initialized. This should be | 273 // RenderFrameHostManager are completely initialized. This should be |
| 273 // removed once the process manager moves away from NotificationService. | 274 // removed once the process manager moves away from NotificationService. |
| 274 // See https://crbug.com/462682. | 275 // See https://crbug.com/462682. |
| 275 delegate_->NotifyMainFrameSwappedFromRenderManager( | 276 delegate_->NotifyMainFrameSwappedFromRenderManager( |
| 276 nullptr, render_frame_host_->render_view_host()); | 277 nullptr, render_frame_host_->render_view_host()); |
| 277 } | 278 } |
| 278 } | 279 } |
| 279 | 280 |
| 280 // If entry includes the request ID of a request that is being transferred, | 281 // If entry includes the request ID of a request that is being transferred, |
| 281 // the destination render frame will take ownership, so release ownership of | 282 // the destination render frame will take ownership, so release ownership of |
| 282 // the transferring NavigationHandle. | 283 // the request. |
| 283 if (transfer_navigation_handle_.get() && | 284 if (cross_site_transferring_request_.get() && |
| 284 transfer_navigation_handle_->request_id() == | 285 cross_site_transferring_request_->request_id() == |
| 285 entry.transferred_global_request_id()) { | 286 entry.transferred_global_request_id()) { |
| 287 cross_site_transferring_request_->ReleaseRequest(); |
| 288 |
| 289 DCHECK(transfer_navigation_handle_); |
| 290 |
| 291 // Update the pending NavigationEntry ID on the transferring handle. |
| 292 // TODO(creis): Make this line unnecessary by avoiding having a pending |
| 293 // entry for transfer navigations. See https://crbug.com/495161. |
| 294 transfer_navigation_handle_->update_entry_id_for_transfer( |
| 295 entry.GetUniqueID()); |
| 296 |
| 286 // The navigating RenderFrameHost should take ownership of the | 297 // The navigating RenderFrameHost should take ownership of the |
| 287 // NavigationHandle that came from the transferring RenderFrameHost. | 298 // NavigationHandle that came from the transferring RenderFrameHost. |
| 288 dest_render_frame_host->SetNavigationHandle( | 299 dest_render_frame_host->SetNavigationHandle( |
| 289 std::move(transfer_navigation_handle_)); | 300 std::move(transfer_navigation_handle_)); |
| 290 | |
| 291 dest_render_frame_host->navigation_handle()->set_render_frame_host( | |
| 292 dest_render_frame_host); | |
| 293 } | 301 } |
| 302 DCHECK(!transfer_navigation_handle_); |
| 294 | 303 |
| 295 return dest_render_frame_host; | 304 return dest_render_frame_host; |
| 296 } | 305 } |
| 297 | 306 |
| 298 void RenderFrameHostManager::Stop() { | 307 void RenderFrameHostManager::Stop() { |
| 299 render_frame_host_->Stop(); | 308 render_frame_host_->Stop(); |
| 300 | 309 |
| 301 // If a cross-process navigation is happening, the pending RenderFrameHost | 310 // If a cross-process navigation is happening, the pending RenderFrameHost |
| 302 // should stop. This will lead to a DidFailProvisionalLoad, which will | 311 // should stop. This will lead to a DidFailProvisionalLoad, which will |
| 303 // properly destroy it. | 312 // properly destroy it. |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 405 | 414 |
| 406 // This is not a cross-process navigation; the tab is being closed. | 415 // This is not a cross-process navigation; the tab is being closed. |
| 407 render_frame_host_->render_view_host()->ClosePage(); | 416 render_frame_host_->render_view_host()->ClosePage(); |
| 408 } | 417 } |
| 409 } | 418 } |
| 410 } | 419 } |
| 411 | 420 |
| 412 void RenderFrameHostManager::OnCrossSiteResponse( | 421 void RenderFrameHostManager::OnCrossSiteResponse( |
| 413 RenderFrameHostImpl* transferring_render_frame_host, | 422 RenderFrameHostImpl* transferring_render_frame_host, |
| 414 const GlobalRequestID& global_request_id, | 423 const GlobalRequestID& global_request_id, |
| 424 std::unique_ptr<CrossSiteTransferringRequest> |
| 425 cross_site_transferring_request, |
| 415 const std::vector<GURL>& transfer_url_chain, | 426 const std::vector<GURL>& transfer_url_chain, |
| 416 const Referrer& referrer, | 427 const Referrer& referrer, |
| 417 ui::PageTransition page_transition, | 428 ui::PageTransition page_transition, |
| 418 bool should_replace_current_entry) { | 429 bool should_replace_current_entry) { |
| 430 // We should only get here for transfer navigations. Most cross-process |
| 431 // navigations can just continue and wait to run the unload handler (by |
| 432 // swapping out) when the new navigation commits. |
| 433 CHECK(cross_site_transferring_request); |
| 434 |
| 419 // A transfer should only have come from our pending or current RFH. If it | 435 // A transfer should only have come from our pending or current RFH. If it |
| 420 // started as a cross-process navigation via OpenURL, this is the pending | 436 // started as a cross-process navigation via OpenURL, this is the pending |
| 421 // one. If it wasn't cross-process until the transfer, this is the current | 437 // one. If it wasn't cross-process until the transfer, this is the current |
| 422 // one. | 438 // one. |
| 423 // | 439 // |
| 424 // Note that having a pending RFH does not imply that it was the one that | 440 // Note that having a pending RFH does not imply that it was the one that |
| 425 // made the request. Suppose that during a pending cross-site navigation, | 441 // made the request. Suppose that during a pending cross-site navigation, |
| 426 // the frame performs a different same-site navigation which redirects | 442 // the frame performs a different same-site navigation which redirects |
| 427 // cross-site. In this case, there will be a pending RFH, but this request | 443 // cross-site. In this case, there will be a pending RFH, but this request |
| 428 // is made by the current RFH. Later, this will create a new pending RFH and | 444 // is made by the current RFH. Later, this will create a new pending RFH and |
| 429 // clean up the old one. | 445 // clean up the old one. |
| 430 // | 446 // |
| 431 // TODO(creis): We need to handle the case that the pending RFH has changed | 447 // TODO(creis): We need to handle the case that the pending RFH has changed |
| 432 // in the mean time, while this was being posted from the IO thread. We | 448 // in the mean time, while this was being posted from the IO thread. We |
| 433 // should probably cancel the request in that case. | 449 // should probably cancel the request in that case. |
| 434 DCHECK(transferring_render_frame_host == pending_render_frame_host_.get() || | 450 DCHECK(transferring_render_frame_host == pending_render_frame_host_.get() || |
| 435 transferring_render_frame_host == render_frame_host_.get()); | 451 transferring_render_frame_host == render_frame_host_.get()); |
| 436 | 452 |
| 437 // Check if the FrameTreeNode is loading. This will be used later to notify | 453 // Check if the FrameTreeNode is loading. This will be used later to notify |
| 438 // the FrameTreeNode that the load stop if the transfer fails. | 454 // the FrameTreeNode that the load stop if the transfer fails. |
| 439 bool frame_tree_node_was_loading = frame_tree_node_->IsLoading(); | 455 bool frame_tree_node_was_loading = frame_tree_node_->IsLoading(); |
| 440 | 456 |
| 441 // Store the NavigationHandle to give it to the appropriate RenderFrameHost | 457 // Store the NavigationHandle to give it to the appropriate RenderFrameHost |
| 442 // after it started navigating. | 458 // after it started navigating. |
| 443 transfer_navigation_handle_ = | 459 transfer_navigation_handle_ = |
| 444 transferring_render_frame_host->PassNavigationHandleOwnership(); | 460 transferring_render_frame_host->PassNavigationHandleOwnership(); |
| 445 CHECK(transfer_navigation_handle_); | 461 |
| 462 // If something caused the cancellation of this navigation on the UI thread |
| 463 // (possibly for security reasons) the navigation should not be allowed to |
| 464 // proceed. |
| 465 if (!transfer_navigation_handle_) |
| 466 return; |
| 467 |
| 468 // Store the transferring request so that we can release it if the transfer |
| 469 // navigation matches. |
| 470 cross_site_transferring_request_ = std::move(cross_site_transferring_request); |
| 446 | 471 |
| 447 // Set the transferring RenderFrameHost as not loading, so that it does not | 472 // Set the transferring RenderFrameHost as not loading, so that it does not |
| 448 // emit a DidStopLoading notification if it is destroyed when creating the | 473 // emit a DidStopLoading notification if it is destroyed when creating the |
| 449 // new navigating RenderFrameHost. | 474 // new navigating RenderFrameHost. |
| 450 transferring_render_frame_host->set_is_loading(false); | 475 transferring_render_frame_host->set_is_loading(false); |
| 451 | 476 |
| 452 // Treat the last URL in the chain as the destination and the remainder as | 477 // Treat the last URL in the chain as the destination and the remainder as |
| 453 // the redirect chain. | 478 // the redirect chain. |
| 454 CHECK(transfer_url_chain.size()); | 479 CHECK(transfer_url_chain.size()); |
| 455 GURL transfer_url = transfer_url_chain.back(); | 480 GURL transfer_url = transfer_url_chain.back(); |
| 456 std::vector<GURL> rest_of_chain = transfer_url_chain; | 481 std::vector<GURL> rest_of_chain = transfer_url_chain; |
| 457 rest_of_chain.pop_back(); | 482 rest_of_chain.pop_back(); |
| 458 | 483 |
| 459 transferring_render_frame_host->frame_tree_node() | 484 transferring_render_frame_host->frame_tree_node() |
| 460 ->navigator() | 485 ->navigator() |
| 461 ->RequestTransferURL( | 486 ->RequestTransferURL( |
| 462 transferring_render_frame_host, transfer_url, nullptr, rest_of_chain, | 487 transferring_render_frame_host, transfer_url, nullptr, rest_of_chain, |
| 463 referrer, page_transition, global_request_id, | 488 referrer, page_transition, global_request_id, |
| 464 should_replace_current_entry, | 489 should_replace_current_entry, |
| 465 transfer_navigation_handle_->IsPost() ? "POST" : "GET", | 490 transfer_navigation_handle_->IsPost() ? "POST" : "GET", |
| 466 transfer_navigation_handle_->resource_request_body()); | 491 transfer_navigation_handle_->resource_request_body()); |
| 467 | 492 |
| 493 // The transferring request was only needed during the RequestTransferURL |
| 494 // call, so it is safe to clear at this point. |
| 495 cross_site_transferring_request_.reset(); |
| 496 |
| 468 // If the navigation continued, the NavigationHandle should have been | 497 // If the navigation continued, the NavigationHandle should have been |
| 469 // transfered to a RenderFrameHost. In the other cases, it should be cleared. | 498 // transfered to a RenderFrameHost. In the other cases, it should be cleared. |
| 470 // If the NavigationHandle wasn't claimed, this will lead to the cancelation | |
| 471 // of the request in the network stack. | |
| 472 transfer_navigation_handle_.reset(); | 499 transfer_navigation_handle_.reset(); |
| 473 | 500 |
| 474 // If the navigation in the new renderer did not start, inform the | 501 // If the navigation in the new renderer did not start, inform the |
| 475 // FrameTreeNode that it stopped loading. | 502 // FrameTreeNode that it stopped loading. |
| 476 if (!frame_tree_node_->IsLoading() && frame_tree_node_was_loading) | 503 if (!frame_tree_node_->IsLoading() && frame_tree_node_was_loading) |
| 477 frame_tree_node_->DidStopLoading(); | 504 frame_tree_node_->DidStopLoading(); |
| 478 } | 505 } |
| 479 | 506 |
| 480 void RenderFrameHostManager::DidNavigateFrame( | 507 void RenderFrameHostManager::DidNavigateFrame( |
| 481 RenderFrameHostImpl* render_frame_host, | 508 RenderFrameHostImpl* render_frame_host, |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 625 return; | 652 return; |
| 626 | 653 |
| 627 // Create a replacement proxy for the old RenderFrameHost. (There should not | 654 // Create a replacement proxy for the old RenderFrameHost. (There should not |
| 628 // be one yet.) This is done even if there are no active frames besides this | 655 // be one yet.) This is done even if there are no active frames besides this |
| 629 // one to simplify cleanup logic on the renderer side (see | 656 // one to simplify cleanup logic on the renderer side (see |
| 630 // https://crbug.com/568836 for motivation). | 657 // https://crbug.com/568836 for motivation). |
| 631 RenderFrameProxyHost* proxy = | 658 RenderFrameProxyHost* proxy = |
| 632 CreateRenderFrameProxyHost(old_render_frame_host->GetSiteInstance(), | 659 CreateRenderFrameProxyHost(old_render_frame_host->GetSiteInstance(), |
| 633 old_render_frame_host->render_view_host()); | 660 old_render_frame_host->render_view_host()); |
| 634 | 661 |
| 635 // Reset any NavigationHandle in the RenderFrameHost. This will prevent any | |
| 636 // ongoing navigation from attempting to transfer. | |
| 637 old_render_frame_host->SetNavigationHandle(nullptr); | |
| 638 | |
| 639 // Tell the old RenderFrameHost to swap out and be replaced by the proxy. | 662 // Tell the old RenderFrameHost to swap out and be replaced by the proxy. |
| 640 old_render_frame_host->SwapOut(proxy, true); | 663 old_render_frame_host->SwapOut(proxy, true); |
| 641 | 664 |
| 642 // SwapOut creates a RenderFrameProxy, so set the proxy to be initialized. | 665 // SwapOut creates a RenderFrameProxy, so set the proxy to be initialized. |
| 643 proxy->set_render_frame_proxy_created(true); | 666 proxy->set_render_frame_proxy_created(true); |
| 644 | 667 |
| 645 // |old_render_frame_host| will be deleted when its SwapOut ACK is received, | 668 // |old_render_frame_host| will be deleted when its SwapOut ACK is received, |
| 646 // or when the timer times out, or when the RFHM itself is deleted (whichever | 669 // or when the timer times out, or when the RFHM itself is deleted (whichever |
| 647 // comes first). | 670 // comes first). |
| 648 pending_delete_hosts_.push_back(std::move(old_render_frame_host)); | 671 pending_delete_hosts_.push_back(std::move(old_render_frame_host)); |
| (...skipping 1564 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2213 // Note: Do not add code here to determine whether the subframe should swap | 2236 // Note: Do not add code here to determine whether the subframe should swap |
| 2214 // or not. Add it to CanSubframeSwapProcess instead. | 2237 // or not. Add it to CanSubframeSwapProcess instead. |
| 2215 return render_frame_host_.get(); | 2238 return render_frame_host_.get(); |
| 2216 } | 2239 } |
| 2217 | 2240 |
| 2218 SiteInstance* current_instance = render_frame_host_->GetSiteInstance(); | 2241 SiteInstance* current_instance = render_frame_host_->GetSiteInstance(); |
| 2219 scoped_refptr<SiteInstance> new_instance = GetSiteInstanceForNavigation( | 2242 scoped_refptr<SiteInstance> new_instance = GetSiteInstanceForNavigation( |
| 2220 dest_url, source_instance, dest_instance, nullptr, transition, | 2243 dest_url, source_instance, dest_instance, nullptr, transition, |
| 2221 dest_is_restore, dest_is_view_source_mode); | 2244 dest_is_restore, dest_is_view_source_mode); |
| 2222 | 2245 |
| 2223 // Inform the transferring NavigationHandle of a transfer to a different | |
| 2224 // SiteInstance. It is important do so now, in order to mark the request as | |
| 2225 // transferring on the IO thread before attempting to destroy the pending RFH. | |
| 2226 // This ensures the network request will not be destroyed along the pending | |
| 2227 // RFH but will persist until it is picked up by the new RFH. | |
| 2228 if (transfer_navigation_handle_.get() && | |
| 2229 transfer_navigation_handle_->request_id() == transferred_request_id && | |
| 2230 new_instance.get() != | |
| 2231 transfer_navigation_handle_->GetRenderFrameHost() | |
| 2232 ->GetSiteInstance()) { | |
| 2233 transfer_navigation_handle_->Transfer(); | |
| 2234 } | |
| 2235 | |
| 2236 // If we are currently navigating cross-process to a pending RFH for a | 2246 // If we are currently navigating cross-process to a pending RFH for a |
| 2237 // different SiteInstance, we want to get back to normal and then navigate as | 2247 // different SiteInstance, we want to get back to normal and then navigate as |
| 2238 // usual. We will reuse the pending RFH below if it matches the destination | 2248 // usual. We will reuse the pending RFH below if it matches the destination |
| 2239 // SiteInstance. | 2249 // SiteInstance. |
| 2240 if (pending_render_frame_host_) { | 2250 if (pending_render_frame_host_) { |
| 2241 if (pending_render_frame_host_->GetSiteInstance() != new_instance) { | 2251 if (pending_render_frame_host_->GetSiteInstance() != new_instance) { |
| 2242 CancelPending(); | 2252 CancelPending(); |
| 2243 } else { | 2253 } else { |
| 2244 // When a pending RFH is reused, it should always be live, since it is | 2254 // When a pending RFH is reused, it should always be live, since it is |
| 2245 // cleared whenever a process dies. | 2255 // cleared whenever a process dies. |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2285 // RFH isn't live.) | 2295 // RFH isn't live.) |
| 2286 CommitPending(); | 2296 CommitPending(); |
| 2287 return render_frame_host_.get(); | 2297 return render_frame_host_.get(); |
| 2288 } | 2298 } |
| 2289 // Otherwise, it's safe to treat this as a pending cross-process transition. | 2299 // Otherwise, it's safe to treat this as a pending cross-process transition. |
| 2290 | 2300 |
| 2291 bool is_transfer = transferred_request_id != GlobalRequestID(); | 2301 bool is_transfer = transferred_request_id != GlobalRequestID(); |
| 2292 if (is_transfer) { | 2302 if (is_transfer) { |
| 2293 // We don't need to stop the old renderer or run beforeunload/unload | 2303 // We don't need to stop the old renderer or run beforeunload/unload |
| 2294 // handlers, because those have already been done. | 2304 // handlers, because those have already been done. |
| 2295 DCHECK(transfer_navigation_handle_ && | 2305 DCHECK(cross_site_transferring_request_->request_id() == |
| 2296 transfer_navigation_handle_->request_id() == | 2306 transferred_request_id); |
| 2297 transferred_request_id); | |
| 2298 } else if (!pending_render_frame_host_->are_navigations_suspended()) { | 2307 } else if (!pending_render_frame_host_->are_navigations_suspended()) { |
| 2299 // If the pending RFH hasn't already been suspended from a previous | 2308 // If the pending RFH hasn't already been suspended from a previous |
| 2300 // attempt to navigate it, then we need to wait for the beforeunload | 2309 // attempt to navigate it, then we need to wait for the beforeunload |
| 2301 // handler to run. Suspend navigations in the pending RFH until we hear | 2310 // handler to run. Suspend navigations in the pending RFH until we hear |
| 2302 // back from the old RFH's beforeunload handler (via OnBeforeUnloadACK or | 2311 // back from the old RFH's beforeunload handler (via OnBeforeUnloadACK or |
| 2303 // a timeout). If the handler returns false, we'll have to cancel the | 2312 // a timeout). If the handler returns false, we'll have to cancel the |
| 2304 // request. | 2313 // request. |
| 2305 // | 2314 // |
| 2306 // Also make sure the old RenderFrame stops, in case a load is in | 2315 // Also make sure the old RenderFrame stops, in case a load is in |
| 2307 // progress. (We don't want to do this for transfers, since it will | 2316 // progress. (We don't want to do this for transfers, since it will |
| (...skipping 364 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2672 resolved_url)) { | 2681 resolved_url)) { |
| 2673 DCHECK(!dest_instance || | 2682 DCHECK(!dest_instance || |
| 2674 dest_instance == render_frame_host_->GetSiteInstance()); | 2683 dest_instance == render_frame_host_->GetSiteInstance()); |
| 2675 return false; | 2684 return false; |
| 2676 } | 2685 } |
| 2677 | 2686 |
| 2678 return true; | 2687 return true; |
| 2679 } | 2688 } |
| 2680 | 2689 |
| 2681 } // namespace content | 2690 } // namespace content |
| OLD | NEW |