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