| // 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/ref_counted.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_data.h" |
| #include "content/public/browser/navigation_throttle.h" |
| #include "url/gurl.h" |
| |
| struct FrameHostMsg_DidCommitProvisionalLoad_Params; |
| |
| namespace content { |
| |
| class NavigatorDelegate; |
| class ResourceRequestBodyImpl; |
| 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 std::unique_ptr<NavigationHandleImpl> Create( |
| const GURL& url, |
| FrameTreeNode* frame_tree_node, |
| bool is_renderer_initiated, |
| bool is_synchronous, |
| bool is_srcdoc, |
| const base::TimeTicks& navigation_start, |
| int pending_nav_entry_id); |
| ~NavigationHandleImpl() override; |
| |
| // NavigationHandle implementation: |
| const GURL& GetURL() override; |
| bool IsInMainFrame() override; |
| bool IsParentMainFrame() override; |
| bool IsRendererInitiated() override; |
| bool IsSynchronousNavigation() override; |
| bool IsSrcdoc() override; |
| bool WasServerRedirect() override; |
| int GetFrameTreeNodeId() override; |
| int GetParentFrameTreeNodeId() 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( |
| std::unique_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; |
| NavigationData* GetNavigationData() override; |
| |
| NavigatorDelegate* GetDelegate() const; |
| |
| // Returns the response headers for the request or nullptr if there are none. |
| // This should only be accessed after a redirect was encountered or after the |
| // navigation is ready to commit. The headers returned should not be modified, |
| // as modifications will not be reflected in the network stack. |
| const net::HttpResponseHeaders* GetResponseHeaders(); |
| |
| // Get the unique id from the NavigationEntry associated with this |
| // NavigationHandle. Note that a synchronous, renderer-initiated navigation |
| // will not have a NavigationEntry associated with it, and this will return 0. |
| int pending_nav_entry_id() const { return pending_nav_entry_id_; } |
| |
| // Changes the pending NavigationEntry ID for this handle. This is currently |
| // required during transfer navigations. |
| // TODO(creis): Remove this when transfer navigations do not require pending |
| // entries. See https://crbug.com/495161. |
| void update_entry_id_for_transfer(int nav_entry_id) { |
| pending_nav_entry_id_ = nav_entry_id; |
| } |
| |
| 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; |
| } |
| |
| // Returns the POST body associated with this navigation. This will be |
| // null for GET and/or other non-POST requests (or if a response to a POST |
| // request was a redirect that changed the method to GET - for example 302). |
| const scoped_refptr<ResourceRequestBodyImpl>& resource_request_body() const { |
| return resource_request_body_; |
| } |
| |
| 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( |
| const std::string& method, |
| scoped_refptr<content::ResourceRequestBodyImpl> resource_request_body, |
| 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. |
| // This will also inform the delegate that the request was redirected. |
| void WillRedirectRequest( |
| const GURL& new_url, |
| const std::string& new_method, |
| const GURL& new_referrer_url, |
| bool new_is_external_protocol, |
| scoped_refptr<net::HttpResponseHeaders> response_headers, |
| const ThrottleChecksFinishedCallback& callback); |
| |
| // Called when the URLRequest has delivered response headers and metadata. |
| // |callback| will be called when all throttle checks have completed, |
| // allowing the caller to cancel the navigation or let it proceed. |
| // NavigationHandle will not call |callback| with a result of DEFER. |
| // If the result is PROCEED, then 'ReadyToCommitNavigation' will be called |
| // with |render_frame_host| and |response_headers| just before calling |
| // |callback|. |
| void WillProcessResponse( |
| RenderFrameHostImpl* render_frame_host, |
| 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 is ready to be committed in |
| // |render_frame_host|. This will update the |state_| and inform the |
| // delegate. |
| void ReadyToCommitNavigation(RenderFrameHostImpl* render_frame_host); |
| |
| // Called when the navigation was committed in |render_frame_host|. This will |
| // update the |state_|. |
| void DidCommitNavigation( |
| const FrameHostMsg_DidCommitProvisionalLoad_Params& params, |
| bool same_page, |
| RenderFrameHostImpl* render_frame_host); |
| |
| // Called during commit. Takes ownership of the embedder's NavigationData |
| // instance. This NavigationData may have been cloned prior to being added |
| // here. |
| void set_navigation_data(std::unique_ptr<NavigationData> navigation_data) { |
| navigation_data_ = std::move(navigation_data); |
| } |
| |
| 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, |
| WILL_PROCESS_RESPONSE, |
| DEFERRING_RESPONSE, |
| READY_TO_COMMIT, |
| DID_COMMIT, |
| DID_COMMIT_ERROR_PAGE, |
| }; |
| |
| NavigationHandleImpl(const GURL& url, |
| FrameTreeNode* frame_tree_node, |
| bool is_renderer_initiated, |
| bool is_synchronous, |
| bool is_srcdoc, |
| const base::TimeTicks& navigation_start, |
| int pending_nav_entry_id); |
| |
| NavigationThrottle::ThrottleCheckResult CheckWillStartRequest(); |
| NavigationThrottle::ThrottleCheckResult CheckWillRedirectRequest(); |
| NavigationThrottle::ThrottleCheckResult CheckWillProcessResponse(); |
| |
| // 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_; } |
| |
| // Populates |throttles_| with the throttles for this navigation. |
| void RegisterNavigationThrottles(); |
| |
| // See NavigationHandle for a description of those member variables. |
| GURL url_; |
| Referrer sanitized_referrer_; |
| bool has_user_gesture_; |
| ui::PageTransition transition_; |
| bool is_external_protocol_; |
| net::Error net_error_code_; |
| RenderFrameHostImpl* render_frame_host_; |
| const bool is_renderer_initiated_; |
| bool is_same_page_; |
| const bool is_synchronous_; |
| const bool is_srcdoc_; |
| bool was_redirected_; |
| scoped_refptr<net::HttpResponseHeaders> response_headers_; |
| |
| // The HTTP method used for the navigation. |
| std::string method_; |
| |
| // The POST body associated with this navigation. This will be null for GET |
| // and/or other non-POST requests (or if a response to a POST request was a |
| // redirect that changed the method to GET - for example 302). |
| scoped_refptr<ResourceRequestBodyImpl> resource_request_body_; |
| |
| // 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_; |
| |
| // The unique id of the corresponding NavigationEntry. |
| int pending_nav_entry_id_; |
| |
| // This callback will be run when all throttle checks have been performed. |
| ThrottleChecksFinishedCallback complete_callback_; |
| |
| // Embedder data tied to this navigation. |
| std::unique_ptr<NavigationData> navigation_data_; |
| |
| DISALLOW_COPY_AND_ASSIGN(NavigationHandleImpl); |
| }; |
| |
| } // namespace content |
| |
| #endif // CONTENT_BROWSER_FRAME_HOST_NAVIGATION_HANDLE_IMPL_H_ |