| 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 beb742447a27e46ce7ed905f6cd4b0850d35bfc4..824063f5578537866e17c5e92f9baa0695283deb 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"
|
| @@ -16,7 +17,9 @@
|
| #include "content/browser/service_worker/service_worker_navigation_handle.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 "content/public/common/url_constants.h"
|
| @@ -70,14 +73,20 @@ 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());
|
| + redirect_chain_.push_back(url);
|
| GetDelegate()->DidStartNavigation(this);
|
|
|
| if (IsInMainFrame()) {
|
| @@ -235,10 +244,14 @@ void NavigationHandleImpl::Resume() {
|
| } else {
|
| 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_);
|
| + // If the navigation is about to proceed after having been deferred while
|
| + // processing the response, then it's ready to commit. Determine which
|
| + // RenderFrameHost should render the response, based on its site (after any
|
| + // redirects).
|
| + // Note: if MaybeTransferAndProceed returns false, this means that this
|
| + // NavigationHandle was deleted, so return immediately.
|
| + if (result == NavigationThrottle::PROCEED && !MaybeTransferAndProceed())
|
| + return;
|
| }
|
|
|
| if (result != NavigationThrottle::DEFER)
|
| @@ -313,7 +326,8 @@ NavigationHandleImpl::CallWillProcessResponseForTesting(
|
| new net::HttpResponseHeaders(raw_response_headers);
|
| NavigationThrottle::ThrottleCheckResult result = NavigationThrottle::DEFER;
|
| WillProcessResponse(static_cast<RenderFrameHostImpl*>(render_frame_host),
|
| - headers, SSLStatus(),
|
| + headers, SSLStatus(), GlobalRequestID(), false, false,
|
| + false, base::Closure(),
|
| base::Bind(&UpdateThrottleCheckResult, &result));
|
|
|
| // Reset the callback to ensure it will not be called later.
|
| @@ -406,6 +420,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;
|
|
|
| @@ -424,20 +439,34 @@ 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 done processing the response, then it's ready to
|
| + // commit. Determine which RenderFrameHost should render the response, based
|
| + // on its site (after any redirects).
|
| + // Note: if MaybeTransferAndProceed returns false, this means that this
|
| + // NavigationHandle was deleted, so return immediately.
|
| + if (result == NavigationThrottle::PROCEED && !MaybeTransferAndProceed())
|
| + return;
|
|
|
| // If the navigation is not deferred, run the callback.
|
| if (result != NavigationThrottle::DEFER)
|
| @@ -450,10 +479,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(
|
| @@ -480,6 +506,17 @@ void NavigationHandleImpl::DidCommitNavigation(
|
| }
|
| }
|
|
|
| +void NavigationHandleImpl::Transfer() {
|
| + DCHECK(!IsBrowserSideNavigationEnabled());
|
| + // This is an actual transfer. Inform the NavigationResourceThrottle. This
|
| + // will allow to mark the URLRequest as transferring. When it is marked as
|
| + // transferring, the URLRequest can no longer be cancelled by its original
|
| + // RenderFrame. Instead it will persist until being picked up by the transfer
|
| + // RenderFrame, even if the original RenderFrame is destroyed.
|
| + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, transfer_callback_);
|
| + transfer_callback_.Reset();
|
| +}
|
| +
|
| NavigationThrottle::ThrottleCheckResult
|
| NavigationHandleImpl::CheckWillStartRequest() {
|
| DCHECK(state_ == WILL_SEND_REQUEST || state_ == DEFERRING_START);
|
| @@ -576,6 +613,84 @@ NavigationHandleImpl::CheckWillProcessResponse() {
|
| return NavigationThrottle::PROCEED;
|
| }
|
|
|
| +bool NavigationHandleImpl::MaybeTransferAndProceed() {
|
| + 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 (!MaybeTransferAndProceedInternal())
|
| + 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::MaybeTransferAndProceedInternal() {
|
| + DCHECK(render_frame_host_);
|
| +
|
| + // PlzNavigate: the final RenderFrameHost handling this navigation has been
|
| + // decided before calling WillProcessResponse in
|
| + // NavigationRequest::OnResponseStarted.
|
| + // TODO(clamy): See if PlzNavigate could use this code to check whether to
|
| + // use the RFH determined at the start of the navigation or to switch to
|
| + // another one.
|
| + 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);
|
|
|