blob: 192cdab3348d3d9dc0bd3ff51c92aa625f7e1ae7 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_FRAME_HOST_NAVIGATION_HANDLE_IMPL_H_
#define CONTENT_BROWSER_FRAME_HOST_NAVIGATION_HANDLE_IMPL_H_
#include "content/public/browser/navigation_handle.h"
#include <stddef.h>
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "content/browser/frame_host/frame_tree_node.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/common/content_export.h"
#include "content/public/browser/navigation_throttle.h"
#include "url/gurl.h"
namespace content {
class NavigatorDelegate;
class ServiceWorkerContextWrapper;
class ServiceWorkerNavigationHandle;
struct NavigationRequestInfo;
// This class keeps track of a single navigation. It is created upon receipt of
// a DidStartProvisionalLoad IPC in a RenderFrameHost. The RenderFrameHost owns
// the newly created NavigationHandleImpl as long as the navigation is ongoing.
// The NavigationHandleImpl in the RenderFrameHost will be reset when the
// navigation stops, that is if one of the following events happen:
// - The RenderFrameHost receives a DidStartProvisionalLoad IPC for a new
// navigation (see below for special cases where the DidStartProvisionalLoad
// message does not indicate the start of a new navigation).
// - The RenderFrameHost stops loading.
// - The RenderFrameHost receives a DidDropNavigation IPC.
//
// When the navigation encounters an error, the DidStartProvisionalLoad marking
// the start of the load of the error page will not be considered as marking a
// new navigation. It will not reset the NavigationHandleImpl in the
// RenderFrameHost.
//
// If the navigation needs a cross-site transfer, then the NavigationHandleImpl
// will briefly be held by the RenderFrameHostManager, until a suitable
// RenderFrameHost for the navigation has been found. The ownership of the
// NavigationHandleImpl will then be transferred to the new RenderFrameHost.
// The DidStartProvisionalLoad received by the new RenderFrameHost for the
// transferring navigation will not reset the NavigationHandleImpl, as it does
// not mark the start of a new navigation.
//
// PlzNavigate: the NavigationHandleImpl is created just after creating a new
// NavigationRequest. It is then owned by the NavigationRequest until the
// navigation is ready to commit. The NavigationHandleImpl ownership is then
// transferred to the RenderFrameHost in which the navigation will commit.
//
// When PlzNavigate is enabled, the NavigationHandleImpl will never be reset
// following the receipt of a DidStartProvisionalLoad IPC. There are also no
// transferring navigations. The other causes of NavigationHandleImpl reset in
// the RenderFrameHost still apply.
class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle {
public:
// |navigation_start| comes from the DidStartProvisionalLoad IPC, which tracks
// both renderer-initiated and browser-initiated navigation start.
// PlzNavigate: This value always comes from the CommonNavigationParams
// associated with this navigation.
static scoped_ptr<NavigationHandleImpl> Create(
const GURL& url,
FrameTreeNode* frame_tree_node,
const base::TimeTicks& navigation_start);
~NavigationHandleImpl() override;
// NavigationHandle implementation:
const GURL& GetURL() override;
bool IsInMainFrame() override;
const base::TimeTicks& NavigationStart() override;
bool IsPost() override;
const Referrer& GetReferrer() override;
bool HasUserGesture() override;
ui::PageTransition GetPageTransition() override;
bool IsExternalProtocol() override;
net::Error GetNetErrorCode() override;
RenderFrameHostImpl* GetRenderFrameHost() override;
bool IsSamePage() override;
bool HasCommitted() override;
bool IsErrorPage() override;
void Resume() override;
void CancelDeferredNavigation(
NavigationThrottle::ThrottleCheckResult result) override;
void RegisterThrottleForTesting(
scoped_ptr<NavigationThrottle> navigation_throttle) override;
NavigationThrottle::ThrottleCheckResult CallWillStartRequestForTesting(
bool is_post,
const Referrer& sanitized_referrer,
bool has_user_gesture,
ui::PageTransition transition,
bool is_external_protocol) override;
NavigationThrottle::ThrottleCheckResult CallWillRedirectRequestForTesting(
const GURL& new_url,
bool new_method_is_post,
const GURL& new_referrer_url,
bool new_is_external_protocol) override;
NavigatorDelegate* GetDelegate() const;
// Returns the response headers for the request. This can only be accessed
// after a redirect was encountered or after the the navigation is ready to
// commit. It should not be modified, as modifications will not be reflected
// in the network stack.
const net::HttpResponseHeaders* GetResponseHeaders();
void set_net_error_code(net::Error net_error_code) {
net_error_code_ = net_error_code;
}
// Returns whether the navigation is currently being transferred from one
// RenderFrameHost to another. In particular, a DidStartProvisionalLoad IPC
// for the navigation URL, received in the new RenderFrameHost, should not
// indicate the start of a new navigation in that case.
bool is_transferring() const { return is_transferring_; }
void set_is_transferring(bool is_transferring) {
is_transferring_ = is_transferring;
}
// Updates the RenderFrameHost that is about to commit the navigation. This
// is used during transfer navigations.
void set_render_frame_host(RenderFrameHostImpl* render_frame_host) {
render_frame_host_ = render_frame_host;
}
// PlzNavigate
void InitServiceWorkerHandle(
ServiceWorkerContextWrapper* service_worker_context);
ServiceWorkerNavigationHandle* service_worker_handle() const {
return service_worker_handle_.get();
}
typedef base::Callback<void(NavigationThrottle::ThrottleCheckResult)>
ThrottleChecksFinishedCallback;
// Called when the URLRequest will start in the network stack. |callback|
// will be called when all throttle checks have completed. This will allow
// the caller to cancel the navigation or let it proceed.
void WillStartRequest(bool is_post,
const Referrer& sanitized_referrer,
bool has_user_gesture,
ui::PageTransition transition,
bool is_external_protocol,
const ThrottleChecksFinishedCallback& callback);
// Called when the URLRequest will be redirected in the network stack.
// |callback| will be called when all throttles check have completed. This
// will allow the caller to cancel the navigation or let it proceed.
void WillRedirectRequest(
const GURL& new_url,
bool new_method_is_post,
const GURL& new_referrer_url,
bool new_is_external_protocol,
scoped_refptr<net::HttpResponseHeaders> response_headers,
const ThrottleChecksFinishedCallback& callback);
// Returns the FrameTreeNode this navigation is happening in.
FrameTreeNode* frame_tree_node() { return frame_tree_node_; }
// Called when the navigation was redirected. This will update the |url_| and
// inform the delegate.
void DidRedirectNavigation(const GURL& new_url);
// Called when the navigation is ready to be committed in
// |render_frame_host|. This will update the |state_| and inform the
// delegate.
void ReadyToCommitNavigation(
RenderFrameHostImpl* render_frame_host,
scoped_refptr<net::HttpResponseHeaders> response_headers);
// Called when the navigation was committed in |render_frame_host|. This will
// update the |state_|.
void DidCommitNavigation(bool same_page,
RenderFrameHostImpl* render_frame_host);
private:
friend class NavigationHandleImplTest;
// Used to track the state the navigation is currently in.
enum State {
INITIAL = 0,
WILL_SEND_REQUEST,
DEFERRING_START,
WILL_REDIRECT_REQUEST,
DEFERRING_REDIRECT,
CANCELING,
READY_TO_COMMIT,
DID_COMMIT,
DID_COMMIT_ERROR_PAGE,
};
NavigationHandleImpl(const GURL& url,
FrameTreeNode* frame_tree_node,
const base::TimeTicks& navigation_start);
NavigationThrottle::ThrottleCheckResult CheckWillStartRequest();
NavigationThrottle::ThrottleCheckResult CheckWillRedirectRequest();
// Helper function to run and reset the |complete_callback_|. This marks the
// end of a round of NavigationThrottleChecks.
void RunCompleteCallback(NavigationThrottle::ThrottleCheckResult result);
// Used in tests.
State state() const { return state_; }
// See NavigationHandle for a description of those member variables.
GURL url_;
bool is_post_;
Referrer sanitized_referrer_;
bool has_user_gesture_;
ui::PageTransition transition_;
bool is_external_protocol_;
net::Error net_error_code_;
RenderFrameHostImpl* render_frame_host_;
bool is_same_page_;
scoped_refptr<net::HttpResponseHeaders> response_headers_;
// The state the navigation is in.
State state_;
// Whether the navigation is in the middle of a transfer. Set to false when
// the DidStartProvisionalLoad is received from the new renderer.
bool is_transferring_;
// The FrameTreeNode this navigation is happening in.
FrameTreeNode* frame_tree_node_;
// A list of Throttles registered for this navigation.
ScopedVector<NavigationThrottle> throttles_;
// The index of the next throttle to check.
size_t next_index_;
// The time this navigation started.
const base::TimeTicks navigation_start_;
// This callback will be run when all throttle checks have been performed.
ThrottleChecksFinishedCallback complete_callback_;
// PlzNavigate
// Manages the lifetime of a pre-created ServiceWorkerProviderHost until a
// corresponding ServiceWorkerNetworkProvider is created in the renderer.
scoped_ptr<ServiceWorkerNavigationHandle> service_worker_handle_;
DISALLOW_COPY_AND_ASSIGN(NavigationHandleImpl);
};
} // namespace content
#endif // CONTENT_BROWSER_FRAME_HOST_NAVIGATION_HANDLE_IMPL_H_