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 void RequestNavigation(FrameTreeNode
* node
, const GURL
& url
) {
54 RequestNavigationWithParameters(node
, url
, Referrer(),
55 ui::PAGE_TRANSITION_LINK
);
58 void RequestNavigationWithParameters(
61 const Referrer
& referrer
,
62 ui::PageTransition transition_type
) {
63 NavigationController::LoadURLParams
load_params(url
);
64 load_params
.frame_tree_node_id
= node
->frame_tree_node_id();
65 load_params
.referrer
= referrer
;
66 load_params
.transition_type
= transition_type
;
68 controller().LoadURLWithParams(load_params
);
71 NavigationRequest
* GetNavigationRequestForFrameTreeNode(
72 FrameTreeNode
* frame_tree_node
) {
73 return static_cast<NavigatorImpl
*>(frame_tree_node
->navigator())
74 ->GetNavigationRequestForNodeForTesting(frame_tree_node
);
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(RenderFrameHostImpl
* rfh
) {
88 MockRenderProcessHost
* rph
=
89 static_cast<MockRenderProcessHost
*>(rfh
->GetProcess());
90 const FrameMsg_CommitNavigation
* commit_message
=
91 static_cast<const FrameMsg_CommitNavigation
*>(
92 rph
->sink().GetUniqueMessageMatching(
93 FrameMsg_CommitNavigation::ID
));
94 return commit_message
&&
95 rfh
->GetRoutingID() == commit_message
->routing_id();
98 SiteInstance
* ConvertToSiteInstance(RenderFrameHostManager
* rfhm
,
99 const SiteInstanceDescriptor
& descriptor
,
100 SiteInstance
* candidate_instance
) {
101 return rfhm
->ConvertToSiteInstance(descriptor
, candidate_instance
);
105 // PlzNavigate: Test a complete browser-initiated navigation starting with a
106 // non-live renderer.
107 TEST_F(NavigatorTestWithBrowserSideNavigation
,
108 SimpleBrowserInitiatedNavigationFromNonLiveRenderer
) {
109 const GURL
kUrl("http://chromium.org/");
111 EXPECT_FALSE(main_test_rfh()->IsRenderFrameLive());
113 // Start a browser-initiated navigation.
114 int32 site_instance_id
= main_test_rfh()->GetSiteInstance()->GetId();
115 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
116 RequestNavigation(node
, kUrl
);
117 NavigationRequest
* request
= GetNavigationRequestForFrameTreeNode(node
);
118 ASSERT_TRUE(request
);
119 EXPECT_EQ(kUrl
, request
->common_params().url
);
120 EXPECT_TRUE(request
->browser_initiated());
122 // As there's no live renderer the navigation should not wait for a
123 // beforeUnload ACK from the renderer and start right away.
124 EXPECT_EQ(NavigationRequest::STARTED
, request
->state());
125 ASSERT_TRUE(GetLoaderForNavigationRequest(request
));
126 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
127 EXPECT_FALSE(node
->render_manager()->pending_frame_host());
129 // Have the current RenderFrameHost commit the navigation.
130 scoped_refptr
<ResourceResponse
> response(new ResourceResponse
);
131 GetLoaderForNavigationRequest(request
)
132 ->CallOnResponseStarted(response
, MakeEmptyStream());
133 EXPECT_TRUE(DidRenderFrameHostRequestCommit(main_test_rfh()));
134 EXPECT_EQ(NavigationRequest::RESPONSE_STARTED
, request
->state());
136 // Commit the navigation.
137 main_test_rfh()->SendNavigate(0, kUrl
);
138 EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT
, main_test_rfh()->rfh_state());
139 EXPECT_EQ(SiteInstanceImpl::GetSiteForURL(browser_context(), kUrl
),
140 main_test_rfh()->GetSiteInstance()->GetSiteURL());
141 EXPECT_EQ(kUrl
, contents()->GetLastCommittedURL());
142 EXPECT_FALSE(GetNavigationRequestForFrameTreeNode(node
));
143 EXPECT_FALSE(node
->render_manager()->pending_frame_host());
145 // The main RenderFrameHost should not have been changed, and the renderer
146 // should have been initialized.
147 EXPECT_EQ(site_instance_id
, main_test_rfh()->GetSiteInstance()->GetId());
148 EXPECT_TRUE(main_test_rfh()->IsRenderFrameLive());
150 // After a navigation is finished no speculative RenderFrameHost should
152 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
154 // With PlzNavigate enabled a pending RenderFrameHost should never exist.
155 EXPECT_FALSE(node
->render_manager()->pending_frame_host());
158 // PlzNavigate: Test a complete renderer-initiated same-site navigation.
159 TEST_F(NavigatorTestWithBrowserSideNavigation
,
160 SimpleRendererInitiatedSameSiteNavigation
) {
161 const GURL
kUrl1("http://www.chromium.org/");
162 const GURL
kUrl2("http://www.chromium.org/Home");
164 contents()->NavigateAndCommit(kUrl1
);
165 EXPECT_TRUE(main_test_rfh()->IsRenderFrameLive());
167 // Start a renderer-initiated non-user-initiated navigation.
168 process()->sink().ClearMessages();
169 main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl2
, false);
170 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
171 NavigationRequest
* request
= GetNavigationRequestForFrameTreeNode(node
);
172 ASSERT_TRUE(request
);
174 // The navigation is immediately started as there's no need to wait for
175 // beforeUnload to be executed.
176 EXPECT_EQ(NavigationRequest::STARTED
, request
->state());
177 EXPECT_FALSE(request
->begin_params().has_user_gesture
);
178 EXPECT_EQ(kUrl2
, request
->common_params().url
);
179 EXPECT_FALSE(request
->browser_initiated());
180 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
182 // Have the current RenderFrameHost commit the navigation.
183 scoped_refptr
<ResourceResponse
> response(new ResourceResponse
);
184 GetLoaderForNavigationRequest(request
)
185 ->CallOnResponseStarted(response
, MakeEmptyStream());
186 EXPECT_TRUE(DidRenderFrameHostRequestCommit(main_test_rfh()));
187 EXPECT_EQ(NavigationRequest::RESPONSE_STARTED
, request
->state());
189 // Commit the navigation.
190 main_test_rfh()->SendNavigate(0, kUrl2
);
191 EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT
, main_test_rfh()->rfh_state());
192 EXPECT_EQ(SiteInstanceImpl::GetSiteForURL(browser_context(), kUrl2
),
193 main_test_rfh()->GetSiteInstance()->GetSiteURL());
194 EXPECT_EQ(kUrl2
, contents()->GetLastCommittedURL());
195 EXPECT_FALSE(GetNavigationRequestForFrameTreeNode(node
));
196 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
197 EXPECT_FALSE(node
->render_manager()->pending_frame_host());
200 // PlzNavigate: Test a complete renderer-initiated navigation that should be
201 // cross-site but does not result in a SiteInstance swap because its
202 // renderer-initiated.
203 TEST_F(NavigatorTestWithBrowserSideNavigation
,
204 SimpleRendererInitiatedCrossSiteNavigation
) {
205 const GURL
kUrl1("http://www.chromium.org/");
206 const GURL
kUrl2("http://www.google.com");
208 contents()->NavigateAndCommit(kUrl1
);
209 EXPECT_TRUE(main_test_rfh()->IsRenderFrameLive());
210 int32 site_instance_id_1
= main_test_rfh()->GetSiteInstance()->GetId();
212 // Start a renderer-initiated non-user-initiated navigation.
213 process()->sink().ClearMessages();
214 main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl2
, false);
215 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
216 NavigationRequest
* request
= GetNavigationRequestForFrameTreeNode(node
);
217 ASSERT_TRUE(request
);
219 // The navigation is immediately started as there's no need to wait for
220 // beforeUnload to be executed.
221 EXPECT_EQ(NavigationRequest::STARTED
, request
->state());
222 EXPECT_FALSE(request
->begin_params().has_user_gesture
);
223 EXPECT_EQ(kUrl2
, request
->common_params().url
);
224 EXPECT_FALSE(request
->browser_initiated());
225 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
227 // Have the current RenderFrameHost commit the navigation.
228 scoped_refptr
<ResourceResponse
> response(new ResourceResponse
);
229 GetLoaderForNavigationRequest(request
)
230 ->CallOnResponseStarted(response
, MakeEmptyStream());
231 EXPECT_TRUE(DidRenderFrameHostRequestCommit(main_test_rfh()));
232 EXPECT_EQ(NavigationRequest::RESPONSE_STARTED
, request
->state());
234 // Commit the navigation.
235 main_test_rfh()->SendNavigate(0, kUrl2
);
236 EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT
, main_test_rfh()->rfh_state());
237 EXPECT_EQ(kUrl2
, contents()->GetLastCommittedURL());
238 EXPECT_FALSE(GetNavigationRequestForFrameTreeNode(node
));
239 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
240 EXPECT_FALSE(node
->render_manager()->pending_frame_host());
242 // The SiteInstance did not change.
243 EXPECT_EQ(site_instance_id_1
, main_test_rfh()->GetSiteInstance()->GetId());
246 // PlzNavigate: Test that a beforeUnload denial cancels the navigation.
247 TEST_F(NavigatorTestWithBrowserSideNavigation
,
248 BeforeUnloadDenialCancelNavigation
) {
249 const GURL
kUrl1("http://www.google.com/");
250 const GURL
kUrl2("http://www.chromium.org/");
252 contents()->NavigateAndCommit(kUrl1
);
254 // Start a new navigation.
255 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
256 RequestNavigation(node
, kUrl2
);
257 NavigationRequest
* request
= GetNavigationRequestForFrameTreeNode(node
);
258 ASSERT_TRUE(request
);
259 EXPECT_TRUE(request
->browser_initiated());
260 EXPECT_EQ(NavigationRequest::WAITING_FOR_RENDERER_RESPONSE
, request
->state());
261 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
263 // Simulate a beforeUnload denial.
264 main_test_rfh()->SendBeforeUnloadACK(false);
265 EXPECT_FALSE(GetNavigationRequestForFrameTreeNode(node
));
266 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
269 // PlzNavigate: Test that a proper NavigationRequest is created by
270 // RequestNavigation.
271 TEST_F(NavigatorTestWithBrowserSideNavigation
, BeginNavigation
) {
272 const GURL
kUrl1("http://www.google.com/");
273 const GURL
kUrl2("http://www.chromium.org/");
274 const GURL
kUrl3("http://www.gmail.com/");
276 contents()->NavigateAndCommit(kUrl1
);
279 FrameTreeNode
* root_node
= contents()->GetFrameTree()->root();
280 TestRenderFrameHost
* subframe_rfh
= main_test_rfh()->AppendChild("Child");
281 ASSERT_TRUE(subframe_rfh
);
283 // Start a navigation at the subframe.
284 FrameTreeNode
* subframe_node
= subframe_rfh
->frame_tree_node();
285 RequestNavigation(subframe_node
, kUrl2
);
286 NavigationRequest
* subframe_request
=
287 GetNavigationRequestForFrameTreeNode(subframe_node
);
288 TestNavigationURLLoader
* subframe_loader
=
289 GetLoaderForNavigationRequest(subframe_request
);
291 // Subframe navigations should start right away as they don't have to request
292 // beforeUnload to run at the renderer.
293 ASSERT_TRUE(subframe_request
);
294 ASSERT_TRUE(subframe_loader
);
295 EXPECT_EQ(NavigationRequest::STARTED
, subframe_request
->state());
296 EXPECT_EQ(kUrl2
, subframe_request
->common_params().url
);
297 EXPECT_EQ(kUrl2
, subframe_loader
->request_info()->common_params
.url
);
298 // First party for cookies url should be that of the main frame.
299 EXPECT_EQ(kUrl1
, subframe_loader
->request_info()->first_party_for_cookies
);
300 EXPECT_FALSE(subframe_loader
->request_info()->is_main_frame
);
301 EXPECT_TRUE(subframe_loader
->request_info()->parent_is_main_frame
);
302 EXPECT_TRUE(subframe_request
->browser_initiated());
303 EXPECT_FALSE(GetSpeculativeRenderFrameHost(root_node
));
305 // Subframe navigations should never create a speculative RenderFrameHost,
306 // unless site-per-process is enabled. In that case, as the subframe
307 // navigation is to a different site and is still ongoing, it should have one.
308 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
309 switches::kSitePerProcess
)) {
310 EXPECT_TRUE(GetSpeculativeRenderFrameHost(subframe_node
));
312 EXPECT_FALSE(GetSpeculativeRenderFrameHost(subframe_node
));
315 // Now start a navigation at the root node.
316 RequestNavigation(root_node
, kUrl3
);
317 NavigationRequest
* main_request
=
318 GetNavigationRequestForFrameTreeNode(root_node
);
319 ASSERT_TRUE(main_request
);
320 EXPECT_EQ(NavigationRequest::WAITING_FOR_RENDERER_RESPONSE
,
321 main_request
->state());
322 EXPECT_FALSE(GetSpeculativeRenderFrameHost(root_node
));
324 // Simulate a BeforeUnloadACK IPC on the main frame.
325 main_test_rfh()->SendBeforeUnloadACK(true);
326 TestNavigationURLLoader
* main_loader
=
327 GetLoaderForNavigationRequest(main_request
);
328 EXPECT_EQ(kUrl3
, main_request
->common_params().url
);
329 EXPECT_EQ(kUrl3
, main_loader
->request_info()->common_params
.url
);
330 EXPECT_EQ(kUrl3
, main_loader
->request_info()->first_party_for_cookies
);
331 EXPECT_TRUE(main_loader
->request_info()->is_main_frame
);
332 EXPECT_FALSE(main_loader
->request_info()->parent_is_main_frame
);
333 EXPECT_TRUE(main_request
->browser_initiated());
334 // BeforeUnloadACK was received from the renderer so the navigation should
336 EXPECT_EQ(NavigationRequest::STARTED
, main_request
->state());
338 // Main frame navigation to a different site should use a speculative
340 EXPECT_TRUE(GetSpeculativeRenderFrameHost(root_node
));
342 // As the main frame hasn't yet committed the subframe still exists. Thus, the
343 // above situation regarding subframe navigations is valid here.
344 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
345 switches::kSitePerProcess
)) {
346 EXPECT_TRUE(GetSpeculativeRenderFrameHost(subframe_node
));
348 EXPECT_FALSE(GetSpeculativeRenderFrameHost(subframe_node
));
352 // PlzNavigate: Test that committing an HTTP 204 or HTTP 205 response cancels
354 TEST_F(NavigatorTestWithBrowserSideNavigation
, NoContent
) {
355 const GURL
kUrl1("http://www.chromium.org/");
356 const GURL
kUrl2("http://www.google.com/");
359 contents()->NavigateAndCommit(kUrl1
);
360 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
362 // Navigate to a different site.
363 process()->sink().ClearMessages();
364 RequestNavigation(node
, kUrl2
);
365 main_test_rfh()->SendBeforeUnloadACK(true);
367 NavigationRequest
* main_request
= GetNavigationRequestForFrameTreeNode(node
);
368 ASSERT_TRUE(main_request
);
370 // Navigations to a different site do create a speculative RenderFrameHost.
371 EXPECT_TRUE(GetSpeculativeRenderFrameHost(node
));
373 // Commit an HTTP 204 response.
374 scoped_refptr
<ResourceResponse
> response(new ResourceResponse
);
375 const char kNoContentHeaders
[] = "HTTP/1.1 204 No Content\0\0";
376 response
->head
.headers
= new net::HttpResponseHeaders(
377 std::string(kNoContentHeaders
, arraysize(kNoContentHeaders
)));
378 GetLoaderForNavigationRequest(main_request
)->CallOnResponseStarted(
379 response
, MakeEmptyStream());
381 // There should be no pending nor speculative RenderFrameHost; the navigation
383 EXPECT_FALSE(DidRenderFrameHostRequestCommit(main_test_rfh()));
384 EXPECT_FALSE(GetNavigationRequestForFrameTreeNode(node
));
385 EXPECT_FALSE(node
->render_manager()->pending_frame_host());
386 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
388 // Now, repeat the test with 205 Reset Content.
390 // Navigate to a different site again.
391 process()->sink().ClearMessages();
392 RequestNavigation(node
, kUrl2
);
393 main_test_rfh()->SendBeforeUnloadACK(true);
395 main_request
= GetNavigationRequestForFrameTreeNode(node
);
396 ASSERT_TRUE(main_request
);
397 EXPECT_TRUE(GetSpeculativeRenderFrameHost(node
));
399 // Commit an HTTP 205 response.
400 response
= new ResourceResponse
;
401 const char kResetContentHeaders
[] = "HTTP/1.1 205 Reset Content\0\0";
402 response
->head
.headers
= new net::HttpResponseHeaders(
403 std::string(kResetContentHeaders
, arraysize(kResetContentHeaders
)));
404 GetLoaderForNavigationRequest(main_request
)->CallOnResponseStarted(
405 response
, MakeEmptyStream());
407 // There should be no pending nor speculative RenderFrameHost; the navigation
409 EXPECT_FALSE(DidRenderFrameHostRequestCommit(main_test_rfh()));
410 EXPECT_FALSE(GetNavigationRequestForFrameTreeNode(node
));
411 EXPECT_FALSE(node
->render_manager()->pending_frame_host());
412 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
415 // PlzNavigate: Test that a new RenderFrameHost is created when doing a cross
417 TEST_F(NavigatorTestWithBrowserSideNavigation
, CrossSiteNavigation
) {
418 const GURL
kUrl1("http://www.chromium.org/");
419 const GURL
kUrl2("http://www.google.com/");
421 contents()->NavigateAndCommit(kUrl1
);
422 RenderFrameHostImpl
* initial_rfh
= main_test_rfh();
423 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
425 // Navigate to a different site.
426 process()->sink().ClearMessages();
427 RequestNavigation(node
, kUrl2
);
428 NavigationRequest
* main_request
= GetNavigationRequestForFrameTreeNode(node
);
429 ASSERT_TRUE(main_request
);
430 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
432 // Receive the beforeUnload ACK.
433 main_test_rfh()->SendBeforeUnloadACK(true);
434 EXPECT_TRUE(GetSpeculativeRenderFrameHost(node
));
436 scoped_refptr
<ResourceResponse
> response(new ResourceResponse
);
437 GetLoaderForNavigationRequest(main_request
)->CallOnResponseStarted(
438 response
, MakeEmptyStream());
439 TestRenderFrameHost
* speculative_rfh
= GetSpeculativeRenderFrameHost(node
);
440 ASSERT_TRUE(speculative_rfh
);
441 EXPECT_TRUE(DidRenderFrameHostRequestCommit(speculative_rfh
));
442 EXPECT_FALSE(DidRenderFrameHostRequestCommit(main_test_rfh()));
444 speculative_rfh
->SendNavigate(0, kUrl2
);
446 RenderFrameHostImpl
* final_rfh
= main_test_rfh();
447 EXPECT_EQ(speculative_rfh
, final_rfh
);
448 EXPECT_NE(initial_rfh
, final_rfh
);
449 EXPECT_TRUE(final_rfh
->IsRenderFrameLive());
450 EXPECT_TRUE(final_rfh
->render_view_host()->IsRenderViewLive());
451 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
454 // PlzNavigate: Test that redirects are followed and the speculative
455 // RenderFrameHost logic behaves as expected.
456 TEST_F(NavigatorTestWithBrowserSideNavigation
, RedirectCrossSite
) {
457 const GURL
kUrl1("http://www.chromium.org/");
458 const GURL
kUrl2("http://www.google.com/");
460 contents()->NavigateAndCommit(kUrl1
);
461 RenderFrameHostImpl
* rfh
= main_test_rfh();
462 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
464 // Navigate to a URL on the same site.
465 process()->sink().ClearMessages();
466 RequestNavigation(node
, kUrl1
);
467 main_test_rfh()->SendBeforeUnloadACK(true);
468 NavigationRequest
* main_request
= GetNavigationRequestForFrameTreeNode(node
);
469 ASSERT_TRUE(main_request
);
470 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
472 // It then redirects to another site.
473 GetLoaderForNavigationRequest(main_request
)->SimulateServerRedirect(kUrl2
);
475 // The redirect should have been followed.
476 EXPECT_EQ(1, GetLoaderForNavigationRequest(main_request
)->redirect_count());
477 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
479 // Have the RenderFrameHost commit the navigation.
480 scoped_refptr
<ResourceResponse
> response(new ResourceResponse
);
481 GetLoaderForNavigationRequest(main_request
)->CallOnResponseStarted(
482 response
, MakeEmptyStream());
483 TestRenderFrameHost
* final_speculative_rfh
=
484 GetSpeculativeRenderFrameHost(node
);
485 EXPECT_TRUE(final_speculative_rfh
);
486 EXPECT_TRUE(DidRenderFrameHostRequestCommit(final_speculative_rfh
));
488 // Commit the navigation.
489 final_speculative_rfh
->SendNavigate(0, kUrl2
);
490 RenderFrameHostImpl
* final_rfh
= main_test_rfh();
491 ASSERT_TRUE(final_rfh
);
492 EXPECT_NE(rfh
, final_rfh
);
493 EXPECT_EQ(final_speculative_rfh
, final_rfh
);
494 EXPECT_TRUE(final_rfh
->IsRenderFrameLive());
495 EXPECT_TRUE(final_rfh
->render_view_host()->IsRenderViewLive());
496 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
499 // PlzNavigate: Test that a navigation is canceled if another browser-initiated
500 // request has been issued in the meantime. Also confirms that the speculative
501 // RenderFrameHost is correctly updated in the process.
502 TEST_F(NavigatorTestWithBrowserSideNavigation
,
503 BrowserInitiatedNavigationCancel
) {
504 const GURL
kUrl0("http://www.wikipedia.org/");
505 const GURL
kUrl1("http://www.chromium.org/");
506 const GURL kUrl1_site
= SiteInstance::GetSiteForURL(browser_context(), kUrl1
);
507 const GURL
kUrl2("http://www.google.com/");
508 const GURL kUrl2_site
= SiteInstance::GetSiteForURL(browser_context(), kUrl2
);
511 contents()->NavigateAndCommit(kUrl0
);
512 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
514 // Request navigation to the 1st URL.
515 process()->sink().ClearMessages();
516 RequestNavigation(node
, kUrl1
);
517 main_test_rfh()->SendBeforeUnloadACK(true);
518 NavigationRequest
* request1
= GetNavigationRequestForFrameTreeNode(node
);
519 ASSERT_TRUE(request1
);
520 EXPECT_EQ(kUrl1
, request1
->common_params().url
);
521 EXPECT_TRUE(request1
->browser_initiated());
522 base::WeakPtr
<TestNavigationURLLoader
> loader1
=
523 GetLoaderForNavigationRequest(request1
)->AsWeakPtr();
524 EXPECT_TRUE(loader1
);
526 // Confirm a speculative RenderFrameHost was created.
527 TestRenderFrameHost
* speculative_rfh
= GetSpeculativeRenderFrameHost(node
);
528 ASSERT_TRUE(speculative_rfh
);
529 int32 site_instance_id_1
= speculative_rfh
->GetSiteInstance()->GetId();
530 EXPECT_EQ(kUrl1_site
, speculative_rfh
->GetSiteInstance()->GetSiteURL());
532 // Request navigation to the 2nd URL; the NavigationRequest must have been
533 // replaced by a new one with a different URL.
534 RequestNavigation(node
, kUrl2
);
535 main_test_rfh()->SendBeforeUnloadACK(true);
536 NavigationRequest
* request2
= GetNavigationRequestForFrameTreeNode(node
);
537 ASSERT_TRUE(request2
);
538 EXPECT_EQ(kUrl2
, request2
->common_params().url
);
539 EXPECT_TRUE(request2
->browser_initiated());
541 // Confirm that the first loader got destroyed.
542 EXPECT_FALSE(loader1
);
544 // Confirm that a new speculative RenderFrameHost was created.
545 speculative_rfh
= GetSpeculativeRenderFrameHost(node
);
546 ASSERT_TRUE(speculative_rfh
);
547 int32 site_instance_id_2
= speculative_rfh
->GetSiteInstance()->GetId();
548 EXPECT_NE(site_instance_id_1
, site_instance_id_2
);
550 // Have the RenderFrameHost commit the navigation.
551 scoped_refptr
<ResourceResponse
> response(new ResourceResponse
);
552 GetLoaderForNavigationRequest(request2
)->CallOnResponseStarted(
553 response
, MakeEmptyStream());
554 EXPECT_TRUE(DidRenderFrameHostRequestCommit(speculative_rfh
));
555 EXPECT_FALSE(DidRenderFrameHostRequestCommit(main_test_rfh()));
557 // Commit the navigation.
558 speculative_rfh
->SendNavigate(0, kUrl2
);
560 // Confirm that the commit corresponds to the new request.
561 ASSERT_TRUE(main_test_rfh());
562 EXPECT_EQ(kUrl2_site
, main_test_rfh()->GetSiteInstance()->GetSiteURL());
563 EXPECT_EQ(kUrl2
, contents()->GetLastCommittedURL());
565 // Confirm that the committed RenderFrameHost is the latest speculative one.
566 EXPECT_EQ(site_instance_id_2
, main_test_rfh()->GetSiteInstance()->GetId());
569 // PlzNavigate: Test that a browser-initiated navigation is canceled if a
570 // renderer-initiated user-initiated request has been issued in the meantime.
571 TEST_F(NavigatorTestWithBrowserSideNavigation
,
572 RendererUserInitiatedNavigationCancel
) {
573 const GURL
kUrl0("http://www.wikipedia.org/");
574 const GURL
kUrl1("http://www.chromium.org/");
575 const GURL
kUrl2("http://www.google.com/");
578 contents()->NavigateAndCommit(kUrl0
);
579 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
581 // Start a browser-initiated navigation to the 1st URL and receive its
583 process()->sink().ClearMessages();
584 RequestNavigation(node
, kUrl1
);
585 main_test_rfh()->SendBeforeUnloadACK(true);
586 NavigationRequest
* request1
= GetNavigationRequestForFrameTreeNode(node
);
587 ASSERT_TRUE(request1
);
588 EXPECT_EQ(kUrl1
, request1
->common_params().url
);
589 EXPECT_TRUE(request1
->browser_initiated());
590 base::WeakPtr
<TestNavigationURLLoader
> loader1
=
591 GetLoaderForNavigationRequest(request1
)->AsWeakPtr();
592 EXPECT_TRUE(loader1
);
594 // Confirm that a speculative RenderFrameHost was created.
595 ASSERT_TRUE(GetSpeculativeRenderFrameHost(node
));
597 // Now receive a renderer-initiated user-initiated request. It should replace
598 // the current NavigationRequest.
599 main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl2
, true);
600 NavigationRequest
* request2
= GetNavigationRequestForFrameTreeNode(node
);
601 ASSERT_TRUE(request2
);
602 EXPECT_EQ(kUrl2
, request2
->common_params().url
);
603 EXPECT_FALSE(request2
->browser_initiated());
604 EXPECT_TRUE(request2
->begin_params().has_user_gesture
);
606 // Confirm that the first loader got destroyed.
607 EXPECT_FALSE(loader1
);
609 // Confirm that the speculative RenderFrameHost was destroyed.
610 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
612 // Have the RenderFrameHost commit the navigation.
613 scoped_refptr
<ResourceResponse
> response(new ResourceResponse
);
614 GetLoaderForNavigationRequest(request2
)
615 ->CallOnResponseStarted(response
, MakeEmptyStream());
616 EXPECT_TRUE(DidRenderFrameHostRequestCommit(main_test_rfh()));
618 // Commit the navigation.
619 main_test_rfh()->SendNavigate(0, kUrl2
);
621 // Confirm that the commit corresponds to the new request.
622 ASSERT_TRUE(main_test_rfh());
623 EXPECT_EQ(kUrl2
, contents()->GetLastCommittedURL());
626 // PlzNavigate: Test that a renderer-initiated user-initiated navigation is NOT
627 // canceled if a renderer-initiated non-user-initiated request is issued in the
629 TEST_F(NavigatorTestWithBrowserSideNavigation
,
630 RendererNonUserInitiatedNavigationDoesntCancelRendererUserInitiated
) {
631 const GURL
kUrl0("http://www.wikipedia.org/");
632 const GURL
kUrl1("http://www.chromium.org/");
633 const GURL
kUrl2("http://www.google.com/");
636 contents()->NavigateAndCommit(kUrl0
);
637 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
639 // Start a renderer-initiated user-initiated navigation to the 1st URL.
640 process()->sink().ClearMessages();
641 main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl1
, true);
642 NavigationRequest
* request1
= GetNavigationRequestForFrameTreeNode(node
);
643 ASSERT_TRUE(request1
);
644 EXPECT_EQ(kUrl1
, request1
->common_params().url
);
645 EXPECT_FALSE(request1
->browser_initiated());
646 EXPECT_TRUE(request1
->begin_params().has_user_gesture
);
647 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
649 // Now receive a renderer-initiated non-user-initiated request. Nothing should
651 main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl2
, false);
652 NavigationRequest
* request2
= GetNavigationRequestForFrameTreeNode(node
);
653 ASSERT_TRUE(request2
);
654 EXPECT_EQ(request1
, request2
);
655 EXPECT_EQ(kUrl1
, request2
->common_params().url
);
656 EXPECT_FALSE(request2
->browser_initiated());
657 EXPECT_TRUE(request2
->begin_params().has_user_gesture
);
658 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
660 // Have the RenderFrameHost commit the navigation.
661 scoped_refptr
<ResourceResponse
> response(new ResourceResponse
);
662 GetLoaderForNavigationRequest(request2
)
663 ->CallOnResponseStarted(response
, MakeEmptyStream());
664 EXPECT_TRUE(DidRenderFrameHostRequestCommit(main_test_rfh()));
666 // Commit the navigation.
667 main_test_rfh()->SendNavigate(0, kUrl1
);
668 EXPECT_EQ(kUrl1
, contents()->GetLastCommittedURL());
671 // PlzNavigate: Test that a browser-initiated navigation is NOT canceled if a
672 // renderer-initiated non-user-initiated request is issued in the meantime.
673 TEST_F(NavigatorTestWithBrowserSideNavigation
,
674 RendererNonUserInitiatedNavigationDoesntCancelBrowserInitiated
) {
675 const GURL
kUrl0("http://www.wikipedia.org/");
676 const GURL
kUrl1("http://www.chromium.org/");
677 const GURL
kUrl2("http://www.google.com/");
680 contents()->NavigateAndCommit(kUrl0
);
681 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
683 // Start a browser-initiated navigation to the 1st URL.
684 process()->sink().ClearMessages();
685 RequestNavigation(node
, kUrl1
);
686 NavigationRequest
* request1
= GetNavigationRequestForFrameTreeNode(node
);
687 ASSERT_TRUE(request1
);
688 EXPECT_EQ(kUrl1
, request1
->common_params().url
);
689 EXPECT_TRUE(request1
->browser_initiated());
690 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
692 // Now receive a renderer-initiated non-user-initiated request. Nothing should
694 main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl2
, false);
695 NavigationRequest
* request2
= GetNavigationRequestForFrameTreeNode(node
);
696 ASSERT_TRUE(request2
);
697 EXPECT_EQ(request1
, request2
);
698 EXPECT_EQ(kUrl1
, request2
->common_params().url
);
699 EXPECT_TRUE(request2
->browser_initiated());
700 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
702 // Now receive the beforeUnload ACK from the still ongoing navigation.
703 main_test_rfh()->SendBeforeUnloadACK(true);
704 TestRenderFrameHost
* speculative_rfh
= GetSpeculativeRenderFrameHost(node
);
705 ASSERT_TRUE(speculative_rfh
);
707 // Have the RenderFrameHost commit the navigation.
708 scoped_refptr
<ResourceResponse
> response(new ResourceResponse
);
709 GetLoaderForNavigationRequest(request2
)
710 ->CallOnResponseStarted(response
, MakeEmptyStream());
711 EXPECT_TRUE(DidRenderFrameHostRequestCommit(speculative_rfh
));
712 EXPECT_FALSE(DidRenderFrameHostRequestCommit(main_test_rfh()));
714 // Commit the navigation.
715 speculative_rfh
->SendNavigate(0, kUrl1
);
716 EXPECT_EQ(kUrl1
, contents()->GetLastCommittedURL());
719 // PlzNavigate: Test that a renderer-initiated non-user-initiated navigation is
720 // canceled if a another similar request is issued in the meantime.
721 TEST_F(NavigatorTestWithBrowserSideNavigation
,
722 RendererNonUserInitiatedNavigationCancelSimilarNavigation
) {
723 const GURL
kUrl0("http://www.wikipedia.org/");
724 const GURL
kUrl1("http://www.chromium.org/");
725 const GURL
kUrl2("http://www.google.com/");
728 contents()->NavigateAndCommit(kUrl0
);
729 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
730 int32 site_instance_id_0
= main_test_rfh()->GetSiteInstance()->GetId();
732 // Start a renderer-initiated non-user-initiated navigation to the 1st URL.
733 process()->sink().ClearMessages();
734 main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl1
, false);
735 NavigationRequest
* request1
= GetNavigationRequestForFrameTreeNode(node
);
736 ASSERT_TRUE(request1
);
737 EXPECT_EQ(kUrl1
, request1
->common_params().url
);
738 EXPECT_FALSE(request1
->browser_initiated());
739 EXPECT_FALSE(request1
->begin_params().has_user_gesture
);
740 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
741 base::WeakPtr
<TestNavigationURLLoader
> loader1
=
742 GetLoaderForNavigationRequest(request1
)->AsWeakPtr();
743 EXPECT_TRUE(loader1
);
745 // Now receive a 2nd similar request that should replace the current one.
746 main_test_rfh()->SendRendererInitiatedNavigationRequest(kUrl2
, false);
747 NavigationRequest
* request2
= GetNavigationRequestForFrameTreeNode(node
);
748 EXPECT_EQ(kUrl2
, request2
->common_params().url
);
749 EXPECT_FALSE(request2
->browser_initiated());
750 EXPECT_FALSE(request2
->begin_params().has_user_gesture
);
751 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
753 // Confirm that the first loader got destroyed.
754 EXPECT_FALSE(loader1
);
756 // Have the RenderFrameHost commit the navigation.
757 scoped_refptr
<ResourceResponse
> response(new ResourceResponse
);
758 GetLoaderForNavigationRequest(request2
)
759 ->CallOnResponseStarted(response
, MakeEmptyStream());
760 EXPECT_TRUE(DidRenderFrameHostRequestCommit(main_test_rfh()));
762 // Commit the navigation.
763 main_test_rfh()->SendNavigate(0, kUrl2
);
764 EXPECT_EQ(kUrl2
, contents()->GetLastCommittedURL());
766 // The SiteInstance did not change.
767 EXPECT_EQ(site_instance_id_0
, main_test_rfh()->GetSiteInstance()->GetId());
770 // PlzNavigate: Test that a reload navigation is properly signaled to the
771 // RenderFrame when the navigation can commit. A speculative RenderFrameHost
772 // should not be created at any step.
773 TEST_F(NavigatorTestWithBrowserSideNavigation
, Reload
) {
774 const GURL
kUrl("http://www.google.com/");
775 contents()->NavigateAndCommit(kUrl
);
777 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
778 controller().Reload(false);
779 // A NavigationRequest should have been generated.
780 NavigationRequest
* main_request
= GetNavigationRequestForFrameTreeNode(node
);
781 ASSERT_TRUE(main_request
!= NULL
);
782 EXPECT_EQ(FrameMsg_Navigate_Type::RELOAD
,
783 main_request
->common_params().navigation_type
);
784 main_test_rfh()->PrepareForCommit();
785 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
787 main_test_rfh()->SendNavigate(0, kUrl
);
788 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
790 // Now do a shift+reload.
791 controller().ReloadIgnoringCache(false);
792 // A NavigationRequest should have been generated.
793 main_request
= GetNavigationRequestForFrameTreeNode(node
);
794 ASSERT_TRUE(main_request
!= NULL
);
795 EXPECT_EQ(FrameMsg_Navigate_Type::RELOAD_IGNORING_CACHE
,
796 main_request
->common_params().navigation_type
);
797 main_test_rfh()->PrepareForCommit();
798 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
801 // PlzNavigate: Confirm that a speculative RenderFrameHost is used when
802 // navigating from one site to another.
803 TEST_F(NavigatorTestWithBrowserSideNavigation
,
804 SpeculativeRendererWorksBaseCase
) {
805 // Navigate to an initial site.
806 const GURL
kUrlInit("http://wikipedia.org/");
807 contents()->NavigateAndCommit(kUrlInit
);
808 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
810 // Begin navigating to another site.
811 const GURL
kUrl("http://google.com/");
812 process()->sink().ClearMessages();
813 RequestNavigation(node
, kUrl
);
814 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
816 // Receive the beforeUnload ACK.
817 main_test_rfh()->SendBeforeUnloadACK(true);
818 TestRenderFrameHost
* speculative_rfh
= GetSpeculativeRenderFrameHost(node
);
819 ASSERT_TRUE(speculative_rfh
);
820 EXPECT_NE(speculative_rfh
, main_test_rfh());
821 EXPECT_EQ(SiteInstanceImpl::GetSiteForURL(browser_context(), kUrl
),
822 speculative_rfh
->GetSiteInstance()->GetSiteURL());
823 EXPECT_FALSE(node
->render_manager()->pending_frame_host());
824 int32 site_instance_id
= speculative_rfh
->GetSiteInstance()->GetId();
826 // Ask Navigator to commit the navigation by simulating a call to
827 // OnResponseStarted.
828 scoped_refptr
<ResourceResponse
> response(new ResourceResponse
);
829 GetLoaderForNavigationRequest(GetNavigationRequestForFrameTreeNode(node
))
830 ->CallOnResponseStarted(response
, MakeEmptyStream());
831 speculative_rfh
= GetSpeculativeRenderFrameHost(node
);
832 ASSERT_TRUE(speculative_rfh
);
833 EXPECT_TRUE(DidRenderFrameHostRequestCommit(speculative_rfh
));
834 EXPECT_EQ(site_instance_id
, speculative_rfh
->GetSiteInstance()->GetId());
835 EXPECT_FALSE(node
->render_manager()->pending_frame_host());
837 // Invoke OnDidCommitProvisionalLoad.
838 speculative_rfh
->SendNavigate(0, kUrl
);
839 EXPECT_EQ(site_instance_id
, main_test_rfh()->GetSiteInstance()->GetId());
840 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
841 EXPECT_FALSE(node
->render_manager()->pending_frame_host());
844 // PlzNavigate: Confirm that a speculative RenderFrameHost is thrown away when
845 // the final URL's site differs from the initial one due to redirects.
846 TEST_F(NavigatorTestWithBrowserSideNavigation
,
847 SpeculativeRendererDiscardedAfterRedirectToAnotherSite
) {
848 // Navigate to an initial site.
849 const GURL
kUrlInit("http://wikipedia.org/");
850 contents()->NavigateAndCommit(kUrlInit
);
851 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
852 int32 init_site_instance_id
= main_test_rfh()->GetSiteInstance()->GetId();
854 // Begin navigating to another site.
855 const GURL
kUrl("http://google.com/");
856 process()->sink().ClearMessages();
857 RequestNavigation(node
, kUrl
);
858 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
860 // Receive the beforeUnload ACK.
861 main_test_rfh()->SendBeforeUnloadACK(true);
862 TestRenderFrameHost
* speculative_rfh
= GetSpeculativeRenderFrameHost(node
);
863 int32 site_instance_id
= speculative_rfh
->GetSiteInstance()->GetId();
864 EXPECT_NE(init_site_instance_id
, site_instance_id
);
865 EXPECT_EQ(init_site_instance_id
, main_test_rfh()->GetSiteInstance()->GetId());
866 ASSERT_TRUE(speculative_rfh
);
867 EXPECT_NE(speculative_rfh
, main_test_rfh());
868 EXPECT_EQ(SiteInstanceImpl::GetSiteForURL(browser_context(), kUrl
),
869 speculative_rfh
->GetSiteInstance()->GetSiteURL());
871 // It then redirects to yet another site.
872 NavigationRequest
* main_request
= GetNavigationRequestForFrameTreeNode(node
);
873 ASSERT_TRUE(main_request
);
874 const GURL
kUrlRedirect("https://www.google.com/");
875 GetLoaderForNavigationRequest(main_request
)
876 ->SimulateServerRedirect(kUrlRedirect
);
877 EXPECT_EQ(init_site_instance_id
, main_test_rfh()->GetSiteInstance()->GetId());
878 speculative_rfh
= GetSpeculativeRenderFrameHost(node
);
879 ASSERT_TRUE(speculative_rfh
);
881 // For now, ensure that the speculative RenderFrameHost does not change after
883 // TODO(carlosk): once the speculative RenderFrameHost updates with redirects
884 // this next check will be changed to verify that it actually happens.
885 EXPECT_EQ(site_instance_id
, speculative_rfh
->GetSiteInstance()->GetId());
887 // Commit the navigation with Navigator by simulating the call to
888 // OnResponseStarted.
889 scoped_refptr
<ResourceResponse
> response(new ResourceResponse
);
890 GetLoaderForNavigationRequest(main_request
)
891 ->CallOnResponseStarted(response
, MakeEmptyStream());
892 speculative_rfh
= GetSpeculativeRenderFrameHost(node
);
893 EXPECT_TRUE(DidRenderFrameHostRequestCommit(speculative_rfh
));
894 EXPECT_EQ(init_site_instance_id
, main_test_rfh()->GetSiteInstance()->GetId());
896 // Once commit happens the speculative RenderFrameHost is updated to match the
897 // known final SiteInstance.
898 ASSERT_TRUE(speculative_rfh
);
899 EXPECT_EQ(SiteInstanceImpl::GetSiteForURL(browser_context(), kUrlRedirect
),
900 speculative_rfh
->GetSiteInstance()->GetSiteURL());
901 int32 redirect_site_instance_id
= speculative_rfh
->GetSiteInstance()->GetId();
902 EXPECT_NE(init_site_instance_id
, redirect_site_instance_id
);
903 EXPECT_NE(site_instance_id
, redirect_site_instance_id
);
905 // Invoke OnDidCommitProvisionalLoad.
906 speculative_rfh
->SendNavigate(0, kUrlRedirect
);
908 // Check that the speculative RenderFrameHost was swapped in.
909 EXPECT_EQ(redirect_site_instance_id
,
910 main_test_rfh()->GetSiteInstance()->GetId());
911 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
914 // PlzNavigate: Verify that a previously swapped out RenderFrameHost is
915 // correctly reused when spawning a speculative RenderFrameHost in a navigation
916 // using the same SiteInstance.
917 TEST_F(NavigatorTestWithBrowserSideNavigation
,
918 SpeculativeRendererReuseSwappedOutRFH
) {
919 // Navigate to an initial site.
920 const GURL
kUrl1("http://wikipedia.org/");
921 contents()->NavigateAndCommit(kUrl1
);
922 TestRenderFrameHost
* rfh1
= main_test_rfh();
923 FrameTreeNode
* node
= rfh1
->frame_tree_node();
924 RenderFrameHostManager
* rfhm
= node
->render_manager();
926 // Increment active frame count to cause the RenderFrameHost to be swapped out
927 // (instead of immediately destroyed).
928 rfh1
->GetSiteInstance()->increment_active_frame_count();
930 // Navigate to another site to swap out the initial RenderFrameHost.
931 const GURL
kUrl2("http://chromium.org/");
932 contents()->NavigateAndCommit(kUrl2
);
933 ASSERT_NE(rfh1
, main_test_rfh());
934 EXPECT_NE(RenderFrameHostImpl::STATE_DEFAULT
, rfh1
->rfh_state());
935 EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT
, main_test_rfh()->rfh_state());
936 EXPECT_TRUE(rfhm
->IsOnSwappedOutList(rfh1
));
938 // Now go back to the initial site so that the swapped out RenderFrameHost
940 process()->sink().ClearMessages();
941 static_cast<MockRenderProcessHost
*>(rfh1
->GetProcess())
944 RequestNavigation(node
, kUrl1
);
945 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
947 main_test_rfh()->SendBeforeUnloadACK(true);
948 EXPECT_EQ(rfh1
, GetSpeculativeRenderFrameHost(node
));
949 EXPECT_NE(RenderFrameHostImpl::STATE_DEFAULT
,
950 GetSpeculativeRenderFrameHost(node
)->rfh_state());
952 scoped_refptr
<ResourceResponse
> response(new ResourceResponse
);
953 GetLoaderForNavigationRequest(GetNavigationRequestForFrameTreeNode(node
))
954 ->CallOnResponseStarted(response
, MakeEmptyStream());
955 EXPECT_EQ(rfh1
, GetSpeculativeRenderFrameHost(node
));
956 EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT
,
957 GetSpeculativeRenderFrameHost(node
)->rfh_state());
958 EXPECT_TRUE(DidRenderFrameHostRequestCommit(rfh1
));
959 EXPECT_FALSE(DidRenderFrameHostRequestCommit(main_test_rfh()));
961 rfh1
->SendNavigate(1, kUrl1
);
962 EXPECT_EQ(rfh1
, main_test_rfh());
963 EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT
, rfh1
->rfh_state());
964 EXPECT_FALSE(rfhm
->IsOnSwappedOutList(rfh1
));
967 // PlzNavigate: Verify that data urls are properly handled.
968 TEST_F(NavigatorTestWithBrowserSideNavigation
, DataUrls
) {
969 const GURL
kUrl1("http://wikipedia.org/");
970 const GURL
kUrl2("data:text/html,test");
972 // Navigate to an initial site.
973 contents()->NavigateAndCommit(kUrl1
);
974 FrameTreeNode
* node
= main_test_rfh()->frame_tree_node();
976 // Navigate to a data url.
977 RequestNavigation(node
, kUrl2
);
978 NavigationRequest
* navigation_request
=
979 GetNavigationRequestForFrameTreeNode(node
);
980 ASSERT_TRUE(navigation_request
);
981 EXPECT_EQ(NavigationRequest::WAITING_FOR_RENDERER_RESPONSE
,
982 navigation_request
->state());
983 main_test_rfh()->SendBeforeUnloadACK(true);
985 // The request should not have been sent to the IO thread but committed
987 EXPECT_EQ(NavigationRequest::RESPONSE_STARTED
,
988 navigation_request
->state());
989 EXPECT_FALSE(navigation_request
->loader_for_testing());
990 TestRenderFrameHost
* speculative_rfh
= GetSpeculativeRenderFrameHost(node
);
991 ASSERT_TRUE(speculative_rfh
);
992 speculative_rfh
->SendNavigate(0, kUrl2
);
993 EXPECT_EQ(main_test_rfh(), speculative_rfh
);
995 // Go back to the initial site.
996 contents()->NavigateAndCommit(kUrl1
);
998 // Do a renderer-initiated navigation to a data url. The request should not be
999 // sent to the IO thread, nor committed.
1000 TestRenderFrameHost
* main_rfh
= main_test_rfh();
1001 main_rfh
->SendRendererInitiatedNavigationRequest(kUrl2
, true);
1002 navigation_request
= GetNavigationRequestForFrameTreeNode(node
);
1003 ASSERT_TRUE(navigation_request
);
1004 EXPECT_EQ(NavigationRequest::RESPONSE_STARTED
,
1005 navigation_request
->state());
1006 EXPECT_FALSE(navigation_request
->loader_for_testing());
1007 EXPECT_FALSE(GetSpeculativeRenderFrameHost(node
));
1010 // Tests several cases for converting SiteInstanceDescriptors into
1012 // 1) Pointer to the current SiteInstance.
1013 // 2) Pointer to an unrelated SiteInstance.
1014 // 3) Same-site URL, related.
1015 // 4) Cross-site URL, related.
1016 // 5) Same-site URL, unrelated (with and without candidate SiteInstances).
1017 // 6) Cross-site URL, unrelated (with candidate SiteInstance).
1018 TEST_F(NavigatorTestWithBrowserSideNavigation
,
1019 SiteInstanceDescriptionConversion
) {
1020 // Navigate to set a current SiteInstance on the RenderFrameHost.
1021 GURL
kUrl1("http://a.com");
1022 contents()->NavigateAndCommit(kUrl1
);
1023 SiteInstance
* current_instance
= main_test_rfh()->GetSiteInstance();
1024 ASSERT_TRUE(current_instance
);
1026 // 1) Convert a descriptor pointing to the current instance.
1027 RenderFrameHostManager
* rfhm
=
1028 main_test_rfh()->frame_tree_node()->render_manager();
1030 SiteInstanceDescriptor
descriptor(current_instance
);
1031 SiteInstance
* converted_instance
=
1032 ConvertToSiteInstance(rfhm
, descriptor
, nullptr);
1033 EXPECT_EQ(current_instance
, converted_instance
);
1036 // 2) Convert a descriptor pointing an instance unrelated to the current one,
1037 // with a different site.
1038 GURL
kUrl2("http://b.com");
1039 scoped_refptr
<SiteInstance
> unrelated_instance(
1040 SiteInstance::CreateForURL(browser_context(), kUrl2
));
1042 current_instance
->IsRelatedSiteInstance(unrelated_instance
.get()));
1044 SiteInstanceDescriptor
descriptor(unrelated_instance
.get());
1045 SiteInstance
* converted_instance
=
1046 ConvertToSiteInstance(rfhm
, descriptor
, nullptr);
1047 EXPECT_EQ(unrelated_instance
.get(), converted_instance
);
1050 // 3) Convert a descriptor of a related instance with the same site as the
1052 GURL
kUrlSameSiteAs1("http://www.a.com/foo");
1054 SiteInstanceDescriptor
descriptor(browser_context(), kUrlSameSiteAs1
, true);
1055 SiteInstance
* converted_instance
=
1056 ConvertToSiteInstance(rfhm
, descriptor
, nullptr);
1057 EXPECT_EQ(current_instance
, converted_instance
);
1060 // 4) Convert a descriptor of a related instance with a site different from
1062 GURL
kUrlSameSiteAs2("http://www.b.com/foo");
1063 scoped_refptr
<SiteInstance
> related_instance
;
1065 SiteInstanceDescriptor
descriptor(browser_context(), kUrlSameSiteAs2
, true);
1066 related_instance
= ConvertToSiteInstance(rfhm
, descriptor
, nullptr);
1067 // Should return a new instance, related to the current, set to the new site
1070 current_instance
->IsRelatedSiteInstance(related_instance
.get()));
1071 EXPECT_NE(current_instance
, related_instance
.get());
1072 EXPECT_NE(unrelated_instance
.get(), related_instance
.get());
1073 EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrlSameSiteAs2
),
1074 related_instance
->GetSiteURL());
1077 // 5) Convert a descriptor of an unrelated instance with the same site as the
1078 // current one, several times, with and without candidate sites.
1080 SiteInstanceDescriptor
descriptor(browser_context(), kUrlSameSiteAs1
,
1082 scoped_refptr
<SiteInstance
> converted_instance_1
=
1083 ConvertToSiteInstance(rfhm
, descriptor
, nullptr);
1084 // Should return a new instance, unrelated to the current one, set to the
1085 // provided site URL.
1087 current_instance
->IsRelatedSiteInstance(converted_instance_1
.get()));
1088 EXPECT_NE(current_instance
, converted_instance_1
.get());
1089 EXPECT_NE(unrelated_instance
.get(), converted_instance_1
.get());
1090 EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrlSameSiteAs1
),
1091 converted_instance_1
->GetSiteURL());
1093 // Does the same but this time using unrelated_instance as a candidate,
1094 // which has a different site.
1095 scoped_refptr
<SiteInstance
> converted_instance_2
=
1096 ConvertToSiteInstance(rfhm
, descriptor
, unrelated_instance
.get());
1097 // Should return yet another new instance, unrelated to the current one, set
1098 // to the same site URL.
1100 current_instance
->IsRelatedSiteInstance(converted_instance_2
.get()));
1101 EXPECT_NE(current_instance
, converted_instance_2
.get());
1102 EXPECT_NE(unrelated_instance
.get(), converted_instance_2
.get());
1103 EXPECT_NE(converted_instance_1
.get(), converted_instance_2
.get());
1104 EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrlSameSiteAs1
),
1105 converted_instance_2
->GetSiteURL());
1107 // Converts once more but with |converted_instance_1| as a candidate.
1108 SiteInstance
* converted_instance_3
=
1109 ConvertToSiteInstance(rfhm
, descriptor
, converted_instance_1
.get());
1110 // Should return |converted_instance_1| because its site matches and it is
1111 // unrelated to the current SiteInstance.
1112 EXPECT_EQ(converted_instance_1
.get(), converted_instance_3
);
1115 // 6) Convert a descriptor of an unrelated instance with the same site of
1116 // related_instance and using it as a candidate.
1118 SiteInstanceDescriptor
descriptor(browser_context(), kUrlSameSiteAs2
,
1120 scoped_refptr
<SiteInstance
> converted_instance_1
=
1121 ConvertToSiteInstance(rfhm
, descriptor
, related_instance
.get());
1122 // Should return a new instance, unrelated to the current, set to the
1123 // provided site URL.
1125 current_instance
->IsRelatedSiteInstance(converted_instance_1
.get()));
1126 EXPECT_NE(related_instance
.get(), converted_instance_1
.get());
1127 EXPECT_NE(unrelated_instance
.get(), converted_instance_1
.get());
1128 EXPECT_EQ(SiteInstance::GetSiteForURL(browser_context(), kUrlSameSiteAs2
),
1129 converted_instance_1
->GetSiteURL());
1131 SiteInstance
* converted_instance_2
=
1132 ConvertToSiteInstance(rfhm
, descriptor
, unrelated_instance
.get());
1133 // Should return |unrelated_instance| because its site matches and it is
1134 // unrelated to the current SiteInstance.
1135 EXPECT_EQ(unrelated_instance
.get(), converted_instance_2
);
1139 } // namespace content