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