1 // Copyright 2019 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CONTENT_TEST_NAVIGATION_SIMULATOR_IMPL_H_ 6 #define CONTENT_TEST_NAVIGATION_SIMULATOR_IMPL_H_ 7 8 #include <memory> 9 #include <string> 10 11 #include "base/callback.h" 12 #include "base/optional.h" 13 #include "content/browser/renderer_host/navigation_request.h" 14 #include "content/public/browser/navigation_controller.h" 15 #include "content/public/browser/navigation_throttle.h" 16 #include "content/public/browser/web_contents_observer.h" 17 #include "content/public/common/impression.h" 18 #include "content/public/test/navigation_simulator.h" 19 #include "content/test/test_render_frame_host.h" 20 #include "mojo/public/cpp/bindings/pending_associated_receiver.h" 21 #include "mojo/public/cpp/bindings/pending_receiver.h" 22 #include "net/base/host_port_pair.h" 23 #include "net/base/ip_endpoint.h" 24 #include "net/dns/public/resolve_error_info.h" 25 #include "services/service_manager/public/cpp/interface_provider.h" 26 #include "third_party/blink/public/mojom/loader/referrer.mojom-forward.h" 27 #include "url/gurl.h" 28 29 struct FrameHostMsg_DidCommitProvisionalLoad_Params; 30 31 namespace content { 32 33 class FrameTreeNode; 34 class NavigationRequest; 35 class TestRenderFrameHost; 36 class WebContentsImpl; 37 38 namespace mojom { 39 class NavigationClient; 40 } 41 42 class NavigationSimulatorImpl : public NavigationSimulator, 43 public WebContentsObserver { 44 public: 45 ~NavigationSimulatorImpl() override; 46 47 static std::unique_ptr<NavigationSimulatorImpl> CreateBrowserInitiated( 48 const GURL& original_url, 49 WebContents* contents); 50 51 static std::unique_ptr<NavigationSimulatorImpl> CreateHistoryNavigation( 52 int offset, 53 WebContents* web_contents); 54 55 static std::unique_ptr<NavigationSimulatorImpl> CreateRendererInitiated( 56 const GURL& original_url, 57 RenderFrameHost* render_frame_host); 58 59 static std::unique_ptr<NavigationSimulatorImpl> CreateFromPending( 60 WebContents* contents); 61 62 // Creates a NavigationSimulator for an already-started navigation happening 63 // in |frame_tree_node|. Can be used to drive the navigation to completion. 64 static std::unique_ptr<NavigationSimulatorImpl> CreateFromPendingInFrame( 65 FrameTreeNode* frame_tree_node); 66 67 // NavigationSimulator implementation. 68 void Start() override; 69 void Redirect(const GURL& new_url) override; 70 void ReadyToCommit() override; 71 void Commit() override; 72 void AbortCommit() override; 73 void AbortFromRenderer() override; 74 void Fail(int error_code) override; 75 void CommitErrorPage() override; 76 void CommitSameDocument() override; 77 RenderFrameHost* GetFinalRenderFrameHost() override; 78 void Wait() override; 79 bool IsDeferred() override; 80 81 void SetInitiatorFrame(RenderFrameHost* initiator_frame_host) override; 82 void SetTransition(ui::PageTransition transition) override; 83 void SetHasUserGesture(bool has_user_gesture) override; 84 void SetReloadType(ReloadType reload_type) override; 85 void SetMethod(const std::string& method) override; 86 void SetIsFormSubmission(bool is_form_submission) override; 87 void SetWasInitiatedByLinkClick(bool was_initiated_by_link_click) override; 88 void SetReferrer(blink::mojom::ReferrerPtr referrer) override; 89 void SetSocketAddress(const net::IPEndPoint& remote_endpoint) override; 90 void SetWasFetchedViaCache(bool was_fetched_via_cache) override; 91 void SetIsSignedExchangeInnerResponse( 92 bool is_signed_exchange_inner_response) override; 93 void SetInterfaceProviderReceiver( 94 mojo::PendingReceiver<service_manager::mojom::InterfaceProvider> receiver) 95 override; 96 void SetContentsMimeType(const std::string& contents_mime_type) override; 97 void SetResponseHeaders( 98 scoped_refptr<net::HttpResponseHeaders> response_headers) override; 99 void SetAutoAdvance(bool auto_advance) override; 100 void SetResolveErrorInfo( 101 const net::ResolveErrorInfo& resolve_error_info) override; 102 void SetSSLInfo(const net::SSLInfo& ssl_info) override; 103 104 NavigationThrottle::ThrottleCheckResult GetLastThrottleCheckResult() override; 105 NavigationRequest* GetNavigationHandle() override; 106 content::GlobalRequestID GetGlobalRequestID() override; 107 108 void SetKeepLoading(bool keep_loading) override; 109 void StopLoading() override; 110 void FailLoading(const GURL& url, int error_code) override; 111 112 // Additional utilities usable only inside content/. 113 114 // This will do the very beginning of a navigation but stop before the 115 // beforeunload event response. Will leave the Simulator in a 116 // WAITING_BEFORE_UNLOAD state. We do not wait for beforeunload event when 117 // starting renderer-side, use solely for browser initiated navigations. 118 void BrowserInitiatedStartAndWaitBeforeUnload(); 119 120 // Set LoadURLParams and make browser initiated navigations use 121 // LoadURLWithParams instead of LoadURL. 122 void SetLoadURLParams(NavigationController::LoadURLParams* load_url_params); set_should_check_main_world_csp(network::mojom::CSPDisposition disposition)123 void set_should_check_main_world_csp( 124 network::mojom::CSPDisposition disposition) { 125 should_check_main_world_csp_ = disposition; 126 } 127 128 // Set DidCommit*Params history_list_was_cleared flag to |history_cleared|. 129 void set_history_list_was_cleared(bool history_cleared); 130 131 // Manually force the value of did_create_new_entry flag in DidCommit*Params 132 // to |did_create_new_entry|. 133 void set_did_create_new_entry(bool did_create_new_entry); 134 135 // Manually force the value of should_replace_current_entry flag in 136 // DidCommit*Params to |should_replace_current_entry|. set_should_replace_current_entry(bool should_replace_current_entry)137 void set_should_replace_current_entry(bool should_replace_current_entry) { 138 should_replace_current_entry_ = should_replace_current_entry; 139 } 140 141 // Manually force the value of intended_as_new_entry flag in DidCommit*Params 142 // to |intended_as_new_entry|. set_intended_as_new_entry(bool intended_as_new_entry)143 void set_intended_as_new_entry(bool intended_as_new_entry) { 144 intended_as_new_entry_ = intended_as_new_entry; 145 } 146 set_http_connection_info(net::HttpResponseInfo::ConnectionInfo info)147 void set_http_connection_info(net::HttpResponseInfo::ConnectionInfo info) { 148 http_connection_info_ = info; 149 } 150 151 // Whether to drop the swap out ack of the previous RenderFrameHost during 152 // cross-process navigations. By default this is false, set to true if you 153 // want the old RenderFrameHost to be left in a pending swap out state. set_drop_unload_ack(bool drop_unload_ack)154 void set_drop_unload_ack(bool drop_unload_ack) { 155 drop_unload_ack_ = drop_unload_ack; 156 } 157 158 // Whether to drop the BeforeUnloadCompleted of the current RenderFrameHost at 159 // the beginning of a browser-initiated navigation. By default this is false, 160 // set to true if you want to simulate the BeforeUnloadCompleted manually. set_block_invoking_before_unload_completed_callback(bool block_invoking_before_unload_completed_callback)161 void set_block_invoking_before_unload_completed_callback( 162 bool block_invoking_before_unload_completed_callback) { 163 block_invoking_before_unload_completed_callback_ = 164 block_invoking_before_unload_completed_callback; 165 } 166 set_page_state(const blink::PageState & page_state)167 void set_page_state(const blink::PageState& page_state) { 168 page_state_ = page_state; 169 } 170 set_origin(const url::Origin & origin)171 void set_origin(const url::Origin& origin) { origin_ = origin; } 172 set_impression(const Impression & impression)173 void set_impression(const Impression& impression) { 174 impression_ = impression; 175 } 176 177 void SetIsPostWithId(int64_t post_id); 178 179 private: 180 NavigationSimulatorImpl(const GURL& original_url, 181 bool browser_initiated, 182 WebContentsImpl* web_contents, 183 TestRenderFrameHost* render_frame_host); 184 185 // Adds a test navigation throttle to |request| which sanity checks various 186 // callbacks have been properly called. 187 void RegisterTestThrottle(NavigationRequest* request); 188 189 // Initializes a NavigationSimulator from an existing NavigationRequest. This 190 // should only be needed if a navigation was started without a valid 191 // NavigationSimulator. 192 void InitializeFromStartedRequest(NavigationRequest* request); 193 194 // WebContentsObserver: 195 void DidStartNavigation(NavigationHandle* navigation_handle) override; 196 void DidRedirectNavigation(NavigationHandle* navigation_handle) override; 197 void ReadyToCommitNavigation(NavigationHandle* navigation_handle) override; 198 void DidFinishNavigation(NavigationHandle* navigation_handle) override; 199 200 void StartComplete(); 201 void RedirectComplete(int previous_num_will_redirect_request_called, 202 int previous_did_redirect_navigation_called); 203 void ReadyToCommitComplete(bool ran_throttles); 204 void FailComplete(int error_code); 205 206 void OnWillStartRequest(); 207 void OnWillRedirectRequest(); 208 void OnWillFailRequest(); 209 void OnWillProcessResponse(); 210 211 // Simulates a browser-initiated navigation starting. Returns false if the 212 // navigation failed synchronously. 213 bool SimulateBrowserInitiatedStart(); 214 215 // Simulates a renderer-initiated navigation starting. Returns false if the 216 // navigation failed synchronously. 217 bool SimulateRendererInitiatedStart(); 218 219 // This method will block waiting for throttle checks to complete if 220 // |auto_advance_|. Otherwise will just set up state for checking the result 221 // when the throttles end up finishing. 222 void MaybeWaitForThrottleChecksComplete(base::OnceClosure complete_closure); 223 224 // Sets |last_throttle_check_result_| and calls both the 225 // |wait_closure_| and the |throttle_checks_complete_closure_|, if they are 226 // set. 227 bool OnThrottleChecksComplete(NavigationThrottle::ThrottleCheckResult result); 228 229 // Helper method to set the OnThrottleChecksComplete callback on the 230 // NavigationRequest. 231 void PrepareCompleteCallbackOnRequest(); 232 233 // Check if the navigation corresponds to a same-document navigation. 234 // Only use on renderer-initiated navigations. 235 bool CheckIfSameDocument(); 236 237 // Infers from internal parameters whether the navigation created a new 238 // entry. 239 bool DidCreateNewEntry(); 240 241 // Set the navigation to be done towards the specified navigation controller 242 // offset. Typically -1 for back navigations or 1 for forward navigations. 243 void SetSessionHistoryOffset(int offset); 244 245 // Build DidCommitProvisionalLoadParams to commit the ongoing navigation, 246 // based on internal NavigationSimulator state and given parameters. 247 std::unique_ptr<FrameHostMsg_DidCommitProvisionalLoad_Params> 248 BuildDidCommitProvisionalLoadParams(bool same_document, 249 bool failed_navigation); 250 251 // Simulate the UnloadACK in the old RenderFrameHost if it was unloaded at the 252 // commit time. 253 void SimulateUnloadCompletionCallbackForPreviousFrameIfNeeded( 254 RenderFrameHostImpl* previous_frame); 255 256 enum State { 257 INITIALIZATION, 258 WAITING_BEFORE_UNLOAD, 259 STARTED, 260 READY_TO_COMMIT, 261 FAILED, 262 FINISHED, 263 }; 264 265 State state_ = INITIALIZATION; 266 267 // The WebContents in which the navigation is taking place. 268 // IMPORTANT: Because NavigationSimulator is used outside content/ where we 269 // sometimes use WebContentsImpl and not TestWebContents, this cannot be 270 // assumed to cast properly to TestWebContents. 271 WebContentsImpl* web_contents_; 272 273 // The renderer associated with this navigation. 274 // Note: this can initially be null for browser-initiated navigations. 275 TestRenderFrameHost* render_frame_host_; 276 277 FrameTreeNode* frame_tree_node_; 278 279 // The NavigationRequest associated with this navigation. 280 NavigationRequest* request_; 281 282 // Note: additional parameters to modify the navigation should be properly 283 // initialized (if needed) in InitializeFromStartedRequest. 284 GURL original_url_; 285 GURL navigation_url_; 286 net::IPEndPoint remote_endpoint_; 287 bool was_fetched_via_cache_ = false; 288 bool is_signed_exchange_inner_response_ = false; 289 std::string initial_method_; 290 bool is_form_submission_ = false; 291 bool was_initiated_by_link_click_ = false; 292 bool browser_initiated_; 293 bool same_document_ = false; 294 TestRenderFrameHost::LoadingScenario loading_scenario_ = 295 TestRenderFrameHost::LoadingScenario::kOther; 296 blink::mojom::ReferrerPtr referrer_; 297 RenderFrameHost* initiator_frame_host_ = nullptr; 298 ui::PageTransition transition_; 299 ReloadType reload_type_ = ReloadType::NONE; 300 int session_history_offset_ = 0; 301 bool has_user_gesture_ = true; 302 mojo::PendingReceiver<service_manager::mojom::InterfaceProvider> 303 interface_provider_receiver_; 304 mojo::PendingReceiver<blink::mojom::BrowserInterfaceBroker> 305 browser_interface_broker_receiver_; 306 std::string contents_mime_type_; 307 scoped_refptr<net::HttpResponseHeaders> response_headers_; 308 network::mojom::CSPDisposition should_check_main_world_csp_ = 309 network::mojom::CSPDisposition::CHECK; 310 net::HttpResponseInfo::ConnectionInfo http_connection_info_ = 311 net::HttpResponseInfo::CONNECTION_INFO_UNKNOWN; 312 net::ResolveErrorInfo resolve_error_info_ = net::ResolveErrorInfo(net::OK); 313 base::Optional<net::SSLInfo> ssl_info_; 314 base::Optional<blink::PageState> page_state_; 315 base::Optional<url::Origin> origin_; 316 base::Optional<Impression> impression_; 317 int64_t post_id_ = -1; 318 319 bool auto_advance_ = true; 320 bool drop_unload_ack_ = false; 321 bool block_invoking_before_unload_completed_callback_ = false; 322 bool keep_loading_ = false; 323 324 // Generic params structure used for fully customized browser initiated 325 // navigation requests. Only valid if explicitely provided. 326 NavigationController::LoadURLParams* load_url_params_; 327 328 bool history_list_was_cleared_ = false; 329 bool should_replace_current_entry_ = false; 330 base::Optional<bool> did_create_new_entry_; 331 base::Optional<bool> intended_as_new_entry_; 332 bool was_aborted_ = false; 333 334 // These are used to sanity check the content/public/ API calls emitted as 335 // part of the navigation. 336 int num_did_start_navigation_called_ = 0; 337 int num_will_start_request_called_ = 0; 338 int num_will_redirect_request_called_ = 0; 339 int num_will_fail_request_called_ = 0; 340 int num_did_redirect_navigation_called_ = 0; 341 int num_will_process_response_called_ = 0; 342 int num_ready_to_commit_called_ = 0; 343 int num_did_finish_navigation_called_ = 0; 344 345 // Holds the last ThrottleCheckResult calculated by the navigation's 346 // throttles. Will be unset before WillStartRequest is finished. Will be unset 347 // while throttles are being run, but before they finish. 348 base::Optional<NavigationThrottle::ThrottleCheckResult> 349 last_throttle_check_result_; 350 351 // GlobalRequestID for the associated NavigationHandle. Only valid after 352 // WillProcessResponse has been invoked on the NavigationHandle. 353 content::GlobalRequestID request_id_; 354 355 // Closure that is set when MaybeWaitForThrottleChecksComplete is called. 356 // Called in OnThrottleChecksComplete. 357 base::OnceClosure throttle_checks_complete_closure_; 358 359 // Closure that is called in OnThrottleChecksComplete if we are waiting on the 360 // result. Calling this will quit the nested run loop. 361 base::OnceClosure wait_closure_; 362 363 // This member simply ensures that we do not disconnect 364 // the NavigationClient interface, as it would be interpreted as a 365 // cancellation coming from the renderer process side. This member interface 366 // will never be bound. 367 // Only used when PerNavigationMojoInterface is enabled. 368 mojo::PendingAssociatedReceiver<mojom::NavigationClient> 369 navigation_client_receiver_; 370 371 base::WeakPtrFactory<NavigationSimulatorImpl> weak_factory_{this}; 372 }; 373 374 } // namespace content 375 376 #endif // CONTENT_PUBLIC_TEST_NAVIGATION_SIMULATOR_H_ 377