1 // Copyright 2014 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/browser/renderer_host/navigator.h"
6 
7 #include <stdint.h>
8 
9 #include "base/feature_list.h"
10 #include "base/stl_util.h"
11 #include "base/time/time.h"
12 #include "build/build_config.h"
13 #include "content/browser/renderer_host/navigation_controller_impl.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/navigation_request_info.h"
17 #include "content/browser/renderer_host/navigator.h"
18 #include "content/browser/renderer_host/render_frame_host_manager.h"
19 #include "content/browser/site_instance_impl.h"
20 #include "content/common/content_navigation_policy.h"
21 #include "content/common/frame.mojom.h"
22 #include "content/common/frame_messages.h"
23 #include "content/common/navigation_params.h"
24 #include "content/public/browser/child_process_security_policy.h"
25 #include "content/public/common/content_features.h"
26 #include "content/public/common/url_constants.h"
27 #include "content/public/common/url_utils.h"
28 #include "content/public/test/mock_render_process_host.h"
29 #include "content/public/test/navigation_simulator.h"
30 #include "content/public/test/test_utils.h"
31 #include "content/test/navigation_simulator_impl.h"
32 #include "content/test/test_navigation_url_loader.h"
33 #include "content/test/test_render_frame_host.h"
34 #include "content/test/test_web_contents.h"
35 #include "net/base/load_flags.h"
36 #include "net/http/http_response_headers.h"
37 #include "net/url_request/redirect_info.h"
38 #include "ui/base/page_transition_types.h"
39 #include "url/url_constants.h"
40 
41 namespace content {
42 
43 class NavigatorTest : public RenderViewHostImplTestHarness {
44  public:
45   using SiteInstanceDescriptor = RenderFrameHostManager::SiteInstanceDescriptor;
46   using SiteInstanceRelation = RenderFrameHostManager::SiteInstanceRelation;
47 
SetUp()48   void SetUp() override { RenderViewHostImplTestHarness::SetUp(); }
49 
TearDown()50   void TearDown() override { RenderViewHostImplTestHarness::TearDown(); }
51 
GetLoaderForNavigationRequest(NavigationRequest * request) const52   TestNavigationURLLoader* GetLoaderForNavigationRequest(
53       NavigationRequest* request) const {
54     return static_cast<TestNavigationURLLoader*>(request->loader_for_testing());
55   }
56 
GetSpeculativeRenderFrameHost(FrameTreeNode * node)57   TestRenderFrameHost* GetSpeculativeRenderFrameHost(FrameTreeNode* node) {
58     return static_cast<TestRenderFrameHost*>(
59         node->render_manager()->speculative_render_frame_host_.get());
60   }
61 
ConvertToSiteInstance(RenderFrameHostManager * rfhm,const SiteInstanceDescriptor & descriptor,SiteInstance * candidate_instance)62   scoped_refptr<SiteInstance> ConvertToSiteInstance(
63       RenderFrameHostManager* rfhm,
64       const SiteInstanceDescriptor& descriptor,
65       SiteInstance* candidate_instance) {
66     return rfhm->ConvertToSiteInstance(
67         descriptor, static_cast<SiteInstanceImpl*>(candidate_instance),
68         false /* is_speculative */);
69   }
70 };
71 
72 // Tests a complete browser-initiated navigation starting with a non-live
73 // renderer.
TEST_F(NavigatorTest,SimpleBrowserInitiatedNavigationFromNonLiveRenderer)74 TEST_F(NavigatorTest, SimpleBrowserInitiatedNavigationFromNonLiveRenderer) {
75   const GURL kUrl("http://chromium.org/");
76 
77   EXPECT_FALSE(main_test_rfh()->IsRenderFrameLive());
78 
79   // Start a browser-initiated navigation.
80   auto navigation =
81       NavigationSimulator::CreateBrowserInitiated(kUrl, contents());
82   int32_t site_instance_id = main_test_rfh()->GetSiteInstance()->GetId();
83   FrameTreeNode* node = main_test_rfh()->frame_tree_node();
84   navigation->Start();
85   NavigationRequest* request = node->navigation_request();
86   ASSERT_TRUE(request);
87   EXPECT_EQ(kUrl, request->common_params().url);
88   EXPECT_TRUE(request->browser_initiated());
89 
90   // As there's no live renderer the navigation should not wait for a
91   // beforeUnload completion callback being invoked by the renderer and
92   // start right away.
93   EXPECT_EQ(NavigationRequest::WILL_START_REQUEST, request->state());
94   ASSERT_TRUE(GetLoaderForNavigationRequest(request));
95   EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
96 
97   navigation->ReadyToCommit();
98   EXPECT_TRUE(main_test_rfh()->is_loading());
99   EXPECT_FALSE(node->navigation_request());
100 
101   // Commit the navigation.
102   navigation->Commit();
103   EXPECT_TRUE(main_test_rfh()->IsCurrent());
104   EXPECT_EQ(main_test_rfh()->lifecycle_state(),
105             RenderFrameHostImpl::LifecycleState::kActive);
106   if (AreDefaultSiteInstancesEnabled()) {
107     EXPECT_TRUE(main_test_rfh()->GetSiteInstance()->IsDefaultSiteInstance());
108   } else {
109     EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrl),
110               main_test_rfh()->GetSiteInstance()->GetSiteURL());
111   }
112   EXPECT_EQ(kUrl, contents()->GetLastCommittedURL());
113 
114   // The main RenderFrameHost should not have been changed, and the renderer
115   // should have been initialized.
116   EXPECT_EQ(site_instance_id, main_test_rfh()->GetSiteInstance()->GetId());
117   EXPECT_TRUE(main_test_rfh()->IsRenderFrameLive());
118 
119   // After a navigation is finished no speculative RenderFrameHost should
120   // exist.
121   EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
122 }
123 
124 // Tests a complete renderer-initiated same-site navigation.
TEST_F(NavigatorTest,SimpleRendererInitiatedSameSiteNavigation)125 TEST_F(NavigatorTest, SimpleRendererInitiatedSameSiteNavigation) {
126   const GURL kUrl1("http://www.chromium.org/");
127   const GURL kUrl2("http://www.chromium.org/Home");
128 
129   contents()->NavigateAndCommit(kUrl1);
130   EXPECT_TRUE(main_test_rfh()->IsRenderFrameLive());
131   static_cast<mojom::FrameHost*>(main_test_rfh())->DidStopLoading();
132 
133   // Start a renderer-initiated non-user-initiated navigation.
134   EXPECT_FALSE(main_test_rfh()->navigation_request());
135   auto navigation =
136       NavigationSimulator::CreateRendererInitiated(kUrl2, main_test_rfh());
137   navigation->SetTransition(ui::PageTransitionFromInt(
138       ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_CLIENT_REDIRECT));
139   navigation->SetHasUserGesture(false);
140   navigation->Start();
141   FrameTreeNode* node = main_test_rfh()->frame_tree_node();
142   NavigationRequest* request = node->navigation_request();
143   ASSERT_TRUE(request);
144 
145   // The navigation is immediately started as there's no need to wait for
146   // beforeUnload to be executed.
147   EXPECT_EQ(NavigationRequest::WILL_START_REQUEST, request->state());
148   EXPECT_FALSE(request->common_params().has_user_gesture);
149   EXPECT_EQ(kUrl2, request->common_params().url);
150   EXPECT_FALSE(request->browser_initiated());
151 
152   if (CanSameSiteMainFrameNavigationsChangeRenderFrameHosts()) {
153     // If same-site ProactivelySwapBrowsingInstance or main-frame RenderDocument
154     // is enabled, the RFH should change so we should have a speculative RFH.
155     EXPECT_TRUE(GetSpeculativeRenderFrameHost(node));
156     EXPECT_FALSE(GetSpeculativeRenderFrameHost(node)->is_loading());
157   } else {
158     EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
159   }
160   EXPECT_FALSE(main_test_rfh()->is_loading());
161 
162   // Have the current RenderFrameHost commit the navigation
163   navigation->ReadyToCommit();
164   if (CanSameSiteMainFrameNavigationsChangeRenderFrameHosts()) {
165     EXPECT_TRUE(GetSpeculativeRenderFrameHost(node)->is_loading());
166   } else {
167     EXPECT_TRUE(main_test_rfh()->is_loading());
168   }
169   EXPECT_FALSE(node->navigation_request());
170 
171   // Commit the navigation.
172   navigation->Commit();
173   EXPECT_TRUE(main_test_rfh()->IsCurrent());
174   if (AreDefaultSiteInstancesEnabled()) {
175     EXPECT_TRUE(main_test_rfh()->GetSiteInstance()->IsDefaultSiteInstance());
176   } else {
177     EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrl2),
178               main_test_rfh()->GetSiteInstance()->GetSiteURL());
179   }
180   EXPECT_EQ(kUrl2, contents()->GetLastCommittedURL());
181   EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
182 }
183 
184 // Tests a complete renderer-initiated navigation that should be
185 // cross-site but does not result in a SiteInstance swap because its
186 // renderer-initiated.
TEST_F(NavigatorTest,SimpleRendererInitiatedCrossSiteNavigation)187 TEST_F(NavigatorTest, SimpleRendererInitiatedCrossSiteNavigation) {
188   const GURL kUrl1("http://www.chromium.org/");
189   const GURL kUrl2("http://www.google.com");
190 
191   contents()->NavigateAndCommit(kUrl1);
192   EXPECT_TRUE(main_test_rfh()->IsRenderFrameLive());
193   int32_t site_instance_id_1 = main_test_rfh()->GetSiteInstance()->GetId();
194 
195   // Start a renderer-initiated navigation.
196   EXPECT_FALSE(main_test_rfh()->navigation_request());
197   auto navigation =
198       NavigationSimulator::CreateRendererInitiated(kUrl2, main_test_rfh());
199   navigation->Start();
200   FrameTreeNode* node = main_test_rfh()->frame_tree_node();
201   NavigationRequest* request = node->navigation_request();
202   ASSERT_TRUE(request);
203 
204   // The navigation is immediately started as there's no need to wait for
205   // beforeUnload to be executed.
206   EXPECT_EQ(NavigationRequest::WILL_START_REQUEST, request->state());
207   EXPECT_EQ(kUrl2, request->common_params().url);
208   EXPECT_FALSE(request->browser_initiated());
209   if (AreAllSitesIsolatedForTesting() ||
210       CanCrossSiteNavigationsProactivelySwapBrowsingInstances()) {
211     EXPECT_TRUE(GetSpeculativeRenderFrameHost(node));
212   } else {
213     EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
214   }
215 
216   // Have the current RenderFrameHost commit the navigation.
217   navigation->ReadyToCommit();
218   if (AreAllSitesIsolatedForTesting() ||
219       CanCrossSiteNavigationsProactivelySwapBrowsingInstances()) {
220     EXPECT_EQ(navigation->GetFinalRenderFrameHost(),
221               GetSpeculativeRenderFrameHost(node));
222   }
223   EXPECT_FALSE(node->navigation_request());
224 
225   // Commit the navigation.
226   navigation->Commit();
227   EXPECT_TRUE(main_test_rfh()->IsCurrent());
228   EXPECT_EQ(kUrl2, contents()->GetLastCommittedURL());
229   EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
230 
231   // The SiteInstance did not change unless site-per-process is enabled.
232   if (AreAllSitesIsolatedForTesting() ||
233       CanCrossSiteNavigationsProactivelySwapBrowsingInstances()) {
234     EXPECT_NE(site_instance_id_1, main_test_rfh()->GetSiteInstance()->GetId());
235   } else {
236     EXPECT_EQ(site_instance_id_1, main_test_rfh()->GetSiteInstance()->GetId());
237   }
238 }
239 
240 // Tests that a beforeUnload denial cancels the navigation.
TEST_F(NavigatorTest,BeforeUnloadDenialCancelNavigation)241 TEST_F(NavigatorTest, BeforeUnloadDenialCancelNavigation) {
242   const GURL kUrl1("http://www.google.com/");
243   const GURL kUrl2("http://www.chromium.org/");
244 
245   contents()->NavigateAndCommit(kUrl1);
246 
247   // Start a new navigation.
248   FrameTreeNode* node = main_test_rfh()->frame_tree_node();
249   auto navigation =
250       NavigationSimulatorImpl::CreateBrowserInitiated(kUrl2, contents());
251   navigation->BrowserInitiatedStartAndWaitBeforeUnload();
252   NavigationRequest* request = node->navigation_request();
253   ASSERT_TRUE(request);
254   EXPECT_TRUE(request->browser_initiated());
255   EXPECT_EQ(NavigationRequest::WAITING_FOR_RENDERER_RESPONSE, request->state());
256   EXPECT_TRUE(GetSpeculativeRenderFrameHost(node));
257   RenderFrameDeletedObserver rfh_deleted_observer(
258       GetSpeculativeRenderFrameHost(node));
259 
260   // Simulate a beforeUnload denial.
261   main_test_rfh()->SimulateBeforeUnloadCompleted(false);
262   EXPECT_FALSE(node->navigation_request());
263   EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
264   EXPECT_TRUE(rfh_deleted_observer.deleted());
265 }
266 
267 // Test that a proper NavigationRequest is created at navigation start.
TEST_F(NavigatorTest,BeginNavigation)268 TEST_F(NavigatorTest, BeginNavigation) {
269   const GURL kUrl1("http://www.google.com/");
270   const GURL kUrl2("http://www.chromium.org/");
271   const GURL kUrl3("http://www.gmail.com/");
272 
273   contents()->NavigateAndCommit(kUrl1);
274 
275   // Add a subframe.
276   FrameTreeNode* root_node = contents()->GetFrameTree()->root();
277   TestRenderFrameHost* subframe_rfh = main_test_rfh()->AppendChild("Child");
278   ASSERT_TRUE(subframe_rfh);
279 
280   // Start a navigation at the subframe.
281   FrameTreeNode* subframe_node = subframe_rfh->frame_tree_node();
282   auto navigation =
283       NavigationSimulatorImpl::CreateBrowserInitiated(kUrl2, contents());
284   NavigationController::LoadURLParams load_url_params(kUrl2);
285   load_url_params.frame_tree_node_id = subframe_node->frame_tree_node_id();
286   navigation->SetLoadURLParams(&load_url_params);
287   navigation->BrowserInitiatedStartAndWaitBeforeUnload();
288   NavigationRequest* subframe_request = subframe_node->navigation_request();
289 
290   // We should be waiting for the BeforeUnload event to execute in the subframe.
291   ASSERT_TRUE(subframe_request);
292   EXPECT_EQ(NavigationRequest::WAITING_FOR_RENDERER_RESPONSE,
293             subframe_request->state());
294   EXPECT_TRUE(subframe_rfh->is_waiting_for_beforeunload_completion());
295 
296   // Start the navigation, which will internally simulate that the beforeUnload
297   // completion callback has been invoked.
298   navigation->Start();
299   TestNavigationURLLoader* subframe_loader =
300       GetLoaderForNavigationRequest(subframe_request);
301   ASSERT_TRUE(subframe_loader);
302   EXPECT_EQ(NavigationRequest::WILL_START_REQUEST, subframe_request->state());
303   EXPECT_EQ(kUrl2, subframe_request->common_params().url);
304   EXPECT_EQ(kUrl2, subframe_loader->request_info()->common_params->url);
305   EXPECT_TRUE(
306       net::IsolationInfo::Create(net::IsolationInfo::RequestType::kSubFrame,
307                                  url::Origin::Create(kUrl1),
308                                  url::Origin::Create(kUrl2),
309                                  net::SiteForCookies::FromUrl(kUrl1))
310           .IsEqualForTesting(subframe_loader->request_info()->isolation_info));
311 
312   EXPECT_FALSE(subframe_loader->request_info()->is_main_frame);
313   EXPECT_TRUE(subframe_loader->request_info()->parent_is_main_frame);
314   EXPECT_TRUE(subframe_request->browser_initiated());
315   EXPECT_FALSE(GetSpeculativeRenderFrameHost(root_node));
316 
317   // Subframe navigations should never create a speculative RenderFrameHost,
318   // unless site-per-process is enabled. In that case, as the subframe
319   // navigation is to a different site and is still ongoing, it should have one.
320   if (AreAllSitesIsolatedForTesting()) {
321     EXPECT_TRUE(GetSpeculativeRenderFrameHost(subframe_node));
322   } else {
323     EXPECT_FALSE(GetSpeculativeRenderFrameHost(subframe_node));
324   }
325 
326   // Now start a navigation at the root node.
327   auto navigation2 =
328       NavigationSimulatorImpl::CreateBrowserInitiated(kUrl3, contents());
329   navigation2->BrowserInitiatedStartAndWaitBeforeUnload();
330   NavigationRequest* main_request = root_node->navigation_request();
331   ASSERT_TRUE(main_request);
332   EXPECT_EQ(NavigationRequest::WAITING_FOR_RENDERER_RESPONSE,
333             main_request->state());
334 
335   // Main frame navigation to a different site should use a speculative
336   // RenderFrameHost.
337   EXPECT_TRUE(GetSpeculativeRenderFrameHost(root_node));
338 
339   // Start the navigation, which will internally simulate that the beforeUnload
340   // completion callback has been invoked.
341   navigation2->Start();
342   TestNavigationURLLoader* main_loader =
343       GetLoaderForNavigationRequest(main_request);
344   EXPECT_EQ(kUrl3, main_request->common_params().url);
345   EXPECT_EQ(kUrl3, main_loader->request_info()->common_params->url);
346   EXPECT_TRUE(
347       net::IsolationInfo::Create(net::IsolationInfo::RequestType::kMainFrame,
348                                  url::Origin::Create(kUrl3),
349                                  url::Origin::Create(kUrl3),
350                                  net::SiteForCookies::FromUrl(kUrl3))
351           .IsEqualForTesting(main_loader->request_info()->isolation_info));
352   EXPECT_TRUE(main_loader->request_info()->is_main_frame);
353   EXPECT_FALSE(main_loader->request_info()->parent_is_main_frame);
354   EXPECT_TRUE(main_request->browser_initiated());
355   // BeforeUnloadCompleted callback was invoked by the renderer so the
356   // navigation should have started.
357   EXPECT_EQ(NavigationRequest::WILL_START_REQUEST, main_request->state());
358   EXPECT_TRUE(GetSpeculativeRenderFrameHost(root_node));
359 
360   // As the main frame hasn't yet committed the subframe still exists. Thus, the
361   // above situation regarding subframe navigations is valid here.
362   if (AreAllSitesIsolatedForTesting()) {
363     EXPECT_TRUE(GetSpeculativeRenderFrameHost(subframe_node));
364   } else {
365     EXPECT_FALSE(GetSpeculativeRenderFrameHost(subframe_node));
366   }
367 }
368 
369 // Tests that committing an HTTP 204 or HTTP 205 response cancels
370 // the navigation.
TEST_F(NavigatorTest,NoContent)371 TEST_F(NavigatorTest, NoContent) {
372   const GURL kUrl1("http://www.chromium.org/");
373   const GURL kUrl2("http://www.google.com/");
374 
375   // Load a URL.
376   contents()->NavigateAndCommit(kUrl1);
377   FrameTreeNode* node = main_test_rfh()->frame_tree_node();
378 
379   // Navigate to a different site.
380   EXPECT_FALSE(main_test_rfh()->navigation_request());
381   auto navigation =
382       NavigationSimulator::CreateBrowserInitiated(kUrl2, contents());
383   navigation->Start();
384 
385   NavigationRequest* main_request = node->navigation_request();
386   ASSERT_TRUE(main_request);
387 
388   // Navigations to a different site do create a speculative RenderFrameHost.
389   EXPECT_TRUE(GetSpeculativeRenderFrameHost(node));
390 
391   // Commit an HTTP 204 response.
392   auto response = network::mojom::URLResponseHead::New();
393   const char kNoContentHeaders[] = "HTTP/1.1 204 No Content\0\0";
394   response->headers = new net::HttpResponseHeaders(
395       std::string(kNoContentHeaders, base::size(kNoContentHeaders)));
396   GetLoaderForNavigationRequest(main_request)
397       ->CallOnResponseStarted(std::move(response));
398 
399   // There should be no pending nor speculative RenderFrameHost; the navigation
400   // was aborted.
401   EXPECT_FALSE(main_test_rfh()->navigation_request());
402   EXPECT_FALSE(node->navigation_request());
403   EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
404 
405   // Now, repeat the test with 205 Reset Content.
406 
407   // Navigate to a different site again.
408   EXPECT_FALSE(main_test_rfh()->navigation_request());
409   auto navigation2 =
410       NavigationSimulator::CreateBrowserInitiated(kUrl2, contents());
411   navigation2->Start();
412 
413   main_request = node->navigation_request();
414   ASSERT_TRUE(main_request);
415   EXPECT_TRUE(GetSpeculativeRenderFrameHost(node));
416 
417   // Commit an HTTP 205 response.
418   response = network::mojom::URLResponseHead::New();
419   const char kResetContentHeaders[] = "HTTP/1.1 205 Reset Content\0\0";
420   response->headers = new net::HttpResponseHeaders(
421       std::string(kResetContentHeaders, base::size(kResetContentHeaders)));
422   GetLoaderForNavigationRequest(main_request)
423       ->CallOnResponseStarted(std::move(response));
424 
425   // There should be no pending nor speculative RenderFrameHost; the navigation
426   // was aborted.
427   EXPECT_FALSE(main_test_rfh()->navigation_request());
428   EXPECT_FALSE(node->navigation_request());
429   EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
430 }
431 
432 // Test that a new RenderFrameHost is created when doing a cross site
433 // navigation.
TEST_F(NavigatorTest,CrossSiteNavigation)434 TEST_F(NavigatorTest, CrossSiteNavigation) {
435   const GURL kUrl1("http://www.chromium.org/");
436   const GURL kUrl2("http://www.google.com/");
437 
438   contents()->NavigateAndCommit(kUrl1);
439   RenderFrameHostImpl* initial_rfh = main_test_rfh();
440   FrameTreeNode* node = main_test_rfh()->frame_tree_node();
441 
442   // Navigate to a different site.
443   EXPECT_EQ(main_test_rfh()->navigation_requests().size(), 0u);
444   auto navigation =
445       NavigationSimulator::CreateBrowserInitiated(kUrl2, contents());
446   navigation->Start();
447   NavigationRequest* main_request = node->navigation_request();
448   ASSERT_TRUE(main_request);
449   TestRenderFrameHost* speculative_rfh = GetSpeculativeRenderFrameHost(node);
450   ASSERT_TRUE(speculative_rfh);
451   EXPECT_EQ(speculative_rfh, GetSpeculativeRenderFrameHost(node));
452 
453   navigation->ReadyToCommit();
454   EXPECT_EQ(speculative_rfh, GetSpeculativeRenderFrameHost(node));
455   EXPECT_EQ(speculative_rfh->navigation_requests().size(), 1u);
456   EXPECT_EQ(main_test_rfh()->navigation_requests().size(), 0u);
457 
458   navigation->Commit();
459   RenderFrameHostImpl* final_rfh = main_test_rfh();
460   EXPECT_EQ(speculative_rfh, final_rfh);
461   EXPECT_NE(initial_rfh, final_rfh);
462   EXPECT_TRUE(final_rfh->IsRenderFrameLive());
463   EXPECT_TRUE(final_rfh->render_view_host()->IsRenderViewLive());
464   EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
465 }
466 
467 // Test that redirects are followed and the speculative RenderFrameHost logic
468 // behaves as expected.
TEST_F(NavigatorTest,RedirectCrossSite)469 TEST_F(NavigatorTest, RedirectCrossSite) {
470   const GURL kUrl1("http://www.chromium.org/");
471   const GURL kUrl2("http://www.google.com/");
472 
473   contents()->NavigateAndCommit(kUrl1);
474   RenderFrameHostImpl* rfh = main_test_rfh();
475   FrameTreeNode* node = main_test_rfh()->frame_tree_node();
476 
477   // Navigate to a URL on the same site.
478   EXPECT_EQ(main_test_rfh()->navigation_requests().size(), 0u);
479   auto navigation =
480       NavigationSimulator::CreateBrowserInitiated(kUrl1, contents());
481   navigation->Start();
482   NavigationRequest* main_request = node->navigation_request();
483   ASSERT_TRUE(main_request);
484   EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
485 
486   // It then redirects to another site.
487   navigation->Redirect(kUrl2);
488 
489   // The redirect should have been followed.
490   EXPECT_EQ(1, GetLoaderForNavigationRequest(main_request)->redirect_count());
491   EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
492 
493   navigation->ReadyToCommit();
494   TestRenderFrameHost* final_speculative_rfh =
495       GetSpeculativeRenderFrameHost(node);
496   EXPECT_TRUE(final_speculative_rfh);
497   EXPECT_EQ(final_speculative_rfh->navigation_requests().size(), 1u);
498 
499   navigation->Commit();
500   RenderFrameHostImpl* final_rfh = main_test_rfh();
501   ASSERT_TRUE(final_rfh);
502   EXPECT_NE(rfh, final_rfh);
503   EXPECT_EQ(final_speculative_rfh, final_rfh);
504   EXPECT_TRUE(final_rfh->IsRenderFrameLive());
505   EXPECT_TRUE(final_rfh->render_view_host()->IsRenderViewLive());
506   EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
507 }
508 
509 // Test that a navigation is canceled if another browser-initiated request has
510 // been issued in the meantime. Also confirms that the speculative
511 // RenderFrameHost is correctly updated in the process.
TEST_F(NavigatorTest,BrowserInitiatedNavigationCancel)512 TEST_F(NavigatorTest, BrowserInitiatedNavigationCancel) {
513   const GURL kUrl0("http://www.wikipedia.org/");
514   const GURL kUrl1("http://www.chromium.org/");
515   const GURL kUrl1_site = SiteInstance::GetSiteForURL(browser_context(), kUrl1);
516   const GURL kUrl2("http://www.google.com/");
517   const GURL kUrl2_site = SiteInstance::GetSiteForURL(browser_context(), kUrl2);
518 
519   // Initialization.
520   contents()->NavigateAndCommit(kUrl0);
521   FrameTreeNode* node = main_test_rfh()->frame_tree_node();
522 
523   // Request navigation to the 1st URL.
524   EXPECT_FALSE(main_test_rfh()->navigation_request());
525   auto navigation1 =
526       NavigationSimulator::CreateBrowserInitiated(kUrl1, contents());
527   navigation1->Start();
528   NavigationRequest* request1 = node->navigation_request();
529   ASSERT_TRUE(request1);
530   EXPECT_EQ(kUrl1, request1->common_params().url);
531   EXPECT_TRUE(request1->browser_initiated());
532   base::WeakPtr<TestNavigationURLLoader> loader1 =
533       GetLoaderForNavigationRequest(request1)->AsWeakPtr();
534   EXPECT_TRUE(loader1);
535 
536   // Confirm a speculative RenderFrameHost was created.
537   TestRenderFrameHost* speculative_rfh = GetSpeculativeRenderFrameHost(node);
538   ASSERT_TRUE(speculative_rfh);
539   int32_t site_instance_id_1 = speculative_rfh->GetSiteInstance()->GetId();
540   if (AreDefaultSiteInstancesEnabled()) {
541     EXPECT_TRUE(speculative_rfh->GetSiteInstance()->IsDefaultSiteInstance());
542   } else {
543     EXPECT_EQ(kUrl1_site, speculative_rfh->GetSiteInstance()->GetSiteURL());
544   }
545 
546   // Request navigation to the 2nd URL; the NavigationRequest must have been
547   // replaced by a new one with a different URL.
548   auto navigation2 =
549       NavigationSimulator::CreateBrowserInitiated(kUrl2, contents());
550   navigation2->Start();
551   NavigationRequest* request2 = node->navigation_request();
552   ASSERT_TRUE(request2);
553   EXPECT_EQ(kUrl2, request2->common_params().url);
554   EXPECT_TRUE(request2->browser_initiated());
555 
556   // Confirm that the first loader got destroyed.
557   EXPECT_FALSE(loader1);
558 
559   // Confirm that a new speculative RenderFrameHost was created.
560   speculative_rfh = GetSpeculativeRenderFrameHost(node);
561   ASSERT_TRUE(speculative_rfh);
562   int32_t site_instance_id_2 = speculative_rfh->GetSiteInstance()->GetId();
563 
564   if (AreDefaultSiteInstancesEnabled()) {
565     EXPECT_TRUE(speculative_rfh->GetSiteInstance()->IsDefaultSiteInstance());
566     EXPECT_EQ(site_instance_id_1, site_instance_id_2);
567   } else {
568     EXPECT_NE(site_instance_id_1, site_instance_id_2);
569   }
570 
571   navigation2->ReadyToCommit();
572   EXPECT_EQ(speculative_rfh->navigation_requests().size(), 1u);
573   EXPECT_EQ(main_test_rfh()->navigation_requests().size(), 0u);
574 
575   // Have the RenderFrameHost commit the navigation.
576   navigation2->Commit();
577 
578   // Confirm that the commit corresponds to the new request.
579   ASSERT_TRUE(main_test_rfh());
580   if (AreDefaultSiteInstancesEnabled()) {
581     EXPECT_TRUE(main_test_rfh()->GetSiteInstance()->IsDefaultSiteInstance());
582   } else {
583     EXPECT_EQ(kUrl2_site, main_test_rfh()->GetSiteInstance()->GetSiteURL());
584   }
585   EXPECT_EQ(kUrl2, contents()->GetLastCommittedURL());
586 
587   // Confirm that the committed RenderFrameHost is the latest speculative one.
588   EXPECT_EQ(site_instance_id_2, main_test_rfh()->GetSiteInstance()->GetId());
589 }
590 
591 // Test that a browser-initiated navigation is canceled if a renderer-initiated
592 // user-initiated request has been issued in the meantime.
TEST_F(NavigatorTest,RendererUserInitiatedNavigationCancel)593 TEST_F(NavigatorTest, RendererUserInitiatedNavigationCancel) {
594   const GURL kUrl0("http://www.wikipedia.org/");
595   const GURL kUrl1("http://www.chromium.org/");
596   const GURL kUrl2("http://www.google.com/");
597 
598   // Initialization.
599   contents()->NavigateAndCommit(kUrl0);
600   FrameTreeNode* node = main_test_rfh()->frame_tree_node();
601 
602   // Start a browser-initiated navigation to the 1st URL and invoke its
603   // beforeUnload completion callback.
604   EXPECT_FALSE(main_test_rfh()->navigation_request());
605   auto navigation2 =
606       NavigationSimulator::CreateBrowserInitiated(kUrl1, contents());
607   navigation2->Start();
608   NavigationRequest* request1 = node->navigation_request();
609   ASSERT_TRUE(request1);
610   EXPECT_EQ(kUrl1, request1->common_params().url);
611   EXPECT_TRUE(request1->browser_initiated());
612   base::WeakPtr<TestNavigationURLLoader> loader1 =
613       GetLoaderForNavigationRequest(request1)->AsWeakPtr();
614   EXPECT_TRUE(loader1);
615 
616   // Confirm that a speculative RenderFrameHost was created.
617   ASSERT_TRUE(GetSpeculativeRenderFrameHost(node));
618 
619   // Now receive a renderer-initiated user-initiated request. It should replace
620   // the current NavigationRequest.
621   auto navigation =
622       NavigationSimulator::CreateRendererInitiated(kUrl2, main_test_rfh());
623   navigation->SetTransition(ui::PAGE_TRANSITION_LINK);
624   navigation->SetHasUserGesture(true);
625   navigation->Start();
626   NavigationRequest* request2 = node->navigation_request();
627   ASSERT_TRUE(request2);
628   EXPECT_EQ(kUrl2, request2->common_params().url);
629   EXPECT_FALSE(request2->browser_initiated());
630   EXPECT_TRUE(request2->common_params().has_user_gesture);
631 
632   // Confirm that the first loader got destroyed.
633   EXPECT_FALSE(loader1);
634 
635   // Confirm that the speculative RenderFrameHost was destroyed in the non
636   // SitePerProcess case.
637   if (AreAllSitesIsolatedForTesting() ||
638       CanCrossSiteNavigationsProactivelySwapBrowsingInstances()) {
639     EXPECT_TRUE(GetSpeculativeRenderFrameHost(node));
640   } else {
641     EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
642   }
643 
644   // Commit the navigation.
645   navigation->Commit();
646 
647   // Confirm that the commit corresponds to the new request.
648   ASSERT_TRUE(main_test_rfh());
649   EXPECT_EQ(kUrl2, contents()->GetLastCommittedURL());
650 }
651 
652 // Tests that a renderer-initiated user-initiated navigation is
653 // canceled if a renderer-initiated non-user-initiated request is issued in the
654 // meantime.
TEST_F(NavigatorTest,RendererNonUserInitiatedNavigationCancelsRendererUserInitiated)655 TEST_F(NavigatorTest,
656        RendererNonUserInitiatedNavigationCancelsRendererUserInitiated) {
657   const GURL kUrl0("http://www.wikipedia.org/");
658   const GURL kUrl1("http://www.chromium.org/");
659   const GURL kUrl2("http://www.google.com/");
660 
661   // Initialization.
662   contents()->NavigateAndCommit(kUrl0);
663   FrameTreeNode* node = main_test_rfh()->frame_tree_node();
664 
665   // Start a renderer-initiated user-initiated navigation to the 1st URL.
666   EXPECT_FALSE(main_test_rfh()->navigation_request());
667   auto user_initiated_navigation =
668       NavigationSimulator::CreateRendererInitiated(kUrl1, main_test_rfh());
669   user_initiated_navigation->SetTransition(ui::PAGE_TRANSITION_LINK);
670   user_initiated_navigation->SetHasUserGesture(true);
671   user_initiated_navigation->Start();
672   NavigationRequest* request1 = node->navigation_request();
673   ASSERT_TRUE(request1);
674   EXPECT_EQ(kUrl1, request1->common_params().url);
675   EXPECT_FALSE(request1->browser_initiated());
676   EXPECT_TRUE(request1->common_params().has_user_gesture);
677   if (AreAllSitesIsolatedForTesting() ||
678       CanCrossSiteNavigationsProactivelySwapBrowsingInstances()) {
679     EXPECT_TRUE(GetSpeculativeRenderFrameHost(node));
680   } else {
681     EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
682   }
683 
684   // Now receive a renderer-initiated non-user-initiated request. The previous
685   // navigation should be replaced.
686   auto non_user_initiated_navigation =
687       NavigationSimulator::CreateRendererInitiated(kUrl2, main_test_rfh());
688   non_user_initiated_navigation->SetTransition(ui::PAGE_TRANSITION_LINK);
689   non_user_initiated_navigation->SetHasUserGesture(false);
690   non_user_initiated_navigation->Start();
691 
692   NavigationRequest* request2 = node->navigation_request();
693   ASSERT_TRUE(request2);
694   EXPECT_NE(request1, request2);
695   EXPECT_EQ(kUrl2, request2->common_params().url);
696   EXPECT_FALSE(request2->browser_initiated());
697   EXPECT_FALSE(request2->common_params().has_user_gesture);
698   if (AreAllSitesIsolatedForTesting() ||
699       CanCrossSiteNavigationsProactivelySwapBrowsingInstances()) {
700     EXPECT_TRUE(GetSpeculativeRenderFrameHost(node));
701   } else {
702     EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
703   }
704 
705   // Commit the navigation.
706   non_user_initiated_navigation->Commit();
707   EXPECT_EQ(kUrl2, contents()->GetLastCommittedURL());
708 }
709 
710 // PlzNavigate: Test that a browser-initiated navigation is NOT canceled if a
711 // renderer-initiated non-user-initiated request is issued in the meantime.
TEST_F(NavigatorTest,RendererNonUserInitiatedNavigationDoesntCancelBrowserInitiated)712 TEST_F(NavigatorTest,
713        RendererNonUserInitiatedNavigationDoesntCancelBrowserInitiated) {
714   const GURL kUrl0("http://www.wikipedia.org/");
715   const GURL kUrl1("http://www.chromium.org/");
716   const GURL kUrl2("http://www.google.com/");
717 
718   // Initialization.
719   contents()->NavigateAndCommit(kUrl0);
720   FrameTreeNode* node = main_test_rfh()->frame_tree_node();
721 
722   // Start a browser-initiated navigation to the 1st URL.
723   EXPECT_FALSE(main_test_rfh()->navigation_request());
724   auto navigation =
725       NavigationSimulator::CreateBrowserInitiated(kUrl1, contents());
726   navigation->Start();
727   NavigationRequest* request1 = node->navigation_request();
728   ASSERT_TRUE(request1);
729   EXPECT_EQ(kUrl1, request1->common_params().url);
730   EXPECT_TRUE(request1->browser_initiated());
731   TestRenderFrameHost* speculative_rfh = GetSpeculativeRenderFrameHost(node);
732   ASSERT_TRUE(speculative_rfh);
733 
734   // Now receive a renderer-initiated non-user-initiated request. Nothing should
735   // change.
736   main_test_rfh()->SendRendererInitiatedNavigationRequest(
737       kUrl2, false /* has_user_gesture */);
738   NavigationRequest* request2 = node->navigation_request();
739   ASSERT_TRUE(request2);
740   EXPECT_EQ(request1, request2);
741   EXPECT_EQ(kUrl1, request2->common_params().url);
742   EXPECT_TRUE(request2->browser_initiated());
743   EXPECT_TRUE(speculative_rfh);
744 
745   navigation->ReadyToCommit();
746   EXPECT_EQ(speculative_rfh->navigation_requests().size(), 1u);
747   EXPECT_EQ(main_test_rfh()->navigation_requests().size(), 0u);
748 
749   navigation->Commit();
750   EXPECT_EQ(kUrl1, contents()->GetLastCommittedURL());
751 }
752 
753 // PlzNavigate: Test that a renderer-initiated non-user-initiated navigation is
754 // canceled if a another similar request is issued in the meantime.
TEST_F(NavigatorTest,RendererNonUserInitiatedNavigationCancelSimilarNavigation)755 TEST_F(NavigatorTest,
756        RendererNonUserInitiatedNavigationCancelSimilarNavigation) {
757   const GURL kUrl0("http://www.wikipedia.org/");
758   const GURL kUrl1("http://www.chromium.org/");
759   const GURL kUrl2("http://www.google.com/");
760 
761   // Initialization.
762   contents()->NavigateAndCommit(kUrl0);
763   FrameTreeNode* node = main_test_rfh()->frame_tree_node();
764   int32_t site_instance_id_0 = main_test_rfh()->GetSiteInstance()->GetId();
765 
766   // Start a renderer-initiated non-user-initiated navigation to the 1st URL.
767   EXPECT_FALSE(main_test_rfh()->navigation_request());
768   auto navigation1 =
769       NavigationSimulator::CreateRendererInitiated(kUrl1, main_test_rfh());
770   navigation1->SetTransition(ui::PageTransitionFromInt(
771       ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_CLIENT_REDIRECT));
772   navigation1->SetHasUserGesture(false);
773   navigation1->Start();
774   NavigationRequest* request1 = node->navigation_request();
775   ASSERT_TRUE(request1);
776   EXPECT_EQ(kUrl1, request1->common_params().url);
777   EXPECT_FALSE(request1->browser_initiated());
778   EXPECT_FALSE(request1->common_params().has_user_gesture);
779   if (AreAllSitesIsolatedForTesting() ||
780       CanCrossSiteNavigationsProactivelySwapBrowsingInstances()) {
781     EXPECT_TRUE(GetSpeculativeRenderFrameHost(node));
782   } else {
783     EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
784   }
785   base::WeakPtr<TestNavigationURLLoader> loader1 =
786       GetLoaderForNavigationRequest(request1)->AsWeakPtr();
787   EXPECT_TRUE(loader1);
788 
789   // Now receive a 2nd similar request that should replace the current one.
790   auto navigation2 =
791       NavigationSimulator::CreateRendererInitiated(kUrl2, main_test_rfh());
792   navigation2->SetTransition(ui::PageTransitionFromInt(
793       ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_CLIENT_REDIRECT));
794   navigation2->SetHasUserGesture(false);
795   navigation2->Start();
796   NavigationRequest* request2 = node->navigation_request();
797   EXPECT_EQ(kUrl2, request2->common_params().url);
798   EXPECT_FALSE(request2->browser_initiated());
799   EXPECT_FALSE(request2->common_params().has_user_gesture);
800   if (AreAllSitesIsolatedForTesting() ||
801       CanCrossSiteNavigationsProactivelySwapBrowsingInstances()) {
802     EXPECT_TRUE(GetSpeculativeRenderFrameHost(node));
803   } else {
804     EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
805   }
806 
807   // Confirm that the first loader got destroyed.
808   EXPECT_FALSE(loader1);
809 
810   // Commit the navigation.
811   navigation2->Commit();
812   EXPECT_EQ(kUrl2, contents()->GetLastCommittedURL());
813 
814   // The SiteInstance did not change unless site-per-process is enabled.
815   if (AreAllSitesIsolatedForTesting() ||
816       CanCrossSiteNavigationsProactivelySwapBrowsingInstances()) {
817     EXPECT_NE(site_instance_id_0, main_test_rfh()->GetSiteInstance()->GetId());
818   } else {
819     EXPECT_EQ(site_instance_id_0, main_test_rfh()->GetSiteInstance()->GetId());
820   }
821 }
822 
823 // PlzNavigate: Test that a reload navigation is properly signaled to the
824 // RenderFrame when the navigation can commit. A speculative RenderFrameHost
825 // should not be created at any step.
TEST_F(NavigatorTest,Reload)826 TEST_F(NavigatorTest, Reload) {
827   const GURL kUrl("http://www.google.com/");
828   contents()->NavigateAndCommit(kUrl);
829 
830   FrameTreeNode* node = main_test_rfh()->frame_tree_node();
831   controller().Reload(ReloadType::NORMAL, false);
832   auto reload1 = NavigationSimulator::CreateFromPending(contents());
833   // A NavigationRequest should have been generated.
834   NavigationRequest* main_request = node->navigation_request();
835   ASSERT_TRUE(main_request != nullptr);
836   EXPECT_EQ(mojom::NavigationType::RELOAD,
837             main_request->common_params().navigation_type);
838   reload1->ReadyToCommit();
839   EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
840 
841   reload1->Commit();
842   EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
843 
844   // Now do a shift+reload.
845   controller().Reload(ReloadType::BYPASSING_CACHE, false);
846   auto reload2 = NavigationSimulator::CreateFromPending(contents());
847   // A NavigationRequest should have been generated.
848   main_request = node->navigation_request();
849   ASSERT_TRUE(main_request != nullptr);
850   EXPECT_EQ(mojom::NavigationType::RELOAD_BYPASSING_CACHE,
851             main_request->common_params().navigation_type);
852   reload2->ReadyToCommit();
853   EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
854 }
855 
856 // PlzNavigate: Confirm that a speculative RenderFrameHost is used when
857 // navigating from one site to another.
TEST_F(NavigatorTest,SpeculativeRendererWorksBaseCase)858 TEST_F(NavigatorTest, SpeculativeRendererWorksBaseCase) {
859   // Navigate to an initial site.
860   const GURL kUrlInit("http://wikipedia.org/");
861   contents()->NavigateAndCommit(kUrlInit);
862   FrameTreeNode* node = main_test_rfh()->frame_tree_node();
863 
864   // Begin navigating to another site.
865   const GURL kUrl("http://google.com/");
866   EXPECT_FALSE(main_test_rfh()->navigation_request());
867   auto navigation =
868       NavigationSimulator::CreateBrowserInitiated(kUrl, contents());
869   navigation->Start();
870   TestRenderFrameHost* speculative_rfh = GetSpeculativeRenderFrameHost(node);
871   int32_t site_instance_id = speculative_rfh->GetSiteInstance()->GetId();
872   ASSERT_TRUE(speculative_rfh);
873   EXPECT_NE(speculative_rfh, main_test_rfh());
874   if (AreDefaultSiteInstancesEnabled()) {
875     EXPECT_TRUE(speculative_rfh->GetSiteInstance()->IsDefaultSiteInstance());
876   } else {
877     EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrl),
878               speculative_rfh->GetSiteInstance()->GetSiteURL());
879   }
880 
881   navigation->ReadyToCommit();
882   EXPECT_EQ(speculative_rfh->navigation_requests().size(), 1u);
883 
884   // Ask the navigation to commit.
885   navigation->Commit();
886   EXPECT_EQ(site_instance_id, main_test_rfh()->GetSiteInstance()->GetId());
887   EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
888 }
889 
890 // PlzNavigate: Confirm that a speculative RenderFrameHost is thrown away when
891 // the final URL's site differs from the initial one due to redirects.
TEST_F(NavigatorTest,SpeculativeRendererDiscardedAfterRedirectToAnotherSite)892 TEST_F(NavigatorTest, SpeculativeRendererDiscardedAfterRedirectToAnotherSite) {
893   // Navigate to an initial site.
894   const GURL kUrlInit("http://wikipedia.org/");
895   contents()->NavigateAndCommit(kUrlInit);
896   FrameTreeNode* node = main_test_rfh()->frame_tree_node();
897   int32_t init_site_instance_id = main_test_rfh()->GetSiteInstance()->GetId();
898 
899   // Begin navigating to another site.
900   const GURL kUrl("http://google.com/");
901   EXPECT_FALSE(main_test_rfh()->navigation_request());
902   auto navigation =
903       NavigationSimulator::CreateBrowserInitiated(kUrl, contents());
904   navigation->Start();
905 
906   TestRenderFrameHost* speculative_rfh = GetSpeculativeRenderFrameHost(node);
907   ASSERT_TRUE(speculative_rfh);
908   int32_t site_instance_id = speculative_rfh->GetSiteInstance()->GetId();
909   RenderFrameDeletedObserver rfh_deleted_observer(speculative_rfh);
910   EXPECT_NE(init_site_instance_id, site_instance_id);
911   EXPECT_EQ(init_site_instance_id, main_test_rfh()->GetSiteInstance()->GetId());
912   EXPECT_NE(speculative_rfh, main_test_rfh());
913 
914   if (AreDefaultSiteInstancesEnabled()) {
915     EXPECT_TRUE(speculative_rfh->GetSiteInstance()->IsDefaultSiteInstance());
916   } else {
917     EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrl),
918               speculative_rfh->GetSiteInstance()->GetSiteURL());
919   }
920 
921   // It then redirects to yet another site.
922   NavigationRequest* main_request = node->navigation_request();
923   ASSERT_TRUE(main_request);
924   const GURL kUrlRedirect("https://www.google.com/");
925   navigation->Redirect(kUrlRedirect);
926   EXPECT_EQ(init_site_instance_id, main_test_rfh()->GetSiteInstance()->GetId());
927 
928   // For now, ensure that the speculative RenderFrameHost does not change after
929   // the redirect.
930   // TODO(carlosk): once the speculative RenderFrameHost updates with redirects
931   // this next check will be changed to verify that it actually happens.
932   EXPECT_EQ(speculative_rfh, GetSpeculativeRenderFrameHost(node));
933   EXPECT_EQ(site_instance_id, speculative_rfh->GetSiteInstance()->GetId());
934   EXPECT_FALSE(rfh_deleted_observer.deleted());
935 
936   // Send the commit to the renderer.
937   navigation->ReadyToCommit();
938 
939   // Once commit happens the speculative RenderFrameHost is updated to match the
940   // known final SiteInstance.
941   speculative_rfh = GetSpeculativeRenderFrameHost(node);
942   ASSERT_TRUE(speculative_rfh);
943   EXPECT_EQ(speculative_rfh->navigation_requests().size(), 1u);
944   EXPECT_EQ(init_site_instance_id, main_test_rfh()->GetSiteInstance()->GetId());
945 
946   int32_t redirect_site_instance_id =
947       speculative_rfh->GetSiteInstance()->GetId();
948 
949   // Expect the initial and redirect SiteInstances to be different because
950   // they should be associated with different BrowsingInstances.
951   EXPECT_NE(init_site_instance_id, redirect_site_instance_id);
952 
953   if (AreDefaultSiteInstancesEnabled()) {
954     EXPECT_TRUE(speculative_rfh->GetSiteInstance()->IsDefaultSiteInstance());
955     EXPECT_EQ(site_instance_id, redirect_site_instance_id);
956 
957     // Verify the old speculative RenderFrameHost was not deleted because
958     // the SiteInstance stayed the same.
959     EXPECT_FALSE(rfh_deleted_observer.deleted());
960   } else {
961     EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrlRedirect),
962               speculative_rfh->GetSiteInstance()->GetSiteURL());
963     EXPECT_NE(site_instance_id, redirect_site_instance_id);
964 
965     // Verify the old speculative RenderFrameHost was deleted because
966     // the SiteInstance changed.
967     EXPECT_TRUE(rfh_deleted_observer.deleted());
968   }
969 
970   // Invoke DidCommitProvisionalLoad.
971   navigation->Commit();
972 
973   // Check that the speculative RenderFrameHost was swapped in.
974   EXPECT_EQ(redirect_site_instance_id,
975             main_test_rfh()->GetSiteInstance()->GetId());
976   EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
977 }
978 
979 // PlzNavigate: Verify that data urls are properly handled.
TEST_F(NavigatorTest,DataUrls)980 TEST_F(NavigatorTest, DataUrls) {
981   const GURL kUrl1("http://wikipedia.org/");
982   const GURL kUrl2("data:text/html,test");
983 
984   // Isolate kUrl1 so it can't be mapped into a default SiteInstance along with
985   // kUrl2. This ensures that the speculative RenderFrameHost will always be
986   // used because the URLs map to different SiteInstances.
987   ChildProcessSecurityPolicy::GetInstance()->AddIsolatedOrigins(
988       {url::Origin::Create(kUrl1)},
989       ChildProcessSecurityPolicy::IsolatedOriginSource::TEST,
990       browser_context());
991 
992   // Navigate to an initial site.
993   contents()->NavigateAndCommit(kUrl1);
994   FrameTreeNode* node = main_test_rfh()->frame_tree_node();
995 
996   EXPECT_FALSE(main_test_rfh()->GetSiteInstance()->IsDefaultSiteInstance());
997 
998   // Navigate to a data url. The request should have been sent to the IO
999   // thread and not committed immediately.
1000   auto navigation =
1001       NavigationSimulator::CreateBrowserInitiated(kUrl2, contents());
1002   navigation->Start();
1003   TestRenderFrameHost* speculative_rfh = GetSpeculativeRenderFrameHost(node);
1004   ASSERT_TRUE(speculative_rfh);
1005   EXPECT_FALSE(speculative_rfh->is_loading());
1006   EXPECT_TRUE(node->navigation_request());
1007   navigation->ReadyToCommit();
1008   EXPECT_TRUE(speculative_rfh->is_loading());
1009   EXPECT_FALSE(node->navigation_request());
1010   EXPECT_NE(main_test_rfh(), speculative_rfh);
1011   navigation->Commit();
1012   EXPECT_EQ(main_test_rfh(), speculative_rfh);
1013 
1014   // Go back to the initial site.
1015   contents()->NavigateAndCommit(kUrl1);
1016 
1017   // Do a renderer-initiated navigation to a data url. The request should be
1018   // sent to the IO thread.
1019   auto navigation_to_data_url =
1020       NavigationSimulator::CreateRendererInitiated(kUrl2, main_test_rfh());
1021   navigation_to_data_url->Start();
1022   EXPECT_FALSE(main_test_rfh()->is_loading());
1023   EXPECT_TRUE(node->navigation_request());
1024   EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
1025 }
1026 
1027 // Tests several cases for converting SiteInstanceDescriptors into
1028 // SiteInstances:
1029 // 1) Pointer to the current SiteInstance.
1030 // 2) Pointer to an unrelated SiteInstance.
1031 // 3) Same-site URL, related.
1032 // 4) Cross-site URL, related.
1033 // 5) Same-site URL, unrelated (with and without candidate SiteInstances).
1034 // 6) Cross-site URL, unrelated (with candidate SiteInstance).
TEST_F(NavigatorTest,SiteInstanceDescriptionConversion)1035 TEST_F(NavigatorTest, SiteInstanceDescriptionConversion) {
1036   // Navigate to set a current SiteInstance on the RenderFrameHost.
1037   GURL kUrl1("http://a.com");
1038   // Isolate one of the sites so the both can't be mapped to the default
1039   // site instance.
1040   ChildProcessSecurityPolicy::GetInstance()->AddIsolatedOrigins(
1041       {url::Origin::Create(kUrl1)},
1042       ChildProcessSecurityPolicy::IsolatedOriginSource::TEST,
1043       browser_context());
1044   contents()->NavigateAndCommit(kUrl1);
1045   SiteInstance* current_instance = main_test_rfh()->GetSiteInstance();
1046   ASSERT_TRUE(current_instance);
1047 
1048   // 1) Convert a descriptor pointing to the current instance.
1049   RenderFrameHostManager* rfhm =
1050       main_test_rfh()->frame_tree_node()->render_manager();
1051   {
1052     SiteInstanceDescriptor descriptor(current_instance);
1053     scoped_refptr<SiteInstance> converted_instance =
1054         ConvertToSiteInstance(rfhm, descriptor, nullptr);
1055     EXPECT_EQ(current_instance, converted_instance);
1056   }
1057 
1058   // 2) Convert a descriptor pointing an instance unrelated to the current one,
1059   // with a different site.
1060   GURL kUrl2("http://b.com");
1061   scoped_refptr<SiteInstance> unrelated_instance(
1062       SiteInstance::CreateForURL(browser_context(), kUrl2));
1063   EXPECT_FALSE(
1064       current_instance->IsRelatedSiteInstance(unrelated_instance.get()));
1065   {
1066     SiteInstanceDescriptor descriptor(unrelated_instance.get());
1067     scoped_refptr<SiteInstance> converted_instance =
1068         ConvertToSiteInstance(rfhm, descriptor, nullptr);
1069     EXPECT_EQ(unrelated_instance.get(), converted_instance);
1070   }
1071 
1072   // 3) Convert a descriptor of a related instance with the same site as the
1073   // current one.
1074   GURL kUrlSameSiteAs1("http://www.a.com/foo");
1075   {
1076     SiteInstanceDescriptor descriptor(
1077         UrlInfo::CreateForTesting(kUrlSameSiteAs1),
1078         SiteInstanceRelation::RELATED,
1079         CoopCoepCrossOriginIsolatedInfo::CreateNonIsolated());
1080     scoped_refptr<SiteInstance> converted_instance =
1081         ConvertToSiteInstance(rfhm, descriptor, nullptr);
1082     EXPECT_EQ(current_instance, converted_instance);
1083   }
1084 
1085   // 4) Convert a descriptor of a related instance with a site different from
1086   // the current one.
1087   GURL kUrlSameSiteAs2("http://www.b.com/foo");
1088   scoped_refptr<SiteInstance> related_instance;
1089   {
1090     SiteInstanceDescriptor descriptor(
1091         UrlInfo::CreateForTesting(kUrlSameSiteAs2),
1092         SiteInstanceRelation::RELATED,
1093         CoopCoepCrossOriginIsolatedInfo::CreateNonIsolated());
1094     related_instance = ConvertToSiteInstance(rfhm, descriptor, nullptr);
1095     // If kUrlSameSiteAs2 requires a dedicated process on this platform, this
1096     // should return a new instance, related to the current and set to the new
1097     // site URL.
1098     // Otherwise, this should return the default site instance
1099     EXPECT_TRUE(
1100         current_instance->IsRelatedSiteInstance(related_instance.get()));
1101     EXPECT_NE(current_instance, related_instance.get());
1102     EXPECT_NE(unrelated_instance.get(), related_instance.get());
1103 
1104     if (AreAllSitesIsolatedForTesting()) {
1105       EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrlSameSiteAs2),
1106                 related_instance->GetSiteURL());
1107     } else {
1108       EXPECT_TRUE(static_cast<SiteInstanceImpl*>(related_instance.get())
1109                       ->IsDefaultSiteInstance());
1110     }
1111   }
1112 
1113   // 5) Convert a descriptor of an unrelated instance with the same site as the
1114   // current one, several times, with and without candidate sites.
1115   {
1116     SiteInstanceDescriptor descriptor(
1117         UrlInfo::CreateForTesting(kUrlSameSiteAs1),
1118         SiteInstanceRelation::UNRELATED,
1119         CoopCoepCrossOriginIsolatedInfo::CreateNonIsolated());
1120     scoped_refptr<SiteInstance> converted_instance_1 =
1121         ConvertToSiteInstance(rfhm, descriptor, nullptr);
1122     // Should return a new instance, unrelated to the current one, set to the
1123     // provided site URL.
1124     EXPECT_FALSE(
1125         current_instance->IsRelatedSiteInstance(converted_instance_1.get()));
1126     EXPECT_NE(current_instance, converted_instance_1.get());
1127     EXPECT_NE(unrelated_instance.get(), converted_instance_1.get());
1128     EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrlSameSiteAs1),
1129               converted_instance_1->GetSiteURL());
1130 
1131     // Does the same but this time using unrelated_instance as a candidate,
1132     // which has a different site.
1133     scoped_refptr<SiteInstance> converted_instance_2 =
1134         ConvertToSiteInstance(rfhm, descriptor, unrelated_instance.get());
1135     // Should return yet another new instance, unrelated to the current one, set
1136     // to the same site URL.
1137     EXPECT_FALSE(
1138         current_instance->IsRelatedSiteInstance(converted_instance_2.get()));
1139     EXPECT_NE(current_instance, converted_instance_2.get());
1140     EXPECT_NE(unrelated_instance.get(), converted_instance_2.get());
1141     EXPECT_NE(converted_instance_1.get(), converted_instance_2.get());
1142     EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrlSameSiteAs1),
1143               converted_instance_2->GetSiteURL());
1144 
1145     // Converts once more but with |converted_instance_1| as a candidate.
1146     scoped_refptr<SiteInstance> converted_instance_3 =
1147         ConvertToSiteInstance(rfhm, descriptor, converted_instance_1.get());
1148     // Should return |converted_instance_1| because its site matches and it is
1149     // unrelated to the current SiteInstance.
1150     EXPECT_EQ(converted_instance_1.get(), converted_instance_3);
1151   }
1152 
1153   // 6) Convert a descriptor of an unrelated instance with the same site of
1154   // related_instance and using it as a candidate.
1155   {
1156     SiteInstanceDescriptor descriptor(
1157         UrlInfo::CreateForTesting(kUrlSameSiteAs2),
1158         SiteInstanceRelation::UNRELATED,
1159         CoopCoepCrossOriginIsolatedInfo::CreateNonIsolated());
1160     scoped_refptr<SiteInstance> converted_instance_1 =
1161         ConvertToSiteInstance(rfhm, descriptor, related_instance.get());
1162     // Should return a new instance, unrelated to the current, set to the
1163     // provided site URL.
1164     EXPECT_FALSE(
1165         current_instance->IsRelatedSiteInstance(converted_instance_1.get()));
1166     EXPECT_NE(related_instance.get(), converted_instance_1.get());
1167     EXPECT_NE(unrelated_instance.get(), converted_instance_1.get());
1168 
1169     if (AreDefaultSiteInstancesEnabled()) {
1170       EXPECT_TRUE(static_cast<SiteInstanceImpl*>(converted_instance_1.get())
1171                       ->IsDefaultSiteInstance());
1172     } else {
1173       EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrlSameSiteAs2),
1174                 converted_instance_1->GetSiteURL());
1175     }
1176 
1177     scoped_refptr<SiteInstance> converted_instance_2 =
1178         ConvertToSiteInstance(rfhm, descriptor, unrelated_instance.get());
1179     // Should return |unrelated_instance| because its site matches and it is
1180     // unrelated to the current SiteInstance.
1181     EXPECT_EQ(unrelated_instance.get(), converted_instance_2);
1182   }
1183 }
1184 
1185 // A renderer process might try and claim that a cross site navigation was
1186 // within the same document by setting was_within_same_document = true in
1187 // FrameHostMsg_DidCommitProvisionalLoad_Params. Such case should be detected on
1188 // the browser side and the renderer process should be killed.
TEST_F(NavigatorTest,CrossSiteClaimWithinPage)1189 TEST_F(NavigatorTest, CrossSiteClaimWithinPage) {
1190   const GURL kUrl1("http://www.chromium.org/");
1191   const GURL kUrl2("http://www.google.com/");
1192 
1193   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), kUrl1);
1194 
1195   // Navigate to a different site and claim that the navigation was within same
1196   // page.
1197   int bad_msg_count = process()->bad_msg_count();
1198   auto simulator =
1199       NavigationSimulator::CreateRendererInitiated(kUrl2, main_test_rfh());
1200   simulator->CommitSameDocument();
1201   EXPECT_EQ(process()->bad_msg_count(), bad_msg_count + 1);
1202 }
1203 
1204 // Tests that an ongoing NavigationRequest is deleted when a same-site
1205 // user-initiated navigation commits.
TEST_F(NavigatorTest,NavigationRequestDeletedWhenUserInitiatedCommits)1206 TEST_F(NavigatorTest, NavigationRequestDeletedWhenUserInitiatedCommits) {
1207   const GURL kUrl1("http://www.chromium.org/");
1208   const GURL kUrl2("http://www.chromium.org/foo");
1209   const GURL kUrl3("http://www.google.com/");
1210 
1211   contents()->NavigateAndCommit(kUrl1);
1212   FrameTreeNode* node = main_test_rfh()->frame_tree_node();
1213 
1214   // The test below only makes sense if the same-site navigation below will not
1215   // create a speculative RFH, so we need to ensure that we won't trigger a
1216   // same-site cross-RFH navigation.
1217   // Note: this will not disable RenderDocument.
1218   // TODO(crbug.com/936696): Skip this test when main-frame RenderDocument is
1219   // enabled.
1220   DisableProactiveBrowsingInstanceSwapFor(main_test_rfh());
1221 
1222   // Navigate same-site.
1223   auto navigation =
1224       NavigationSimulator::CreateBrowserInitiated(kUrl2, contents());
1225   navigation->ReadyToCommit();
1226   EXPECT_TRUE(main_test_rfh()->is_loading());
1227   EXPECT_FALSE(node->navigation_request());
1228 
1229   // Start a new cross-site navigation. The current RFH should still be trying
1230   // to commit the previous navigation, but we create a NavigationRequest in the
1231   // FrameTreeNode.
1232   auto navigation2 =
1233       NavigationSimulator::CreateBrowserInitiated(kUrl3, contents());
1234   navigation2->Start();
1235   EXPECT_TRUE(main_test_rfh()->is_loading());
1236   EXPECT_TRUE(node->navigation_request());
1237   EXPECT_TRUE(GetSpeculativeRenderFrameHost(node));
1238 
1239   // The first navigation commits. This should clear up the speculative RFH and
1240   // the ongoing NavigationRequest.
1241   navigation->Commit();
1242   EXPECT_FALSE(node->navigation_request());
1243   EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
1244 }
1245 
1246 // Tests that an ongoing NavigationRequest is deleted when a cross-site
1247 // navigation commits.
TEST_F(NavigatorTest,NavigationRequestDeletedWhenCrossSiteCommits)1248 TEST_F(NavigatorTest, NavigationRequestDeletedWhenCrossSiteCommits) {
1249   const GURL kUrl1("http://www.chromium.org/");
1250   const GURL kUrl2("http://www.google.com/");
1251   const GURL kUrl3("http://www.google.com/foo");
1252 
1253   contents()->NavigateAndCommit(kUrl1);
1254   FrameTreeNode* node = main_test_rfh()->frame_tree_node();
1255 
1256   // Navigate cross-site.
1257   auto navigation =
1258       NavigationSimulator::CreateBrowserInitiated(kUrl2, contents());
1259   navigation->ReadyToCommit();
1260   TestRenderFrameHost* speculative_rfh = GetSpeculativeRenderFrameHost(node);
1261   ASSERT_TRUE(speculative_rfh);
1262   EXPECT_TRUE(speculative_rfh->is_loading());
1263   EXPECT_FALSE(node->navigation_request());
1264 
1265   // Start a new cross-site navigation to the same-site as the ongoing
1266   // navigation. The speculative RFH should still be live and trying
1267   // to commit the previous navigation, and we create a NavigationRequest in the
1268   // FrameTreeNode.
1269   auto navigation2 =
1270       NavigationSimulator::CreateBrowserInitiated(kUrl3, contents());
1271   navigation2->Start();
1272   TestRenderFrameHost* speculative_rfh_2 = GetSpeculativeRenderFrameHost(node);
1273   ASSERT_TRUE(speculative_rfh_2);
1274   EXPECT_EQ(speculative_rfh_2, speculative_rfh);
1275   EXPECT_TRUE(speculative_rfh->is_loading());
1276   EXPECT_TRUE(node->navigation_request());
1277 
1278   // The first navigation commits. This should clear up the speculative RFH and
1279   // the ongoing NavigationRequest.
1280   navigation->Commit();
1281   EXPECT_FALSE(node->navigation_request());
1282   EXPECT_FALSE(GetSpeculativeRenderFrameHost(node));
1283   EXPECT_EQ(speculative_rfh, main_test_rfh());
1284 }
1285 
1286 // Feature Policy: Test that the feature policy is reset when navigating pages
1287 // within a site.
TEST_F(NavigatorTest,FeaturePolicySameSiteNavigation)1288 TEST_F(NavigatorTest, FeaturePolicySameSiteNavigation) {
1289   const GURL kUrl1("http://www.chromium.org/");
1290   const GURL kUrl2("http://www.chromium.org/Home");
1291 
1292   contents()->NavigateAndCommit(kUrl1);
1293 
1294   // Check the feature policy before navigation.
1295   const blink::FeaturePolicy* original_feature_policy =
1296       main_test_rfh()->feature_policy();
1297   ASSERT_TRUE(original_feature_policy);
1298 
1299   // Navigate to the new URL.
1300   contents()->NavigateAndCommit(kUrl2);
1301 
1302   // Check the feature policy after navigation.
1303   const blink::FeaturePolicy* final_feature_policy =
1304       main_test_rfh()->feature_policy();
1305   ASSERT_TRUE(final_feature_policy);
1306   ASSERT_NE(original_feature_policy, final_feature_policy);
1307 }
1308 
1309 // Feature Policy: Test that the feature policy is not reset when navigating
1310 // within a page.
TEST_F(NavigatorTest,FeaturePolicyFragmentNavigation)1311 TEST_F(NavigatorTest, FeaturePolicyFragmentNavigation) {
1312   const GURL kUrl1("http://www.chromium.org/");
1313   const GURL kUrl2("http://www.chromium.org/#Home");
1314 
1315   contents()->NavigateAndCommit(kUrl1);
1316 
1317   // Check the feature policy before navigation.
1318   const blink::FeaturePolicy* original_feature_policy =
1319       main_test_rfh()->feature_policy();
1320   ASSERT_TRUE(original_feature_policy);
1321 
1322   // Navigate to the new URL.
1323   contents()->NavigateAndCommit(kUrl2);
1324 
1325   // Check the feature policy after navigation.
1326   const blink::FeaturePolicy* final_feature_policy =
1327       main_test_rfh()->feature_policy();
1328   ASSERT_EQ(original_feature_policy, final_feature_policy);
1329 }
1330 
1331 // Feature Policy: Test that the feature policy is set correctly when inserting
1332 // a new child frame.
TEST_F(NavigatorTest,FeaturePolicyNewChild)1333 TEST_F(NavigatorTest, FeaturePolicyNewChild) {
1334   const GURL kUrl1("http://www.chromium.org/");
1335   const GURL kUrl2("http://www.chromium.org/Home");
1336 
1337   contents()->NavigateAndCommit(kUrl1);
1338 
1339   // Simulate the navigation triggered by inserting a child frame into a page.
1340   TestRenderFrameHost* subframe_rfh =
1341       contents()->GetMainFrame()->AppendChild("child");
1342   NavigationSimulator::NavigateAndCommitFromDocument(kUrl2, subframe_rfh);
1343 
1344   const blink::FeaturePolicy* subframe_feature_policy =
1345       subframe_rfh->feature_policy();
1346   ASSERT_TRUE(subframe_feature_policy);
1347   ASSERT_FALSE(subframe_feature_policy->GetOriginForTest().opaque());
1348 }
1349 
TEST_F(NavigatorTest,TwoNavigationsRacingCommit)1350 TEST_F(NavigatorTest, TwoNavigationsRacingCommit) {
1351   const GURL kUrl1("http://www.chromium.org/");
1352   const GURL kUrl2("http://www.chromium.org/Home");
1353 
1354   EXPECT_EQ(0u, contents()->GetMainFrame()->navigation_requests_.size());
1355 
1356   // Have the first navigation reach ReadyToCommit.
1357   auto first_navigation =
1358       NavigationSimulator::CreateBrowserInitiated(kUrl1, contents());
1359   first_navigation->ReadyToCommit();
1360   EXPECT_EQ(1u, contents()->GetMainFrame()->navigation_requests_.size());
1361 
1362   // A second navigation starts and reaches ReadyToCommit.
1363   auto second_navigation =
1364       NavigationSimulator::CreateBrowserInitiated(kUrl1, contents());
1365   second_navigation->ReadyToCommit();
1366   EXPECT_EQ(2u, contents()->GetMainFrame()->navigation_requests_.size());
1367 
1368   // The first navigation commits.
1369   first_navigation->Commit();
1370   EXPECT_EQ(1u, contents()->GetMainFrame()->navigation_requests_.size());
1371 
1372   // The second navigation commits.
1373   second_navigation->Commit();
1374   EXPECT_EQ(0u, contents()->GetMainFrame()->navigation_requests_.size());
1375 }
1376 
1377 }  // namespace content
1378