1 // Copyright 2017 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 #include "content/test/navigation_simulator_impl.h"
6 
7 #include <utility>
8 #include "base/bind.h"
9 #include "base/debug/stack_trace.h"
10 #include "base/memory/ptr_util.h"
11 #include "base/run_loop.h"
12 #include "content/browser/renderer_host/debug_urls.h"
13 #include "content/browser/renderer_host/frame_tree_node.h"
14 #include "content/browser/renderer_host/navigation_entry_impl.h"
15 #include "content/browser/renderer_host/navigation_request.h"
16 #include "content/browser/renderer_host/render_frame_host_impl.h"
17 #include "content/browser/web_contents/web_contents_impl.h"
18 #include "content/common/content_navigation_policy.h"
19 #include "content/common/frame_messages.h"
20 #include "content/common/navigation_params.h"
21 #include "content/common/navigation_params_utils.h"
22 #include "content/public/browser/web_contents.h"
23 #include "content/public/common/navigation_policy.h"
24 #include "content/public/common/url_utils.h"
25 #include "content/test/test_navigation_url_loader.h"
26 #include "content/test/test_render_frame_host.h"
27 #include "content/test/test_web_contents.h"
28 #include "ipc/ipc_message.h"
29 #include "mojo/public/cpp/bindings/pending_associated_remote.h"
30 #include "mojo/public/cpp/bindings/pending_remote.h"
31 #include "net/base/load_flags.h"
32 #include "net/url_request/redirect_info.h"
33 #include "services/metrics/public/cpp/ukm_recorder.h"
34 
35 namespace content {
36 
37 namespace {
38 
39 class NavigationThrottleCallbackRunner : public NavigationThrottle {
40  public:
NavigationThrottleCallbackRunner(NavigationHandle * handle,base::OnceClosure on_will_start_request,const base::RepeatingClosure & on_will_redirect_request,base::OnceClosure on_will_fail_request,base::OnceClosure on_will_process_response)41   NavigationThrottleCallbackRunner(
42       NavigationHandle* handle,
43       base::OnceClosure on_will_start_request,
44       const base::RepeatingClosure& on_will_redirect_request,
45       base::OnceClosure on_will_fail_request,
46       base::OnceClosure on_will_process_response)
47       : NavigationThrottle(handle),
48         on_will_start_request_(std::move(on_will_start_request)),
49         on_will_redirect_request_(on_will_redirect_request),
50         on_will_fail_request_(std::move(on_will_fail_request)),
51         on_will_process_response_(std::move(on_will_process_response)) {}
52 
WillStartRequest()53   NavigationThrottle::ThrottleCheckResult WillStartRequest() override {
54     std::move(on_will_start_request_).Run();
55     return NavigationThrottle::PROCEED;
56   }
57 
WillRedirectRequest()58   NavigationThrottle::ThrottleCheckResult WillRedirectRequest() override {
59     on_will_redirect_request_.Run();
60     return NavigationThrottle::PROCEED;
61   }
62 
WillFailRequest()63   NavigationThrottle::ThrottleCheckResult WillFailRequest() override {
64     std::move(on_will_fail_request_).Run();
65     return NavigationThrottle::PROCEED;
66   }
67 
WillProcessResponse()68   NavigationThrottle::ThrottleCheckResult WillProcessResponse() override {
69     std::move(on_will_process_response_).Run();
70     return NavigationThrottle::PROCEED;
71   }
72 
GetNameForLogging()73   const char* GetNameForLogging() override {
74     return "NavigationThrottleCallbackRunner";
75   }
76 
77  private:
78   base::OnceClosure on_will_start_request_;
79   base::RepeatingClosure on_will_redirect_request_;
80   base::OnceClosure on_will_fail_request_;
81   base::OnceClosure on_will_process_response_;
82 };
83 
84 int64_t g_unique_identifier = 0;
85 
GetFrameTreeNodeForPendingEntry(WebContentsImpl * contents)86 FrameTreeNode* GetFrameTreeNodeForPendingEntry(WebContentsImpl* contents) {
87   NavigationEntryImpl* pending_entry =
88       contents->GetController().GetPendingEntry();
89   int frame_tree_node_id = pending_entry->frame_tree_node_id();
90   FrameTree* frame_tree = contents->GetFrameTree();
91   if (frame_tree_node_id == FrameTreeNode::kFrameTreeNodeInvalidId)
92     return frame_tree->root();
93   return frame_tree->FindByID(frame_tree_node_id);
94 }
95 
96 }  // namespace
97 
98 // static
NavigateAndCommitFromBrowser(WebContents * web_contents,const GURL & url)99 RenderFrameHost* NavigationSimulator::NavigateAndCommitFromBrowser(
100     WebContents* web_contents,
101     const GURL& url) {
102   auto simulator =
103       NavigationSimulatorImpl::CreateBrowserInitiated(url, web_contents);
104   simulator->Commit();
105   return simulator->GetFinalRenderFrameHost();
106 }
107 
108 // static
Reload(WebContents * web_contents)109 RenderFrameHost* NavigationSimulator::Reload(WebContents* web_contents) {
110   NavigationEntry* entry =
111       web_contents->GetController().GetLastCommittedEntry();
112   CHECK(entry);
113   auto simulator = NavigationSimulatorImpl::CreateBrowserInitiated(
114       entry->GetURL(), web_contents);
115   simulator->SetReloadType(ReloadType::NORMAL);
116   simulator->Commit();
117   return simulator->GetFinalRenderFrameHost();
118 }
119 
120 // static
GoBack(WebContents * web_contents)121 RenderFrameHost* NavigationSimulator::GoBack(WebContents* web_contents) {
122   return GoToOffset(web_contents, -1);
123 }
124 
125 // static
GoForward(WebContents * web_contents)126 RenderFrameHost* NavigationSimulator::GoForward(WebContents* web_contents) {
127   return GoToOffset(web_contents, 1);
128 }
129 
130 // static
GoToOffset(WebContents * web_contents,int offset)131 RenderFrameHost* NavigationSimulator::GoToOffset(WebContents* web_contents,
132                                                  int offset) {
133   auto simulator =
134       NavigationSimulatorImpl::CreateHistoryNavigation(offset, web_contents);
135   simulator->Commit();
136   return simulator->GetFinalRenderFrameHost();
137 }
138 
139 // static
NavigateAndCommitFromDocument(const GURL & original_url,RenderFrameHost * render_frame_host)140 RenderFrameHost* NavigationSimulator::NavigateAndCommitFromDocument(
141     const GURL& original_url,
142     RenderFrameHost* render_frame_host) {
143   auto simulator = NavigationSimulator::CreateRendererInitiated(
144       original_url, render_frame_host);
145   simulator->Commit();
146   return simulator->GetFinalRenderFrameHost();
147 }
148 
149 // static
NavigateAndFailFromBrowser(WebContents * web_contents,const GURL & url,int net_error_code)150 RenderFrameHost* NavigationSimulator::NavigateAndFailFromBrowser(
151     WebContents* web_contents,
152     const GURL& url,
153     int net_error_code) {
154   auto simulator =
155       NavigationSimulator::CreateBrowserInitiated(url, web_contents);
156   simulator->Fail(net_error_code);
157   if (net_error_code == net::ERR_ABORTED)
158     return nullptr;
159   simulator->CommitErrorPage();
160   return simulator->GetFinalRenderFrameHost();
161 }
162 
163 // static
ReloadAndFail(WebContents * web_contents,int net_error_code)164 RenderFrameHost* NavigationSimulator::ReloadAndFail(WebContents* web_contents,
165                                                     int net_error_code) {
166   NavigationEntry* entry =
167       web_contents->GetController().GetLastCommittedEntry();
168   CHECK(entry);
169   auto simulator = NavigationSimulator::CreateBrowserInitiated(entry->GetURL(),
170                                                                web_contents);
171   simulator->SetReloadType(ReloadType::NORMAL);
172   simulator->Fail(net_error_code);
173   if (net_error_code == net::ERR_ABORTED)
174     return nullptr;
175   simulator->CommitErrorPage();
176   return simulator->GetFinalRenderFrameHost();
177 }
178 
179 // static
GoBackAndFail(WebContents * web_contents,int net_error_code)180 RenderFrameHost* NavigationSimulator::GoBackAndFail(WebContents* web_contents,
181                                                     int net_error_code) {
182   return GoToOffsetAndFail(web_contents, -1, net_error_code);
183 }
184 
185 // static
GoToOffsetAndFail(WebContents * web_contents,int offset,int net_error_code)186 RenderFrameHost* NavigationSimulator::GoToOffsetAndFail(
187     WebContents* web_contents,
188     int offset,
189     int net_error_code) {
190   auto simulator =
191       NavigationSimulator::CreateHistoryNavigation(offset, web_contents);
192   simulator->Fail(net_error_code);
193   if (net_error_code == net::ERR_ABORTED)
194     return nullptr;
195   simulator->CommitErrorPage();
196   return simulator->GetFinalRenderFrameHost();
197 }
198 
199 // static
NavigateAndFailFromDocument(const GURL & original_url,int net_error_code,RenderFrameHost * render_frame_host)200 RenderFrameHost* NavigationSimulator::NavigateAndFailFromDocument(
201     const GURL& original_url,
202     int net_error_code,
203     RenderFrameHost* render_frame_host) {
204   auto simulator = NavigationSimulator::CreateRendererInitiated(
205       original_url, render_frame_host);
206   simulator->Fail(net_error_code);
207   if (net_error_code == net::ERR_ABORTED)
208     return nullptr;
209   simulator->CommitErrorPage();
210   return simulator->GetFinalRenderFrameHost();
211 }
212 
213 // static
214 std::unique_ptr<NavigationSimulator>
CreateBrowserInitiated(const GURL & original_url,WebContents * web_contents)215 NavigationSimulator::CreateBrowserInitiated(const GURL& original_url,
216                                             WebContents* web_contents) {
217   return NavigationSimulatorImpl::CreateBrowserInitiated(original_url,
218                                                          web_contents);
219 }
220 
221 // static
222 std::unique_ptr<NavigationSimulatorImpl>
CreateBrowserInitiated(const GURL & original_url,WebContents * web_contents)223 NavigationSimulatorImpl::CreateBrowserInitiated(const GURL& original_url,
224                                                 WebContents* web_contents) {
225   return std::unique_ptr<NavigationSimulatorImpl>(new NavigationSimulatorImpl(
226       original_url, true /* browser_initiated */,
227       static_cast<WebContentsImpl*>(web_contents), nullptr));
228 }
229 
230 // static
231 std::unique_ptr<NavigationSimulator>
CreateHistoryNavigation(int offset,WebContents * web_contents)232 NavigationSimulator::CreateHistoryNavigation(int offset,
233                                              WebContents* web_contents) {
234   return NavigationSimulatorImpl::CreateHistoryNavigation(offset, web_contents);
235 }
236 
237 // static
238 std::unique_ptr<NavigationSimulatorImpl>
CreateHistoryNavigation(int offset,WebContents * web_contents)239 NavigationSimulatorImpl::CreateHistoryNavigation(int offset,
240                                                  WebContents* web_contents) {
241   auto simulator =
242       NavigationSimulatorImpl::CreateBrowserInitiated(GURL(), web_contents);
243   simulator->SetSessionHistoryOffset(offset);
244   return simulator;
245 }
246 
247 // static
248 std::unique_ptr<NavigationSimulator>
CreateRendererInitiated(const GURL & original_url,RenderFrameHost * render_frame_host)249 NavigationSimulator::CreateRendererInitiated(
250     const GURL& original_url,
251     RenderFrameHost* render_frame_host) {
252   return NavigationSimulatorImpl::CreateRendererInitiated(original_url,
253                                                           render_frame_host);
254 }
255 
256 // static
257 std::unique_ptr<NavigationSimulatorImpl>
CreateRendererInitiated(const GURL & original_url,RenderFrameHost * render_frame_host)258 NavigationSimulatorImpl::CreateRendererInitiated(
259     const GURL& original_url,
260     RenderFrameHost* render_frame_host) {
261   return std::unique_ptr<NavigationSimulatorImpl>(new NavigationSimulatorImpl(
262       original_url, false /* browser_initiated */,
263       static_cast<WebContentsImpl*>(
264           WebContents::FromRenderFrameHost(render_frame_host)),
265       static_cast<TestRenderFrameHost*>(render_frame_host)));
266 }
267 
268 // static
CreateFromPending(WebContents * contents)269 std::unique_ptr<NavigationSimulator> NavigationSimulator::CreateFromPending(
270     WebContents* contents) {
271   return NavigationSimulatorImpl::CreateFromPending(contents);
272 }
273 
274 // static
275 std::unique_ptr<NavigationSimulatorImpl>
CreateFromPending(WebContents * contents)276 NavigationSimulatorImpl::CreateFromPending(WebContents* contents) {
277   WebContentsImpl* contents_impl = static_cast<WebContentsImpl*>(contents);
278 
279   FrameTreeNode* frame_tree_node =
280       GetFrameTreeNodeForPendingEntry(contents_impl);
281   return NavigationSimulatorImpl::CreateFromPendingInFrame(frame_tree_node);
282 }
283 
284 // static
285 std::unique_ptr<NavigationSimulatorImpl>
CreateFromPendingInFrame(FrameTreeNode * frame_tree_node)286 NavigationSimulatorImpl::CreateFromPendingInFrame(
287     FrameTreeNode* frame_tree_node) {
288   CHECK(frame_tree_node);
289   TestRenderFrameHost* test_frame_host =
290       static_cast<TestRenderFrameHost*>(frame_tree_node->current_frame_host());
291   CHECK(test_frame_host);
292   NavigationRequest* request = frame_tree_node->navigation_request();
293   // It is possible to not have a NavigationRequest in the frame tree node if
294   // it did not go to the network (such as about:blank). In that case it is
295   // already in the RenderFrameHost.
296   if (!request)
297     request = test_frame_host->navigation_requests().begin()->second.get();
298   CHECK(request);
299 
300   // Simulate the BeforeUnload completion callback if needed.
301   if (request->state() == NavigationRequest::WAITING_FOR_RENDERER_RESPONSE)
302     test_frame_host->SimulateBeforeUnloadCompleted(true /* proceed */);
303 
304   auto simulator = base::WrapUnique(new NavigationSimulatorImpl(
305       GURL(), request->browser_initiated(),
306       WebContentsImpl::FromFrameTreeNode(frame_tree_node), test_frame_host));
307   simulator->frame_tree_node_ = frame_tree_node;
308   simulator->InitializeFromStartedRequest(request);
309   return simulator;
310 }
311 
NavigationSimulatorImpl(const GURL & original_url,bool browser_initiated,WebContentsImpl * web_contents,TestRenderFrameHost * render_frame_host)312 NavigationSimulatorImpl::NavigationSimulatorImpl(
313     const GURL& original_url,
314     bool browser_initiated,
315     WebContentsImpl* web_contents,
316     TestRenderFrameHost* render_frame_host)
317     : WebContentsObserver(web_contents),
318       web_contents_(web_contents),
319       render_frame_host_(render_frame_host),
320       frame_tree_node_(render_frame_host
321                            ? render_frame_host->frame_tree_node()
322                            : web_contents->GetMainFrame()->frame_tree_node()),
323       request_(nullptr),
324       original_url_(original_url),
325       navigation_url_(original_url),
326       initial_method_("GET"),
327       browser_initiated_(browser_initiated),
328       referrer_(blink::mojom::Referrer::New()),
329       transition_(browser_initiated ? ui::PAGE_TRANSITION_TYPED
330                                     : ui::PAGE_TRANSITION_LINK),
331       contents_mime_type_("text/html"),
332       load_url_params_(nullptr) {
333   net::IPAddress address;
334   CHECK(address.AssignFromIPLiteral("2001:db8::1"));
335   remote_endpoint_ = net::IPEndPoint(address, 80);
336 
337   // For renderer-initiated navigation, the RenderFrame must be initialized. Do
338   // it if it hasn't happened yet.
339   if (!browser_initiated)
340     render_frame_host->InitializeRenderFrameIfNeeded();
341 
342   if (render_frame_host && render_frame_host->GetParent()) {
343     if (!render_frame_host->frame_tree_node()->has_committed_real_load())
344       transition_ = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
345     else
346       transition_ = ui::PAGE_TRANSITION_MANUAL_SUBFRAME;
347   }
348 
349   mojo::PendingRemote<service_manager::mojom::InterfaceProvider>
350       stub_interface_provider;
351   interface_provider_receiver_ =
352       stub_interface_provider.InitWithNewPipeAndPassReceiver();
353   browser_interface_broker_receiver_ =
354       mojo::PendingRemote<blink::mojom::BrowserInterfaceBroker>()
355           .InitWithNewPipeAndPassReceiver();
356 }
357 
~NavigationSimulatorImpl()358 NavigationSimulatorImpl::~NavigationSimulatorImpl() {}
359 
SetIsPostWithId(int64_t post_id)360 void NavigationSimulatorImpl::SetIsPostWithId(int64_t post_id) {
361   post_id_ = post_id;
362   SetMethod("POST");
363 }
364 
InitializeFromStartedRequest(NavigationRequest * request)365 void NavigationSimulatorImpl::InitializeFromStartedRequest(
366     NavigationRequest* request) {
367   CHECK(request);
368   request_ = request;
369   CHECK(request_->IsNavigationStarted());
370   CHECK_EQ(web_contents_, request_->GetDelegate());
371   CHECK(render_frame_host_);
372   CHECK_EQ(frame_tree_node_, request_->frame_tree_node());
373   state_ = STARTED;
374   original_url_ = request->commit_params().original_url;
375   navigation_url_ = request_->GetURL();
376   // |remote_endpoint_| cannot be inferred from the request.
377   // |initial_method_| cannot be set after the request has started.
378   browser_initiated_ = request_->browser_initiated();
379   // |same_document_| should always be false here.
380   referrer_ = request_->common_params().referrer.Clone();
381   transition_ = request_->GetPageTransition();
382   // |reload_type_| cannot be set after the request has started.
383   // |session_history_offset_| cannot be set after the request has started.
384   has_user_gesture_ = request_->HasUserGesture();
385   // |contents_mime_type_| cannot be inferred from the request.
386 
387   // Add a throttle to count NavigationThrottle calls count. Bump
388   // num_did_start_navigation to account for the fact that the navigation handle
389   // has already been created.
390   num_did_start_navigation_called_++;
391   RegisterTestThrottle(request);
392   PrepareCompleteCallbackOnRequest();
393 }
394 
RegisterTestThrottle(NavigationRequest * request)395 void NavigationSimulatorImpl::RegisterTestThrottle(NavigationRequest* request) {
396   request->RegisterThrottleForTesting(
397       std::make_unique<NavigationThrottleCallbackRunner>(
398           request,
399           base::BindOnce(&NavigationSimulatorImpl::OnWillStartRequest,
400                          weak_factory_.GetWeakPtr()),
401           base::BindRepeating(&NavigationSimulatorImpl::OnWillRedirectRequest,
402                               weak_factory_.GetWeakPtr()),
403           base::BindOnce(&NavigationSimulatorImpl::OnWillFailRequest,
404                          weak_factory_.GetWeakPtr()),
405           base::BindOnce(&NavigationSimulatorImpl::OnWillProcessResponse,
406                          weak_factory_.GetWeakPtr())));
407 }
408 
Start()409 void NavigationSimulatorImpl::Start() {
410   CHECK(state_ == INITIALIZATION || state_ == WAITING_BEFORE_UNLOAD)
411       << "NavigationSimulatorImpl::Start should only be called once.";
412 
413   if (browser_initiated_) {
414     if (!SimulateBrowserInitiatedStart())
415       return;
416   } else {
417     if (!SimulateRendererInitiatedStart())
418       return;
419   }
420   state_ = STARTED;
421 
422   CHECK(request_);
423   if (IsRendererDebugURL(navigation_url_))
424     return;
425 
426   if (same_document_ || !IsURLHandledByNetworkStack(navigation_url_) ||
427       navigation_url_.IsAboutBlank()) {
428     CHECK_EQ(1, num_did_start_navigation_called_);
429     return;
430   }
431 
432   MaybeWaitForThrottleChecksComplete(base::BindOnce(
433       &NavigationSimulatorImpl::StartComplete, weak_factory_.GetWeakPtr()));
434 }
435 
StartComplete()436 void NavigationSimulatorImpl::StartComplete() {
437   CHECK_EQ(1, num_did_start_navigation_called_);
438   if (GetLastThrottleCheckResult().action() == NavigationThrottle::PROCEED) {
439     CHECK_EQ(1, num_will_start_request_called_);
440   } else {
441     state_ = FAILED;
442   }
443 }
444 
Redirect(const GURL & new_url)445 void NavigationSimulatorImpl::Redirect(const GURL& new_url) {
446   CHECK_LE(state_, STARTED) << "NavigationSimulatorImpl::Redirect should be "
447                                "called before Fail or Commit";
448   CHECK_EQ(0, num_did_finish_navigation_called_)
449       << "NavigationSimulatorImpl::Redirect cannot be called after the "
450          "navigation has finished";
451 
452   if (state_ < STARTED) {
453     Start();
454     if (state_ == FAILED)
455       return;
456   }
457 
458   navigation_url_ = new_url;
459 
460   int previous_num_will_redirect_request_called =
461       num_will_redirect_request_called_;
462   int previous_did_redirect_navigation_called =
463       num_did_redirect_navigation_called_;
464 
465   PrepareCompleteCallbackOnRequest();
466   NavigationRequest* request = frame_tree_node_->navigation_request();
467   CHECK(request) << "Trying to redirect a navigation that does not go to the "
468                     "network stack.";
469 
470   TestNavigationURLLoader* url_loader =
471       static_cast<TestNavigationURLLoader*>(request->loader_for_testing());
472   CHECK(url_loader);
473 
474   net::RedirectInfo redirect_info;
475   redirect_info.status_code = 302;
476   redirect_info.new_method = "GET";
477   redirect_info.new_url = new_url;
478   redirect_info.new_site_for_cookies = net::SiteForCookies::FromUrl(new_url);
479   redirect_info.new_referrer = referrer_->url.spec();
480   redirect_info.new_referrer_policy =
481       Referrer::ReferrerPolicyForUrlRequest(referrer_->policy);
482   auto response = network::mojom::URLResponseHead::New();
483   response->connection_info = http_connection_info_;
484   response->ssl_info = ssl_info_;
485 
486   url_loader->CallOnRequestRedirected(redirect_info, std::move(response));
487 
488   MaybeWaitForThrottleChecksComplete(base::BindOnce(
489       &NavigationSimulatorImpl::RedirectComplete, weak_factory_.GetWeakPtr(),
490       previous_num_will_redirect_request_called,
491       previous_did_redirect_navigation_called));
492 }
493 
RedirectComplete(int previous_num_will_redirect_request_called,int previous_did_redirect_navigation_called)494 void NavigationSimulatorImpl::RedirectComplete(
495     int previous_num_will_redirect_request_called,
496     int previous_did_redirect_navigation_called) {
497   if (GetLastThrottleCheckResult().action() == NavigationThrottle::PROCEED) {
498     CHECK_EQ(previous_num_will_redirect_request_called + 1,
499              num_will_redirect_request_called_);
500     CHECK_EQ(previous_did_redirect_navigation_called + 1,
501              num_did_redirect_navigation_called_);
502   } else {
503     state_ = FAILED;
504   }
505 }
506 
ReadyToCommit()507 void NavigationSimulatorImpl::ReadyToCommit() {
508   CHECK_LE(state_, STARTED)
509       << "NavigationSimulatorImpl::ReadyToCommit can only "
510          "be called once, and cannot be called after "
511          "NavigationSimulatorImpl::Fail";
512   CHECK_EQ(0, num_did_finish_navigation_called_)
513       << "NavigationSimulatorImpl::ReadyToCommit cannot be called after the "
514          "navigation has finished";
515 
516   if (state_ < STARTED) {
517     if (block_invoking_before_unload_completed_callback_ &&
518         state_ == WAITING_BEFORE_UNLOAD) {
519       // The user should have simulated the BeforeUnloadCompleted by themselves.
520       // Finish the initialization and skip the Start simulation.
521       InitializeFromStartedRequest(request_);
522     } else {
523       Start();
524       if (state_ == FAILED)
525         return;
526     }
527   }
528 
529   if (!response_headers_) {
530     response_headers_ =
531         base::MakeRefCounted<net::HttpResponseHeaders>(std::string());
532   }
533   response_headers_->SetHeader("Content-Type", contents_mime_type_);
534   PrepareCompleteCallbackOnRequest();
535   if (frame_tree_node_->navigation_request()) {
536     static_cast<TestRenderFrameHost*>(frame_tree_node_->current_frame_host())
537         ->PrepareForCommitDeprecatedForNavigationSimulator(
538             remote_endpoint_, was_fetched_via_cache_,
539             is_signed_exchange_inner_response_, http_connection_info_,
540             ssl_info_, response_headers_);
541   }
542 
543   // Synchronous failure can cause the navigation to finish here.
544   if (!request_) {
545     state_ = FAILED;
546     return;
547   }
548 
549   bool needs_throttle_checks = !same_document_ &&
550                                !navigation_url_.IsAboutBlank() &&
551                                IsURLHandledByNetworkStack(navigation_url_);
552   auto complete_closure =
553       base::BindOnce(&NavigationSimulatorImpl::ReadyToCommitComplete,
554                      weak_factory_.GetWeakPtr(), needs_throttle_checks);
555   if (needs_throttle_checks) {
556     MaybeWaitForThrottleChecksComplete(std::move(complete_closure));
557     return;
558   }
559   std::move(complete_closure).Run();
560 }
561 
ReadyToCommitComplete(bool ran_throttles)562 void NavigationSimulatorImpl::ReadyToCommitComplete(bool ran_throttles) {
563   if (ran_throttles) {
564     if (GetLastThrottleCheckResult().action() != NavigationThrottle::PROCEED) {
565       state_ = FAILED;
566       return;
567     }
568     CHECK_EQ(1, num_will_process_response_called_);
569     CHECK_EQ(1, num_ready_to_commit_called_);
570   }
571 
572   request_id_ = request_->GetGlobalRequestID();
573 
574   // Update the RenderFrameHost now that we know which RenderFrameHost will
575   // commit the navigation.
576   render_frame_host_ =
577       static_cast<TestRenderFrameHost*>(request_->GetRenderFrameHost());
578   state_ = READY_TO_COMMIT;
579 }
580 
Commit()581 void NavigationSimulatorImpl::Commit() {
582   CHECK_LE(state_, READY_TO_COMMIT)
583       << "NavigationSimulatorImpl::Commit can only "
584          "be called once, and cannot be called "
585          "after NavigationSimulatorImpl::Fail";
586   CHECK_EQ(0, num_did_finish_navigation_called_)
587       << "NavigationSimulatorImpl::Commit cannot be called after the "
588          "navigation "
589          "has finished";
590 
591   if (state_ < READY_TO_COMMIT) {
592     ReadyToCommit();
593     if (state_ == FAILED || state_ == FINISHED)
594       return;
595   }
596 
597   // Keep a pointer to the current RenderFrameHost that may be pending deletion
598   // after commit.
599   RenderFrameHostImpl* previous_rfh =
600       render_frame_host_->frame_tree_node()->current_frame_host();
601 
602   // RenderDocument: Do not dispatch UnloadACK if the navigation was committed
603   // in the same SiteInstance. This has already been dispatched during the
604   // navigation in the renderer process.
605   if (previous_rfh->GetSiteInstance() == render_frame_host_->GetSiteInstance())
606     drop_unload_ack_ = true;
607 
608   // If the frame is not alive we do not displatch Unload ACK. CommitPending()
609   // may be called immediately and delete the old RenderFrameHost, so we need to
610   // record that now while we can still access the object.
611   if (!previous_rfh->IsRenderFrameLive())
612     drop_unload_ack_ = true;
613 
614   if (same_document_) {
615     interface_provider_receiver_.reset();
616     browser_interface_broker_receiver_.reset();
617   }
618 
619   auto params = BuildDidCommitProvisionalLoadParams(
620       same_document_ /* same_document */, false /* failed_navigation */);
621   render_frame_host_->SimulateCommitProcessed(
622       request_, std::move(params), std::move(interface_provider_receiver_),
623       std::move(browser_interface_broker_receiver_), same_document_);
624 
625   if (previous_rfh)
626     SimulateUnloadCompletionCallbackForPreviousFrameIfNeeded(previous_rfh);
627 
628   loading_scenario_ =
629       TestRenderFrameHost::LoadingScenario::NewDocumentNavigation;
630   state_ = FINISHED;
631   if (!keep_loading_)
632     StopLoading();
633 
634   if (!IsRendererDebugURL(navigation_url_))
635     CHECK_EQ(1, num_did_finish_navigation_called_);
636 }
637 
AbortCommit()638 void NavigationSimulatorImpl::AbortCommit() {
639   CHECK_LE(state_, FAILED)
640       << "NavigationSimulatorImpl::AbortCommit cannot be called after "
641          "NavigationSimulatorImpl::Commit or  "
642          "NavigationSimulatorImpl::CommitErrorPage.";
643   if (state_ < READY_TO_COMMIT) {
644     ReadyToCommit();
645     if (state_ == FINISHED)
646       return;
647   }
648 
649   CHECK(render_frame_host_)
650       << "NavigationSimulatorImpl::AbortCommit can only be "
651          "called for navigations that commit.";
652   render_frame_host_->AbortCommit(request_);
653 
654   state_ = FINISHED;
655   StopLoading();
656 
657   CHECK_EQ(1, num_did_finish_navigation_called_);
658 }
659 
AbortFromRenderer()660 void NavigationSimulatorImpl::AbortFromRenderer() {
661   CHECK(!browser_initiated_)
662       << "NavigationSimulatorImpl::AbortFromRenderer cannot be called for "
663          "browser-initiated navigation.";
664   CHECK_LE(state_, FAILED)
665       << "NavigationSimulatorImpl::AbortFromRenderer cannot be called after "
666          "NavigationSimulatorImpl::Commit or  "
667          "NavigationSimulatorImpl::CommitErrorPage.";
668 
669   was_aborted_ = true;
670   request_->RendererAbortedNavigationForTesting();
671   state_ = FINISHED;
672 
673   CHECK_EQ(1, num_did_finish_navigation_called_);
674 }
675 
Fail(int error_code)676 void NavigationSimulatorImpl::Fail(int error_code) {
677   CHECK_LE(state_, STARTED) << "NavigationSimulatorImpl::Fail can only be "
678                                "called once, and cannot be called after "
679                                "NavigationSimulatorImpl::ReadyToCommit";
680   CHECK_EQ(0, num_did_finish_navigation_called_)
681       << "NavigationSimulatorImpl::Fail cannot be called after the "
682          "navigation has finished";
683   CHECK(!IsRendererDebugURL(navigation_url_));
684 
685   if (state_ == INITIALIZATION)
686     Start();
687 
688   state_ = FAILED;
689 
690   PrepareCompleteCallbackOnRequest();
691   CHECK(request_);
692   TestNavigationURLLoader* url_loader =
693       static_cast<TestNavigationURLLoader*>(request_->loader_for_testing());
694   CHECK(url_loader);
695   network::URLLoaderCompletionStatus status(error_code);
696   status.resolve_error_info = resolve_error_info_;
697   status.ssl_info = ssl_info_;
698   url_loader->SimulateErrorWithStatus(status);
699 
700   auto complete_closure =
701       base::BindOnce(&NavigationSimulatorImpl::FailComplete,
702                      weak_factory_.GetWeakPtr(), error_code);
703   if (error_code != net::ERR_ABORTED) {
704     MaybeWaitForThrottleChecksComplete(std::move(complete_closure));
705     return;
706   }
707   std::move(complete_closure).Run();
708 }
709 
FailComplete(int error_code)710 void NavigationSimulatorImpl::FailComplete(int error_code) {
711   bool should_result_in_error_page = error_code != net::ERR_ABORTED;
712   if (error_code != net::ERR_ABORTED) {
713     NavigationThrottle::ThrottleCheckResult result =
714         GetLastThrottleCheckResult();
715     if (result.action() == NavigationThrottle::CANCEL ||
716         result.action() == NavigationThrottle::CANCEL_AND_IGNORE) {
717       should_result_in_error_page = false;
718     }
719   }
720 
721   if (should_result_in_error_page) {
722     // TODO(clamy): Check that ReadyToCommit has been called once, once the test
723     // architecture of NavigationRequest vs NavigationHandle has been clarified.
724     // Currently, when auto-advance is off, this function will be called before
725     // NavigationRequest::CommitErrorPage which is the one that triggers the
726     // call to observers.
727     CHECK_EQ(0, num_did_finish_navigation_called_);
728     // Update the RenderFrameHost now that we know which RenderFrameHost will
729     // commit the error page.
730     render_frame_host_ =
731         static_cast<TestRenderFrameHost*>(request_->GetRenderFrameHost());
732   }
733 }
734 
CommitErrorPage()735 void NavigationSimulatorImpl::CommitErrorPage() {
736   CHECK_EQ(FAILED, state_)
737       << "NavigationSimulatorImpl::CommitErrorPage can only be "
738          "called once, and should be called after Fail "
739          "has been called";
740   CHECK_EQ(0, num_did_finish_navigation_called_)
741       << "NavigationSimulatorImpl::CommitErrorPage cannot be called after the "
742          "navigation has finished";
743 
744   // Keep a pointer to the current RenderFrameHost that may be pending deletion
745   // after commit.
746   // RenderDocument: The |previous_rfh| might also be immediately deleted after
747   // commit, because it has already run its unload handler.
748   RenderFrameHostImpl* previous_rfh =
749       render_frame_host_->frame_tree_node()->current_frame_host();
750 
751   // RenderDocument: Do not dispatch UnloadACK if the navigation was committed
752   // in the same SiteInstance. This has already been dispatched during the
753   // navigation in the renderer process.
754   if (previous_rfh->GetSiteInstance() == render_frame_host_->GetSiteInstance())
755     drop_unload_ack_ = true;
756 
757   // If the frame is not alive we do not displatch Unload ACK. CommitPending()
758   // may be called immediately and delete the old RenderFrameHost, so we need to
759   // record that now while we can still access the object.
760   if (!previous_rfh->IsRenderFrameLive())
761     drop_unload_ack_ = true;
762 
763   auto params = BuildDidCommitProvisionalLoadParams(
764       false /* same_document */, true /* failed_navigation */);
765   render_frame_host_->SimulateCommitProcessed(
766       request_, std::move(params), std::move(interface_provider_receiver_),
767       std::move(browser_interface_broker_receiver_), false /* same_document */);
768 
769   SimulateUnloadCompletionCallbackForPreviousFrameIfNeeded(previous_rfh);
770 
771   state_ = FINISHED;
772   if (!keep_loading_)
773     StopLoading();
774 
775   CHECK_EQ(1, num_did_finish_navigation_called_);
776 }
777 
CommitSameDocument()778 void NavigationSimulatorImpl::CommitSameDocument() {
779   if (!browser_initiated_) {
780     CHECK_EQ(INITIALIZATION, state_)
781         << "NavigationSimulatorImpl::CommitSameDocument should be the only "
782            "navigation event function called on the NavigationSimulatorImpl";
783   } else {
784     // This function is intended for same document navigations initiating from
785     // the renderer. For regular same document navigations simply use Commit().
786     Commit();
787     return;
788   }
789 
790   auto params = BuildDidCommitProvisionalLoadParams(
791       true /* same_document */, false /* failed_navigation */);
792 
793   interface_provider_receiver_.reset();
794   browser_interface_broker_receiver_.reset();
795 
796   render_frame_host_->SimulateCommitProcessed(
797       request_, std::move(params),
798       mojo::NullReceiver() /* interface_provider_receiver_ */,
799       mojo::NullReceiver() /* browser_interface_broker_receiver */,
800       true /* same_document */);
801 
802   // Same-document commits should never hit network-related stages of committing
803   // a navigation.
804   CHECK_EQ(0, num_will_start_request_called_);
805   CHECK_EQ(0, num_will_process_response_called_);
806   CHECK_EQ(0, num_ready_to_commit_called_);
807 
808   if (num_did_finish_navigation_called_ == 0) {
809     // Fail the navigation if it results in a process kill (e.g. see
810     // NavigatorTestWithBrowserSideNavigation.CrossSiteClaimWithinPage test).
811     state_ = FAILED;
812     return;
813   }
814   loading_scenario_ =
815       TestRenderFrameHost::LoadingScenario::kSameDocumentNavigation;
816   state_ = FINISHED;
817   if (!keep_loading_)
818     StopLoading();
819 
820   CHECK_EQ(1, num_did_start_navigation_called_);
821   CHECK_EQ(1, num_did_finish_navigation_called_);
822 }
823 
SetInitiatorFrame(RenderFrameHost * initiator_frame_host)824 void NavigationSimulatorImpl::SetInitiatorFrame(
825     RenderFrameHost* initiator_frame_host) {
826   // Browser-initiated navigations are not associated with an initiator frame.
827   CHECK(!browser_initiated_);
828   CHECK(initiator_frame_host);
829 
830   // TODO(https://crbug.com/1072790): Support cross-process initiators here by
831   // using NavigationRequest::CreateBrowserInitiated() (like
832   // RenderFrameProxyHost does) for the navigation.
833   CHECK_EQ(render_frame_host_->GetProcess(), initiator_frame_host->GetProcess())
834       << "The initiator frame must belong to the same process as the frame you "
835          "are navigating";
836   initiator_frame_host_ = initiator_frame_host;
837 }
838 
SetTransition(ui::PageTransition transition)839 void NavigationSimulatorImpl::SetTransition(ui::PageTransition transition) {
840   if (frame_tree_node_ && !frame_tree_node_->IsMainFrame()) {
841     // Subframe case. The subframe page transition is only set at commit time in
842     // the navigation code, so it can be modified later in time.
843     CHECK(PageTransitionCoreTypeIs(transition,
844                                    ui::PAGE_TRANSITION_AUTO_SUBFRAME) ||
845           PageTransitionCoreTypeIs(transition,
846                                    ui::PAGE_TRANSITION_MANUAL_SUBFRAME))
847         << "The transition type is not appropriate for a subframe";
848   } else {
849     CHECK_EQ(INITIALIZATION, state_)
850         << "The transition cannot be set after the navigation has started";
851     CHECK_EQ(ReloadType::NONE, reload_type_)
852         << "The transition cannot be specified for reloads";
853     CHECK_EQ(0, session_history_offset_)
854         << "The transition cannot be specified for back/forward navigations";
855   }
856   transition_ = transition;
857 }
858 
SetHasUserGesture(bool has_user_gesture)859 void NavigationSimulatorImpl::SetHasUserGesture(bool has_user_gesture) {
860   CHECK_EQ(INITIALIZATION, state_) << "The has_user_gesture parameter cannot "
861                                       "be set after the navigation has started";
862   has_user_gesture_ = has_user_gesture;
863 }
864 
SetReloadType(ReloadType reload_type)865 void NavigationSimulatorImpl::SetReloadType(ReloadType reload_type) {
866   CHECK_EQ(INITIALIZATION, state_) << "The reload_type parameter cannot "
867                                       "be set after the navigation has started";
868   CHECK(browser_initiated_) << "The reload_type parameter can only be set for "
869                                "browser-intiated navigations";
870   CHECK_EQ(0, session_history_offset_)
871       << "The reload_type parameter cannot be set for "
872          "session history navigations";
873   reload_type_ = reload_type;
874   if (reload_type_ != ReloadType::NONE)
875     transition_ = ui::PAGE_TRANSITION_RELOAD;
876 }
877 
SetMethod(const std::string & method)878 void NavigationSimulatorImpl::SetMethod(const std::string& method) {
879   CHECK_EQ(INITIALIZATION, state_) << "The method parameter cannot "
880                                       "be set after the navigation has started";
881   initial_method_ = method;
882 }
883 
SetIsFormSubmission(bool is_form_submission)884 void NavigationSimulatorImpl::SetIsFormSubmission(bool is_form_submission) {
885   CHECK_EQ(INITIALIZATION, state_) << "The form submission parameter cannot "
886                                       "be set after the navigation has started";
887   is_form_submission_ = is_form_submission;
888 }
889 
SetWasInitiatedByLinkClick(bool was_initiated_by_link_click)890 void NavigationSimulatorImpl::SetWasInitiatedByLinkClick(
891     bool was_initiated_by_link_click) {
892   CHECK_EQ(INITIALIZATION, state_) << "The form submission parameter cannot "
893                                       "be set after the navigation has started";
894   was_initiated_by_link_click_ = was_initiated_by_link_click;
895 }
896 
SetReferrer(blink::mojom::ReferrerPtr referrer)897 void NavigationSimulatorImpl::SetReferrer(blink::mojom::ReferrerPtr referrer) {
898   CHECK_LE(state_, STARTED) << "The referrer cannot be set after the "
899                                "navigation has committed or has failed";
900   referrer_ = std::move(referrer);
901 }
902 
SetSocketAddress(const net::IPEndPoint & remote_endpoint)903 void NavigationSimulatorImpl::SetSocketAddress(
904     const net::IPEndPoint& remote_endpoint) {
905   CHECK_LE(state_, STARTED) << "The socket address cannot be set after the "
906                                "navigation has committed or failed";
907   remote_endpoint_ = remote_endpoint;
908 }
909 
SetWasFetchedViaCache(bool was_fetched_via_cache)910 void NavigationSimulatorImpl::SetWasFetchedViaCache(
911     bool was_fetched_via_cache) {
912   CHECK_LE(state_, STARTED) << "The was_fetched_via_cache flag cannot be set "
913                                "after the navigation has committed or failed";
914   was_fetched_via_cache_ = was_fetched_via_cache;
915 }
916 
SetIsSignedExchangeInnerResponse(bool is_signed_exchange_inner_response)917 void NavigationSimulatorImpl::SetIsSignedExchangeInnerResponse(
918     bool is_signed_exchange_inner_response) {
919   CHECK_LE(state_, STARTED) << "The signed exchange flag cannot be set after "
920                                "the navigation has committed or failed";
921   is_signed_exchange_inner_response_ = is_signed_exchange_inner_response;
922 }
923 
SetInterfaceProviderReceiver(mojo::PendingReceiver<service_manager::mojom::InterfaceProvider> receiver)924 void NavigationSimulatorImpl::SetInterfaceProviderReceiver(
925     mojo::PendingReceiver<service_manager::mojom::InterfaceProvider> receiver) {
926   CHECK_LE(state_, STARTED) << "The InterfaceProvider cannot be set "
927                                "after the navigation has committed or failed";
928   CHECK(receiver.is_valid());
929   interface_provider_receiver_ = std::move(receiver);
930 }
931 
SetContentsMimeType(const std::string & contents_mime_type)932 void NavigationSimulatorImpl::SetContentsMimeType(
933     const std::string& contents_mime_type) {
934   CHECK_LE(state_, STARTED) << "The contents mime type cannot be set after the "
935                                "navigation has committed or failed";
936   contents_mime_type_ = contents_mime_type;
937 }
938 
SetResponseHeaders(scoped_refptr<net::HttpResponseHeaders> response_headers)939 void NavigationSimulatorImpl::SetResponseHeaders(
940     scoped_refptr<net::HttpResponseHeaders> response_headers) {
941   CHECK_LE(state_, STARTED) << "The response headers cannot be set after the "
942                                "navigation has committed or failed";
943   response_headers_ = response_headers;
944 }
945 
SetLoadURLParams(NavigationController::LoadURLParams * load_url_params)946 void NavigationSimulatorImpl::SetLoadURLParams(
947     NavigationController::LoadURLParams* load_url_params) {
948   load_url_params_ = load_url_params;
949 
950   // Make sure the internal attributes of NavigationSimulatorImpl match the
951   // LoadURLParams that is going to be sent.
952   referrer_ = blink::mojom::Referrer::New(load_url_params->referrer.url,
953                                           load_url_params->referrer.policy);
954   transition_ = load_url_params->transition_type;
955 }
956 
SetAutoAdvance(bool auto_advance)957 void NavigationSimulatorImpl::SetAutoAdvance(bool auto_advance) {
958   auto_advance_ = auto_advance;
959 }
960 
SetResolveErrorInfo(const net::ResolveErrorInfo & resolve_error_info)961 void NavigationSimulatorImpl::SetResolveErrorInfo(
962     const net::ResolveErrorInfo& resolve_error_info) {
963   resolve_error_info_ = resolve_error_info;
964 }
965 
SetSSLInfo(const net::SSLInfo & ssl_info)966 void NavigationSimulatorImpl::SetSSLInfo(const net::SSLInfo& ssl_info) {
967   ssl_info_ = ssl_info;
968 }
969 
970 NavigationThrottle::ThrottleCheckResult
GetLastThrottleCheckResult()971 NavigationSimulatorImpl::GetLastThrottleCheckResult() {
972   return last_throttle_check_result_.value();
973 }
974 
GetNavigationHandle()975 NavigationRequest* NavigationSimulatorImpl::GetNavigationHandle() {
976   CHECK_GE(state_, STARTED);
977   return request_;
978 }
979 
GetGlobalRequestID()980 content::GlobalRequestID NavigationSimulatorImpl::GetGlobalRequestID() {
981   CHECK_GT(state_, STARTED) << "The GlobalRequestID is not available until "
982                                "after the navigation has completed "
983                                "WillProcessResponse";
984   return request_id_;
985 }
986 
BrowserInitiatedStartAndWaitBeforeUnload()987 void NavigationSimulatorImpl::BrowserInitiatedStartAndWaitBeforeUnload() {
988   if (reload_type_ != ReloadType::NONE) {
989     web_contents_->GetController().Reload(reload_type_,
990                                           false /*check_for_repost */);
991   } else if (session_history_offset_) {
992     web_contents_->GetController().GoToOffset(session_history_offset_);
993   } else {
994     if (load_url_params_) {
995       web_contents_->GetController().LoadURLWithParams(*load_url_params_);
996       load_url_params_ = nullptr;
997     } else {
998       NavigationController::LoadURLParams load_url_params(navigation_url_);
999       load_url_params.referrer = Referrer(*referrer_);
1000       load_url_params.transition_type = transition_;
1001       if (initial_method_ == "POST")
1002         load_url_params.load_type = NavigationController::LOAD_TYPE_HTTP_POST;
1003 
1004       web_contents_->GetController().LoadURLWithParams(load_url_params);
1005     }
1006   }
1007 
1008   frame_tree_node_ = GetFrameTreeNodeForPendingEntry(web_contents_);
1009   CHECK(frame_tree_node_);
1010   render_frame_host_ =
1011       static_cast<TestRenderFrameHost*>(frame_tree_node_->current_frame_host());
1012 
1013   // The navigation url might have been rewritten by the NavigationController.
1014   // Update it.
1015   navigation_url_ = web_contents_->GetController().GetPendingEntry()->GetURL();
1016 
1017   state_ = WAITING_BEFORE_UNLOAD;
1018 }
1019 
DidStartNavigation(NavigationHandle * navigation_handle)1020 void NavigationSimulatorImpl::DidStartNavigation(
1021     NavigationHandle* navigation_handle) {
1022   // Check if this navigation is the one we're simulating.
1023   if (request_)
1024     return;
1025 
1026   NavigationRequest* request = NavigationRequest::From(navigation_handle);
1027 
1028   if (request->frame_tree_node() != frame_tree_node_)
1029     return;
1030 
1031   request_ = request;
1032   num_did_start_navigation_called_++;
1033 
1034   // Add a throttle to count NavigationThrottle calls count.
1035   RegisterTestThrottle(request);
1036   PrepareCompleteCallbackOnRequest();
1037 }
1038 
DidRedirectNavigation(NavigationHandle * navigation_handle)1039 void NavigationSimulatorImpl::DidRedirectNavigation(
1040     NavigationHandle* navigation_handle) {
1041   if (request_ == navigation_handle)
1042     num_did_redirect_navigation_called_++;
1043 }
1044 
ReadyToCommitNavigation(NavigationHandle * navigation_handle)1045 void NavigationSimulatorImpl::ReadyToCommitNavigation(
1046     NavigationHandle* navigation_handle) {
1047   if (request_ && navigation_handle == request_)
1048     num_ready_to_commit_called_++;
1049 }
1050 
DidFinishNavigation(NavigationHandle * navigation_handle)1051 void NavigationSimulatorImpl::DidFinishNavigation(
1052     NavigationHandle* navigation_handle) {
1053   NavigationRequest* request = NavigationRequest::From(navigation_handle);
1054   if (request == request_) {
1055     num_did_finish_navigation_called_++;
1056     if (navigation_handle->IsServedFromBackForwardCache()) {
1057       // Back-forward cache navigations commit and finish synchronously, unlike
1058       // all other navigations, which wait for a reply from the renderer.
1059       // The |state_| is normally updated to 'FINISHED' when we simulate a
1060       // renderer reply at the end of the NavigationSimulatorImpl::Commit()
1061       // function, but we have not reached this stage yet.
1062       // Set |state_| to FINISHED to ensure that we would not try to simulate
1063       // navigation commit for the second time.
1064       RenderFrameHostImpl* previous_rfh = RenderFrameHostImpl::FromID(
1065           navigation_handle->GetPreviousRenderFrameHostId());
1066       CHECK(previous_rfh) << "Previous RenderFrameHost should not be destroyed "
1067                              "without a Unload_ACK";
1068 
1069       // If the frame is not alive we do not displatch Unload ACK.
1070       // CommitPending() may be called immediately and delete the old
1071       // RenderFrameHost, so we need to record that now while we can still
1072       // access the object.
1073       if (!previous_rfh->IsRenderFrameLive())
1074         drop_unload_ack_ = true;
1075       SimulateUnloadCompletionCallbackForPreviousFrameIfNeeded(previous_rfh);
1076       state_ = FINISHED;
1077     }
1078     request_ = nullptr;
1079     if (was_aborted_)
1080       CHECK_EQ(net::ERR_ABORTED, request->GetNetErrorCode());
1081   }
1082 }
1083 
OnWillStartRequest()1084 void NavigationSimulatorImpl::OnWillStartRequest() {
1085   num_will_start_request_called_++;
1086 }
1087 
OnWillRedirectRequest()1088 void NavigationSimulatorImpl::OnWillRedirectRequest() {
1089   num_will_redirect_request_called_++;
1090 }
1091 
OnWillFailRequest()1092 void NavigationSimulatorImpl::OnWillFailRequest() {
1093   num_will_fail_request_called_++;
1094 }
1095 
OnWillProcessResponse()1096 void NavigationSimulatorImpl::OnWillProcessResponse() {
1097   num_will_process_response_called_++;
1098 }
1099 
SimulateBrowserInitiatedStart()1100 bool NavigationSimulatorImpl::SimulateBrowserInitiatedStart() {
1101   if (state_ == INITIALIZATION)
1102     BrowserInitiatedStartAndWaitBeforeUnload();
1103 
1104   // Simulate the BeforeUnload completion callback if needed.
1105   NavigationRequest* request = frame_tree_node_->navigation_request();
1106   if (request &&
1107       request->state() == NavigationRequest::WAITING_FOR_RENDERER_RESPONSE) {
1108     if (block_invoking_before_unload_completed_callback_) {
1109       // Since we do not simulate the BeforeUnloadCompleted, DidStartNavigation
1110       // will not have been called, and |request_| will not be properly set. Do
1111       // it manually.
1112       request_ = request;
1113       return false;
1114     }
1115     render_frame_host_->SimulateBeforeUnloadCompleted(true /* proceed */);
1116   }
1117 
1118   // Note: WillStartRequest checks can destroy the request synchronously, or
1119   // this can be a navigation that doesn't need a network request and that was
1120   // passed directly to a RenderFrameHost for commit.
1121   request =
1122       web_contents_->GetMainFrame()->frame_tree_node()->navigation_request();
1123   if (!request) {
1124     if (IsRendererDebugURL(navigation_url_)) {
1125       // We don't create NavigationRequests nor NavigationHandles for a
1126       // navigation to a renderer-debug URL. Instead, the URL is passed to the
1127       // current RenderFrameHost so that the renderer process can handle it.
1128       CHECK(!request_);
1129       CHECK(web_contents_->GetMainFrame()->is_loading());
1130 
1131       // A navigation to a renderer-debug URL cannot commit. Simulate the
1132       // renderer process aborting it.
1133       render_frame_host_ =
1134           static_cast<TestRenderFrameHost*>(web_contents_->GetMainFrame());
1135       StopLoading();
1136       state_ = FAILED;
1137       return false;
1138     } else if (request_ &&
1139                web_contents_->GetMainFrame()->navigation_request() ==
1140                    request_) {
1141       CHECK(!IsURLHandledByNetworkStack(request_->common_params().url));
1142       return true;
1143     } else if (web_contents_->GetMainFrame()
1144                    ->same_document_navigation_request() &&
1145                web_contents_->GetMainFrame()
1146                        ->same_document_navigation_request() == request_) {
1147       CHECK(request_->IsSameDocument());
1148       same_document_ = true;
1149       return true;
1150     }
1151     return false;
1152   }
1153 
1154   CHECK_EQ(request_, request);
1155   return true;
1156 }
1157 
SimulateRendererInitiatedStart()1158 bool NavigationSimulatorImpl::SimulateRendererInitiatedStart() {
1159   mojom::BeginNavigationParamsPtr begin_params =
1160       mojom::BeginNavigationParams::New(
1161           initiator_frame_host_ ? initiator_frame_host_->GetRoutingID()
1162                                 : MSG_ROUTING_NONE /* initiator_routing_id */,
1163           std::string() /* headers */, net::LOAD_NORMAL,
1164           false /* skip_service_worker */,
1165           blink::mojom::RequestContextType::HYPERLINK,
1166           network::mojom::RequestDestination::kDocument,
1167           blink::WebMixedContentContextType::kBlockable, is_form_submission_,
1168           was_initiated_by_link_click_, GURL() /* searchable_form_url */,
1169           std::string() /* searchable_form_encoding */,
1170           GURL() /* client_side_redirect_url */,
1171           base::nullopt /* detools_initiator_info */,
1172           false /* force_ignore_site_for_cookies */,
1173           nullptr /* trust_token_params */, impression_,
1174           base::TimeTicks() /* renderer_before_unload_start */,
1175           base::TimeTicks() /* renderer_before_unload_end */);
1176   auto common_params = CreateCommonNavigationParams();
1177   common_params->navigation_start = base::TimeTicks::Now();
1178   common_params->url = navigation_url_;
1179   common_params->initiator_origin = url::Origin();
1180   common_params->method = initial_method_;
1181   common_params->referrer = referrer_.Clone();
1182   common_params->transition = transition_;
1183   common_params->navigation_type =
1184       PageTransitionCoreTypeIs(transition_, ui::PAGE_TRANSITION_RELOAD)
1185           ? mojom::NavigationType::RELOAD
1186           : mojom::NavigationType::DIFFERENT_DOCUMENT;
1187   common_params->has_user_gesture = has_user_gesture_;
1188   common_params->initiator_csp_info = mojom::InitiatorCSPInfo::New(
1189       should_check_main_world_csp_,
1190       std::vector<network::mojom::ContentSecurityPolicyPtr>(), nullptr);
1191 
1192   mojo::PendingAssociatedRemote<mojom::NavigationClient>
1193       navigation_client_remote;
1194   navigation_client_receiver_ =
1195       navigation_client_remote.InitWithNewEndpointAndPassReceiver();
1196   render_frame_host_->frame_host_receiver_for_testing().impl()->BeginNavigation(
1197       std::move(common_params), std::move(begin_params), mojo::NullRemote(),
1198       std::move(navigation_client_remote), mojo::NullRemote());
1199 
1200   NavigationRequest* request =
1201       render_frame_host_->frame_tree_node()->navigation_request();
1202 
1203   // The request failed synchronously.
1204   if (!request)
1205     return false;
1206 
1207   CHECK_EQ(request_, request);
1208   return true;
1209 }
1210 
MaybeWaitForThrottleChecksComplete(base::OnceClosure complete_closure)1211 void NavigationSimulatorImpl::MaybeWaitForThrottleChecksComplete(
1212     base::OnceClosure complete_closure) {
1213   // If last_throttle_check_result_ is set, then throttle checks completed
1214   // synchronously.
1215   if (last_throttle_check_result_) {
1216     std::move(complete_closure).Run();
1217     return;
1218   }
1219 
1220   throttle_checks_complete_closure_ = std::move(complete_closure);
1221   if (auto_advance_)
1222     Wait();
1223 }
1224 
Wait()1225 void NavigationSimulatorImpl::Wait() {
1226   CHECK(!wait_closure_);
1227   if (!IsDeferred())
1228     return;
1229   base::RunLoop run_loop;
1230   wait_closure_ = run_loop.QuitClosure();
1231   run_loop.Run();
1232 }
1233 
OnThrottleChecksComplete(NavigationThrottle::ThrottleCheckResult result)1234 bool NavigationSimulatorImpl::OnThrottleChecksComplete(
1235     NavigationThrottle::ThrottleCheckResult result) {
1236   CHECK(!last_throttle_check_result_);
1237   last_throttle_check_result_ = result;
1238   if (wait_closure_)
1239     std::move(wait_closure_).Run();
1240   if (throttle_checks_complete_closure_)
1241     std::move(throttle_checks_complete_closure_).Run();
1242   return false;
1243 }
1244 
PrepareCompleteCallbackOnRequest()1245 void NavigationSimulatorImpl::PrepareCompleteCallbackOnRequest() {
1246   last_throttle_check_result_.reset();
1247   request_->set_complete_callback_for_testing(
1248       base::BindOnce(&NavigationSimulatorImpl::OnThrottleChecksComplete,
1249                      base::Unretained(this)));
1250 }
1251 
GetFinalRenderFrameHost()1252 RenderFrameHost* NavigationSimulatorImpl::GetFinalRenderFrameHost() {
1253   CHECK_GE(state_, READY_TO_COMMIT);
1254   return render_frame_host_;
1255 }
1256 
IsDeferred()1257 bool NavigationSimulatorImpl::IsDeferred() {
1258   return !throttle_checks_complete_closure_.is_null();
1259 }
1260 
CheckIfSameDocument()1261 bool NavigationSimulatorImpl::CheckIfSameDocument() {
1262   // This approach to determining whether a navigation is to be treated as
1263   // same document is not robust, as it will not handle pushState type
1264   // navigation. Do not use elsewhere!
1265 
1266   // First we need a valid document that is not an error page.
1267   if (!render_frame_host_->GetLastCommittedURL().is_valid() ||
1268       render_frame_host_->last_commit_was_error_page()) {
1269     return false;
1270   }
1271 
1272   // Exclude reloads.
1273   if (ui::PageTransitionCoreTypeIs(transition_, ui::PAGE_TRANSITION_RELOAD)) {
1274     return false;
1275   }
1276 
1277   // A browser-initiated navigation to the exact same url in the address bar is
1278   // not a same document navigation.
1279   if (browser_initiated_ &&
1280       render_frame_host_->GetLastCommittedURL() == navigation_url_) {
1281     return false;
1282   }
1283 
1284   // Finally, the navigation url and the last committed url should match,
1285   // except for the fragment.
1286   GURL url_copy(navigation_url_);
1287   url::Replacements<char> replacements;
1288   replacements.ClearRef();
1289   return url_copy.ReplaceComponents(replacements) ==
1290          render_frame_host_->GetLastCommittedURL().ReplaceComponents(
1291              replacements);
1292 }
1293 
DidCreateNewEntry()1294 bool NavigationSimulatorImpl::DidCreateNewEntry() {
1295   if (did_create_new_entry_.has_value())
1296     return did_create_new_entry_.value();
1297   if (ui::PageTransitionCoreTypeIs(transition_,
1298                                    ui::PAGE_TRANSITION_AUTO_SUBFRAME))
1299     return false;
1300   if (reload_type_ != ReloadType::NONE ||
1301       (request_ && NavigationTypeUtils::IsReload(
1302                        request_->common_params().navigation_type))) {
1303     return false;
1304   }
1305   if (session_history_offset_ ||
1306       (request_ && NavigationTypeUtils::IsHistory(
1307                        request_->common_params().navigation_type))) {
1308     return false;
1309   }
1310   if (request_ && (request_->common_params().navigation_type ==
1311                        mojom::NavigationType::RESTORE ||
1312                    request_->common_params().navigation_type ==
1313                        mojom::NavigationType::RESTORE_WITH_POST)) {
1314     return false;
1315   }
1316 
1317   return true;
1318 }
1319 
SetSessionHistoryOffset(int session_history_offset)1320 void NavigationSimulatorImpl::SetSessionHistoryOffset(
1321     int session_history_offset) {
1322   CHECK(session_history_offset);
1323   session_history_offset_ = session_history_offset;
1324   transition_ =
1325       ui::PageTransitionFromInt(transition_ | ui::PAGE_TRANSITION_FORWARD_BACK);
1326 }
1327 
set_did_create_new_entry(bool did_create_new_entry)1328 void NavigationSimulatorImpl::set_did_create_new_entry(
1329     bool did_create_new_entry) {
1330   did_create_new_entry_ = did_create_new_entry;
1331 }
1332 
set_history_list_was_cleared(bool history_cleared)1333 void NavigationSimulatorImpl::set_history_list_was_cleared(
1334     bool history_cleared) {
1335   history_list_was_cleared_ = history_cleared;
1336 }
1337 
1338 std::unique_ptr<FrameHostMsg_DidCommitProvisionalLoad_Params>
BuildDidCommitProvisionalLoadParams(bool same_document,bool failed_navigation)1339 NavigationSimulatorImpl::BuildDidCommitProvisionalLoadParams(
1340     bool same_document,
1341     bool failed_navigation) {
1342   std::unique_ptr<FrameHostMsg_DidCommitProvisionalLoad_Params> params =
1343       std::make_unique<FrameHostMsg_DidCommitProvisionalLoad_Params>();
1344   params->url = navigation_url_;
1345   params->original_request_url = original_url_;
1346   params->referrer = Referrer(*referrer_);
1347   params->contents_mime_type = contents_mime_type_;
1348   params->transition = transition_;
1349   params->gesture =
1350       has_user_gesture_ ? NavigationGestureUser : NavigationGestureAuto;
1351   params->history_list_was_cleared = history_list_was_cleared_;
1352   params->did_create_new_entry = DidCreateNewEntry();
1353   params->should_replace_current_entry = should_replace_current_entry_;
1354   params->navigation_token = request_
1355                                  ? request_->commit_params().navigation_token
1356                                  : base::UnguessableToken::Create();
1357   params->post_id = post_id_;
1358 
1359   if (intended_as_new_entry_.has_value())
1360     params->intended_as_new_entry = intended_as_new_entry_.value();
1361 
1362   if (failed_navigation) {
1363     // Note: Error pages must commit in a unique origin. So it is left unset.
1364     params->url_is_unreachable = true;
1365   } else {
1366     params->origin = origin_.value_or(url::Origin::Create(navigation_url_));
1367     params->redirects.push_back(navigation_url_);
1368     params->method = request_ ? request_->common_params().method : "GET";
1369     params->http_status_code = 200;
1370     params->should_update_history = true;
1371   }
1372 
1373   CHECK(same_document || request_);
1374   params->nav_entry_id = request_ ? request_->nav_entry_id() : 0;
1375 
1376   // Simulate Blink assigning a item sequence number and document sequence
1377   // number to the navigation.
1378   params->item_sequence_number = ++g_unique_identifier;
1379   if (same_document) {
1380     FrameNavigationEntry* current_entry =
1381         web_contents_->GetController().GetLastCommittedEntry()->GetFrameEntry(
1382             frame_tree_node_);
1383     params->document_sequence_number =
1384         current_entry->document_sequence_number();
1385   } else {
1386     params->document_sequence_number = ++g_unique_identifier;
1387   }
1388 
1389   // Simulate embedding token creation.
1390   if (!same_document)
1391     params->embedding_token = base::UnguessableToken::Create();
1392 
1393   params->page_state = page_state_.value_or(
1394       blink::PageState::CreateForTestingWithSequenceNumbers(
1395           navigation_url_, params->item_sequence_number,
1396           params->document_sequence_number));
1397 
1398   return params;
1399 }
1400 
SetKeepLoading(bool keep_loading)1401 void NavigationSimulatorImpl::SetKeepLoading(bool keep_loading) {
1402   keep_loading_ = keep_loading;
1403 }
1404 
StopLoading()1405 void NavigationSimulatorImpl::StopLoading() {
1406   CHECK(render_frame_host_);
1407   render_frame_host_->SimulateLoadingCompleted(loading_scenario_);
1408 }
1409 
FailLoading(const GURL & url,int error_code)1410 void NavigationSimulatorImpl::FailLoading(const GURL& url, int error_code) {
1411   CHECK(render_frame_host_);
1412   render_frame_host_->DidFailLoadWithError(url, error_code);
1413 }
1414 
1415 void NavigationSimulatorImpl::
SimulateUnloadCompletionCallbackForPreviousFrameIfNeeded(RenderFrameHostImpl * previous_rfh)1416     SimulateUnloadCompletionCallbackForPreviousFrameIfNeeded(
1417         RenderFrameHostImpl* previous_rfh) {
1418   // Do not dispatch FrameHostMsg_Unload_ACK if the navigation was committed in
1419   // the same RenderFrameHost.
1420   if (previous_rfh == render_frame_host_)
1421     return;
1422   if (drop_unload_ack_)
1423     return;
1424   // The previous RenderFrameHost is not live, we will not attempt to unload
1425   // it.
1426   if (!previous_rfh->IsRenderFrameLive())
1427     return;
1428   // The previous RenderFrameHost entered the back-forward cache and hasn't been
1429   // requested to unload. The browser process do not expect
1430   // FrameHostMsg_Unload_ACK.
1431   if (previous_rfh->IsInBackForwardCache())
1432     return;
1433   previous_rfh->OnMessageReceived(
1434       FrameHostMsg_Unload_ACK(previous_rfh->GetRoutingID()));
1435 }
1436 
1437 }  // namespace content
1438