| // 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; } | 
 |  | 
 |  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_; | 
 |  | 
 |   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_ |