Index: content/browser/frame_host/navigation_handle_impl.cc |
diff --git a/content/browser/frame_host/navigation_handle_impl.cc b/content/browser/frame_host/navigation_handle_impl.cc |
index bb59cb07a25bbb960e2cd5965a3b2cc73a0f9460..e2836bfe7adc72cafae4439ba9559c8f29a2890e 100644 |
--- a/content/browser/frame_host/navigation_handle_impl.cc |
+++ b/content/browser/frame_host/navigation_handle_impl.cc |
@@ -8,6 +8,7 @@ |
#include "base/logging.h" |
#include "content/browser/browsing_data/clear_site_data_throttle.h" |
+#include "content/browser/child_process_security_policy_impl.h" |
#include "content/browser/devtools/render_frame_devtools_agent_host.h" |
#include "content/browser/frame_host/frame_tree_node.h" |
#include "content/browser/frame_host/navigator.h" |
@@ -15,7 +16,9 @@ |
#include "content/browser/service_worker/service_worker_context_wrapper.h" |
#include "content/common/frame_messages.h" |
#include "content/common/resource_request_body_impl.h" |
+#include "content/common/site_isolation_policy.h" |
#include "content/public/browser/content_browser_client.h" |
+#include "content/public/browser/site_instance.h" |
#include "content/public/common/browser_side_navigation_policy.h" |
#include "content/public/common/content_client.h" |
#include "net/url_request/redirect_info.h" |
@@ -68,15 +71,21 @@ NavigationHandleImpl::NavigationHandleImpl( |
is_synchronous_(is_synchronous), |
is_srcdoc_(is_srcdoc), |
was_redirected_(false), |
+ original_url_(url), |
state_(INITIAL), |
is_transferring_(false), |
frame_tree_node_(frame_tree_node), |
next_index_(0), |
navigation_start_(navigation_start), |
pending_nav_entry_id_(pending_nav_entry_id), |
- request_context_type_(REQUEST_CONTEXT_TYPE_UNSPECIFIED) { |
+ request_context_type_(REQUEST_CONTEXT_TYPE_UNSPECIFIED), |
+ should_replace_current_entry_(false), |
+ is_download_(false), |
+ is_stream_(false), |
+ weak_factory_(this) { |
DCHECK(!navigation_start.is_null()); |
GetDelegate()->DidStartNavigation(this); |
+ redirect_chain_.push_back(url); |
Charlie Reis
2016/09/16 21:19:25
Why is this after the DidStartNavigation call? I
clamy
2016/09/20 15:57:22
Done.
|
if (IsInMainFrame()) { |
TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP1( |
@@ -234,9 +243,11 @@ void NavigationHandleImpl::Resume() { |
result = CheckWillProcessResponse(); |
// If the navigation is about to proceed after processing the response, then |
- // it's ready to commit. |
- if (result == NavigationThrottle::PROCEED) |
- ReadyToCommitNavigation(render_frame_host_); |
+ // it's ready to commit. Determine the final RenderFrameHost handling it. |
Charlie Reis
2016/09/16 21:19:25
nit: Change last sentence to: Determine which Rend
clamy
2016/09/20 15:57:22
Done.
|
+ // Note: if FindFinalRenderFrameHost() returns false, this means that this |
+ // NavigationHandle was deleted, so return immediately. |
+ if (result == NavigationThrottle::PROCEED && !FindFinalRenderFrameHost()) |
+ return; |
} |
if (result != NavigationThrottle::DEFER) |
@@ -309,6 +320,7 @@ NavigationHandleImpl::CallWillProcessResponseForTesting( |
NavigationThrottle::ThrottleCheckResult result = NavigationThrottle::DEFER; |
WillProcessResponse(static_cast<RenderFrameHostImpl*>(render_frame_host), |
scoped_refptr<net::HttpResponseHeaders>(), SSLStatus(), |
+ GlobalRequestID(), false, false, false, base::Closure(), |
base::Bind(&UpdateThrottleCheckResult, &result)); |
// Reset the callback to ensure it will not be called later. |
@@ -372,6 +384,7 @@ void NavigationHandleImpl::WillRedirectRequest( |
is_external_protocol_ = new_is_external_protocol; |
response_headers_ = response_headers; |
was_redirected_ = true; |
+ redirect_chain_.push_back(new_url); |
if (new_method != "POST") |
resource_request_body_ = nullptr; |
@@ -390,20 +403,33 @@ void NavigationHandleImpl::WillProcessResponse( |
RenderFrameHostImpl* render_frame_host, |
scoped_refptr<net::HttpResponseHeaders> response_headers, |
const SSLStatus& ssl_status, |
+ const GlobalRequestID& request_id, |
+ bool should_replace_current_entry, |
+ bool is_download, |
+ bool is_stream, |
+ const base::Closure& transfer_callback, |
const ThrottleChecksFinishedCallback& callback) { |
DCHECK(!render_frame_host_ || render_frame_host_ == render_frame_host); |
render_frame_host_ = render_frame_host; |
response_headers_ = response_headers; |
+ request_id_ = request_id; |
+ should_replace_current_entry_ = should_replace_current_entry; |
+ is_download_ = is_download; |
+ is_stream_ = is_stream; |
state_ = WILL_PROCESS_RESPONSE; |
ssl_status_ = ssl_status; |
complete_callback_ = callback; |
+ transfer_callback_ = transfer_callback; |
// Notify each throttle of the response. |
NavigationThrottle::ThrottleCheckResult result = CheckWillProcessResponse(); |
- // If the navigation is about to proceed, then it's ready to commit. |
- if (result == NavigationThrottle::PROCEED) |
- ReadyToCommitNavigation(render_frame_host); |
+ // If the navigation is about to proceed, check for the final RenderFrameHost |
+ // for the navigation. |
Charlie Reis
2016/09/16 21:19:25
Let's use the same comment as in Resume().
Why do
clamy
2016/09/20 15:57:22
Done. I've slightly modified the first part of the
|
+ // Note: if FindFinalRenderFrameHost() returns false, this means that this |
+ // NavigationHandle was deleted, so return immediately. |
+ if (result == NavigationThrottle::PROCEED && !FindFinalRenderFrameHost()) |
+ return; |
// If the navigation is not deferred, run the callback. |
if (result != NavigationThrottle::DEFER) |
@@ -416,10 +442,7 @@ void NavigationHandleImpl::ReadyToCommitNavigation( |
render_frame_host_ = render_frame_host; |
state_ = READY_TO_COMMIT; |
- // Only notify the WebContentsObservers when PlzNavigate is enabled, as |
- // |render_frame_host_| may be wrong in the case of transfer navigations. |
- if (IsBrowserSideNavigationEnabled()) |
- GetDelegate()->ReadyToCommitNavigation(this); |
+ GetDelegate()->ReadyToCommitNavigation(this); |
} |
void NavigationHandleImpl::DidCommitNavigation( |
@@ -439,6 +462,21 @@ void NavigationHandleImpl::DidCommitNavigation( |
state_ = net_error_code_ == net::OK ? DID_COMMIT : DID_COMMIT_ERROR_PAGE; |
} |
+void NavigationHandleImpl::TransferToSiteInstance(SiteInstance* site_instance) { |
+ DCHECK(!IsBrowserSideNavigationEnabled()); |
+ if (site_instance->GetId() != |
+ render_frame_host_->GetSiteInstance()->GetId()) { |
Charlie Reis
2016/09/16 21:19:26
It's a bit unexpected to call this method if no tr
clamy
2016/09/20 15:57:21
Done.
|
+ // This is an actual transfer. Inform the NavigationResourceThrottle. |
Charlie Reis
2016/09/16 21:19:25
Please elaborate on why the IO thread needs to kno
clamy
2016/09/20 15:57:21
I have elaborated in the comments.
|
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, transfer_callback_); |
+ transfer_callback_.Reset(); |
+ } |
+} |
+ |
+void NavigationHandleImpl::TransferToRenderFrameHost( |
Charlie Reis
2016/09/16 21:19:26
This is very different from TransferToSiteInstance
clamy
2016/09/20 15:57:21
Done.
|
+ RenderFrameHostImpl* render_frame_host) { |
+ render_frame_host_ = render_frame_host; |
+} |
+ |
NavigationThrottle::ThrottleCheckResult |
NavigationHandleImpl::CheckWillStartRequest() { |
DCHECK(state_ == WILL_SEND_REQUEST || state_ == DEFERRING_START); |
@@ -535,6 +573,79 @@ NavigationHandleImpl::CheckWillProcessResponse() { |
return NavigationThrottle::PROCEED; |
} |
+bool NavigationHandleImpl::FindFinalRenderFrameHost() { |
Charlie Reis
2016/09/16 21:19:25
This method feels misnamed, because it doesn't do
clamy
2016/09/20 15:57:22
Done.
|
+ DCHECK_EQ(WILL_PROCESS_RESPONSE, state_); |
+ |
+ // Check if the navigation should transfer. This may result in the |
+ // destruction of this NavigationHandle, and the cancellation of the request. |
+ if (!MaybeTransferAndProceed()) |
+ return false; |
+ |
+ // Inform observers that the navigation is now ready to commit, unless a |
+ // transfer of the navigation failed. |
+ ReadyToCommitNavigation(render_frame_host_); |
+ return true; |
+} |
+ |
+bool NavigationHandleImpl::MaybeTransferAndProceed() { |
+ DCHECK(render_frame_host_); |
+ // PlzNavigate: the final RenderFrameHost handling this navigation has been |
+ // decided before calling WillProcessResponse. |
Charlie Reis
2016/09/16 21:19:26
Where does this happen? It would have been nice t
clamy
2016/09/20 15:57:22
We already had code written to chose a RFH to comm
Charlie Reis
2016/09/21 03:31:47
Yes, no need to move PlzNavigate code in this CL.
|
+ if (IsBrowserSideNavigationEnabled()) |
+ return true; |
+ |
+ // Subframes shouldn't swap processes unless out-of-process iframes are |
+ // possible. |
+ if (!IsInMainFrame() && !SiteIsolationPolicy::AreCrossProcessFramesPossible()) |
+ return true; |
+ |
+ // If this is a download, do not do a cross-site check. The renderer will |
+ // see it is a download and abort the request. |
+ // |
+ // Similarly, HTTP 204 (No Content) responses leave the renderer showing the |
+ // previous page. The navigation should be allowed to finish without running |
+ // the unload handler or swapping in the pending RenderFrameHost. |
+ if (is_download_ || is_stream_ || |
+ (response_headers_.get() && response_headers_->response_code() == 204)) { |
+ return true; |
+ } |
+ |
+ // The content embedder can decide that a transfer to a different process is |
+ // required for this URL. |
+ bool should_transfer = |
+ GetContentClient()->browser()->ShouldSwapProcessesForRedirect( |
+ frame_tree_node_->navigator()->GetController()->GetBrowserContext(), |
+ original_url_, url_); |
+ |
+ RenderFrameHostManager* manager = |
+ render_frame_host_->frame_tree_node()->render_manager(); |
+ |
+ // In the site-per-process model, the RenderFrameHostManager may also decide |
+ // (independently from the content embedder's ShouldSwapProcessesForRedirect |
+ // above) that a process transfer is needed. Process transfers are skipped for |
+ // WebUI processes for now, since e.g. chrome://settings has multiple |
+ // "cross-site" chrome:// frames, and that doesn't yet work cross- process. |
+ if (SiteIsolationPolicy::AreCrossProcessFramesPossible() && |
+ !ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings( |
+ render_frame_host_->GetProcess()->GetID())) { |
+ should_transfer |= manager->IsRendererTransferNeededForNavigation( |
+ render_frame_host_, url_); |
+ } |
+ |
+ // Start the transfer if needed. |
+ if (should_transfer) { |
+ // This may destroy the NavigationHandle if the transfer fails. |
+ base::WeakPtr<NavigationHandleImpl> weak_self = weak_factory_.GetWeakPtr(); |
+ manager->OnCrossSiteResponse(render_frame_host_, request_id_, |
+ redirect_chain_, sanitized_referrer_, |
+ transition_, should_replace_current_entry_); |
+ if (!weak_self) |
+ return false; |
+ } |
+ |
+ return true; |
+} |
+ |
void NavigationHandleImpl::RunCompleteCallback( |
NavigationThrottle::ThrottleCheckResult result) { |
DCHECK(result != NavigationThrottle::DEFER); |