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.
6 #include "base/command_line.h"
7 #include "base/strings/stringprintf.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "content/browser/frame_host/frame_navigation_entry.h"
10 #include "content/browser/frame_host/frame_tree.h"
11 #include "content/browser/frame_host/navigation_controller_impl.h"
12 #include "content/browser/frame_host/navigation_entry_impl.h"
13 #include "content/browser/web_contents/web_contents_impl.h"
14 #include "content/public/browser/render_view_host.h"
15 #include "content/public/browser/resource_controller.h"
16 #include "content/public/browser/resource_dispatcher_host.h"
17 #include "content/public/browser/resource_dispatcher_host_delegate.h"
18 #include "content/public/browser/resource_throttle.h"
19 #include "content/public/browser/web_contents.h"
20 #include "content/public/browser/web_contents_observer.h"
21 #include "content/public/common/bindings_policy.h"
22 #include "content/public/common/content_switches.h"
23 #include "content/public/common/url_constants.h"
24 #include "content/public/test/browser_test_utils.h"
25 #include "content/public/test/content_browser_test.h"
26 #include "content/public/test/content_browser_test_utils.h"
27 #include "content/public/test/test_navigation_observer.h"
28 #include "content/public/test/test_utils.h"
29 #include "content/shell/browser/shell.h"
30 #include "content/test/content_browser_test_utils_internal.h"
31 #include "net/dns/mock_host_resolver.h"
32 #include "net/test/embedded_test_server/embedded_test_server.h"
33 #include "net/test/url_request/url_request_failed_job.h"
37 class NavigationControllerBrowserTest
: public ContentBrowserTest
{
39 void SetUpOnMainThread() override
{
40 host_resolver()->AddRule("*", "127.0.0.1");
41 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
45 // Ensure that tests can navigate subframes cross-site in both default mode and
46 // --site-per-process, but that they only go cross-process in the latter.
47 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
, LoadCrossSiteSubframe
) {
48 // Load a main frame with a subframe.
49 GURL
main_url(embedded_test_server()->GetURL(
50 "/navigation_controller/page_with_iframe.html"));
51 NavigateToURL(shell(), main_url
);
52 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
55 ASSERT_EQ(1U, root
->child_count());
56 ASSERT_NE(nullptr, root
->child_at(0));
58 // Use NavigateFrameToURL to go cross-site in the subframe.
59 GURL
foo_url(embedded_test_server()->GetURL(
60 "foo.com", "/navigation_controller/simple_page_1.html"));
61 NavigateFrameToURL(root
->child_at(0), foo_url
);
62 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
64 // We should only have swapped processes in --site-per-process.
65 bool cross_process
= root
->current_frame_host()->GetProcess() !=
66 root
->child_at(0)->current_frame_host()->GetProcess();
67 EXPECT_EQ(base::CommandLine::ForCurrentProcess()->HasSwitch(
68 switches::kSitePerProcess
),
72 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
, LoadDataWithBaseURL
) {
73 const GURL
base_url("http://baseurl");
74 const GURL
history_url("http://historyurl");
75 const std::string data
= "<html><body>foo</body></html>";
77 const NavigationController
& controller
=
78 shell()->web_contents()->GetController();
79 // Load data. Blocks until it is done.
80 content::LoadDataWithBaseURL(shell(), history_url
, data
, base_url
);
82 // We should use history_url instead of the base_url as the original url of
83 // this navigation entry, because base_url is only used for resolving relative
84 // paths in the data, or enforcing same origin policy.
85 EXPECT_EQ(controller
.GetVisibleEntry()->GetOriginalRequestURL(), history_url
);
88 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
, UniqueIDs
) {
89 const NavigationControllerImpl
& controller
=
90 static_cast<const NavigationControllerImpl
&>(
91 shell()->web_contents()->GetController());
93 GURL
main_url(embedded_test_server()->GetURL(
94 "/navigation_controller/page_with_link_to_load_iframe.html"));
95 NavigateToURL(shell(), main_url
);
96 ASSERT_EQ(1, controller
.GetEntryCount());
98 // Use JavaScript to click the link and load the iframe.
99 std::string script
= "document.getElementById('link').click()";
100 EXPECT_TRUE(content::ExecuteScript(shell()->web_contents(), script
));
101 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
102 ASSERT_EQ(2, controller
.GetEntryCount());
104 // Unique IDs should... um... be unique.
105 ASSERT_NE(controller
.GetEntryAtIndex(0)->GetUniqueID(),
106 controller
.GetEntryAtIndex(1)->GetUniqueID());
109 // This test used to make sure that a scheme used to prevent spoofs didn't ever
110 // interfere with navigations. We switched to a different scheme, so now this is
111 // just a test to make sure we can still navigate once we prune the history
113 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
114 DontIgnoreBackAfterNavEntryLimit
) {
115 NavigationController
& controller
=
116 shell()->web_contents()->GetController();
118 const int kMaxEntryCount
=
119 static_cast<int>(NavigationControllerImpl::max_entry_count());
121 // Load up to the max count, all entries should be there.
122 for (int url_index
= 0; url_index
< kMaxEntryCount
; ++url_index
) {
123 GURL
url(base::StringPrintf("data:text/html,page%d", url_index
));
124 EXPECT_TRUE(NavigateToURL(shell(), url
));
127 EXPECT_EQ(controller
.GetEntryCount(), kMaxEntryCount
);
129 // Navigate twice more more.
130 for (int url_index
= kMaxEntryCount
;
131 url_index
< kMaxEntryCount
+ 2; ++url_index
) {
132 GURL
url(base::StringPrintf("data:text/html,page%d", url_index
));
133 EXPECT_TRUE(NavigateToURL(shell(), url
));
136 // We expect page0 and page1 to be gone.
137 EXPECT_EQ(kMaxEntryCount
, controller
.GetEntryCount());
138 EXPECT_EQ(GURL("data:text/html,page2"),
139 controller
.GetEntryAtIndex(0)->GetURL());
141 // Now try to go back. This should not hang.
142 ASSERT_TRUE(controller
.CanGoBack());
144 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
146 // This should have successfully gone back.
147 EXPECT_EQ(GURL(base::StringPrintf("data:text/html,page%d", kMaxEntryCount
)),
148 controller
.GetLastCommittedEntry()->GetURL());
153 int RendererHistoryLength(Shell
* shell
) {
155 EXPECT_TRUE(ExecuteScriptAndExtractInt(
156 shell
->web_contents(),
157 "domAutomationController.send(history.length)",
162 // Similar to the ones from content_browser_test_utils.
163 bool NavigateToURLAndReplace(Shell
* shell
, const GURL
& url
) {
164 WebContents
* web_contents
= shell
->web_contents();
165 WaitForLoadStop(web_contents
);
166 TestNavigationObserver
same_tab_observer(web_contents
, 1);
167 NavigationController::LoadURLParams
params(url
);
168 params
.should_replace_current_entry
= true;
169 web_contents
->GetController().LoadURLWithParams(params
);
170 web_contents
->Focus();
171 same_tab_observer
.Wait();
172 if (!IsLastCommittedEntryOfPageType(web_contents
, PAGE_TYPE_NORMAL
))
174 return web_contents
->GetLastCommittedURL() == url
;
179 // When loading a new page to replace an old page in the history list, make sure
180 // that the browser and renderer agree, and that both get it right.
181 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
182 CorrectLengthWithCurrentItemReplacement
) {
183 NavigationController
& controller
=
184 shell()->web_contents()->GetController();
186 EXPECT_TRUE(NavigateToURL(shell(), GURL("data:text/html,page1")));
187 EXPECT_EQ(1, controller
.GetEntryCount());
188 EXPECT_EQ(1, RendererHistoryLength(shell()));
190 EXPECT_TRUE(NavigateToURLAndReplace(shell(), GURL("data:text/html,page1a")));
191 EXPECT_EQ(1, controller
.GetEntryCount());
192 EXPECT_EQ(1, RendererHistoryLength(shell()));
194 // Now create two more entries and go back, to test replacing an entry without
195 // pruning the forward history.
196 EXPECT_TRUE(NavigateToURL(shell(), GURL("data:text/html,page2")));
197 EXPECT_EQ(2, controller
.GetEntryCount());
198 EXPECT_EQ(2, RendererHistoryLength(shell()));
200 EXPECT_TRUE(NavigateToURL(shell(), GURL("data:text/html,page3")));
201 EXPECT_EQ(3, controller
.GetEntryCount());
202 EXPECT_EQ(3, RendererHistoryLength(shell()));
205 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
207 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
208 EXPECT_TRUE(controller
.CanGoForward());
210 EXPECT_TRUE(NavigateToURLAndReplace(shell(), GURL("data:text/html,page1b")));
211 EXPECT_EQ(3, controller
.GetEntryCount());
212 EXPECT_EQ(3, RendererHistoryLength(shell()));
213 EXPECT_TRUE(controller
.CanGoForward());
215 // Note that there's no way to access the renderer's notion of the history
216 // offset via JavaScript. Checking just the history length, though, is enough;
217 // if the replacement failed, there would be a new history entry and thus an
221 // When spawning a new page from a WebUI page, make sure that the browser and
222 // renderer agree about the length of the history list, and that both get it
224 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
225 CorrectLengthWithNewTabNavigatingFromWebUI
) {
226 GURL
web_ui_page(std::string(kChromeUIScheme
) + "://" +
227 std::string(kChromeUIGpuHost
));
228 EXPECT_TRUE(NavigateToURL(shell(), web_ui_page
));
229 EXPECT_EQ(BINDINGS_POLICY_WEB_UI
,
230 shell()->web_contents()->GetRenderViewHost()->GetEnabledBindings());
232 ShellAddedObserver observer
;
233 std::string page_url
= embedded_test_server()->GetURL(
234 "/navigation_controller/simple_page_1.html").spec();
235 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
236 "window.open('" + page_url
+ "', '_blank')"));
237 Shell
* shell2
= observer
.GetShell();
238 EXPECT_TRUE(WaitForLoadStop(shell2
->web_contents()));
240 EXPECT_EQ(1, shell2
->web_contents()->GetController().GetEntryCount());
241 EXPECT_EQ(1, RendererHistoryLength(shell2
));
243 // Again, as above, there's no way to access the renderer's notion of the
244 // history offset via JavaScript. Checking just the history length, again,
245 // will have to suffice.
250 class NoNavigationsObserver
: public WebContentsObserver
{
252 // Observes navigation for the specified |web_contents|.
253 explicit NoNavigationsObserver(WebContents
* web_contents
)
254 : WebContentsObserver(web_contents
) {}
257 void DidNavigateAnyFrame(RenderFrameHost
* render_frame_host
,
258 const LoadCommittedDetails
& details
,
259 const FrameNavigateParams
& params
) override
{
260 FAIL() << "No navigations should occur";
266 // Some pages create a popup, then write an iframe into it. This causes a
267 // subframe navigation without having any committed entry. Such navigations
268 // just get thrown on the ground, but we shouldn't crash.
270 // This test actually hits NAVIGATION_TYPE_NAV_IGNORE three times. Two of them,
271 // the initial window.open() and the iframe creation, don't try to create
272 // navigation entries, and the third, the new navigation, tries to.
273 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
, SubframeOnEmptyPage
) {
274 NavigateToURL(shell(), GURL(url::kAboutBlankURL
));
275 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
277 FrameTreeNode
* root
=
278 static_cast<WebContentsImpl
*>(shell()->web_contents())->
279 GetFrameTree()->root();
281 // Pop open a new window.
282 ShellAddedObserver new_shell_observer
;
283 std::string script
= "window.open()";
284 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
285 Shell
* new_shell
= new_shell_observer
.GetShell();
286 ASSERT_NE(new_shell
->web_contents(), shell()->web_contents());
287 FrameTreeNode
* new_root
=
288 static_cast<WebContentsImpl
*>(new_shell
->web_contents())->
289 GetFrameTree()->root();
291 // Make a new iframe in it.
292 NoNavigationsObserver
observer(new_shell
->web_contents());
293 script
= "var iframe = document.createElement('iframe');"
294 "iframe.src = 'data:text/html,<p>some page</p>';"
295 "document.body.appendChild(iframe);";
296 EXPECT_TRUE(content::ExecuteScript(new_root
->current_frame_host(), script
));
297 // The success check is of the last-committed entry, and there is none.
298 WaitForLoadStopWithoutSuccessCheck(new_shell
->web_contents());
300 ASSERT_EQ(1U, new_root
->child_count());
301 ASSERT_NE(nullptr, new_root
->child_at(0));
304 GURL frame_url
= embedded_test_server()->GetURL(
305 "/navigation_controller/simple_page_2.html");
306 script
= "location.assign('" + frame_url
.spec() + "')";
307 EXPECT_TRUE(content::ExecuteScript(
308 new_root
->child_at(0)->current_frame_host(), script
));
310 // Success is not crashing, and not navigating.
312 new_shell
->web_contents()->GetController().GetLastCommittedEntry());
317 class FrameNavigateParamsCapturer
: public WebContentsObserver
{
319 // Observes navigation for the specified |node|.
320 explicit FrameNavigateParamsCapturer(FrameTreeNode
* node
)
321 : WebContentsObserver(
322 node
->current_frame_host()->delegate()->GetAsWebContents()),
323 frame_tree_node_id_(node
->frame_tree_node_id()),
324 navigations_remaining_(1),
325 wait_for_load_(true),
326 message_loop_runner_(new MessageLoopRunner
) {}
328 void set_navigations_remaining(int count
) {
329 navigations_remaining_
= count
;
332 void set_wait_for_load(bool ignore
) {
333 wait_for_load_
= ignore
;
337 message_loop_runner_
->Run();
340 const FrameNavigateParams
& params() const {
341 EXPECT_EQ(1U, params_
.size());
345 const std::vector
<FrameNavigateParams
>& all_params() const {
349 const LoadCommittedDetails
& details() const {
350 EXPECT_EQ(1U, details_
.size());
354 const std::vector
<LoadCommittedDetails
>& all_details() const {
359 void DidNavigateAnyFrame(RenderFrameHost
* render_frame_host
,
360 const LoadCommittedDetails
& details
,
361 const FrameNavigateParams
& params
) override
{
362 RenderFrameHostImpl
* rfh
=
363 static_cast<RenderFrameHostImpl
*>(render_frame_host
);
364 if (rfh
->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_
)
367 --navigations_remaining_
;
368 params_
.push_back(params
);
369 details_
.push_back(details
);
370 if (!navigations_remaining_
&&
371 (!web_contents()->IsLoading() || !wait_for_load_
))
372 message_loop_runner_
->Quit();
375 void DidStopLoading() override
{
376 if (!navigations_remaining_
)
377 message_loop_runner_
->Quit();
380 // The id of the FrameTreeNode whose navigations to observe.
381 int frame_tree_node_id_
;
383 // How many navigations remain to capture.
384 int navigations_remaining_
;
386 // Whether to also wait for the load to complete.
389 // The params of the navigations.
390 std::vector
<FrameNavigateParams
> params_
;
392 // The details of the navigations.
393 std::vector
<LoadCommittedDetails
> details_
;
395 // The MessageLoopRunner used to spin the message loop.
396 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
399 class LoadCommittedCapturer
: public WebContentsObserver
{
401 // Observes the load commit for the specified |node|.
402 explicit LoadCommittedCapturer(FrameTreeNode
* node
)
403 : WebContentsObserver(
404 node
->current_frame_host()->delegate()->GetAsWebContents()),
405 frame_tree_node_id_(node
->frame_tree_node_id()),
406 message_loop_runner_(new MessageLoopRunner
) {}
408 // Observes the load commit for the next created frame in the specified
410 explicit LoadCommittedCapturer(WebContents
* web_contents
)
411 : WebContentsObserver(web_contents
),
412 frame_tree_node_id_(0),
413 message_loop_runner_(new MessageLoopRunner
) {}
416 message_loop_runner_
->Run();
419 ui::PageTransition
transition_type() const {
420 return transition_type_
;
424 void RenderFrameCreated(RenderFrameHost
* render_frame_host
) override
{
425 RenderFrameHostImpl
* rfh
=
426 static_cast<RenderFrameHostImpl
*>(render_frame_host
);
428 // Don't pay attention to swapped out RenderFrameHosts in the main frame.
429 // TODO(nasko): Remove once swappedout:// is gone.
430 // See https://crbug.com/357747.
431 if (!RenderFrameHostImpl::IsRFHStateActive(rfh
->rfh_state())) {
432 DLOG(INFO
) << "Skipping swapped out RFH: "
433 << rfh
->GetSiteInstance()->GetSiteURL();
437 // If this object was not created with a specified frame tree node, then use
438 // the first created active RenderFrameHost. Once a node is selected, there
439 // shouldn't be any other frames being created.
440 int frame_tree_node_id
= rfh
->frame_tree_node()->frame_tree_node_id();
441 DCHECK(frame_tree_node_id_
== 0 ||
442 frame_tree_node_id_
== frame_tree_node_id
);
443 frame_tree_node_id_
= frame_tree_node_id
;
446 void DidCommitProvisionalLoadForFrame(
447 RenderFrameHost
* render_frame_host
,
449 ui::PageTransition transition_type
) override
{
450 DCHECK_NE(0, frame_tree_node_id_
);
451 RenderFrameHostImpl
* rfh
=
452 static_cast<RenderFrameHostImpl
*>(render_frame_host
);
453 if (rfh
->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_
)
456 transition_type_
= transition_type
;
457 if (!web_contents()->IsLoading())
458 message_loop_runner_
->Quit();
461 void DidStopLoading() override
{ message_loop_runner_
->Quit(); }
463 // The id of the FrameTreeNode whose navigations to observe.
464 int frame_tree_node_id_
;
466 // The transition_type of the last navigation.
467 ui::PageTransition transition_type_
;
469 // The MessageLoopRunner used to spin the message loop.
470 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
475 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
476 ErrorPageReplacement
) {
477 NavigationController
& controller
= shell()->web_contents()->GetController();
479 net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_RESET
));
480 net::URLRequestFailedJob::AddUrlHandler();
482 NavigateToURL(shell(), GURL(url::kAboutBlankURL
));
483 EXPECT_EQ(1, controller
.GetEntryCount());
485 FrameTreeNode
* root
=
486 static_cast<WebContentsImpl
*>(shell()->web_contents())->
487 GetFrameTree()->root();
489 // Navigate to a page that fails to load. It must result in an error page, the
490 // NEW_PAGE navigation type, and an addition to the history list.
492 FrameNavigateParamsCapturer
capturer(root
);
493 NavigateFrameToURL(root
, error_url
);
495 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
496 NavigationEntry
* entry
= controller
.GetLastCommittedEntry();
497 EXPECT_EQ(PAGE_TYPE_ERROR
, entry
->GetPageType());
498 EXPECT_EQ(2, controller
.GetEntryCount());
501 // Navigate again to the page that fails to load. It must result in an error
502 // page, the EXISTING_PAGE navigation type, and no addition to the history
503 // list. We do not use SAME_PAGE here; that case only differs in that it
504 // clears the pending entry, and there is no pending entry after a load
507 FrameNavigateParamsCapturer
capturer(root
);
508 NavigateFrameToURL(root
, error_url
);
510 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
511 NavigationEntry
* entry
= controller
.GetLastCommittedEntry();
512 EXPECT_EQ(PAGE_TYPE_ERROR
, entry
->GetPageType());
513 EXPECT_EQ(2, controller
.GetEntryCount());
516 // Make a new entry ...
517 NavigateToURL(shell(), GURL(url::kAboutBlankURL
));
518 EXPECT_EQ(3, controller
.GetEntryCount());
520 // ... and replace it with a failed load. (Note that when you set the
521 // should_replace_current_entry flag, the navigation is classified as NEW_PAGE
522 // because that is a classification of the renderer's behavior, and the flag
523 // is a browser-side flag.)
525 FrameNavigateParamsCapturer
capturer(root
);
526 NavigateToURLAndReplace(shell(), error_url
);
528 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
529 NavigationEntry
* entry
= controller
.GetLastCommittedEntry();
530 EXPECT_EQ(PAGE_TYPE_ERROR
, entry
->GetPageType());
531 EXPECT_EQ(3, controller
.GetEntryCount());
534 // Make a new web ui page to force a process swap ...
535 GURL
web_ui_page(std::string(kChromeUIScheme
) + "://" +
536 std::string(kChromeUIGpuHost
));
537 NavigateToURL(shell(), web_ui_page
);
538 EXPECT_EQ(4, controller
.GetEntryCount());
540 // ... and replace it with a failed load. (It is NEW_PAGE for the reason noted
543 FrameNavigateParamsCapturer
capturer(root
);
544 NavigateToURLAndReplace(shell(), error_url
);
546 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
547 NavigationEntry
* entry
= controller
.GetLastCommittedEntry();
548 EXPECT_EQ(PAGE_TYPE_ERROR
, entry
->GetPageType());
549 EXPECT_EQ(4, controller
.GetEntryCount());
553 // Various tests for navigation type classifications. TODO(avi): It's rather
554 // bogus that the same info is in two different enums; http://crbug.com/453555.
556 // Verify that navigations for NAVIGATION_TYPE_NEW_PAGE are correctly
558 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
559 NavigationTypeClassification_NewPage
) {
560 NavigateToURL(shell(), GURL(url::kAboutBlankURL
));
562 FrameTreeNode
* root
=
563 static_cast<WebContentsImpl
*>(shell()->web_contents())->
564 GetFrameTree()->root();
568 FrameNavigateParamsCapturer
capturer(root
);
569 GURL
frame_url(embedded_test_server()->GetURL(
570 "/navigation_controller/page_with_links.html"));
571 NavigateFrameToURL(root
, frame_url
);
573 // TODO(avi,creis): Why is this (and quite a few others below) a "link"
574 // transition? Lots of these transitions should be cleaned up.
575 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
, capturer
.params().transition
);
576 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
577 EXPECT_FALSE(capturer
.details().is_in_page
);
581 // Load via a fragment link click.
582 FrameNavigateParamsCapturer
capturer(root
);
583 std::string script
= "document.getElementById('fraglink').click()";
584 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
586 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
, capturer
.params().transition
);
587 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
588 EXPECT_TRUE(capturer
.details().is_in_page
);
592 // Load via link click.
593 FrameNavigateParamsCapturer
capturer(root
);
594 std::string script
= "document.getElementById('thelink').click()";
595 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
597 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
, capturer
.params().transition
);
598 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
599 EXPECT_FALSE(capturer
.details().is_in_page
);
603 // location.assign().
604 FrameNavigateParamsCapturer
capturer(root
);
605 GURL
frame_url(embedded_test_server()->GetURL(
606 "/navigation_controller/simple_page_2.html"));
607 std::string script
= "location.assign('" + frame_url
.spec() + "')";
608 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
610 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_CLIENT_REDIRECT
,
611 capturer
.params().transition
);
612 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
613 EXPECT_FALSE(capturer
.details().is_in_page
);
617 // history.pushState().
618 FrameNavigateParamsCapturer
capturer(root
);
620 "history.pushState({}, 'page 1', 'simple_page_1.html')";
621 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
623 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_CLIENT_REDIRECT
,
624 capturer
.params().transition
);
625 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
626 EXPECT_TRUE(capturer
.details().is_in_page
);
630 // Verify that navigations for NAVIGATION_TYPE_EXISTING_PAGE are correctly
632 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
633 NavigationTypeClassification_ExistingPage
) {
634 GURL
url1(embedded_test_server()->GetURL(
635 "/navigation_controller/simple_page_1.html"));
636 NavigateToURL(shell(), url1
);
637 GURL
url2(embedded_test_server()->GetURL(
638 "/navigation_controller/simple_page_2.html"));
639 NavigateToURL(shell(), url2
);
641 FrameTreeNode
* root
=
642 static_cast<WebContentsImpl
*>(shell()->web_contents())->
643 GetFrameTree()->root();
646 // Back from the browser side.
647 FrameNavigateParamsCapturer
capturer(root
);
648 shell()->web_contents()->GetController().GoBack();
650 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
651 | ui::PAGE_TRANSITION_FORWARD_BACK
652 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
,
653 capturer
.params().transition
);
654 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
655 EXPECT_FALSE(capturer
.details().is_in_page
);
659 // Forward from the browser side.
660 FrameNavigateParamsCapturer
capturer(root
);
661 shell()->web_contents()->GetController().GoForward();
663 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
664 | ui::PAGE_TRANSITION_FORWARD_BACK
665 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
,
666 capturer
.params().transition
);
667 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
668 EXPECT_FALSE(capturer
.details().is_in_page
);
672 // Back from the renderer side.
673 FrameNavigateParamsCapturer
capturer(root
);
674 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(),
677 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
678 | ui::PAGE_TRANSITION_FORWARD_BACK
679 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
,
680 capturer
.params().transition
);
681 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
682 EXPECT_FALSE(capturer
.details().is_in_page
);
686 // Forward from the renderer side.
687 FrameNavigateParamsCapturer
capturer(root
);
688 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(),
689 "history.forward()"));
691 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
692 | ui::PAGE_TRANSITION_FORWARD_BACK
693 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
,
694 capturer
.params().transition
);
695 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
696 EXPECT_FALSE(capturer
.details().is_in_page
);
700 // Back from the renderer side via history.go().
701 FrameNavigateParamsCapturer
capturer(root
);
702 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(),
705 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
706 | ui::PAGE_TRANSITION_FORWARD_BACK
707 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
,
708 capturer
.params().transition
);
709 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
710 EXPECT_FALSE(capturer
.details().is_in_page
);
714 // Forward from the renderer side via history.go().
715 FrameNavigateParamsCapturer
capturer(root
);
716 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(),
719 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
720 | ui::PAGE_TRANSITION_FORWARD_BACK
721 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
,
722 capturer
.params().transition
);
723 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
724 EXPECT_FALSE(capturer
.details().is_in_page
);
728 // Reload from the browser side.
729 FrameNavigateParamsCapturer
capturer(root
);
730 shell()->web_contents()->GetController().Reload(false);
732 EXPECT_EQ(ui::PAGE_TRANSITION_RELOAD
, capturer
.params().transition
);
733 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
734 EXPECT_FALSE(capturer
.details().is_in_page
);
738 // Reload from the renderer side.
739 FrameNavigateParamsCapturer
capturer(root
);
740 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(),
741 "location.reload()"));
743 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_CLIENT_REDIRECT
,
744 capturer
.params().transition
);
745 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
746 EXPECT_FALSE(capturer
.details().is_in_page
);
750 // location.replace().
751 FrameNavigateParamsCapturer
capturer(root
);
752 GURL
frame_url(embedded_test_server()->GetURL(
753 "/navigation_controller/simple_page_1.html"));
754 std::string script
= "location.replace('" + frame_url
.spec() + "')";
755 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
757 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_CLIENT_REDIRECT
,
758 capturer
.params().transition
);
759 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
760 EXPECT_FALSE(capturer
.details().is_in_page
);
763 // Now, various in-page navigations.
766 // history.replaceState().
767 FrameNavigateParamsCapturer
capturer(root
);
769 "history.replaceState({}, 'page 2', 'simple_page_2.html')";
770 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
772 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_CLIENT_REDIRECT
,
773 capturer
.params().transition
);
774 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
775 EXPECT_TRUE(capturer
.details().is_in_page
);
778 // Back and forward across a fragment navigation.
780 GURL
url_links(embedded_test_server()->GetURL(
781 "/navigation_controller/page_with_links.html"));
782 NavigateToURL(shell(), url_links
);
783 std::string script
= "document.getElementById('fraglink').click()";
784 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
785 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
789 FrameNavigateParamsCapturer
capturer(root
);
790 shell()->web_contents()->GetController().GoBack();
792 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
793 | ui::PAGE_TRANSITION_FORWARD_BACK
794 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
,
795 capturer
.params().transition
);
796 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
797 EXPECT_TRUE(capturer
.details().is_in_page
);
802 FrameNavigateParamsCapturer
capturer(root
);
803 shell()->web_contents()->GetController().GoForward();
805 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_FORWARD_BACK
,
806 capturer
.params().transition
);
807 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
808 EXPECT_TRUE(capturer
.details().is_in_page
);
811 // Back and forward across a pushState-created navigation.
813 NavigateToURL(shell(), url1
);
814 script
= "history.pushState({}, 'page 2', 'simple_page_2.html')";
815 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
816 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
820 FrameNavigateParamsCapturer
capturer(root
);
821 shell()->web_contents()->GetController().GoBack();
823 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
824 | ui::PAGE_TRANSITION_FORWARD_BACK
825 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
,
826 capturer
.params().transition
);
827 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
828 EXPECT_TRUE(capturer
.details().is_in_page
);
833 FrameNavigateParamsCapturer
capturer(root
);
834 shell()->web_contents()->GetController().GoForward();
836 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_FORWARD_BACK
,
837 capturer
.params().transition
);
838 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
839 EXPECT_TRUE(capturer
.details().is_in_page
);
843 // Verify that navigations for NAVIGATION_TYPE_SAME_PAGE are correctly
845 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
846 NavigationTypeClassification_SamePage
) {
847 GURL
url1(embedded_test_server()->GetURL(
848 "/navigation_controller/simple_page_1.html"));
849 NavigateToURL(shell(), url1
);
851 FrameTreeNode
* root
=
852 static_cast<WebContentsImpl
*>(shell()->web_contents())->
853 GetFrameTree()->root();
857 FrameNavigateParamsCapturer
capturer(root
);
858 GURL
frame_url(embedded_test_server()->GetURL(
859 "/navigation_controller/simple_page_1.html"));
860 NavigateFrameToURL(root
, frame_url
);
862 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
, capturer
.params().transition
);
863 EXPECT_EQ(NAVIGATION_TYPE_SAME_PAGE
, capturer
.details().type
);
867 // Verify that navigations for NAVIGATION_TYPE_NEW_SUBFRAME and
868 // NAVIGATION_TYPE_AUTO_SUBFRAME are properly classified.
869 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
870 NavigationTypeClassification_NewAndAutoSubframe
) {
871 GURL
main_url(embedded_test_server()->GetURL(
872 "/navigation_controller/page_with_iframe.html"));
873 NavigateToURL(shell(), main_url
);
875 // It is safe to obtain the root frame tree node here, as it doesn't change.
876 FrameTreeNode
* root
=
877 static_cast<WebContentsImpl
*>(shell()->web_contents())->
878 GetFrameTree()->root();
880 ASSERT_EQ(1U, root
->child_count());
881 ASSERT_NE(nullptr, root
->child_at(0));
885 LoadCommittedCapturer
capturer(root
->child_at(0));
886 GURL
frame_url(embedded_test_server()->GetURL(
887 "/navigation_controller/simple_page_1.html"));
888 NavigateFrameToURL(root
->child_at(0), frame_url
);
890 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
895 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
896 GURL
frame_url(embedded_test_server()->GetURL(
897 "/navigation_controller/simple_page_2.html"));
898 NavigateFrameToURL(root
->child_at(0), frame_url
);
900 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
901 capturer
.params().transition
);
902 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
907 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
908 shell()->web_contents()->GetController().GoBack();
910 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.params().transition
);
911 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME
, capturer
.details().type
);
916 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
917 shell()->web_contents()->GetController().GoForward();
919 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.params().transition
);
920 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME
, capturer
.details().type
);
925 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
926 GURL
frame_url(embedded_test_server()->GetURL(
927 "/navigation_controller/page_with_links.html"));
928 NavigateFrameToURL(root
->child_at(0), frame_url
);
930 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
931 capturer
.params().transition
);
932 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
936 // Load via a fragment link click.
937 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
938 std::string script
= "document.getElementById('fraglink').click()";
939 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
942 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
943 capturer
.params().transition
);
944 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
948 // location.assign().
949 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
950 GURL
frame_url(embedded_test_server()->GetURL(
951 "/navigation_controller/simple_page_1.html"));
952 std::string script
= "location.assign('" + frame_url
.spec() + "')";
953 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
956 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
957 capturer
.params().transition
);
958 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
962 // location.replace().
963 LoadCommittedCapturer
capturer(root
->child_at(0));
964 GURL
frame_url(embedded_test_server()->GetURL(
965 "/navigation_controller/simple_page_2.html"));
966 std::string script
= "location.replace('" + frame_url
.spec() + "')";
967 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
970 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
974 // history.pushState().
975 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
977 "history.pushState({}, 'page 1', 'simple_page_1.html')";
978 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
981 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
982 capturer
.params().transition
);
983 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
987 // history.replaceState().
988 LoadCommittedCapturer
capturer(root
->child_at(0));
990 "history.replaceState({}, 'page 2', 'simple_page_2.html')";
991 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
994 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
999 LoadCommittedCapturer
capturer(root
->child_at(0));
1000 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
1001 "location.reload()"));
1003 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1007 // Create an iframe.
1008 LoadCommittedCapturer
capturer(shell()->web_contents());
1009 GURL
frame_url(embedded_test_server()->GetURL(
1010 "/navigation_controller/simple_page_1.html"));
1011 std::string script
= "var iframe = document.createElement('iframe');"
1012 "iframe.src = '" + frame_url
.spec() + "';"
1013 "document.body.appendChild(iframe);";
1014 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1016 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1020 // Verify that navigations caused by client-side redirects are correctly
1022 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1023 NavigationTypeClassification_ClientSideRedirect
) {
1024 NavigateToURL(shell(), GURL(url::kAboutBlankURL
));
1025 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1027 FrameTreeNode
* root
=
1028 static_cast<WebContentsImpl
*>(shell()->web_contents())->
1029 GetFrameTree()->root();
1032 // Load the redirecting page.
1033 FrameNavigateParamsCapturer
capturer(root
);
1034 capturer
.set_navigations_remaining(2);
1035 GURL
frame_url(embedded_test_server()->GetURL(
1036 "/navigation_controller/client_redirect.html"));
1037 NavigateFrameToURL(root
, frame_url
);
1040 std::vector
<FrameNavigateParams
> params
= capturer
.all_params();
1041 std::vector
<LoadCommittedDetails
> details
= capturer
.all_details();
1042 ASSERT_EQ(2U, params
.size());
1043 ASSERT_EQ(2U, details
.size());
1044 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
, params
[0].transition
);
1045 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, details
[0].type
);
1046 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_CLIENT_REDIRECT
,
1047 params
[1].transition
);
1048 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, details
[1].type
);
1052 // Verify that the LoadCommittedDetails::is_in_page value is properly set for
1053 // non-IN_PAGE navigations. (It's tested for IN_PAGE navigations with the
1054 // NavigationTypeClassification_InPage test.)
1055 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1056 LoadCommittedDetails_IsInPage
) {
1057 GURL
links_url(embedded_test_server()->GetURL(
1058 "/navigation_controller/page_with_links.html"));
1059 NavigateToURL(shell(), links_url
);
1060 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1062 FrameTreeNode
* root
=
1063 static_cast<WebContentsImpl
*>(shell()->web_contents())->
1064 GetFrameTree()->root();
1067 // Do a fragment link click.
1068 FrameNavigateParamsCapturer
capturer(root
);
1069 std::string script
= "document.getElementById('fraglink').click()";
1070 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1072 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
, capturer
.params().transition
);
1073 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
1074 EXPECT_TRUE(capturer
.details().is_in_page
);
1078 // Do a non-fragment link click.
1079 FrameNavigateParamsCapturer
capturer(root
);
1080 std::string script
= "document.getElementById('thelink').click()";
1081 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1083 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
, capturer
.params().transition
);
1084 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
1085 EXPECT_FALSE(capturer
.details().is_in_page
);
1088 // Second verse, same as the first. (But in a subframe.)
1090 GURL
iframe_url(embedded_test_server()->GetURL(
1091 "/navigation_controller/page_with_iframe.html"));
1092 NavigateToURL(shell(), iframe_url
);
1094 root
= static_cast<WebContentsImpl
*>(shell()->web_contents())->
1095 GetFrameTree()->root();
1097 ASSERT_EQ(1U, root
->child_count());
1098 ASSERT_NE(nullptr, root
->child_at(0));
1100 NavigateFrameToURL(root
->child_at(0), links_url
);
1101 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1104 // Do a fragment link click.
1105 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1106 std::string script
= "document.getElementById('fraglink').click()";
1107 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
1110 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
1111 capturer
.params().transition
);
1112 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
1113 EXPECT_TRUE(capturer
.details().is_in_page
);
1117 // Do a non-fragment link click.
1118 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1119 std::string script
= "document.getElementById('thelink').click()";
1120 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
1123 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
1124 capturer
.params().transition
);
1125 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
1126 EXPECT_FALSE(capturer
.details().is_in_page
);
1130 // Verify the tree of FrameNavigationEntries after initial about:blank commits
1131 // in subframes, which should not count as real committed loads.
1132 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1133 FrameNavigationEntry_BlankAutoSubframe
) {
1134 GURL
about_blank_url(url::kAboutBlankURL
);
1135 GURL
main_url(embedded_test_server()->GetURL(
1136 "/navigation_controller/simple_page_1.html"));
1137 NavigateToURL(shell(), main_url
);
1138 const NavigationControllerImpl
& controller
=
1139 static_cast<const NavigationControllerImpl
&>(
1140 shell()->web_contents()->GetController());
1141 FrameTreeNode
* root
=
1142 static_cast<WebContentsImpl
*>(shell()->web_contents())->
1143 GetFrameTree()->root();
1145 // 1. Create a iframe with no URL.
1147 LoadCommittedCapturer
capturer(shell()->web_contents());
1148 std::string script
= "var iframe = document.createElement('iframe');"
1149 "document.body.appendChild(iframe);";
1150 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1152 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1155 // Check last committed NavigationEntry.
1156 EXPECT_EQ(1, controller
.GetEntryCount());
1157 NavigationEntryImpl
* entry
= controller
.GetLastCommittedEntry();
1158 EXPECT_EQ(main_url
, entry
->GetURL());
1159 FrameNavigationEntry
* root_entry
= entry
->root_node()->frame_entry
.get();
1160 EXPECT_EQ(main_url
, root_entry
->url());
1162 // Verify subframe entries if we're in --site-per-process mode.
1163 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1164 switches::kSitePerProcess
)) {
1165 // The entry should now have one blank subframe FrameNavigationEntry, but
1166 // this does not count as committing a real load.
1167 ASSERT_EQ(1U, entry
->root_node()->children
.size());
1168 FrameNavigationEntry
* frame_entry
=
1169 entry
->root_node()->children
[0]->frame_entry
.get();
1170 EXPECT_EQ(about_blank_url
, frame_entry
->url());
1172 // There are no subframe FrameNavigationEntries by default.
1173 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1175 EXPECT_FALSE(root
->child_at(0)->has_committed_real_load());
1177 // 1a. A nested iframe with no URL should also create a subframe entry but not
1178 // count as a real load.
1180 LoadCommittedCapturer
capturer(shell()->web_contents());
1181 std::string script
= "var iframe = document.createElement('iframe');"
1182 "document.body.appendChild(iframe);";
1183 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
1186 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1189 // Verify subframe entries if we're in --site-per-process mode.
1190 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1191 switches::kSitePerProcess
)) {
1192 // The nested entry should have one blank subframe FrameNavigationEntry, but
1193 // this does not count as committing a real load.
1194 ASSERT_EQ(1U, entry
->root_node()->children
[0]->children
.size());
1195 FrameNavigationEntry
* frame_entry
=
1196 entry
->root_node()->children
[0]->children
[0]->frame_entry
.get();
1197 EXPECT_EQ(about_blank_url
, frame_entry
->url());
1199 // There are no subframe FrameNavigationEntries by default.
1200 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1202 EXPECT_FALSE(root
->child_at(0)->child_at(0)->has_committed_real_load());
1204 // 2. Create another iframe with an explicit about:blank URL.
1206 LoadCommittedCapturer
capturer(shell()->web_contents());
1207 std::string script
= "var iframe = document.createElement('iframe');"
1208 "iframe.src = 'about:blank';"
1209 "document.body.appendChild(iframe);";
1210 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1212 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1215 // Check last committed NavigationEntry.
1216 EXPECT_EQ(1, controller
.GetEntryCount());
1217 EXPECT_EQ(entry
, controller
.GetLastCommittedEntry());
1219 // Verify subframe entries if we're in --site-per-process mode.
1220 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1221 switches::kSitePerProcess
)) {
1222 // The new entry should have one blank subframe FrameNavigationEntry, but
1223 // this does not count as committing a real load.
1224 ASSERT_EQ(2U, entry
->root_node()->children
.size());
1225 FrameNavigationEntry
* frame_entry
=
1226 entry
->root_node()->children
[1]->frame_entry
.get();
1227 EXPECT_EQ(about_blank_url
, frame_entry
->url());
1229 // There are no subframe FrameNavigationEntries by default.
1230 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1232 EXPECT_FALSE(root
->child_at(1)->has_committed_real_load());
1234 // 3. A real same-site navigation in the nested iframe should be AUTO.
1235 GURL
frame_url(embedded_test_server()->GetURL(
1236 "/navigation_controller/simple_page_1.html"));
1238 LoadCommittedCapturer
capturer(root
->child_at(0)->child_at(0));
1239 std::string script
= "var frames = document.getElementsByTagName('iframe');"
1240 "frames[0].src = '" + frame_url
.spec() + "';";
1241 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
1244 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1247 // Check last committed NavigationEntry. It should have replaced the previous
1248 // frame entry in the original NavigationEntry.
1249 EXPECT_EQ(1, controller
.GetEntryCount());
1250 EXPECT_EQ(entry
, controller
.GetLastCommittedEntry());
1252 // Verify subframe entries if we're in --site-per-process mode.
1253 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1254 switches::kSitePerProcess
)) {
1255 // The entry should still have one nested subframe FrameNavigationEntry.
1256 ASSERT_EQ(1U, entry
->root_node()->children
[0]->children
.size());
1257 FrameNavigationEntry
* frame_entry
=
1258 entry
->root_node()->children
[0]->children
[0]->frame_entry
.get();
1259 EXPECT_EQ(frame_url
, frame_entry
->url());
1261 // There are no subframe FrameNavigationEntries by default.
1262 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1264 EXPECT_FALSE(root
->child_at(0)->has_committed_real_load());
1265 EXPECT_TRUE(root
->child_at(0)->child_at(0)->has_committed_real_load());
1266 EXPECT_FALSE(root
->child_at(1)->has_committed_real_load());
1268 // 4. A real cross-site navigation in the second iframe should be AUTO.
1269 GURL
foo_url(embedded_test_server()->GetURL(
1270 "foo.com", "/navigation_controller/simple_page_2.html"));
1272 LoadCommittedCapturer
capturer(root
->child_at(1));
1273 std::string script
= "var frames = document.getElementsByTagName('iframe');"
1274 "frames[1].src = '" + foo_url
.spec() + "';";
1275 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1277 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1280 // Check last committed NavigationEntry.
1281 EXPECT_EQ(1, controller
.GetEntryCount());
1282 EXPECT_EQ(entry
, controller
.GetLastCommittedEntry());
1284 // Verify subframe entries if we're in --site-per-process mode.
1285 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1286 switches::kSitePerProcess
)) {
1287 // The entry should still have two subframe FrameNavigationEntries.
1288 ASSERT_EQ(2U, entry
->root_node()->children
.size());
1289 FrameNavigationEntry
* frame_entry
=
1290 entry
->root_node()->children
[1]->frame_entry
.get();
1291 EXPECT_EQ(foo_url
, frame_entry
->url());
1293 // There are no subframe FrameNavigationEntries by default.
1294 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1296 EXPECT_FALSE(root
->child_at(0)->has_committed_real_load());
1297 EXPECT_TRUE(root
->child_at(0)->child_at(0)->has_committed_real_load());
1298 EXPECT_TRUE(root
->child_at(1)->has_committed_real_load());
1300 // 5. A new navigation to about:blank in the nested frame should count as a
1301 // real load, since that frame has already committed a real load and this is
1302 // not the initial blank page.
1304 LoadCommittedCapturer
capturer(root
->child_at(0)->child_at(0));
1305 std::string script
= "var frames = document.getElementsByTagName('iframe');"
1306 "frames[0].src = 'about:blank';";
1307 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
1310 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
, capturer
.transition_type());
1313 // This should have created a new NavigationEntry.
1314 EXPECT_EQ(2, controller
.GetEntryCount());
1315 EXPECT_NE(entry
, controller
.GetLastCommittedEntry());
1316 NavigationEntryImpl
* entry2
= controller
.GetLastCommittedEntry();
1318 // Verify subframe entries if we're in --site-per-process mode.
1319 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1320 switches::kSitePerProcess
)) {
1321 ASSERT_EQ(2U, entry
->root_node()->children
.size());
1322 FrameNavigationEntry
* frame_entry
=
1323 entry2
->root_node()->children
[0]->children
[0]->frame_entry
.get();
1324 EXPECT_EQ(about_blank_url
, frame_entry
->url());
1326 // There are no subframe FrameNavigationEntries by default.
1327 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1329 EXPECT_FALSE(root
->child_at(0)->has_committed_real_load());
1330 EXPECT_TRUE(root
->child_at(0)->child_at(0)->has_committed_real_load());
1331 EXPECT_TRUE(root
->child_at(1)->has_committed_real_load());
1333 // Check the end result of the frame tree.
1334 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1335 switches::kSitePerProcess
)) {
1336 FrameTreeVisualizer visualizer
;
1338 " Site A ------------ proxies for B\n"
1339 " |--Site A ------- proxies for B\n"
1340 " | +--Site A -- proxies for B\n"
1341 " +--Site B ------- proxies for A\n"
1342 "Where A = http://127.0.0.1/\n"
1343 " B = http://foo.com/",
1344 visualizer
.DepictFrameTree(root
));
1348 // Verify the tree of FrameNavigationEntries after NAVIGATION_TYPE_AUTO_SUBFRAME
1350 // TODO(creis): Test updating entries for history auto subframe navigations.
1351 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1352 FrameNavigationEntry_AutoSubframe
) {
1353 GURL
main_url(embedded_test_server()->GetURL(
1354 "/navigation_controller/simple_page_1.html"));
1355 NavigateToURL(shell(), main_url
);
1356 const NavigationControllerImpl
& controller
=
1357 static_cast<const NavigationControllerImpl
&>(
1358 shell()->web_contents()->GetController());
1359 FrameTreeNode
* root
=
1360 static_cast<WebContentsImpl
*>(shell()->web_contents())->
1361 GetFrameTree()->root();
1363 // 1. Create a same-site iframe.
1364 GURL
frame_url(embedded_test_server()->GetURL(
1365 "/navigation_controller/simple_page_2.html"));
1367 LoadCommittedCapturer
capturer(shell()->web_contents());
1368 std::string script
= "var iframe = document.createElement('iframe');"
1369 "iframe.src = '" + frame_url
.spec() + "';"
1370 "document.body.appendChild(iframe);";
1371 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1373 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1376 // Check last committed NavigationEntry.
1377 EXPECT_EQ(1, controller
.GetEntryCount());
1378 NavigationEntryImpl
* entry
= controller
.GetLastCommittedEntry();
1379 EXPECT_EQ(main_url
, entry
->GetURL());
1380 FrameNavigationEntry
* root_entry
= entry
->root_node()->frame_entry
.get();
1381 EXPECT_EQ(main_url
, root_entry
->url());
1382 EXPECT_FALSE(controller
.GetPendingEntry());
1384 // Verify subframe entries if we're in --site-per-process mode.
1385 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1386 switches::kSitePerProcess
)) {
1387 // The entry should now have a subframe FrameNavigationEntry.
1388 ASSERT_EQ(1U, entry
->root_node()->children
.size());
1389 FrameNavigationEntry
* frame_entry
=
1390 entry
->root_node()->children
[0]->frame_entry
.get();
1391 EXPECT_EQ(frame_url
, frame_entry
->url());
1392 EXPECT_TRUE(root
->child_at(0)->has_committed_real_load());
1394 // There are no subframe FrameNavigationEntries by default.
1395 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1398 // 2. Create a second, initially cross-site iframe.
1399 GURL
foo_url(embedded_test_server()->GetURL(
1400 "foo.com", "/navigation_controller/simple_page_1.html"));
1402 LoadCommittedCapturer
capturer(shell()->web_contents());
1403 std::string script
= "var iframe = document.createElement('iframe');"
1404 "iframe.src = '" + foo_url
.spec() + "';"
1405 "document.body.appendChild(iframe);";
1406 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1408 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1411 // The last committed NavigationEntry shouldn't have changed.
1412 EXPECT_EQ(1, controller
.GetEntryCount());
1413 entry
= controller
.GetLastCommittedEntry();
1414 EXPECT_EQ(main_url
, entry
->GetURL());
1415 root_entry
= entry
->root_node()->frame_entry
.get();
1416 EXPECT_EQ(main_url
, root_entry
->url());
1417 EXPECT_FALSE(controller
.GetPendingEntry());
1419 // Verify subframe entries if we're in --site-per-process mode.
1420 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1421 switches::kSitePerProcess
)) {
1422 // The entry should now have 2 subframe FrameNavigationEntries.
1423 ASSERT_EQ(2U, entry
->root_node()->children
.size());
1424 FrameNavigationEntry
* frame_entry
=
1425 entry
->root_node()->children
[1]->frame_entry
.get();
1426 EXPECT_EQ(foo_url
, frame_entry
->url());
1427 EXPECT_TRUE(root
->child_at(1)->has_committed_real_load());
1429 // There are no subframe FrameNavigationEntries by default.
1430 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1433 // 3. Create a nested iframe in the second subframe.
1435 LoadCommittedCapturer
capturer(shell()->web_contents());
1436 std::string script
= "var iframe = document.createElement('iframe');"
1437 "iframe.src = '" + foo_url
.spec() + "';"
1438 "document.body.appendChild(iframe);";
1439 EXPECT_TRUE(content::ExecuteScript(root
->child_at(1)->current_frame_host(),
1442 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1445 // The last committed NavigationEntry shouldn't have changed.
1446 EXPECT_EQ(1, controller
.GetEntryCount());
1447 entry
= controller
.GetLastCommittedEntry();
1448 EXPECT_EQ(main_url
, entry
->GetURL());
1449 root_entry
= entry
->root_node()->frame_entry
.get();
1450 EXPECT_EQ(main_url
, root_entry
->url());
1452 // Verify subframe entries if we're in --site-per-process mode.
1453 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1454 switches::kSitePerProcess
)) {
1455 // The entry should now have 2 subframe FrameNavigationEntries.
1456 ASSERT_EQ(2U, entry
->root_node()->children
.size());
1457 ASSERT_EQ(1U, entry
->root_node()->children
[1]->children
.size());
1458 FrameNavigationEntry
* frame_entry
=
1459 entry
->root_node()->children
[1]->children
[0]->frame_entry
.get();
1460 EXPECT_EQ(foo_url
, frame_entry
->url());
1462 // There are no subframe FrameNavigationEntries by default.
1463 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1466 // 4. Create a third iframe on the same site as the second. This ensures that
1467 // the commit type is correct even when the subframe process already exists.
1469 LoadCommittedCapturer
capturer(shell()->web_contents());
1470 std::string script
= "var iframe = document.createElement('iframe');"
1471 "iframe.src = '" + foo_url
.spec() + "';"
1472 "document.body.appendChild(iframe);";
1473 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1475 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1478 // The last committed NavigationEntry shouldn't have changed.
1479 EXPECT_EQ(1, controller
.GetEntryCount());
1480 entry
= controller
.GetLastCommittedEntry();
1481 EXPECT_EQ(main_url
, entry
->GetURL());
1482 root_entry
= entry
->root_node()->frame_entry
.get();
1483 EXPECT_EQ(main_url
, root_entry
->url());
1485 // Verify subframe entries if we're in --site-per-process mode.
1486 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1487 switches::kSitePerProcess
)) {
1488 // The entry should now have 3 subframe FrameNavigationEntries.
1489 ASSERT_EQ(3U, entry
->root_node()->children
.size());
1490 FrameNavigationEntry
* frame_entry
=
1491 entry
->root_node()->children
[2]->frame_entry
.get();
1492 EXPECT_EQ(foo_url
, frame_entry
->url());
1494 // There are no subframe FrameNavigationEntries by default.
1495 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1498 // 5. Create a nested iframe on the original site (A-B-A).
1500 LoadCommittedCapturer
capturer(shell()->web_contents());
1501 std::string script
= "var iframe = document.createElement('iframe');"
1502 "iframe.src = '" + frame_url
.spec() + "';"
1503 "document.body.appendChild(iframe);";
1504 FrameTreeNode
* child
= root
->child_at(2);
1505 EXPECT_TRUE(content::ExecuteScript(child
->current_frame_host(), script
));
1507 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1510 // The last committed NavigationEntry shouldn't have changed.
1511 EXPECT_EQ(1, controller
.GetEntryCount());
1512 entry
= controller
.GetLastCommittedEntry();
1513 EXPECT_EQ(main_url
, entry
->GetURL());
1514 root_entry
= entry
->root_node()->frame_entry
.get();
1515 EXPECT_EQ(main_url
, root_entry
->url());
1517 // Verify subframe entries if we're in --site-per-process mode.
1518 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1519 switches::kSitePerProcess
)) {
1520 // There should be a corresponding FrameNavigationEntry.
1521 ASSERT_EQ(1U, entry
->root_node()->children
[2]->children
.size());
1522 FrameNavigationEntry
* frame_entry
=
1523 entry
->root_node()->children
[2]->children
[0]->frame_entry
.get();
1524 EXPECT_EQ(frame_url
, frame_entry
->url());
1526 // There are no subframe FrameNavigationEntries by default.
1527 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1530 // Check the end result of the frame tree.
1531 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1532 switches::kSitePerProcess
)) {
1533 FrameTreeVisualizer visualizer
;
1535 " Site A ------------ proxies for B\n"
1536 " |--Site A ------- proxies for B\n"
1537 " |--Site B ------- proxies for A\n"
1538 " | +--Site B -- proxies for A\n"
1539 " +--Site B ------- proxies for A\n"
1540 " +--Site A -- proxies for B\n"
1541 "Where A = http://127.0.0.1/\n"
1542 " B = http://foo.com/",
1543 visualizer
.DepictFrameTree(root
));
1547 // Verify the tree of FrameNavigationEntries after NAVIGATION_TYPE_NEW_SUBFRAME
1549 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1550 FrameNavigationEntry_NewSubframe
) {
1551 GURL
main_url(embedded_test_server()->GetURL(
1552 "/navigation_controller/simple_page_1.html"));
1553 NavigateToURL(shell(), main_url
);
1554 const NavigationControllerImpl
& controller
=
1555 static_cast<const NavigationControllerImpl
&>(
1556 shell()->web_contents()->GetController());
1557 FrameTreeNode
* root
=
1558 static_cast<WebContentsImpl
*>(shell()->web_contents())->
1559 GetFrameTree()->root();
1561 // 1. Create a same-site iframe.
1562 GURL
frame_url(embedded_test_server()->GetURL(
1563 "/navigation_controller/simple_page_2.html"));
1565 LoadCommittedCapturer
capturer(shell()->web_contents());
1566 std::string script
= "var iframe = document.createElement('iframe');"
1567 "iframe.src = '" + frame_url
.spec() + "';"
1568 "document.body.appendChild(iframe);";
1569 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1572 NavigationEntryImpl
* entry
= controller
.GetLastCommittedEntry();
1574 // 2. Navigate in the subframe same-site.
1575 GURL
frame_url2(embedded_test_server()->GetURL(
1576 "/navigation_controller/page_with_links.html"));
1578 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1579 NavigateFrameToURL(root
->child_at(0), frame_url2
);
1581 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
1582 capturer
.params().transition
);
1583 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
1586 // We should have created a new NavigationEntry with the same main frame URL.
1587 EXPECT_EQ(2, controller
.GetEntryCount());
1588 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
1589 NavigationEntryImpl
* entry2
= controller
.GetLastCommittedEntry();
1590 EXPECT_NE(entry
, entry2
);
1591 EXPECT_EQ(main_url
, entry2
->GetURL());
1592 FrameNavigationEntry
* root_entry2
= entry2
->root_node()->frame_entry
.get();
1593 EXPECT_EQ(main_url
, root_entry2
->url());
1595 // Verify subframe entries if we're in --site-per-process mode.
1596 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1597 switches::kSitePerProcess
)) {
1598 // The entry should have a new FrameNavigationEntries for the subframe.
1599 ASSERT_EQ(1U, entry2
->root_node()->children
.size());
1600 EXPECT_EQ(frame_url2
, entry2
->root_node()->children
[0]->frame_entry
->url());
1602 // There are no subframe FrameNavigationEntries by default.
1603 EXPECT_EQ(0U, entry2
->root_node()->children
.size());
1606 // 3. Create a second, initially cross-site iframe.
1607 GURL
foo_url(embedded_test_server()->GetURL(
1608 "foo.com", "/navigation_controller/simple_page_1.html"));
1610 LoadCommittedCapturer
capturer(shell()->web_contents());
1611 std::string script
= "var iframe = document.createElement('iframe');"
1612 "iframe.src = '" + foo_url
.spec() + "';"
1613 "document.body.appendChild(iframe);";
1614 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1618 // 4. Create a nested same-site iframe in the second subframe, wait for it to
1619 // commit, then navigate it again.
1621 LoadCommittedCapturer
capturer(shell()->web_contents());
1622 std::string script
= "var iframe = document.createElement('iframe');"
1623 "iframe.src = '" + foo_url
.spec() + "';"
1624 "document.body.appendChild(iframe);";
1625 EXPECT_TRUE(content::ExecuteScript(root
->child_at(1)->current_frame_host(),
1629 GURL
bar_url(embedded_test_server()->GetURL(
1630 "bar.com", "/navigation_controller/simple_page_1.html"));
1632 FrameNavigateParamsCapturer
capturer(root
->child_at(1)->child_at(0));
1633 NavigateFrameToURL(root
->child_at(1)->child_at(0), bar_url
);
1635 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
1636 capturer
.params().transition
);
1637 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
1640 // We should have created a new NavigationEntry with the same main frame URL.
1641 EXPECT_EQ(3, controller
.GetEntryCount());
1642 EXPECT_EQ(2, controller
.GetLastCommittedEntryIndex());
1643 NavigationEntryImpl
* entry3
= controller
.GetLastCommittedEntry();
1644 EXPECT_NE(entry
, entry3
);
1645 EXPECT_EQ(main_url
, entry3
->GetURL());
1646 FrameNavigationEntry
* root_entry3
= entry3
->root_node()->frame_entry
.get();
1647 EXPECT_EQ(main_url
, root_entry3
->url());
1649 // Verify subframe entries if we're in --site-per-process mode.
1650 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1651 switches::kSitePerProcess
)) {
1652 // The entry should still have FrameNavigationEntries for all 3 subframes.
1653 ASSERT_EQ(2U, entry3
->root_node()->children
.size());
1654 EXPECT_EQ(frame_url2
, entry3
->root_node()->children
[0]->frame_entry
->url());
1655 EXPECT_EQ(foo_url
, entry3
->root_node()->children
[1]->frame_entry
->url());
1656 ASSERT_EQ(1U, entry3
->root_node()->children
[1]->children
.size());
1659 entry3
->root_node()->children
[1]->children
[0]->frame_entry
->url());
1661 // There are no subframe FrameNavigationEntries by default.
1662 EXPECT_EQ(0U, entry3
->root_node()->children
.size());
1665 // 6. Navigate the second subframe cross-site, clearing its existing subtree.
1666 GURL
baz_url(embedded_test_server()->GetURL(
1667 "baz.com", "/navigation_controller/simple_page_1.html"));
1669 FrameNavigateParamsCapturer
capturer(root
->child_at(1));
1670 std::string script
= "var frames = document.getElementsByTagName('iframe');"
1671 "frames[1].src = '" + baz_url
.spec() + "';";
1672 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1674 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
1675 capturer
.params().transition
);
1676 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
1679 // We should have created a new NavigationEntry with the same main frame URL.
1680 EXPECT_EQ(4, controller
.GetEntryCount());
1681 EXPECT_EQ(3, controller
.GetLastCommittedEntryIndex());
1682 NavigationEntryImpl
* entry4
= controller
.GetLastCommittedEntry();
1683 EXPECT_NE(entry
, entry4
);
1684 EXPECT_EQ(main_url
, entry4
->GetURL());
1685 FrameNavigationEntry
* root_entry4
= entry4
->root_node()->frame_entry
.get();
1686 EXPECT_EQ(main_url
, root_entry4
->url());
1688 // Verify subframe entries if we're in --site-per-process mode.
1689 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1690 switches::kSitePerProcess
)) {
1691 // The entry should still have FrameNavigationEntries for all 3 subframes.
1692 ASSERT_EQ(2U, entry4
->root_node()->children
.size());
1693 EXPECT_EQ(frame_url2
, entry4
->root_node()->children
[0]->frame_entry
->url());
1694 EXPECT_EQ(baz_url
, entry4
->root_node()->children
[1]->frame_entry
->url());
1695 ASSERT_EQ(0U, entry4
->root_node()->children
[1]->children
.size());
1697 // There are no subframe FrameNavigationEntries by default.
1698 EXPECT_EQ(0U, entry4
->root_node()->children
.size());
1701 // Check the end result of the frame tree.
1702 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1703 switches::kSitePerProcess
)) {
1704 FrameTreeVisualizer visualizer
;
1706 " Site A ------------ proxies for B\n"
1707 " |--Site A ------- proxies for B\n"
1708 " +--Site B ------- proxies for A\n"
1709 "Where A = http://127.0.0.1/\n"
1710 " B = http://baz.com/",
1711 visualizer
.DepictFrameTree(root
));
1715 // Verify the tree of FrameNavigationEntries after back/forward navigations in a
1716 // cross-site subframe.
1717 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1718 FrameNavigationEntry_SubframeBackForward
) {
1719 GURL
main_url(embedded_test_server()->GetURL(
1720 "/navigation_controller/simple_page_1.html"));
1721 NavigateToURL(shell(), main_url
);
1722 const NavigationControllerImpl
& controller
=
1723 static_cast<const NavigationControllerImpl
&>(
1724 shell()->web_contents()->GetController());
1725 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1729 // 1. Create a same-site iframe.
1730 GURL
frame_url(embedded_test_server()->GetURL(
1731 "/navigation_controller/simple_page_2.html"));
1733 LoadCommittedCapturer
capturer(shell()->web_contents());
1734 std::string script
= "var iframe = document.createElement('iframe');"
1735 "iframe.src = '" + frame_url
.spec() + "';"
1736 "document.body.appendChild(iframe);";
1737 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1740 NavigationEntryImpl
* entry1
= controller
.GetLastCommittedEntry();
1742 // 2. Navigate in the subframe cross-site.
1743 GURL
frame_url2(embedded_test_server()->GetURL(
1744 "foo.com", "/navigation_controller/page_with_links.html"));
1746 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1747 NavigateFrameToURL(root
->child_at(0), frame_url2
);
1750 EXPECT_EQ(2, controller
.GetEntryCount());
1751 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
1752 NavigationEntryImpl
* entry2
= controller
.GetLastCommittedEntry();
1754 // 3. Navigate in the subframe cross-site again.
1755 GURL
frame_url3(embedded_test_server()->GetURL(
1756 "bar.com", "/navigation_controller/page_with_links.html"));
1758 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1759 NavigateFrameToURL(root
->child_at(0), frame_url3
);
1762 EXPECT_EQ(3, controller
.GetEntryCount());
1763 EXPECT_EQ(2, controller
.GetLastCommittedEntryIndex());
1764 NavigationEntryImpl
* entry3
= controller
.GetLastCommittedEntry();
1766 // 4. Go back in the subframe.
1768 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1769 shell()->web_contents()->GetController().GoBack();
1771 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.params().transition
);
1772 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME
, capturer
.details().type
);
1774 EXPECT_EQ(3, controller
.GetEntryCount());
1775 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
1776 EXPECT_EQ(entry2
, controller
.GetLastCommittedEntry());
1778 // Verify subframe entries if we're in --site-per-process mode.
1779 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1780 switches::kSitePerProcess
)) {
1781 // The entry should have a new FrameNavigationEntries for the subframe.
1782 ASSERT_EQ(1U, entry2
->root_node()->children
.size());
1783 EXPECT_EQ(frame_url2
, entry2
->root_node()->children
[0]->frame_entry
->url());
1785 // There are no subframe FrameNavigationEntries by default.
1786 EXPECT_EQ(0U, entry2
->root_node()->children
.size());
1789 // 5. Go back in the subframe again to the parent page's site.
1791 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1792 shell()->web_contents()->GetController().GoBack();
1794 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.params().transition
);
1795 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME
, capturer
.details().type
);
1797 EXPECT_EQ(3, controller
.GetEntryCount());
1798 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
1799 EXPECT_EQ(entry1
, controller
.GetLastCommittedEntry());
1801 // Verify subframe entries if we're in --site-per-process mode.
1802 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1803 switches::kSitePerProcess
)) {
1804 // The entry should have a new FrameNavigationEntries for the subframe.
1805 ASSERT_EQ(1U, entry1
->root_node()->children
.size());
1806 EXPECT_EQ(frame_url
, entry1
->root_node()->children
[0]->frame_entry
->url());
1808 // There are no subframe FrameNavigationEntries by default.
1809 EXPECT_EQ(0U, entry1
->root_node()->children
.size());
1812 // 6. Go forward in the subframe cross-site.
1814 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1815 shell()->web_contents()->GetController().GoForward();
1817 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.params().transition
);
1818 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME
, capturer
.details().type
);
1820 EXPECT_EQ(3, controller
.GetEntryCount());
1821 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
1822 EXPECT_EQ(entry2
, controller
.GetLastCommittedEntry());
1824 // Verify subframe entries if we're in --site-per-process mode.
1825 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1826 switches::kSitePerProcess
)) {
1827 // The entry should have a new FrameNavigationEntries for the subframe.
1828 ASSERT_EQ(1U, entry2
->root_node()->children
.size());
1829 EXPECT_EQ(frame_url2
, entry2
->root_node()->children
[0]->frame_entry
->url());
1831 // There are no subframe FrameNavigationEntries by default.
1832 EXPECT_EQ(0U, entry2
->root_node()->children
.size());
1835 // 7. Go forward in the subframe again, cross-site.
1837 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1838 shell()->web_contents()->GetController().GoForward();
1840 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.params().transition
);
1841 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME
, capturer
.details().type
);
1843 EXPECT_EQ(3, controller
.GetEntryCount());
1844 EXPECT_EQ(2, controller
.GetLastCommittedEntryIndex());
1845 EXPECT_EQ(entry3
, controller
.GetLastCommittedEntry());
1847 // Verify subframe entries if we're in --site-per-process mode.
1848 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1849 switches::kSitePerProcess
)) {
1850 // The entry should have a new FrameNavigationEntries for the subframe.
1851 ASSERT_EQ(1U, entry3
->root_node()->children
.size());
1852 EXPECT_EQ(frame_url3
, entry3
->root_node()->children
[0]->frame_entry
->url());
1854 // There are no subframe FrameNavigationEntries by default.
1855 EXPECT_EQ(0U, entry3
->root_node()->children
.size());
1859 // Verifies that item sequence numbers and document sequence numbers update
1860 // properly for main frames and subframes.
1861 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1862 FrameNavigationEntry_SequenceNumbers
) {
1863 const NavigationControllerImpl
& controller
=
1864 static_cast<const NavigationControllerImpl
&>(
1865 shell()->web_contents()->GetController());
1867 // 1. Navigate the main frame.
1868 GURL
url(embedded_test_server()->GetURL(
1869 "/navigation_controller/page_with_links.html"));
1870 NavigateToURL(shell(), url
);
1871 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1875 FrameNavigationEntry
* frame_entry
=
1876 controller
.GetLastCommittedEntry()->GetFrameEntry(root
);
1877 int64 isn_1
= frame_entry
->item_sequence_number();
1878 int64 dsn_1
= frame_entry
->document_sequence_number();
1879 EXPECT_NE(-1, isn_1
);
1880 EXPECT_NE(-1, dsn_1
);
1882 // 2. Do an in-page fragment navigation.
1883 std::string script
= "document.getElementById('fraglink').click()";
1884 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1885 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1887 frame_entry
= controller
.GetLastCommittedEntry()->GetFrameEntry(root
);
1888 int64 isn_2
= frame_entry
->item_sequence_number();
1889 int64 dsn_2
= frame_entry
->document_sequence_number();
1890 EXPECT_NE(-1, isn_2
);
1891 EXPECT_NE(isn_1
, isn_2
);
1892 EXPECT_EQ(dsn_1
, dsn_2
);
1894 // Also test subframe sequence numbers, but only in --site-per-proces mode.
1895 // (We do not create subframe FrameNavigationEntries in default mode yet.)
1896 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
1897 switches::kSitePerProcess
))
1900 // 3. Add a subframe, which does an AUTO_SUBFRAME navigation.
1902 LoadCommittedCapturer
capturer(shell()->web_contents());
1903 std::string script
= "var iframe = document.createElement('iframe');"
1904 "iframe.src = '" + url
.spec() + "';"
1905 "document.body.appendChild(iframe);";
1906 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1908 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1911 // The root FrameNavigationEntry hasn't changed.
1912 EXPECT_EQ(frame_entry
,
1913 controller
.GetLastCommittedEntry()->GetFrameEntry(root
));
1915 // We should have a unique ISN and DSN for the subframe entry.
1916 FrameTreeNode
* subframe
= root
->child_at(0);
1917 FrameNavigationEntry
* subframe_entry
=
1918 controller
.GetLastCommittedEntry()->GetFrameEntry(subframe
);
1919 int64 isn_3
= subframe_entry
->item_sequence_number();
1920 int64 dsn_3
= subframe_entry
->document_sequence_number();
1921 EXPECT_NE(-1, isn_2
);
1922 EXPECT_NE(isn_2
, isn_3
);
1923 EXPECT_NE(dsn_2
, dsn_3
);
1925 // 4. Do an in-page fragment navigation in the subframe.
1926 EXPECT_TRUE(content::ExecuteScript(subframe
->current_frame_host(), script
));
1927 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1929 subframe_entry
= controller
.GetLastCommittedEntry()->GetFrameEntry(subframe
);
1930 int64 isn_4
= subframe_entry
->item_sequence_number();
1931 int64 dsn_4
= subframe_entry
->document_sequence_number();
1932 EXPECT_NE(-1, isn_4
);
1933 EXPECT_NE(isn_3
, isn_4
);
1934 EXPECT_EQ(dsn_3
, dsn_4
);
1939 class HttpThrottle
: public ResourceThrottle
{
1942 void WillStartRequest(bool* defer
) override
{
1946 const char* GetNameForLogging() const override
{
1947 return "HttpThrottle";
1951 class StallDelegate
: public ResourceDispatcherHostDelegate
{
1952 // ResourceDispatcherHostDelegate
1953 void RequestBeginning(
1954 net::URLRequest
* request
,
1955 content::ResourceContext
* resource_context
,
1956 content::AppCacheService
* appcache_service
,
1957 ResourceType resource_type
,
1958 ScopedVector
<content::ResourceThrottle
>* throttles
) override
{
1959 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1960 throttles
->push_back(new HttpThrottle
);
1964 // Loads |start_url|, then loads |stalled_url| which stalls. While the page is
1965 // stalled, an in-page navigation happens. Make sure that all the navigations
1966 // are properly classified.
1967 void DoReplaceStateWhilePending(Shell
* shell
,
1968 const GURL
& start_url
,
1969 const GURL
& stalled_url
,
1970 const std::string
& replace_state_filename
) {
1971 NavigationControllerImpl
& controller
=
1972 static_cast<NavigationControllerImpl
&>(
1973 shell
->web_contents()->GetController());
1975 FrameTreeNode
* root
=
1976 static_cast<WebContentsImpl
*>(shell
->web_contents())->
1977 GetFrameTree()->root();
1979 // Start with one page.
1980 EXPECT_TRUE(NavigateToURL(shell
, start_url
));
1982 // Have the user decide to go to a different page which is very slow.
1983 StallDelegate stall_delegate
;
1984 ResourceDispatcherHost::Get()->SetDelegate(&stall_delegate
);
1986 stalled_url
, Referrer(), ui::PAGE_TRANSITION_LINK
, std::string());
1988 // That should be the pending entry.
1989 NavigationEntryImpl
* entry
= controller
.GetPendingEntry();
1990 ASSERT_NE(nullptr, entry
);
1991 EXPECT_EQ(stalled_url
, entry
->GetURL());
1994 // Now the existing page uses history.replaceState().
1995 FrameNavigateParamsCapturer
capturer(root
);
1996 capturer
.set_wait_for_load(false);
1997 std::string script
=
1998 "history.replaceState({}, '', '" + replace_state_filename
+ "')";
1999 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
2002 // The fact that there was a pending entry shouldn't interfere with the
2004 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
2005 EXPECT_TRUE(capturer
.details().is_in_page
);
2008 ResourceDispatcherHost::Get()->SetDelegate(nullptr);
2013 IN_PROC_BROWSER_TEST_F(
2014 NavigationControllerBrowserTest
,
2015 NavigationTypeClassification_On1InPageToXWhile2Pending
) {
2016 GURL
url1(embedded_test_server()->GetURL(
2017 "/navigation_controller/simple_page_1.html"));
2018 GURL
url2(embedded_test_server()->GetURL(
2019 "/navigation_controller/simple_page_2.html"));
2020 DoReplaceStateWhilePending(shell(), url1
, url2
, "x");
2023 IN_PROC_BROWSER_TEST_F(
2024 NavigationControllerBrowserTest
,
2025 NavigationTypeClassification_On1InPageTo2While2Pending
) {
2026 GURL
url1(embedded_test_server()->GetURL(
2027 "/navigation_controller/simple_page_1.html"));
2028 GURL
url2(embedded_test_server()->GetURL(
2029 "/navigation_controller/simple_page_2.html"));
2030 DoReplaceStateWhilePending(shell(), url1
, url2
, "simple_page_2.html");
2033 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
2034 NavigationTypeClassification_On1InPageToXWhile1Pending
) {
2035 GURL
url(embedded_test_server()->GetURL(
2036 "/navigation_controller/simple_page_1.html"));
2037 DoReplaceStateWhilePending(shell(), url
, url
, "x");
2040 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
2041 NavigationTypeClassification_On1InPageTo1While1Pending
) {
2042 GURL
url(embedded_test_server()->GetURL(
2043 "/navigation_controller/simple_page_1.html"));
2044 DoReplaceStateWhilePending(shell(), url
, url
, "simple_page_1.html");
2047 // Ensure the renderer process does not get confused about the current entry
2048 // due to subframes and replaced entries. See https://crbug.com/480201.
2049 // TODO(creis): Re-enable for Site Isolation FYI bots: https://crbug.com/502317.
2050 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
2051 PreventSpoofFromSubframeAndReplace
) {
2052 // Start at an initial URL.
2053 GURL
url1(embedded_test_server()->GetURL(
2054 "/navigation_controller/simple_page_1.html"));
2055 NavigateToURL(shell(), url1
);
2057 // Now go to a page with a real iframe.
2058 GURL
url2(embedded_test_server()->GetURL(
2059 "/navigation_controller/page_with_data_iframe.html"));
2060 NavigateToURL(shell(), url2
);
2062 // It is safe to obtain the root frame tree node here, as it doesn't change.
2063 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
2066 ASSERT_EQ(1U, root
->child_count());
2067 ASSERT_NE(nullptr, root
->child_at(0));
2070 // Navigate in the iframe.
2071 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
2072 GURL
frame_url(embedded_test_server()->GetURL(
2073 "/navigation_controller/simple_page_2.html"));
2074 NavigateFrameToURL(root
->child_at(0), frame_url
);
2076 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
2080 // Go back in the iframe.
2081 TestNavigationObserver
back_load_observer(shell()->web_contents());
2082 shell()->web_contents()->GetController().GoBack();
2083 back_load_observer
.Wait();
2087 // Go forward in the iframe.
2088 TestNavigationObserver
forward_load_observer(shell()->web_contents());
2089 shell()->web_contents()->GetController().GoForward();
2090 forward_load_observer
.Wait();
2093 GURL
url3(embedded_test_server()->GetURL(
2094 "/navigation_controller/page_with_iframe.html"));
2096 // location.replace() to cause an inert commit.
2097 TestNavigationObserver
replace_load_observer(shell()->web_contents());
2098 std::string script
= "location.replace('" + url3
.spec() + "')";
2099 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
2100 replace_load_observer
.Wait();
2105 TestNavigationObserver
back_load_observer(shell()->web_contents());
2106 shell()->web_contents()->GetController().GoBack();
2107 back_load_observer
.Wait();
2109 // Make sure the URL is correct for both the entry and the main frame, and
2110 // that the process hasn't been killed for showing a spoof.
2111 EXPECT_TRUE(root
->current_frame_host()->IsRenderFrameLive());
2112 EXPECT_EQ(url2
, shell()->web_contents()->GetLastCommittedURL());
2113 EXPECT_EQ(url2
, root
->current_url());
2117 // Go back to reset main frame entirely.
2118 TestNavigationObserver
back_load_observer(shell()->web_contents());
2119 shell()->web_contents()->GetController().GoBack();
2120 back_load_observer
.Wait();
2121 EXPECT_EQ(url1
, shell()->web_contents()->GetLastCommittedURL());
2122 EXPECT_EQ(url1
, root
->current_url());
2127 TestNavigationObserver
back_load_observer(shell()->web_contents());
2128 shell()->web_contents()->GetController().GoForward();
2129 back_load_observer
.Wait();
2130 EXPECT_EQ(url2
, shell()->web_contents()->GetLastCommittedURL());
2131 EXPECT_EQ(url2
, root
->current_url());
2135 // Go forward to the replaced URL.
2136 TestNavigationObserver
forward_load_observer(shell()->web_contents());
2137 shell()->web_contents()->GetController().GoForward();
2138 forward_load_observer
.Wait();
2140 // Make sure the URL is correct for both the entry and the main frame, and
2141 // that the process hasn't been killed for showing a spoof.
2142 EXPECT_TRUE(root
->current_frame_host()->IsRenderFrameLive());
2143 EXPECT_EQ(url3
, shell()->web_contents()->GetLastCommittedURL());
2144 EXPECT_EQ(url3
, root
->current_url());
2148 // Ensure the renderer process does not get killed if the main frame URL's path
2149 // changes when going back in a subframe, since this is currently possible after
2150 // a replaceState in the main frame (thanks to https://crbug.com/373041).
2151 // See https:///crbug.com/486916.
2152 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
2153 SubframeBackFromReplaceState
) {
2154 // Start at a page with a real iframe.
2155 GURL
url1(embedded_test_server()->GetURL(
2156 "/navigation_controller/page_with_data_iframe.html"));
2157 NavigateToURL(shell(), url1
);
2159 // It is safe to obtain the root frame tree node here, as it doesn't change.
2160 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
2163 ASSERT_EQ(1U, root
->child_count());
2164 ASSERT_NE(nullptr, root
->child_at(0));
2167 // Navigate in the iframe.
2168 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
2169 GURL
frame_url(embedded_test_server()->GetURL(
2170 "/navigation_controller/simple_page_2.html"));
2171 NavigateFrameToURL(root
->child_at(0), frame_url
);
2173 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
2177 // history.replaceState().
2178 FrameNavigateParamsCapturer
capturer(root
);
2179 std::string script
=
2180 "history.replaceState({}, 'replaced', 'replaced')";
2181 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
2186 // Go back in the iframe.
2187 TestNavigationObserver
back_load_observer(shell()->web_contents());
2188 shell()->web_contents()->GetController().GoBack();
2189 back_load_observer
.Wait();
2192 // For now, we expect the main frame's URL to revert. This won't happen once
2193 // https://crbug.com/373041 is fixed.
2194 EXPECT_EQ(url1
, shell()->web_contents()->GetLastCommittedURL());
2196 // Make sure the renderer process has not been killed.
2197 EXPECT_TRUE(root
->current_frame_host()->IsRenderFrameLive());
2202 class FailureWatcher
: public WebContentsObserver
{
2204 // Observes failure for the specified |node|.
2205 explicit FailureWatcher(FrameTreeNode
* node
)
2206 : WebContentsObserver(
2207 node
->current_frame_host()->delegate()->GetAsWebContents()),
2208 frame_tree_node_id_(node
->frame_tree_node_id()),
2209 message_loop_runner_(new MessageLoopRunner
) {}
2212 message_loop_runner_
->Run();
2216 void DidFailLoad(RenderFrameHost
* render_frame_host
,
2217 const GURL
& validated_url
,
2219 const base::string16
& error_description
,
2220 bool was_ignored_by_handler
) override
{
2221 RenderFrameHostImpl
* rfh
=
2222 static_cast<RenderFrameHostImpl
*>(render_frame_host
);
2223 if (rfh
->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_
)
2226 message_loop_runner_
->Quit();
2229 void DidFailProvisionalLoad(
2230 RenderFrameHost
* render_frame_host
,
2231 const GURL
& validated_url
,
2233 const base::string16
& error_description
,
2234 bool was_ignored_by_handler
) override
{
2235 RenderFrameHostImpl
* rfh
=
2236 static_cast<RenderFrameHostImpl
*>(render_frame_host
);
2237 if (rfh
->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_
)
2240 message_loop_runner_
->Quit();
2243 // The id of the FrameTreeNode whose navigations to observe.
2244 int frame_tree_node_id_
;
2246 // The MessageLoopRunner used to spin the message loop.
2247 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
2252 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
2253 StopCausesFailureDespiteJavaScriptURL
) {
2254 NavigationControllerImpl
& controller
=
2255 static_cast<NavigationControllerImpl
&>(
2256 shell()->web_contents()->GetController());
2258 FrameTreeNode
* root
=
2259 static_cast<WebContentsImpl
*>(shell()->web_contents())->
2260 GetFrameTree()->root();
2262 // Start with a normal page.
2263 GURL
url1(embedded_test_server()->GetURL(
2264 "/navigation_controller/simple_page_1.html"));
2265 EXPECT_TRUE(NavigateToURL(shell(), url1
));
2267 // Have the user decide to go to a different page which is very slow.
2268 StallDelegate stall_delegate
;
2269 ResourceDispatcherHost::Get()->SetDelegate(&stall_delegate
);
2270 GURL
url2(embedded_test_server()->GetURL(
2271 "/navigation_controller/simple_page_2.html"));
2272 controller
.LoadURL(url2
, Referrer(), ui::PAGE_TRANSITION_LINK
, std::string());
2274 // That should be the pending entry.
2275 NavigationEntryImpl
* entry
= controller
.GetPendingEntry();
2276 ASSERT_NE(nullptr, entry
);
2277 EXPECT_EQ(url2
, entry
->GetURL());
2279 // Loading a JavaScript URL shouldn't affect the ability to stop.
2281 FailureWatcher
watcher(root
);
2282 GURL
js("javascript:(function(){})()");
2283 controller
.LoadURL(js
, Referrer(), ui::PAGE_TRANSITION_LINK
, std::string());
2284 // This LoadURL ends up purging the pending entry, which is why this is
2286 EXPECT_EQ(nullptr, controller
.GetPendingEntry());
2287 shell()->web_contents()->Stop();
2291 ResourceDispatcherHost::Get()->SetDelegate(nullptr);
2295 class RenderProcessKilledObserver
: public WebContentsObserver
{
2297 RenderProcessKilledObserver(WebContents
* web_contents
)
2298 : WebContentsObserver(web_contents
) {}
2299 ~RenderProcessKilledObserver() override
{}
2301 void RenderProcessGone(base::TerminationStatus status
) override
{
2303 base::TerminationStatus::TERMINATION_STATUS_PROCESS_WAS_KILLED
);
2308 // This tests a race in ReloadOriginalRequest, where a cross-origin reload was
2309 // causing an in-flight replaceState to look like a cross-origin navigation,
2310 // even though it's in-page. (The reload should not modify the underlying last
2311 // committed entry.) Not crashing means that the test is successful.
2312 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
, ReloadOriginalRequest
) {
2313 GURL
original_url(embedded_test_server()->GetURL(
2314 "/navigation_controller/simple_page_1.html"));
2315 NavigateToURL(shell(), original_url
);
2316 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
2319 RenderProcessKilledObserver
kill_observer(shell()->web_contents());
2321 // Redirect so that we can use ReloadOriginalRequest.
2322 GURL
redirect_url(embedded_test_server()->GetURL(
2323 "foo.com", "/navigation_controller/simple_page_1.html"));
2325 std::string script
= "location.replace('" + redirect_url
.spec() + "');";
2326 FrameNavigateParamsCapturer
capturer(root
);
2327 EXPECT_TRUE(ExecuteScript(shell()->web_contents(), script
));
2329 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_CLIENT_REDIRECT
,
2330 capturer
.params().transition
);
2331 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
2334 // Modify an entry in the session history and reload the original request.
2336 // We first send a replaceState() to the renderer, which will cause the
2337 // renderer to send back a DidCommitProvisionalLoad. Immediately after,
2338 // we send a ReloadOriginalRequest (which in this case is a different
2339 // origin) and will also cause the renderer to commit the frame. In the
2340 // end we verify that both navigations committed and that the URLs are
2342 std::string script
= "history.replaceState({}, '', 'foo');";
2343 root
->render_manager()
2344 ->current_frame_host()
2345 ->ExecuteJavaScriptWithUserGestureForTests(base::UTF8ToUTF16(script
));
2346 EXPECT_FALSE(shell()->web_contents()->IsLoading());
2347 shell()->web_contents()->GetController().ReloadOriginalRequestURL(false);
2348 EXPECT_TRUE(shell()->web_contents()->IsLoading());
2349 EXPECT_EQ(redirect_url
, shell()->web_contents()->GetLastCommittedURL());
2351 // Wait until there's no more navigations.
2352 GURL
modified_url(embedded_test_server()->GetURL(
2353 "foo.com", "/navigation_controller/foo"));
2354 FrameNavigateParamsCapturer
capturer(root
);
2355 capturer
.set_wait_for_load(false);
2356 capturer
.set_navigations_remaining(2);
2358 EXPECT_EQ(2U, capturer
.all_details().size());
2359 EXPECT_EQ(modified_url
, capturer
.all_params()[0].url
);
2360 EXPECT_EQ(original_url
, capturer
.all_params()[1].url
);
2361 EXPECT_EQ(original_url
, shell()->web_contents()->GetLastCommittedURL());
2364 // Make sure the renderer is still alive.
2366 ExecuteScript(shell()->web_contents(), "console.log('Success');"));
2369 } // namespace content