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.
5 #include "base/command_line.h"
6 #include "base/macros.h"
7 #include "base/time/time.h"
8 #include "content/browser/frame_host/navigation_controller_impl.h"
9 #include "content/browser/frame_host/navigation_entry_impl.h"
10 #include "content/browser/frame_host/navigation_request.h"
11 #include "content/browser/frame_host/navigation_request_info.h"
12 #include "content/browser/frame_host/navigator.h"
13 #include "content/browser/frame_host/navigator_impl.h"
14 #include "content/browser/frame_host/render_frame_host_manager.h"
15 #include "content/browser/site_instance_impl.h"
16 #include "content/browser/streams/stream.h"
17 #include "content/common/frame_messages.h"
18 #include "content/common/navigation_params.h"
19 #include "content/public/browser/stream_handle.h"
20 #include "content/public/common/content_switches.h"
21 #include "content/public/common/url_constants.h"
22 #include "content/public/common/url_utils.h"
23 #include "content/public/test/mock_render_process_host.h"
24 #include "content/test/browser_side_navigation_test_utils.h"
25 #include "content/test/test_navigation_url_loader.h"
26 #include "content/test/test_render_frame_host.h"
27 #include "content/test/test_web_contents.h"
28 #include "net/base/load_flags.h"
29 #include "net/http/http_response_headers.h"
30 #include "net/url_request/redirect_info.h"
31 #include "ui/base/page_transition_types.h"
32 #include "url/url_constants.h"
36 class NavigatorTestWithBrowserSideNavigation
37 : public RenderViewHostImplTestHarness
{
39 // Re-defines the private RenderFrameHostManager::SiteInstanceDescriptor here
40 // to allow access to it from tests.
41 typedef RenderFrameHostManager::SiteInstanceDescriptor SiteInstanceDescriptor
;
43 void SetUp() override
{
44 EnableBrowserSideNavigation();
45 RenderViewHostImplTestHarness::SetUp();
48 TestNavigationURLLoader
* GetLoaderForNavigationRequest(
49 NavigationRequest
* request
) const {
50 return static_cast<TestNavigationURLLoader
*>(request
->loader_for_testing());
53 // Requests a navigation of the specified FrameTreeNode to the specified URL;
54 // returns the unique ID of the pending NavigationEntry.
55 int RequestNavigation(FrameTreeNode
* node
, const GURL
& url
) {
56 return RequestNavigationWithParameters(node
, url
, Referrer(),
57 ui::PAGE_TRANSITION_LINK
);
60 // Requests a navigation of the specified FrameTreeNode to the specified URL,
61 // using other specified parameters; returns the unique ID of the pending
63 int RequestNavigationWithParameters(
66 const Referrer
& referrer
,
67 ui::PageTransition transition_type
) {
68 NavigationController::LoadURLParams
load_params(url
);
69 load_params
.frame_tree_node_id
= node
->frame_tree_node_id();
70 load_params
.referrer
= referrer
;
71 load_params
.transition_type
= transition_type
;
73 controller().LoadURLWithParams(load_params
);
74 return controller().GetPendingEntry()->GetUniqueID();
77 TestRenderFrameHost
* GetSpeculativeRenderFrameHost(FrameTreeNode
* node
) {
78 return static_cast<TestRenderFrameHost
*>(
79 node
->render_manager()->speculative_render_frame_host_
.get());
82 // Checks if this RenderFrameHost sent a single FrameMsg_CommitNavigation
83 // since the last clearing of the sink.
84 // Note: caller must invoke ClearMessages on the sink at some point before
85 // the tracked commit happens to clear up commit messages from previous
87 bool DidRenderFrameHostRequestCommit(TestRenderFrameHost
* rfh
) {
88 const FrameMsg_CommitNavigation
* commit_message
=
89 static_cast<const FrameMsg_CommitNavigation
*>(
90 rfh
->GetProcess()->sink().GetUniqueMessageMatching(
91 FrameMsg_CommitNavigation::ID
));
92 return commit_message
&&
93 rfh
->GetRoutingID() == commit_message
->routing_id();
96 SiteInstance
* ConvertToSiteInstance(RenderFrameHostManager
* rfhm
,
97 const SiteInstanceDescriptor
& descriptor
,
98 SiteInstance
* candidate_instance
) {
99 return rfhm
->ConvertToSiteInstance(descriptor
, candidate_instance
);
103 // PlzNavigate: Test a complete browser-initiated navigation starting with a
104 // non-live renderer.
105 TEST_F(NavigatorTestWithBrowserSideNavigation
,
106 SimpleBrowserInitiatedNavigationFromNonLiveRenderer
) {
107 const GURL
kUrl("http://chromium.org/");
109 EXPECT_FALSE(main_test_rfh()->IsRenderFrameLive());
111 // Start a browser-initiated navigation.
112 int32 site_instance_id
= main_test_rfh()->GetSiteInstance()->GetId();
113 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
114 int entry_id
= RequestNavigation(node
, kUrl
);
115 NavigationRequest
* request
= node
->navigation_request();
116 ASSERT_TRUE(request
);
117 EXPECT_EQ(kUrl
, request
->common_params().url
);
118 EXPECT_TRUE(request
->browser_initiated());
120 // As there's no live renderer the navigation should not wait for a
121 // beforeUnload ACK from the renderer and start right away.
122 EXPECT_EQ(NavigationRequest::STARTED
, request
->state());
123 ASSERT_TRUE(GetLoaderForNavigationRequest(request
));
124 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
125 EXPECT_FALSE(node
->render_manager()->pending_frame_host());
127 // Have the current RenderFrameHost commit the navigation.
128 scoped_refptr
<ResourceResponse
> response(new ResourceResponse
);
129 GetLoaderForNavigationRequest(request
)
130 ->CallOnResponseStarted(response
, MakeEmptyStream());
131 EXPECT_TRUE(DidRenderFrameHostRequestCommit(main_test_rfh()));
132 EXPECT_EQ(NavigationRequest::RESPONSE_STARTED
, request
->state());
134 // Commit the navigation.
135 main_test_rfh()->SendNavigate(0, entry_id
, true, kUrl
);
136 EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT
, main_test_rfh()->rfh_state());
137 EXPECT_EQ(SiteInstanceImpl::GetSiteForURL(browser_context(), kUrl
),
138 main_test_rfh()->GetSiteInstance()->GetSiteURL());
139 EXPECT_EQ(kUrl
, contents()->GetLastCommittedURL());
140 EXPECT_FALSE(node
->navigation_request());
141 EXPECT_FALSE(node
->render_manager()->pending_frame_host());
143 // The main RenderFrameHost should not have been changed, and the renderer
144 // should have been initialized.
145 EXPECT_EQ(site_instance_id
, main_test_rfh()->GetSiteInstance()->GetId());
146 EXPECT_TRUE(main_test_rfh()->IsRenderFrameLive());
148 // After a navigation is finished no speculative RenderFrameHost should
150 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
152 // With PlzNavigate enabled a pending RenderFrameHost should never exist.
153 EXPECT_FALSE(node
->render_manager()->pending_frame_host());
156 // PlzNavigate: Test a complete renderer-initiated same-site navigation.
157 TEST_F(NavigatorTestWithBrowserSideNavigation
,
158 SimpleRendererInitiatedSameSiteNavigation
) {
159 const GURL
kUrl1("http://www.chromium.org/");
160 const GURL
kUrl2("http://www.chromium.org/Home");
162 contents()->NavigateAndCommit(kUrl1
);
163 EXPECT_TRUE(main_test_rfh()->IsRenderFrameLive());
165 // Start a renderer-initiated non-user-initiated navigation.
166 process()->sink().ClearMessages();
167 main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl2
, false);
168 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
169 NavigationRequest
* request
= node
->navigation_request();
170 ASSERT_TRUE(request
);
172 // The navigation is immediately started as there's no need to wait for
173 // beforeUnload to be executed.
174 EXPECT_EQ(NavigationRequest::STARTED
, request
->state());
175 EXPECT_FALSE(request
->begin_params().has_user_gesture
);
176 EXPECT_EQ(kUrl2
, request
->common_params().url
);
177 EXPECT_FALSE(request
->browser_initiated());
178 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
180 // Have the current RenderFrameHost commit the navigation.
181 scoped_refptr
<ResourceResponse
> response(new ResourceResponse
);
182 GetLoaderForNavigationRequest(request
)
183 ->CallOnResponseStarted(response
, MakeEmptyStream());
184 EXPECT_TRUE(DidRenderFrameHostRequestCommit(main_test_rfh()));
185 EXPECT_EQ(NavigationRequest::RESPONSE_STARTED
, request
->state());
187 // Commit the navigation.
188 main_test_rfh()->SendNavigate(1, 0, true, kUrl2
);
189 EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT
, main_test_rfh()->rfh_state());
190 EXPECT_EQ(SiteInstanceImpl::GetSiteForURL(browser_context(), kUrl2
),
191 main_test_rfh()->GetSiteInstance()->GetSiteURL());
192 EXPECT_EQ(kUrl2
, contents()->GetLastCommittedURL());
193 EXPECT_FALSE(node
->navigation_request());
194 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
195 EXPECT_FALSE(node
->render_manager()->pending_frame_host());
198 // PlzNavigate: Test a complete renderer-initiated navigation that should be
199 // cross-site but does not result in a SiteInstance swap because its
200 // renderer-initiated.
201 TEST_F(NavigatorTestWithBrowserSideNavigation
,
202 SimpleRendererInitiatedCrossSiteNavigation
) {
203 const GURL
kUrl1("http://www.chromium.org/");
204 const GURL
kUrl2("http://www.google.com");
206 contents()->NavigateAndCommit(kUrl1
);
207 EXPECT_TRUE(main_test_rfh()->IsRenderFrameLive());
208 int32 site_instance_id_1
= main_test_rfh()->GetSiteInstance()->GetId();
210 // Start a renderer-initiated non-user-initiated navigation.
211 process()->sink().ClearMessages();
212 main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl2
, false);
213 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
214 NavigationRequest
* request
= node
->navigation_request();
215 ASSERT_TRUE(request
);
217 // The navigation is immediately started as there's no need to wait for
218 // beforeUnload to be executed.
219 EXPECT_EQ(NavigationRequest::STARTED
, request
->state());
220 EXPECT_FALSE(request
->begin_params().has_user_gesture
);
221 EXPECT_EQ(kUrl2
, request
->common_params().url
);
222 EXPECT_FALSE(request
->browser_initiated());
223 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
225 // Have the current RenderFrameHost commit the navigation.
226 scoped_refptr
<ResourceResponse
> response(new ResourceResponse
);
227 GetLoaderForNavigationRequest(request
)
228 ->CallOnResponseStarted(response
, MakeEmptyStream());
229 EXPECT_TRUE(DidRenderFrameHostRequestCommit(main_test_rfh()));
230 EXPECT_EQ(NavigationRequest::RESPONSE_STARTED
, request
->state());
232 // Commit the navigation.
233 main_test_rfh()->SendNavigate(1, 0, true, kUrl2
);
234 EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT
, main_test_rfh()->rfh_state());
235 EXPECT_EQ(kUrl2
, contents()->GetLastCommittedURL());
236 EXPECT_FALSE(node
->navigation_request());
237 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
238 EXPECT_FALSE(node
->render_manager()->pending_frame_host());
240 // The SiteInstance did not change.
241 EXPECT_EQ(site_instance_id_1
, main_test_rfh()->GetSiteInstance()->GetId());
244 // PlzNavigate: Test that a beforeUnload denial cancels the navigation.
245 TEST_F(NavigatorTestWithBrowserSideNavigation
,
246 BeforeUnloadDenialCancelNavigation
) {
247 const GURL
kUrl1("http://www.google.com/");
248 const GURL
kUrl2("http://www.chromium.org/");
250 contents()->NavigateAndCommit(kUrl1
);
252 // Start a new navigation.
253 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
254 RequestNavigation(node
, kUrl2
);
255 NavigationRequest
* request
= node
->navigation_request();
256 ASSERT_TRUE(request
);
257 EXPECT_TRUE(request
->browser_initiated());
258 EXPECT_EQ(NavigationRequest::WAITING_FOR_RENDERER_RESPONSE
, request
->state());
259 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
261 // Simulate a beforeUnload denial.
262 main_test_rfh()->SendBeforeUnloadACK(false);
263 EXPECT_FALSE(node
->navigation_request());
264 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
267 // PlzNavigate: Test that a proper NavigationRequest is created by
268 // RequestNavigation.
269 TEST_F(NavigatorTestWithBrowserSideNavigation
, BeginNavigation
) {
270 const GURL
kUrl1("http://www.google.com/");
271 const GURL
kUrl2("http://www.chromium.org/");
272 const GURL
kUrl3("http://www.gmail.com/");
274 contents()->NavigateAndCommit(kUrl1
);
277 FrameTreeNode
* root_node
= contents()->GetFrameTree()->root();
278 TestRenderFrameHost
* subframe_rfh
= main_test_rfh()->AppendChild("Child");
279 ASSERT_TRUE(subframe_rfh
);
281 // Start a navigation at the subframe.
282 FrameTreeNode
* subframe_node
= subframe_rfh
->frame_tree_node();
283 RequestNavigation(subframe_node
, kUrl2
);
284 NavigationRequest
* subframe_request
= subframe_node
->navigation_request();
285 TestNavigationURLLoader
* subframe_loader
=
286 GetLoaderForNavigationRequest(subframe_request
);
288 // Subframe navigations should start right away as they don't have to request
289 // beforeUnload to run at the renderer.
290 ASSERT_TRUE(subframe_request
);
291 ASSERT_TRUE(subframe_loader
);
292 EXPECT_EQ(NavigationRequest::STARTED
, subframe_request
->state());
293 EXPECT_EQ(kUrl2
, subframe_request
->common_params().url
);
294 EXPECT_EQ(kUrl2
, subframe_loader
->request_info()->common_params
.url
);
295 // First party for cookies url should be that of the main frame.
296 EXPECT_EQ(kUrl1
, subframe_loader
->request_info()->first_party_for_cookies
);
297 EXPECT_FALSE(subframe_loader
->request_info()->is_main_frame
);
298 EXPECT_TRUE(subframe_loader
->request_info()->parent_is_main_frame
);
299 EXPECT_TRUE(subframe_request
->browser_initiated());
300 EXPECT_FALSE(GetSpeculativeRenderFrameHost(root_node
));
302 // Subframe navigations should never create a speculative RenderFrameHost,
303 // unless site-per-process is enabled. In that case, as the subframe
304 // navigation is to a different site and is still ongoing, it should have one.
305 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
306 switches::kSitePerProcess
)) {
307 EXPECT_TRUE(GetSpeculativeRenderFrameHost(subframe_node
));
309 EXPECT_FALSE(GetSpeculativeRenderFrameHost(subframe_node
));
312 // Now start a navigation at the root node.
313 RequestNavigation(root_node
, kUrl3
);
314 NavigationRequest
* main_request
= root_node
->navigation_request();
315 ASSERT_TRUE(main_request
);
316 EXPECT_EQ(NavigationRequest::WAITING_FOR_RENDERER_RESPONSE
,
317 main_request
->state());
318 EXPECT_FALSE(GetSpeculativeRenderFrameHost(root_node
));
320 // Simulate a BeforeUnloadACK IPC on the main frame.
321 main_test_rfh()->SendBeforeUnloadACK(true);
322 TestNavigationURLLoader
* main_loader
=
323 GetLoaderForNavigationRequest(main_request
);
324 EXPECT_EQ(kUrl3
, main_request
->common_params().url
);
325 EXPECT_EQ(kUrl3
, main_loader
->request_info()->common_params
.url
);
326 EXPECT_EQ(kUrl3
, main_loader
->request_info()->first_party_for_cookies
);
327 EXPECT_TRUE(main_loader
->request_info()->is_main_frame
);
328 EXPECT_FALSE(main_loader
->request_info()->parent_is_main_frame
);
329 EXPECT_TRUE(main_request
->browser_initiated());
330 // BeforeUnloadACK was received from the renderer so the navigation should
332 EXPECT_EQ(NavigationRequest::STARTED
, main_request
->state());
334 // Main frame navigation to a different site should use a speculative
336 EXPECT_TRUE(GetSpeculativeRenderFrameHost(root_node
));
338 // As the main frame hasn't yet committed the subframe still exists. Thus, the
339 // above situation regarding subframe navigations is valid here.
340 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
341 switches::kSitePerProcess
)) {
342 EXPECT_TRUE(GetSpeculativeRenderFrameHost(subframe_node
));
344 EXPECT_FALSE(GetSpeculativeRenderFrameHost(subframe_node
));
348 // PlzNavigate: Test that committing an HTTP 204 or HTTP 205 response cancels
350 TEST_F(NavigatorTestWithBrowserSideNavigation
, NoContent
) {
351 const GURL
kUrl1("http://www.chromium.org/");
352 const GURL
kUrl2("http://www.google.com/");
355 contents()->NavigateAndCommit(kUrl1
);
356 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
358 // Navigate to a different site.
359 process()->sink().ClearMessages();
360 RequestNavigation(node
, kUrl2
);
361 main_test_rfh()->SendBeforeUnloadACK(true);
363 NavigationRequest
* main_request
= node
->navigation_request();
364 ASSERT_TRUE(main_request
);
366 // Navigations to a different site do create a speculative RenderFrameHost.
367 EXPECT_TRUE(GetSpeculativeRenderFrameHost(node
));
369 // Commit an HTTP 204 response.
370 scoped_refptr
<ResourceResponse
> response(new ResourceResponse
);
371 const char kNoContentHeaders
[] = "HTTP/1.1 204 No Content\0\0";
372 response
->head
.headers
= new net::HttpResponseHeaders(
373 std::string(kNoContentHeaders
, arraysize(kNoContentHeaders
)));
374 GetLoaderForNavigationRequest(main_request
)->CallOnResponseStarted(
375 response
, MakeEmptyStream());
377 // There should be no pending nor speculative RenderFrameHost; the navigation
379 EXPECT_FALSE(DidRenderFrameHostRequestCommit(main_test_rfh()));
380 EXPECT_FALSE(node
->navigation_request());
381 EXPECT_FALSE(node
->render_manager()->pending_frame_host());
382 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
384 // Now, repeat the test with 205 Reset Content.
386 // Navigate to a different site again.
387 process()->sink().ClearMessages();
388 RequestNavigation(node
, kUrl2
);
389 main_test_rfh()->SendBeforeUnloadACK(true);
391 main_request
= node
->navigation_request();
392 ASSERT_TRUE(main_request
);
393 EXPECT_TRUE(GetSpeculativeRenderFrameHost(node
));
395 // Commit an HTTP 205 response.
396 response
= new ResourceResponse
;
397 const char kResetContentHeaders
[] = "HTTP/1.1 205 Reset Content\0\0";
398 response
->head
.headers
= new net::HttpResponseHeaders(
399 std::string(kResetContentHeaders
, arraysize(kResetContentHeaders
)));
400 GetLoaderForNavigationRequest(main_request
)->CallOnResponseStarted(
401 response
, MakeEmptyStream());
403 // There should be no pending nor speculative RenderFrameHost; the navigation
405 EXPECT_FALSE(DidRenderFrameHostRequestCommit(main_test_rfh()));
406 EXPECT_FALSE(node
->navigation_request());
407 EXPECT_FALSE(node
->render_manager()->pending_frame_host());
408 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
411 // PlzNavigate: Test that a new RenderFrameHost is created when doing a cross
413 TEST_F(NavigatorTestWithBrowserSideNavigation
, CrossSiteNavigation
) {
414 const GURL
kUrl1("http://www.chromium.org/");
415 const GURL
kUrl2("http://www.google.com/");
417 contents()->NavigateAndCommit(kUrl1
);
418 RenderFrameHostImpl
* initial_rfh
= main_test_rfh();
419 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
421 // Navigate to a different site.
422 process()->sink().ClearMessages();
423 int entry_id
= RequestNavigation(node
, kUrl2
);
424 NavigationRequest
* main_request
= node
->navigation_request();
425 ASSERT_TRUE(main_request
);
426 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
428 // Receive the beforeUnload ACK.
429 main_test_rfh()->SendBeforeUnloadACK(true);
430 EXPECT_TRUE(GetSpeculativeRenderFrameHost(node
));
431 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
433 scoped_refptr
<ResourceResponse
> response(new ResourceResponse
);
434 GetLoaderForNavigationRequest(main_request
)->CallOnResponseStarted(
435 response
, MakeEmptyStream());
436 TestRenderFrameHost
* speculative_rfh
= GetSpeculativeRenderFrameHost(node
);
437 ASSERT_TRUE(speculative_rfh
);
438 EXPECT_TRUE(DidRenderFrameHostRequestCommit(speculative_rfh
));
439 EXPECT_FALSE(DidRenderFrameHostRequestCommit(main_test_rfh()));
440 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
442 speculative_rfh
->SendNavigate(0, entry_id
, true, kUrl2
);
444 RenderFrameHostImpl
* final_rfh
= main_test_rfh();
445 EXPECT_EQ(speculative_rfh
, final_rfh
);
446 EXPECT_NE(initial_rfh
, final_rfh
);
447 EXPECT_TRUE(final_rfh
->IsRenderFrameLive());
448 EXPECT_TRUE(final_rfh
->render_view_host()->IsRenderViewLive());
449 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
452 // PlzNavigate: Test that redirects are followed and the speculative
453 // RenderFrameHost logic behaves as expected.
454 TEST_F(NavigatorTestWithBrowserSideNavigation
, RedirectCrossSite
) {
455 const GURL
kUrl1("http://www.chromium.org/");
456 const GURL
kUrl2("http://www.google.com/");
458 contents()->NavigateAndCommit(kUrl1
);
459 RenderFrameHostImpl
* rfh
= main_test_rfh();
460 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
462 // Navigate to a URL on the same site.
463 process()->sink().ClearMessages();
464 int entry_id
= RequestNavigation(node
, kUrl1
);
465 main_test_rfh()->SendBeforeUnloadACK(true);
466 NavigationRequest
* main_request
= node
->navigation_request();
467 ASSERT_TRUE(main_request
);
468 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
470 // It then redirects to another site.
471 GetLoaderForNavigationRequest(main_request
)->SimulateServerRedirect(kUrl2
);
473 // The redirect should have been followed.
474 EXPECT_EQ(1, GetLoaderForNavigationRequest(main_request
)->redirect_count());
475 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
477 // Have the RenderFrameHost commit the navigation.
478 scoped_refptr
<ResourceResponse
> response(new ResourceResponse
);
479 GetLoaderForNavigationRequest(main_request
)->CallOnResponseStarted(
480 response
, MakeEmptyStream());
481 TestRenderFrameHost
* final_speculative_rfh
=
482 GetSpeculativeRenderFrameHost(node
);
483 EXPECT_TRUE(final_speculative_rfh
);
484 EXPECT_TRUE(DidRenderFrameHostRequestCommit(final_speculative_rfh
));
486 // Commit the navigation.
487 final_speculative_rfh
->SendNavigate(0, entry_id
, true, kUrl2
);
488 RenderFrameHostImpl
* final_rfh
= main_test_rfh();
489 ASSERT_TRUE(final_rfh
);
490 EXPECT_NE(rfh
, final_rfh
);
491 EXPECT_EQ(final_speculative_rfh
, final_rfh
);
492 EXPECT_TRUE(final_rfh
->IsRenderFrameLive());
493 EXPECT_TRUE(final_rfh
->render_view_host()->IsRenderViewLive());
494 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
497 // PlzNavigate: Test that a navigation is canceled if another browser-initiated
498 // request has been issued in the meantime. Also confirms that the speculative
499 // RenderFrameHost is correctly updated in the process.
500 TEST_F(NavigatorTestWithBrowserSideNavigation
,
501 BrowserInitiatedNavigationCancel
) {
502 const GURL
kUrl0("http://www.wikipedia.org/");
503 const GURL
kUrl1("http://www.chromium.org/");
504 const GURL kUrl1_site
= SiteInstance::GetSiteForURL(browser_context(), kUrl1
);
505 const GURL
kUrl2("http://www.google.com/");
506 const GURL kUrl2_site
= SiteInstance::GetSiteForURL(browser_context(), kUrl2
);
509 contents()->NavigateAndCommit(kUrl0
);
510 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
512 // Request navigation to the 1st URL.
513 process()->sink().ClearMessages();
514 RequestNavigation(node
, kUrl1
);
515 main_test_rfh()->SendBeforeUnloadACK(true);
516 NavigationRequest
* request1
= node
->navigation_request();
517 ASSERT_TRUE(request1
);
518 EXPECT_EQ(kUrl1
, request1
->common_params().url
);
519 EXPECT_TRUE(request1
->browser_initiated());
520 base::WeakPtr
<TestNavigationURLLoader
> loader1
=
521 GetLoaderForNavigationRequest(request1
)->AsWeakPtr();
522 EXPECT_TRUE(loader1
);
524 // Confirm a speculative RenderFrameHost was created.
525 TestRenderFrameHost
* speculative_rfh
= GetSpeculativeRenderFrameHost(node
);
526 ASSERT_TRUE(speculative_rfh
);
527 int32 site_instance_id_1
= speculative_rfh
->GetSiteInstance()->GetId();
528 EXPECT_EQ(kUrl1_site
, speculative_rfh
->GetSiteInstance()->GetSiteURL());
530 // Request navigation to the 2nd URL; the NavigationRequest must have been
531 // replaced by a new one with a different URL.
532 int entry_id
= RequestNavigation(node
, kUrl2
);
533 main_test_rfh()->SendBeforeUnloadACK(true);
534 NavigationRequest
* request2
= node
->navigation_request();
535 ASSERT_TRUE(request2
);
536 EXPECT_EQ(kUrl2
, request2
->common_params().url
);
537 EXPECT_TRUE(request2
->browser_initiated());
539 // Confirm that the first loader got destroyed.
540 EXPECT_FALSE(loader1
);
542 // Confirm that a new speculative RenderFrameHost was created.
543 speculative_rfh
= GetSpeculativeRenderFrameHost(node
);
544 ASSERT_TRUE(speculative_rfh
);
545 int32 site_instance_id_2
= speculative_rfh
->GetSiteInstance()->GetId();
546 EXPECT_NE(site_instance_id_1
, site_instance_id_2
);
548 // Have the RenderFrameHost commit the navigation.
549 scoped_refptr
<ResourceResponse
> response(new ResourceResponse
);
550 GetLoaderForNavigationRequest(request2
)->CallOnResponseStarted(
551 response
, MakeEmptyStream());
552 EXPECT_TRUE(DidRenderFrameHostRequestCommit(speculative_rfh
));
553 EXPECT_FALSE(DidRenderFrameHostRequestCommit(main_test_rfh()));
555 // Commit the navigation.
556 speculative_rfh
->SendNavigate(0, entry_id
, true, kUrl2
);
558 // Confirm that the commit corresponds to the new request.
559 ASSERT_TRUE(main_test_rfh());
560 EXPECT_EQ(kUrl2_site
, main_test_rfh()->GetSiteInstance()->GetSiteURL());
561 EXPECT_EQ(kUrl2
, contents()->GetLastCommittedURL());
563 // Confirm that the committed RenderFrameHost is the latest speculative one.
564 EXPECT_EQ(site_instance_id_2
, main_test_rfh()->GetSiteInstance()->GetId());
567 // PlzNavigate: Test that a browser-initiated navigation is canceled if a
568 // renderer-initiated user-initiated request has been issued in the meantime.
569 TEST_F(NavigatorTestWithBrowserSideNavigation
,
570 RendererUserInitiatedNavigationCancel
) {
571 const GURL
kUrl0("http://www.wikipedia.org/");
572 const GURL
kUrl1("http://www.chromium.org/");
573 const GURL
kUrl2("http://www.google.com/");
576 contents()->NavigateAndCommit(kUrl0
);
577 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
579 // Start a browser-initiated navigation to the 1st URL and receive its
581 process()->sink().ClearMessages();
582 RequestNavigation(node
, kUrl1
);
583 main_test_rfh()->SendBeforeUnloadACK(true);
584 NavigationRequest
* request1
= node
->navigation_request();
585 ASSERT_TRUE(request1
);
586 EXPECT_EQ(kUrl1
, request1
->common_params().url
);
587 EXPECT_TRUE(request1
->browser_initiated());
588 base::WeakPtr
<TestNavigationURLLoader
> loader1
=
589 GetLoaderForNavigationRequest(request1
)->AsWeakPtr();
590 EXPECT_TRUE(loader1
);
592 // Confirm that a speculative RenderFrameHost was created.
593 ASSERT_TRUE(GetSpeculativeRenderFrameHost(node
));
595 // Now receive a renderer-initiated user-initiated request. It should replace
596 // the current NavigationRequest.
597 main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl2
, true);
598 NavigationRequest
* request2
= node
->navigation_request();
599 ASSERT_TRUE(request2
);
600 EXPECT_EQ(kUrl2
, request2
->common_params().url
);
601 EXPECT_FALSE(request2
->browser_initiated());
602 EXPECT_TRUE(request2
->begin_params().has_user_gesture
);
604 // Confirm that the first loader got destroyed.
605 EXPECT_FALSE(loader1
);
607 // Confirm that the speculative RenderFrameHost was destroyed.
608 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
610 // Have the RenderFrameHost commit the navigation.
611 scoped_refptr
<ResourceResponse
> response(new ResourceResponse
);
612 GetLoaderForNavigationRequest(request2
)
613 ->CallOnResponseStarted(response
, MakeEmptyStream());
614 EXPECT_TRUE(DidRenderFrameHostRequestCommit(main_test_rfh()));
616 // Commit the navigation.
617 main_test_rfh()->SendNavigate(1, 0, true, kUrl2
);
619 // Confirm that the commit corresponds to the new request.
620 ASSERT_TRUE(main_test_rfh());
621 EXPECT_EQ(kUrl2
, contents()->GetLastCommittedURL());
624 // PlzNavigate: Test that a renderer-initiated user-initiated navigation is NOT
625 // canceled if a renderer-initiated non-user-initiated request is issued in the
627 TEST_F(NavigatorTestWithBrowserSideNavigation
,
628 RendererNonUserInitiatedNavigationDoesntCancelRendererUserInitiated
) {
629 const GURL
kUrl0("http://www.wikipedia.org/");
630 const GURL
kUrl1("http://www.chromium.org/");
631 const GURL
kUrl2("http://www.google.com/");
634 contents()->NavigateAndCommit(kUrl0
);
635 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
637 // Start a renderer-initiated user-initiated navigation to the 1st URL.
638 process()->sink().ClearMessages();
639 main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl1
, true);
640 NavigationRequest
* request1
= node
->navigation_request();
641 ASSERT_TRUE(request1
);
642 EXPECT_EQ(kUrl1
, request1
->common_params().url
);
643 EXPECT_FALSE(request1
->browser_initiated());
644 EXPECT_TRUE(request1
->begin_params().has_user_gesture
);
645 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
647 // Now receive a renderer-initiated non-user-initiated request. Nothing should
649 main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl2
, false);
650 NavigationRequest
* request2
= node
->navigation_request();
651 ASSERT_TRUE(request2
);
652 EXPECT_EQ(request1
, request2
);
653 EXPECT_EQ(kUrl1
, request2
->common_params().url
);
654 EXPECT_FALSE(request2
->browser_initiated());
655 EXPECT_TRUE(request2
->begin_params().has_user_gesture
);
656 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
658 // Have the RenderFrameHost commit the navigation.
659 scoped_refptr
<ResourceResponse
> response(new ResourceResponse
);
660 GetLoaderForNavigationRequest(request2
)
661 ->CallOnResponseStarted(response
, MakeEmptyStream());
662 EXPECT_TRUE(DidRenderFrameHostRequestCommit(main_test_rfh()));
664 // Commit the navigation.
665 main_test_rfh()->SendNavigate(1, 0, true, kUrl1
);
666 EXPECT_EQ(kUrl1
, contents()->GetLastCommittedURL());
669 // PlzNavigate: Test that a browser-initiated navigation is NOT canceled if a
670 // renderer-initiated non-user-initiated request is issued in the meantime.
671 TEST_F(NavigatorTestWithBrowserSideNavigation
,
672 RendererNonUserInitiatedNavigationDoesntCancelBrowserInitiated
) {
673 const GURL
kUrl0("http://www.wikipedia.org/");
674 const GURL
kUrl1("http://www.chromium.org/");
675 const GURL
kUrl2("http://www.google.com/");
678 contents()->NavigateAndCommit(kUrl0
);
679 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
681 // Start a browser-initiated navigation to the 1st URL.
682 process()->sink().ClearMessages();
683 int entry_id
= RequestNavigation(node
, kUrl1
);
684 NavigationRequest
* request1
= node
->navigation_request();
685 ASSERT_TRUE(request1
);
686 EXPECT_EQ(kUrl1
, request1
->common_params().url
);
687 EXPECT_TRUE(request1
->browser_initiated());
688 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
690 // Now receive a renderer-initiated non-user-initiated request. Nothing should
692 main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl2
, false);
693 NavigationRequest
* request2
= node
->navigation_request();
694 ASSERT_TRUE(request2
);
695 EXPECT_EQ(request1
, request2
);
696 EXPECT_EQ(kUrl1
, request2
->common_params().url
);
697 EXPECT_TRUE(request2
->browser_initiated());
698 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
700 // Now receive the beforeUnload ACK from the still ongoing navigation.
701 main_test_rfh()->SendBeforeUnloadACK(true);
702 TestRenderFrameHost
* speculative_rfh
= GetSpeculativeRenderFrameHost(node
);
703 ASSERT_TRUE(speculative_rfh
);
705 // Have the RenderFrameHost commit the navigation.
706 scoped_refptr
<ResourceResponse
> response(new ResourceResponse
);
707 GetLoaderForNavigationRequest(request2
)
708 ->CallOnResponseStarted(response
, MakeEmptyStream());
709 EXPECT_TRUE(DidRenderFrameHostRequestCommit(speculative_rfh
));
710 EXPECT_FALSE(DidRenderFrameHostRequestCommit(main_test_rfh()));
712 // Commit the navigation.
713 speculative_rfh
->SendNavigate(0, entry_id
, true, kUrl1
);
714 EXPECT_EQ(kUrl1
, contents()->GetLastCommittedURL());
717 // PlzNavigate: Test that a renderer-initiated non-user-initiated navigation is
718 // canceled if a another similar request is issued in the meantime.
719 TEST_F(NavigatorTestWithBrowserSideNavigation
,
720 RendererNonUserInitiatedNavigationCancelSimilarNavigation
) {
721 const GURL
kUrl0("http://www.wikipedia.org/");
722 const GURL
kUrl1("http://www.chromium.org/");
723 const GURL
kUrl2("http://www.google.com/");
726 contents()->NavigateAndCommit(kUrl0
);
727 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
728 int32 site_instance_id_0
= main_test_rfh()->GetSiteInstance()->GetId();
730 // Start a renderer-initiated non-user-initiated navigation to the 1st URL.
731 process()->sink().ClearMessages();
732 main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl1
, false);
733 NavigationRequest
* request1
= node
->navigation_request();
734 ASSERT_TRUE(request1
);
735 EXPECT_EQ(kUrl1
, request1
->common_params().url
);
736 EXPECT_FALSE(request1
->browser_initiated());
737 EXPECT_FALSE(request1
->begin_params().has_user_gesture
);
738 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
739 base::WeakPtr
<TestNavigationURLLoader
> loader1
=
740 GetLoaderForNavigationRequest(request1
)->AsWeakPtr();
741 EXPECT_TRUE(loader1
);
743 // Now receive a 2nd similar request that should replace the current one.
744 main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl2
, false);
745 NavigationRequest
* request2
= node
->navigation_request();
746 EXPECT_EQ(kUrl2
, request2
->common_params().url
);
747 EXPECT_FALSE(request2
->browser_initiated());
748 EXPECT_FALSE(request2
->begin_params().has_user_gesture
);
749 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
751 // Confirm that the first loader got destroyed.
752 EXPECT_FALSE(loader1
);
754 // Have the RenderFrameHost commit the navigation.
755 scoped_refptr
<ResourceResponse
> response(new ResourceResponse
);
756 GetLoaderForNavigationRequest(request2
)
757 ->CallOnResponseStarted(response
, MakeEmptyStream());
758 EXPECT_TRUE(DidRenderFrameHostRequestCommit(main_test_rfh()));
760 // Commit the navigation.
761 main_test_rfh()->SendNavigate(1, 0, true, kUrl2
);
762 EXPECT_EQ(kUrl2
, contents()->GetLastCommittedURL());
764 // The SiteInstance did not change.
765 EXPECT_EQ(site_instance_id_0
, main_test_rfh()->GetSiteInstance()->GetId());
768 // PlzNavigate: Test that a reload navigation is properly signaled to the
769 // RenderFrame when the navigation can commit. A speculative RenderFrameHost
770 // should not be created at any step.
771 TEST_F(NavigatorTestWithBrowserSideNavigation
, Reload
) {
772 const GURL
kUrl("http://www.google.com/");
773 contents()->NavigateAndCommit(kUrl
);
775 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
776 controller().Reload(false);
777 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
778 // A NavigationRequest should have been generated.
779 NavigationRequest
* main_request
= node
->navigation_request();
780 ASSERT_TRUE(main_request
!= NULL
);
781 EXPECT_EQ(FrameMsg_Navigate_Type::RELOAD
,
782 main_request
->common_params().navigation_type
);
783 main_test_rfh()->PrepareForCommit();
784 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
786 main_test_rfh()->SendNavigate(0, entry_id
, false, kUrl
);
787 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
789 // Now do a shift+reload.
790 controller().ReloadIgnoringCache(false);
791 // A NavigationRequest should have been generated.
792 main_request
= node
->navigation_request();
793 ASSERT_TRUE(main_request
!= NULL
);
794 EXPECT_EQ(FrameMsg_Navigate_Type::RELOAD_IGNORING_CACHE
,
795 main_request
->common_params().navigation_type
);
796 main_test_rfh()->PrepareForCommit();
797 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
800 // PlzNavigate: Confirm that a speculative RenderFrameHost is used when
801 // navigating from one site to another.
802 TEST_F(NavigatorTestWithBrowserSideNavigation
,
803 SpeculativeRendererWorksBaseCase
) {
804 // Navigate to an initial site.
805 const GURL
kUrlInit("http://wikipedia.org/");
806 contents()->NavigateAndCommit(kUrlInit
);
807 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
809 // Begin navigating to another site.
810 const GURL
kUrl("http://google.com/");
811 process()->sink().ClearMessages();
812 int entry_id
= RequestNavigation(node
, kUrl
);
813 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
815 // Receive the beforeUnload ACK.
816 main_test_rfh()->SendBeforeUnloadACK(true);
817 TestRenderFrameHost
* speculative_rfh
= GetSpeculativeRenderFrameHost(node
);
818 ASSERT_TRUE(speculative_rfh
);
819 EXPECT_NE(speculative_rfh
, main_test_rfh());
820 EXPECT_EQ(SiteInstanceImpl::GetSiteForURL(browser_context(), kUrl
),
821 speculative_rfh
->GetSiteInstance()->GetSiteURL());
822 EXPECT_FALSE(node
->render_manager()->pending_frame_host());
823 int32 site_instance_id
= speculative_rfh
->GetSiteInstance()->GetId();
825 // Ask Navigator to commit the navigation by simulating a call to
826 // OnResponseStarted.
827 scoped_refptr
<ResourceResponse
> response(new ResourceResponse
);
828 GetLoaderForNavigationRequest(node
->navigation_request())
829 ->CallOnResponseStarted(response
, MakeEmptyStream());
830 speculative_rfh
= GetSpeculativeRenderFrameHost(node
);
831 ASSERT_TRUE(speculative_rfh
);
832 EXPECT_TRUE(DidRenderFrameHostRequestCommit(speculative_rfh
));
833 EXPECT_EQ(site_instance_id
, speculative_rfh
->GetSiteInstance()->GetId());
834 EXPECT_FALSE(node
->render_manager()->pending_frame_host());
836 // Invoke OnDidCommitProvisionalLoad.
837 speculative_rfh
->SendNavigate(0, entry_id
, true, kUrl
);
838 EXPECT_EQ(site_instance_id
, main_test_rfh()->GetSiteInstance()->GetId());
839 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
840 EXPECT_FALSE(node
->render_manager()->pending_frame_host());
843 // PlzNavigate: Confirm that a speculative RenderFrameHost is thrown away when
844 // the final URL's site differs from the initial one due to redirects.
845 TEST_F(NavigatorTestWithBrowserSideNavigation
,
846 SpeculativeRendererDiscardedAfterRedirectToAnotherSite
) {
847 // Navigate to an initial site.
848 const GURL
kUrlInit("http://wikipedia.org/");
849 contents()->NavigateAndCommit(kUrlInit
);
850 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
851 int32 init_site_instance_id
= main_test_rfh()->GetSiteInstance()->GetId();
853 // Begin navigating to another site.
854 const GURL
kUrl("http://google.com/");
855 process()->sink().ClearMessages();
856 int entry_id
= RequestNavigation(node
, kUrl
);
857 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
859 // Receive the beforeUnload ACK.
860 main_test_rfh()->SendBeforeUnloadACK(true);
861 TestRenderFrameHost
* speculative_rfh
= GetSpeculativeRenderFrameHost(node
);
862 int32 site_instance_id
= speculative_rfh
->GetSiteInstance()->GetId();
863 EXPECT_NE(init_site_instance_id
, site_instance_id
);
864 EXPECT_EQ(init_site_instance_id
, main_test_rfh()->GetSiteInstance()->GetId());
865 ASSERT_TRUE(speculative_rfh
);
866 EXPECT_NE(speculative_rfh
, main_test_rfh());
867 EXPECT_EQ(SiteInstanceImpl::GetSiteForURL(browser_context(), kUrl
),
868 speculative_rfh
->GetSiteInstance()->GetSiteURL());
870 // It then redirects to yet another site.
871 NavigationRequest
* main_request
= node
->navigation_request();
872 ASSERT_TRUE(main_request
);
873 const GURL
kUrlRedirect("https://www.google.com/");
874 GetLoaderForNavigationRequest(main_request
)
875 ->SimulateServerRedirect(kUrlRedirect
);
876 EXPECT_EQ(init_site_instance_id
, main_test_rfh()->GetSiteInstance()->GetId());
877 speculative_rfh
= GetSpeculativeRenderFrameHost(node
);
878 ASSERT_TRUE(speculative_rfh
);
880 // For now, ensure that the speculative RenderFrameHost does not change after
882 // TODO(carlosk): once the speculative RenderFrameHost updates with redirects
883 // this next check will be changed to verify that it actually happens.
884 EXPECT_EQ(site_instance_id
, speculative_rfh
->GetSiteInstance()->GetId());
886 // Commit the navigation with Navigator by simulating the call to
887 // OnResponseStarted.
888 scoped_refptr
<ResourceResponse
> response(new ResourceResponse
);
889 GetLoaderForNavigationRequest(main_request
)
890 ->CallOnResponseStarted(response
, MakeEmptyStream());
891 speculative_rfh
= GetSpeculativeRenderFrameHost(node
);
892 EXPECT_TRUE(DidRenderFrameHostRequestCommit(speculative_rfh
));
893 EXPECT_EQ(init_site_instance_id
, main_test_rfh()->GetSiteInstance()->GetId());
895 // Once commit happens the speculative RenderFrameHost is updated to match the
896 // known final SiteInstance.
897 ASSERT_TRUE(speculative_rfh
);
898 EXPECT_EQ(SiteInstanceImpl::GetSiteForURL(browser_context(), kUrlRedirect
),
899 speculative_rfh
->GetSiteInstance()->GetSiteURL());
900 int32 redirect_site_instance_id
= speculative_rfh
->GetSiteInstance()->GetId();
901 EXPECT_NE(init_site_instance_id
, redirect_site_instance_id
);
902 EXPECT_NE(site_instance_id
, redirect_site_instance_id
);
904 // Invoke OnDidCommitProvisionalLoad.
905 speculative_rfh
->SendNavigate(0, entry_id
, true, kUrlRedirect
);
907 // Check that the speculative RenderFrameHost was swapped in.
908 EXPECT_EQ(redirect_site_instance_id
,
909 main_test_rfh()->GetSiteInstance()->GetId());
910 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
913 // PlzNavigate: Verify that a previously swapped out RenderFrameHost is
914 // correctly reused when spawning a speculative RenderFrameHost in a navigation
915 // using the same SiteInstance.
916 TEST_F(NavigatorTestWithBrowserSideNavigation
,
917 SpeculativeRendererReuseSwappedOutRFH
) {
918 // Navigate to an initial site.
919 const GURL
kUrl1("http://wikipedia.org/");
920 contents()->NavigateAndCommit(kUrl1
);
921 TestRenderFrameHost
* rfh1
= main_test_rfh();
922 FrameTreeNode
* node
= rfh1
->frame_tree_node();
923 RenderFrameHostManager
* rfhm
= node
->render_manager();
925 // Increment active frame count to cause the RenderFrameHost to be swapped out
926 // (instead of immediately destroyed).
927 rfh1
->GetSiteInstance()->increment_active_frame_count();
929 // Navigate to another site to swap out the initial RenderFrameHost.
930 const GURL
kUrl2("http://chromium.org/");
931 contents()->NavigateAndCommit(kUrl2
);
932 ASSERT_NE(rfh1
, main_test_rfh());
933 EXPECT_NE(RenderFrameHostImpl::STATE_DEFAULT
, rfh1
->rfh_state());
934 EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT
, main_test_rfh()->rfh_state());
935 EXPECT_TRUE(rfhm
->IsOnSwappedOutList(rfh1
));
937 // Now go back to the initial site so that the swapped out RenderFrameHost
939 process()->sink().ClearMessages();
940 rfh1
->GetProcess()->sink().ClearMessages();
941 int entry_id
= RequestNavigation(node
, kUrl1
);
942 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
944 main_test_rfh()->SendBeforeUnloadACK(true);
945 EXPECT_EQ(rfh1
, GetSpeculativeRenderFrameHost(node
));
946 EXPECT_NE(RenderFrameHostImpl::STATE_DEFAULT
,
947 GetSpeculativeRenderFrameHost(node
)->rfh_state());
949 scoped_refptr
<ResourceResponse
> response(new ResourceResponse
);
950 GetLoaderForNavigationRequest(node
->navigation_request())
951 ->CallOnResponseStarted(response
, MakeEmptyStream());
952 EXPECT_EQ(rfh1
, GetSpeculativeRenderFrameHost(node
));
953 EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT
,
954 GetSpeculativeRenderFrameHost(node
)->rfh_state());
955 EXPECT_TRUE(DidRenderFrameHostRequestCommit(rfh1
));
956 EXPECT_FALSE(DidRenderFrameHostRequestCommit(main_test_rfh()));
958 rfh1
->SendNavigate(1, entry_id
, true, kUrl1
);
959 EXPECT_EQ(rfh1
, main_test_rfh());
960 EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT
, rfh1
->rfh_state());
961 EXPECT_FALSE(rfhm
->IsOnSwappedOutList(rfh1
));
964 // PlzNavigate: Verify that data urls are properly handled.
965 TEST_F(NavigatorTestWithBrowserSideNavigation
, DataUrls
) {
966 const GURL
kUrl1("http://wikipedia.org/");
967 const GURL
kUrl2("data:text/html,test");
969 // Navigate to an initial site.
970 contents()->NavigateAndCommit(kUrl1
);
971 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
973 // Navigate to a data url.
974 int entry_id
= RequestNavigation(node
, kUrl2
);
975 NavigationRequest
* navigation_request
= node
->navigation_request();
976 ASSERT_TRUE(navigation_request
);
977 EXPECT_EQ(NavigationRequest::WAITING_FOR_RENDERER_RESPONSE
,
978 navigation_request
->state());
979 main_test_rfh()->SendBeforeUnloadACK(true);
981 // The request should not have been sent to the IO thread but committed
983 EXPECT_EQ(NavigationRequest::RESPONSE_STARTED
,
984 navigation_request
->state());
985 EXPECT_FALSE(navigation_request
->loader_for_testing());
986 TestRenderFrameHost
* speculative_rfh
= GetSpeculativeRenderFrameHost(node
);
987 ASSERT_TRUE(speculative_rfh
);
988 speculative_rfh
->SendNavigate(0, entry_id
, true, kUrl2
);
989 EXPECT_EQ(main_test_rfh(), speculative_rfh
);
991 // Go back to the initial site.
992 contents()->NavigateAndCommit(kUrl1
);
994 // Do a renderer-initiated navigation to a data url. The request should not be
995 // sent to the IO thread, nor committed.
996 TestRenderFrameHost
* main_rfh
= main_test_rfh();
997 main_rfh
->SendRendererInitiatedNavigationRequest(kUrl2
, true);
998 navigation_request
= node
->navigation_request();
999 ASSERT_TRUE(navigation_request
);
1000 EXPECT_EQ(NavigationRequest::RESPONSE_STARTED
,
1001 navigation_request
->state());
1002 EXPECT_FALSE(navigation_request
->loader_for_testing());
1003 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
1006 // Tests several cases for converting SiteInstanceDescriptors into
1008 // 1) Pointer to the current SiteInstance.
1009 // 2) Pointer to an unrelated SiteInstance.
1010 // 3) Same-site URL, related.
1011 // 4) Cross-site URL, related.
1012 // 5) Same-site URL, unrelated (with and without candidate SiteInstances).
1013 // 6) Cross-site URL, unrelated (with candidate SiteInstance).
1014 TEST_F(NavigatorTestWithBrowserSideNavigation
,
1015 SiteInstanceDescriptionConversion
) {
1016 // Navigate to set a current SiteInstance on the RenderFrameHost.
1017 GURL
kUrl1("http://a.com");
1018 contents()->NavigateAndCommit(kUrl1
);
1019 SiteInstance
* current_instance
= main_test_rfh()->GetSiteInstance();
1020 ASSERT_TRUE(current_instance
);
1022 // 1) Convert a descriptor pointing to the current instance.
1023 RenderFrameHostManager
* rfhm
=
1024 main_test_rfh()->frame_tree_node()->render_manager();
1026 SiteInstanceDescriptor
descriptor(current_instance
);
1027 SiteInstance
* converted_instance
=
1028 ConvertToSiteInstance(rfhm
, descriptor
, nullptr);
1029 EXPECT_EQ(current_instance
, converted_instance
);
1032 // 2) Convert a descriptor pointing an instance unrelated to the current one,
1033 // with a different site.
1034 GURL
kUrl2("http://b.com");
1035 scoped_refptr
<SiteInstance
> unrelated_instance(
1036 SiteInstance::CreateForURL(browser_context(), kUrl2
));
1038 current_instance
->IsRelatedSiteInstance(unrelated_instance
.get()));
1040 SiteInstanceDescriptor
descriptor(unrelated_instance
.get());
1041 SiteInstance
* converted_instance
=
1042 ConvertToSiteInstance(rfhm
, descriptor
, nullptr);
1043 EXPECT_EQ(unrelated_instance
.get(), converted_instance
);
1046 // 3) Convert a descriptor of a related instance with the same site as the
1048 GURL
kUrlSameSiteAs1("http://www.a.com/foo");
1050 SiteInstanceDescriptor
descriptor(browser_context(), kUrlSameSiteAs1
, true);
1051 SiteInstance
* converted_instance
=
1052 ConvertToSiteInstance(rfhm
, descriptor
, nullptr);
1053 EXPECT_EQ(current_instance
, converted_instance
);
1056 // 4) Convert a descriptor of a related instance with a site different from
1058 GURL
kUrlSameSiteAs2("http://www.b.com/foo");
1059 scoped_refptr
<SiteInstance
> related_instance
;
1061 SiteInstanceDescriptor
descriptor(browser_context(), kUrlSameSiteAs2
, true);
1062 related_instance
= ConvertToSiteInstance(rfhm
, descriptor
, nullptr);
1063 // Should return a new instance, related to the current, set to the new site
1066 current_instance
->IsRelatedSiteInstance(related_instance
.get()));
1067 EXPECT_NE(current_instance
, related_instance
.get());
1068 EXPECT_NE(unrelated_instance
.get(), related_instance
.get());
1069 EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrlSameSiteAs2
),
1070 related_instance
->GetSiteURL());
1073 // 5) Convert a descriptor of an unrelated instance with the same site as the
1074 // current one, several times, with and without candidate sites.
1076 SiteInstanceDescriptor
descriptor(browser_context(), kUrlSameSiteAs1
,
1078 scoped_refptr
<SiteInstance
> converted_instance_1
=
1079 ConvertToSiteInstance(rfhm
, descriptor
, nullptr);
1080 // Should return a new instance, unrelated to the current one, set to the
1081 // provided site URL.
1083 current_instance
->IsRelatedSiteInstance(converted_instance_1
.get()));
1084 EXPECT_NE(current_instance
, converted_instance_1
.get());
1085 EXPECT_NE(unrelated_instance
.get(), converted_instance_1
.get());
1086 EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrlSameSiteAs1
),
1087 converted_instance_1
->GetSiteURL());
1089 // Does the same but this time using unrelated_instance as a candidate,
1090 // which has a different site.
1091 scoped_refptr
<SiteInstance
> converted_instance_2
=
1092 ConvertToSiteInstance(rfhm
, descriptor
, unrelated_instance
.get());
1093 // Should return yet another new instance, unrelated to the current one, set
1094 // to the same site URL.
1096 current_instance
->IsRelatedSiteInstance(converted_instance_2
.get()));
1097 EXPECT_NE(current_instance
, converted_instance_2
.get());
1098 EXPECT_NE(unrelated_instance
.get(), converted_instance_2
.get());
1099 EXPECT_NE(converted_instance_1
.get(), converted_instance_2
.get());
1100 EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrlSameSiteAs1
),
1101 converted_instance_2
->GetSiteURL());
1103 // Converts once more but with |converted_instance_1| as a candidate.
1104 SiteInstance
* converted_instance_3
=
1105 ConvertToSiteInstance(rfhm
, descriptor
, converted_instance_1
.get());
1106 // Should return |converted_instance_1| because its site matches and it is
1107 // unrelated to the current SiteInstance.
1108 EXPECT_EQ(converted_instance_1
.get(), converted_instance_3
);
1111 // 6) Convert a descriptor of an unrelated instance with the same site of
1112 // related_instance and using it as a candidate.
1114 SiteInstanceDescriptor
descriptor(browser_context(), kUrlSameSiteAs2
,
1116 scoped_refptr
<SiteInstance
> converted_instance_1
=
1117 ConvertToSiteInstance(rfhm
, descriptor
, related_instance
.get());
1118 // Should return a new instance, unrelated to the current, set to the
1119 // provided site URL.
1121 current_instance
->IsRelatedSiteInstance(converted_instance_1
.get()));
1122 EXPECT_NE(related_instance
.get(), converted_instance_1
.get());
1123 EXPECT_NE(unrelated_instance
.get(), converted_instance_1
.get());
1124 EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrlSameSiteAs2
),
1125 converted_instance_1
->GetSiteURL());
1127 SiteInstance
* converted_instance_2
=
1128 ConvertToSiteInstance(rfhm
, descriptor
, unrelated_instance
.get());
1129 // Should return |unrelated_instance| because its site matches and it is
1130 // unrelated to the current SiteInstance.
1131 EXPECT_EQ(unrelated_instance
.get(), converted_instance_2
);
1135 } // namespace content