| // Copyright 2019 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_TEST_NAVIGATION_SIMULATOR_IMPL_H_ |
| #define CONTENT_TEST_NAVIGATION_SIMULATOR_IMPL_H_ |
| |
| #include <memory> |
| #include <string> |
| |
| #include "base/callback.h" |
| #include "base/optional.h" |
| #include "content/browser/frame_host/navigation_handle_impl.h" |
| #include "content/common/content_security_policy/csp_disposition_enum.h" |
| #include "content/public/browser/navigation_controller.h" |
| #include "content/public/browser/navigation_throttle.h" |
| #include "content/public/browser/web_contents_observer.h" |
| #include "content/public/common/referrer.h" |
| #include "content/public/test/navigation_simulator.h" |
| #include "mojo/public/cpp/bindings/associated_interface_request.h" |
| #include "net/base/host_port_pair.h" |
| #include "net/base/ip_endpoint.h" |
| #include "services/service_manager/public/cpp/interface_provider.h" |
| #include "third_party/blink/public/mojom/frame/document_interface_broker.mojom.h" |
| #include "url/gurl.h" |
| |
| struct FrameHostMsg_DidCommitProvisionalLoad_Params; |
| |
| namespace content { |
| |
| class FrameTreeNode; |
| class NavigationHandleImpl; |
| class NavigationRequest; |
| class TestRenderFrameHost; |
| class WebContentsImpl; |
| |
| namespace mojom { |
| class NavigationClient; |
| } |
| |
| class NavigationSimulatorImpl : public NavigationSimulator, |
| public WebContentsObserver { |
| public: |
| ~NavigationSimulatorImpl() override; |
| |
| static std::unique_ptr<NavigationSimulatorImpl> CreateBrowserInitiated( |
| const GURL& original_url, |
| WebContents* contents); |
| |
| static std::unique_ptr<NavigationSimulatorImpl> CreateHistoryNavigation( |
| int offset, |
| WebContents* web_contents); |
| |
| static std::unique_ptr<NavigationSimulatorImpl> CreateRendererInitiated( |
| const GURL& original_url, |
| RenderFrameHost* render_frame_host); |
| |
| static std::unique_ptr<NavigationSimulatorImpl> CreateFromPending( |
| WebContents* contents); |
| |
| // NavigationSimulator implementation. |
| void Start() override; |
| void Redirect(const GURL& new_url) override; |
| void ReadyToCommit() override; |
| void Commit() override; |
| void AbortCommit() override; |
| void FailWithResponseHeaders( |
| int error_code, |
| scoped_refptr<net::HttpResponseHeaders> response_headers) override; |
| void Fail(int error_code) override; |
| void CommitErrorPage() override; |
| void CommitSameDocument() override; |
| RenderFrameHost* GetFinalRenderFrameHost() override; |
| void Wait() override; |
| bool IsDeferred() override; |
| |
| void SetTransition(ui::PageTransition transition) override; |
| void SetHasUserGesture(bool has_user_gesture) override; |
| void SetReloadType(ReloadType reload_type) override; |
| void SetMethod(const std::string& method) override; |
| void SetIsFormSubmission(bool is_form_submission) override; |
| void SetReferrer(const Referrer& referrer) override; |
| void SetSocketAddress(const net::IPEndPoint& remote_endpoint) override; |
| void SetWasFetchedViaCache(bool was_fetched_via_cache) override; |
| void SetIsSignedExchangeInnerResponse( |
| bool is_signed_exchange_inner_response) override; |
| void SetInterfaceProviderRequest( |
| service_manager::mojom::InterfaceProviderRequest request) override; |
| void SetContentsMimeType(const std::string& contents_mime_type) override; |
| void SetAutoAdvance(bool auto_advance) override; |
| |
| NavigationThrottle::ThrottleCheckResult GetLastThrottleCheckResult() override; |
| NavigationHandleImpl* GetNavigationHandle() const override; |
| content::GlobalRequestID GetGlobalRequestID() const override; |
| |
| // Additional utilites usable only inside content/. |
| |
| // This will do the very beginning of a navigation but stop before the |
| // beforeunload event response. Will leave the Simulator in a |
| // WAITING_BEFORE_UNLOAD state. We do not wait for beforeunload event when |
| // starting renderer-side, use solely for browser initiated navigations. |
| void BrowserInitiatedStartAndWaitBeforeUnload(); |
| |
| // Set LoadURLParams and make browser initiated navigations use |
| // LoadURLWithParams instead of LoadURL. |
| void SetLoadURLParams(NavigationController::LoadURLParams* load_url_params); |
| void set_should_check_main_world_csp(CSPDisposition disposition) { |
| should_check_main_world_csp_ = disposition; |
| } |
| |
| // Set DidCommit*Params history_list_was_cleared flag to |history_cleared|. |
| void set_history_list_was_cleared(bool history_cleared); |
| |
| // Manually force the value of did_create_new_entry flag in DidCommit*Params |
| // to |did_create_new_entry|. |
| void set_did_create_new_entry(bool did_create_new_entry); |
| |
| // Manually force the value of should_replace_current_entry flag in |
| // DidCommit*Params to |should_replace_current_entry|. |
| void set_should_replace_current_entry(bool should_replace_current_entry) { |
| should_replace_current_entry_ = should_replace_current_entry; |
| } |
| |
| // Manually force the value of intended_as_new_entry flag in DidCommit*Params |
| // to |intended_as_new_entry|. |
| void set_intended_as_new_entry(bool intended_as_new_entry) { |
| intended_as_new_entry_ = intended_as_new_entry; |
| } |
| |
| void set_http_connection_info(net::HttpResponseInfo::ConnectionInfo info) { |
| http_connection_info_ = info; |
| } |
| |
| void set_ssl_info(net::SSLInfo ssl_info) { ssl_info_ = ssl_info; } |
| |
| // Whether to drop the swap out ack of the previous RenderFrameHost during |
| // cross-process navigations. By default this is false, set to true if you |
| // want the old RenderFrameHost to be left in a pending swap out state. |
| void set_drop_swap_out_ack(bool drop_swap_out_ack) { |
| drop_swap_out_ack_ = drop_swap_out_ack; |
| } |
| |
| // Whether to drop the BeforeUnloadACK of the current RenderFrameHost at the |
| // beginning of a browser-initiated navigation. By default this is false, set |
| // to true if you want to simulate the BeforeUnloadACK manually. |
| void set_block_on_before_unload_ack(bool block_on_before_unload_ack) { |
| block_on_before_unload_ack_ = block_on_before_unload_ack; |
| } |
| |
| void set_page_state(const PageState& page_state) { page_state_ = page_state; } |
| |
| void set_origin(const url::Origin& origin) { origin_ = origin; } |
| |
| void SetIsPostWithId(int64_t post_id); |
| |
| private: |
| NavigationSimulatorImpl(const GURL& original_url, |
| bool browser_initiated, |
| WebContentsImpl* web_contents, |
| TestRenderFrameHost* render_frame_host); |
| |
| // Adds a test navigation throttle to |handle| which sanity checks various |
| // callbacks have been properly called. |
| void RegisterTestThrottle(NavigationHandle* handle); |
| |
| // Initializes a NavigationSimulator from an existing NavigationRequest. This |
| // should only be needed if a navigation was started without a valid |
| // NavigationSimulator. |
| void InitializeFromStartedRequest(NavigationRequest* request); |
| |
| // WebContentsObserver: |
| void DidStartNavigation(NavigationHandle* navigation_handle) override; |
| void DidRedirectNavigation(NavigationHandle* navigation_handle) override; |
| void ReadyToCommitNavigation(NavigationHandle* navigation_handle) override; |
| void DidFinishNavigation(NavigationHandle* navigation_handle) override; |
| |
| void StartComplete(); |
| void RedirectComplete(int previous_num_will_redirect_request_called, |
| int previous_did_redirect_navigation_called); |
| void ReadyToCommitComplete(bool ran_throttles); |
| void FailComplete(int error_code); |
| |
| void OnWillStartRequest(); |
| void OnWillRedirectRequest(); |
| void OnWillFailRequest(); |
| void OnWillProcessResponse(); |
| |
| // Simulates a browser-initiated navigation starting. Returns false if the |
| // navigation failed synchronously. |
| bool SimulateBrowserInitiatedStart(); |
| |
| // Simulates a renderer-initiated navigation starting. Returns false if the |
| // navigation failed synchronously. |
| bool SimulateRendererInitiatedStart(); |
| |
| // This method will block waiting for throttle checks to complete if |
| // |auto_advance_|. Otherwise will just set up state for checking the result |
| // when the throttles end up finishing. |
| void MaybeWaitForThrottleChecksComplete(base::OnceClosure complete_closure); |
| |
| // Sets |last_throttle_check_result_| and calls both the |
| // |wait_closure_| and the |throttle_checks_complete_closure_|, if they are |
| // set. |
| void OnThrottleChecksComplete(NavigationThrottle::ThrottleCheckResult result); |
| |
| // Helper method to set the OnThrottleChecksComplete callback on the |
| // NavigationHandle. |
| void PrepareCompleteCallbackOnHandle(NavigationHandleImpl* handle); |
| |
| // Check if the navigation corresponds to a same-document navigation. |
| // Only use on renderer-initiated navigations. |
| bool CheckIfSameDocument(); |
| |
| // Infers from internal parameters whether the navigation created a new |
| // entry. |
| bool DidCreateNewEntry(); |
| |
| // Set the navigation to be done towards the specified navigation controller |
| // offset. Typically -1 for back navigations or 1 for forward navigations. |
| void SetSessionHistoryOffset(int offset); |
| |
| // Build DidCommitProvisionalLoadParams to commit the ongoing navigation, |
| // based on internal NavigationSimulator state and given parameters. |
| std::unique_ptr<FrameHostMsg_DidCommitProvisionalLoad_Params> |
| BuildDidCommitProvisionalLoadParams(bool same_document, |
| bool failed_navigation); |
| |
| enum State { |
| INITIALIZATION, |
| WAITING_BEFORE_UNLOAD, |
| STARTED, |
| READY_TO_COMMIT, |
| FAILED, |
| FINISHED, |
| }; |
| |
| State state_ = INITIALIZATION; |
| |
| // The WebContents in which the navigation is taking place. |
| // IMPORTANT: Because NavigationSimulator is used outside content/ where we |
| // sometimes use WebContentsImpl and not TestWebContents, this cannot be |
| // assumed to cast properly to TestWebContents. |
| WebContentsImpl* web_contents_; |
| |
| // The renderer associated with this navigation. |
| // Note: this can initially be null for browser-initiated navigations. |
| TestRenderFrameHost* render_frame_host_; |
| |
| FrameTreeNode* frame_tree_node_; |
| |
| // The NavigationRequest associated with this navigation. |
| NavigationRequest* request_; |
| |
| // Note: additional parameters to modify the navigation should be properly |
| // initialized (if needed) in InitializeFromStartedRequest. |
| GURL original_url_; |
| GURL navigation_url_; |
| net::IPEndPoint remote_endpoint_; |
| bool was_fetched_via_cache_ = false; |
| bool is_signed_exchange_inner_response_ = false; |
| std::string initial_method_; |
| bool is_form_submission_ = false; |
| bool browser_initiated_; |
| bool same_document_ = false; |
| Referrer referrer_; |
| ui::PageTransition transition_; |
| ReloadType reload_type_ = ReloadType::NONE; |
| int session_history_offset_ = 0; |
| bool has_user_gesture_ = true; |
| service_manager::mojom::InterfaceProviderRequest interface_provider_request_; |
| blink::mojom::DocumentInterfaceBrokerRequest |
| document_interface_broker_content_request_; |
| blink::mojom::DocumentInterfaceBrokerRequest |
| document_interface_broker_blink_request_; |
| std::string contents_mime_type_; |
| CSPDisposition should_check_main_world_csp_ = CSPDisposition::CHECK; |
| net::HttpResponseInfo::ConnectionInfo http_connection_info_ = |
| net::HttpResponseInfo::CONNECTION_INFO_UNKNOWN; |
| base::Optional<net::SSLInfo> ssl_info_; |
| base::Optional<PageState> page_state_; |
| base::Optional<url::Origin> origin_; |
| int64_t post_id_ = -1; |
| |
| bool auto_advance_ = true; |
| bool drop_swap_out_ack_ = false; |
| bool block_on_before_unload_ack_ = false; |
| |
| // Generic params structure used for fully customized browser initiated |
| // navigation requests. Only valid if explicitely provided. |
| NavigationController::LoadURLParams* load_url_params_; |
| |
| bool history_list_was_cleared_ = false; |
| bool should_replace_current_entry_ = false; |
| base::Optional<bool> did_create_new_entry_; |
| base::Optional<bool> intended_as_new_entry_; |
| |
| // These are used to sanity check the content/public/ API calls emitted as |
| // part of the navigation. |
| int num_did_start_navigation_called_ = 0; |
| int num_will_start_request_called_ = 0; |
| int num_will_redirect_request_called_ = 0; |
| int num_will_fail_request_called_ = 0; |
| int num_did_redirect_navigation_called_ = 0; |
| int num_will_process_response_called_ = 0; |
| int num_ready_to_commit_called_ = 0; |
| int num_did_finish_navigation_called_ = 0; |
| |
| // Holds the last ThrottleCheckResult calculated by the navigation's |
| // throttles. Will be unset before WillStartRequest is finished. Will be unset |
| // while throttles are being run, but before they finish. |
| base::Optional<NavigationThrottle::ThrottleCheckResult> |
| last_throttle_check_result_; |
| |
| // GlobalRequestID for the associated NavigationHandle. Only valid after |
| // WillProcessResponse has been invoked on the NavigationHandle. |
| content::GlobalRequestID request_id_; |
| |
| // Closure that is set when MaybeWaitForThrottleChecksComplete is called. |
| // Called in OnThrottleChecksComplete. |
| base::OnceClosure throttle_checks_complete_closure_; |
| |
| // Closure that is called in OnThrottleChecksComplete if we are waiting on the |
| // result. Calling this will quit the nested run loop. |
| base::OnceClosure wait_closure_; |
| |
| // This member simply ensures that we do not disconnect |
| // the NavigationClient interface, as it would be interpreted as a |
| // cancellation coming from the renderer process side. This member interface |
| // will never be bound. |
| // Only used when PerNavigationMojoInterface is enabled. |
| mojo::AssociatedInterfaceRequest<mojom::NavigationClient> |
| navigation_client_request_; |
| |
| base::WeakPtrFactory<NavigationSimulatorImpl> weak_factory_; |
| }; |
| |
| } // namespace content |
| |
| #endif // CONTENT_PUBLIC_TEST_NAVIGATION_SIMULATOR_H_ |