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/strings/stringprintf.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "content/browser/frame_host/frame_navigation_entry.h"
9 #include "content/browser/frame_host/frame_tree.h"
10 #include "content/browser/frame_host/navigation_controller_impl.h"
11 #include "content/browser/frame_host/navigation_entry_impl.h"
12 #include "content/browser/web_contents/web_contents_impl.h"
13 #include "content/common/site_isolation_policy.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/url_constants.h"
23 #include "content/public/test/browser_test_utils.h"
24 #include "content/public/test/content_browser_test.h"
25 #include "content/public/test/content_browser_test_utils.h"
26 #include "content/public/test/test_navigation_observer.h"
27 #include "content/public/test/test_utils.h"
28 #include "content/shell/browser/shell.h"
29 #include "content/test/content_browser_test_utils_internal.h"
30 #include "net/dns/mock_host_resolver.h"
31 #include "net/test/embedded_test_server/embedded_test_server.h"
32 #include "net/test/url_request/url_request_failed_job.h"
36 class NavigationControllerBrowserTest
: public ContentBrowserTest
{
38 void SetUpOnMainThread() override
{
39 host_resolver()->AddRule("*", "127.0.0.1");
40 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
44 // Ensure that tests can navigate subframes cross-site in both default mode and
45 // --site-per-process, but that they only go cross-process in the latter.
46 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
, LoadCrossSiteSubframe
) {
47 // Load a main frame with a subframe.
48 GURL
main_url(embedded_test_server()->GetURL(
49 "/navigation_controller/page_with_iframe.html"));
50 NavigateToURL(shell(), main_url
);
51 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
54 ASSERT_EQ(1U, root
->child_count());
55 ASSERT_NE(nullptr, root
->child_at(0));
57 // Use NavigateFrameToURL to go cross-site in the subframe.
58 GURL
foo_url(embedded_test_server()->GetURL(
59 "foo.com", "/navigation_controller/simple_page_1.html"));
60 NavigateFrameToURL(root
->child_at(0), foo_url
);
61 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
63 // We should only have swapped processes in --site-per-process.
64 bool cross_process
= root
->current_frame_host()->GetProcess() !=
65 root
->child_at(0)->current_frame_host()->GetProcess();
66 EXPECT_EQ(AreAllSitesIsolatedForTesting(), cross_process
);
69 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
, LoadDataWithBaseURL
) {
70 const GURL
base_url("http://baseurl");
71 const GURL
history_url("http://historyurl");
72 const std::string data
= "<html><body>foo</body></html>";
74 const NavigationController
& controller
=
75 shell()->web_contents()->GetController();
76 // Load data. Blocks until it is done.
77 content::LoadDataWithBaseURL(shell(), history_url
, data
, base_url
);
79 // We should use history_url instead of the base_url as the original url of
80 // this navigation entry, because base_url is only used for resolving relative
81 // paths in the data, or enforcing same origin policy.
82 EXPECT_EQ(controller
.GetVisibleEntry()->GetOriginalRequestURL(), history_url
);
85 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
, UniqueIDs
) {
86 const NavigationControllerImpl
& controller
=
87 static_cast<const NavigationControllerImpl
&>(
88 shell()->web_contents()->GetController());
90 GURL
main_url(embedded_test_server()->GetURL(
91 "/navigation_controller/page_with_link_to_load_iframe.html"));
92 NavigateToURL(shell(), main_url
);
93 ASSERT_EQ(1, controller
.GetEntryCount());
95 // Use JavaScript to click the link and load the iframe.
96 std::string script
= "document.getElementById('link').click()";
97 EXPECT_TRUE(content::ExecuteScript(shell()->web_contents(), script
));
98 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
99 ASSERT_EQ(2, controller
.GetEntryCount());
101 // Unique IDs should... um... be unique.
102 ASSERT_NE(controller
.GetEntryAtIndex(0)->GetUniqueID(),
103 controller
.GetEntryAtIndex(1)->GetUniqueID());
106 // This test used to make sure that a scheme used to prevent spoofs didn't ever
107 // interfere with navigations. We switched to a different scheme, so now this is
108 // just a test to make sure we can still navigate once we prune the history
110 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
111 DontIgnoreBackAfterNavEntryLimit
) {
112 NavigationController
& controller
=
113 shell()->web_contents()->GetController();
115 const int kMaxEntryCount
=
116 static_cast<int>(NavigationControllerImpl::max_entry_count());
118 // Load up to the max count, all entries should be there.
119 for (int url_index
= 0; url_index
< kMaxEntryCount
; ++url_index
) {
120 GURL
url(base::StringPrintf("data:text/html,page%d", url_index
));
121 EXPECT_TRUE(NavigateToURL(shell(), url
));
124 EXPECT_EQ(controller
.GetEntryCount(), kMaxEntryCount
);
126 // Navigate twice more more.
127 for (int url_index
= kMaxEntryCount
;
128 url_index
< kMaxEntryCount
+ 2; ++url_index
) {
129 GURL
url(base::StringPrintf("data:text/html,page%d", url_index
));
130 EXPECT_TRUE(NavigateToURL(shell(), url
));
133 // We expect page0 and page1 to be gone.
134 EXPECT_EQ(kMaxEntryCount
, controller
.GetEntryCount());
135 EXPECT_EQ(GURL("data:text/html,page2"),
136 controller
.GetEntryAtIndex(0)->GetURL());
138 // Now try to go back. This should not hang.
139 ASSERT_TRUE(controller
.CanGoBack());
141 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
143 // This should have successfully gone back.
144 EXPECT_EQ(GURL(base::StringPrintf("data:text/html,page%d", kMaxEntryCount
)),
145 controller
.GetLastCommittedEntry()->GetURL());
150 int RendererHistoryLength(Shell
* shell
) {
152 EXPECT_TRUE(ExecuteScriptAndExtractInt(
153 shell
->web_contents(),
154 "domAutomationController.send(history.length)",
159 // Similar to the ones from content_browser_test_utils.
160 bool NavigateToURLAndReplace(Shell
* shell
, const GURL
& url
) {
161 WebContents
* web_contents
= shell
->web_contents();
162 WaitForLoadStop(web_contents
);
163 TestNavigationObserver
same_tab_observer(web_contents
, 1);
164 NavigationController::LoadURLParams
params(url
);
165 params
.should_replace_current_entry
= true;
166 web_contents
->GetController().LoadURLWithParams(params
);
167 web_contents
->Focus();
168 same_tab_observer
.Wait();
169 if (!IsLastCommittedEntryOfPageType(web_contents
, PAGE_TYPE_NORMAL
))
171 return web_contents
->GetLastCommittedURL() == url
;
176 // When loading a new page to replace an old page in the history list, make sure
177 // that the browser and renderer agree, and that both get it right.
178 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
179 CorrectLengthWithCurrentItemReplacement
) {
180 NavigationController
& controller
=
181 shell()->web_contents()->GetController();
183 EXPECT_TRUE(NavigateToURL(shell(), GURL("data:text/html,page1")));
184 EXPECT_EQ(1, controller
.GetEntryCount());
185 EXPECT_EQ(1, RendererHistoryLength(shell()));
187 EXPECT_TRUE(NavigateToURLAndReplace(shell(), GURL("data:text/html,page1a")));
188 EXPECT_EQ(1, controller
.GetEntryCount());
189 EXPECT_EQ(1, RendererHistoryLength(shell()));
191 // Now create two more entries and go back, to test replacing an entry without
192 // pruning the forward history.
193 EXPECT_TRUE(NavigateToURL(shell(), GURL("data:text/html,page2")));
194 EXPECT_EQ(2, controller
.GetEntryCount());
195 EXPECT_EQ(2, RendererHistoryLength(shell()));
197 EXPECT_TRUE(NavigateToURL(shell(), GURL("data:text/html,page3")));
198 EXPECT_EQ(3, controller
.GetEntryCount());
199 EXPECT_EQ(3, RendererHistoryLength(shell()));
202 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
204 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
205 EXPECT_TRUE(controller
.CanGoForward());
207 EXPECT_TRUE(NavigateToURLAndReplace(shell(), GURL("data:text/html,page1b")));
208 EXPECT_EQ(3, controller
.GetEntryCount());
209 EXPECT_EQ(3, RendererHistoryLength(shell()));
210 EXPECT_TRUE(controller
.CanGoForward());
212 // Note that there's no way to access the renderer's notion of the history
213 // offset via JavaScript. Checking just the history length, though, is enough;
214 // if the replacement failed, there would be a new history entry and thus an
218 // When spawning a new page from a WebUI page, make sure that the browser and
219 // renderer agree about the length of the history list, and that both get it
221 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
222 CorrectLengthWithNewTabNavigatingFromWebUI
) {
223 GURL
web_ui_page(std::string(kChromeUIScheme
) + "://" +
224 std::string(kChromeUIGpuHost
));
225 EXPECT_TRUE(NavigateToURL(shell(), web_ui_page
));
226 EXPECT_EQ(BINDINGS_POLICY_WEB_UI
,
227 shell()->web_contents()->GetRenderViewHost()->GetEnabledBindings());
229 ShellAddedObserver observer
;
230 std::string page_url
= embedded_test_server()->GetURL(
231 "/navigation_controller/simple_page_1.html").spec();
232 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
233 "window.open('" + page_url
+ "', '_blank')"));
234 Shell
* shell2
= observer
.GetShell();
235 EXPECT_TRUE(WaitForLoadStop(shell2
->web_contents()));
237 EXPECT_EQ(1, shell2
->web_contents()->GetController().GetEntryCount());
238 EXPECT_EQ(1, RendererHistoryLength(shell2
));
240 // Again, as above, there's no way to access the renderer's notion of the
241 // history offset via JavaScript. Checking just the history length, again,
242 // will have to suffice.
247 class NoNavigationsObserver
: public WebContentsObserver
{
249 // Observes navigation for the specified |web_contents|.
250 explicit NoNavigationsObserver(WebContents
* web_contents
)
251 : WebContentsObserver(web_contents
) {}
254 void DidNavigateAnyFrame(RenderFrameHost
* render_frame_host
,
255 const LoadCommittedDetails
& details
,
256 const FrameNavigateParams
& params
) override
{
257 FAIL() << "No navigations should occur";
263 // Some pages create a popup, then write an iframe into it. This causes a
264 // subframe navigation without having any committed entry. Such navigations
265 // just get thrown on the ground, but we shouldn't crash.
267 // This test actually hits NAVIGATION_TYPE_NAV_IGNORE three times. Two of them,
268 // the initial window.open() and the iframe creation, don't try to create
269 // navigation entries, and the third, the new navigation, tries to.
270 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
, SubframeOnEmptyPage
) {
271 NavigateToURL(shell(), GURL(url::kAboutBlankURL
));
272 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
274 FrameTreeNode
* root
=
275 static_cast<WebContentsImpl
*>(shell()->web_contents())->
276 GetFrameTree()->root();
278 // Pop open a new window.
279 ShellAddedObserver new_shell_observer
;
280 std::string script
= "window.open()";
281 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
282 Shell
* new_shell
= new_shell_observer
.GetShell();
283 ASSERT_NE(new_shell
->web_contents(), shell()->web_contents());
284 FrameTreeNode
* new_root
=
285 static_cast<WebContentsImpl
*>(new_shell
->web_contents())->
286 GetFrameTree()->root();
288 // Make a new iframe in it.
289 NoNavigationsObserver
observer(new_shell
->web_contents());
290 script
= "var iframe = document.createElement('iframe');"
291 "iframe.src = 'data:text/html,<p>some page</p>';"
292 "document.body.appendChild(iframe);";
293 EXPECT_TRUE(content::ExecuteScript(new_root
->current_frame_host(), script
));
294 // The success check is of the last-committed entry, and there is none.
295 WaitForLoadStopWithoutSuccessCheck(new_shell
->web_contents());
297 ASSERT_EQ(1U, new_root
->child_count());
298 ASSERT_NE(nullptr, new_root
->child_at(0));
301 GURL frame_url
= embedded_test_server()->GetURL(
302 "/navigation_controller/simple_page_2.html");
303 script
= "location.assign('" + frame_url
.spec() + "')";
304 EXPECT_TRUE(content::ExecuteScript(
305 new_root
->child_at(0)->current_frame_host(), script
));
307 // Success is not crashing, and not navigating.
309 new_shell
->web_contents()->GetController().GetLastCommittedEntry());
314 class FrameNavigateParamsCapturer
: public WebContentsObserver
{
316 // Observes navigation for the specified |node|.
317 explicit FrameNavigateParamsCapturer(FrameTreeNode
* node
)
318 : WebContentsObserver(
319 node
->current_frame_host()->delegate()->GetAsWebContents()),
320 frame_tree_node_id_(node
->frame_tree_node_id()),
321 navigations_remaining_(1),
322 wait_for_load_(true),
323 message_loop_runner_(new MessageLoopRunner
) {}
325 void set_navigations_remaining(int count
) {
326 navigations_remaining_
= count
;
329 void set_wait_for_load(bool ignore
) {
330 wait_for_load_
= ignore
;
334 message_loop_runner_
->Run();
337 const FrameNavigateParams
& params() const {
338 EXPECT_EQ(1U, params_
.size());
342 const std::vector
<FrameNavigateParams
>& all_params() const {
346 const LoadCommittedDetails
& details() const {
347 EXPECT_EQ(1U, details_
.size());
351 const std::vector
<LoadCommittedDetails
>& all_details() const {
356 void DidNavigateAnyFrame(RenderFrameHost
* render_frame_host
,
357 const LoadCommittedDetails
& details
,
358 const FrameNavigateParams
& params
) override
{
359 RenderFrameHostImpl
* rfh
=
360 static_cast<RenderFrameHostImpl
*>(render_frame_host
);
361 if (rfh
->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_
)
364 --navigations_remaining_
;
365 params_
.push_back(params
);
366 details_
.push_back(details
);
367 if (!navigations_remaining_
&&
368 (!web_contents()->IsLoading() || !wait_for_load_
))
369 message_loop_runner_
->Quit();
372 void DidStopLoading() override
{
373 if (!navigations_remaining_
)
374 message_loop_runner_
->Quit();
377 // The id of the FrameTreeNode whose navigations to observe.
378 int frame_tree_node_id_
;
380 // How many navigations remain to capture.
381 int navigations_remaining_
;
383 // Whether to also wait for the load to complete.
386 // The params of the navigations.
387 std::vector
<FrameNavigateParams
> params_
;
389 // The details of the navigations.
390 std::vector
<LoadCommittedDetails
> details_
;
392 // The MessageLoopRunner used to spin the message loop.
393 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
396 class LoadCommittedCapturer
: public WebContentsObserver
{
398 // Observes the load commit for the specified |node|.
399 explicit LoadCommittedCapturer(FrameTreeNode
* node
)
400 : WebContentsObserver(
401 node
->current_frame_host()->delegate()->GetAsWebContents()),
402 frame_tree_node_id_(node
->frame_tree_node_id()),
403 message_loop_runner_(new MessageLoopRunner
) {}
405 // Observes the load commit for the next created frame in the specified
407 explicit LoadCommittedCapturer(WebContents
* web_contents
)
408 : WebContentsObserver(web_contents
),
409 frame_tree_node_id_(0),
410 message_loop_runner_(new MessageLoopRunner
) {}
413 message_loop_runner_
->Run();
416 ui::PageTransition
transition_type() const {
417 return transition_type_
;
421 void RenderFrameCreated(RenderFrameHost
* render_frame_host
) override
{
422 RenderFrameHostImpl
* rfh
=
423 static_cast<RenderFrameHostImpl
*>(render_frame_host
);
425 // Don't pay attention to swapped out RenderFrameHosts in the main frame.
426 // TODO(nasko): Remove once swappedout:// is gone.
427 // See https://crbug.com/357747.
428 if (!RenderFrameHostImpl::IsRFHStateActive(rfh
->rfh_state())) {
429 DLOG(INFO
) << "Skipping swapped out RFH: "
430 << rfh
->GetSiteInstance()->GetSiteURL();
434 // If this object was not created with a specified frame tree node, then use
435 // the first created active RenderFrameHost. Once a node is selected, there
436 // shouldn't be any other frames being created.
437 int frame_tree_node_id
= rfh
->frame_tree_node()->frame_tree_node_id();
438 DCHECK(frame_tree_node_id_
== 0 ||
439 frame_tree_node_id_
== frame_tree_node_id
);
440 frame_tree_node_id_
= frame_tree_node_id
;
443 void DidCommitProvisionalLoadForFrame(
444 RenderFrameHost
* render_frame_host
,
446 ui::PageTransition transition_type
) override
{
447 DCHECK_NE(0, frame_tree_node_id_
);
448 RenderFrameHostImpl
* rfh
=
449 static_cast<RenderFrameHostImpl
*>(render_frame_host
);
450 if (rfh
->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_
)
453 transition_type_
= transition_type
;
454 if (!web_contents()->IsLoading())
455 message_loop_runner_
->Quit();
458 void DidStopLoading() override
{ message_loop_runner_
->Quit(); }
460 // The id of the FrameTreeNode whose navigations to observe.
461 int frame_tree_node_id_
;
463 // The transition_type of the last navigation.
464 ui::PageTransition transition_type_
;
466 // The MessageLoopRunner used to spin the message loop.
467 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
472 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
473 ErrorPageReplacement
) {
474 NavigationController
& controller
= shell()->web_contents()->GetController();
476 net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_RESET
));
477 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
478 base::Bind(&net::URLRequestFailedJob::AddUrlHandler
));
480 NavigateToURL(shell(), GURL(url::kAboutBlankURL
));
481 EXPECT_EQ(1, controller
.GetEntryCount());
483 FrameTreeNode
* root
=
484 static_cast<WebContentsImpl
*>(shell()->web_contents())->
485 GetFrameTree()->root();
487 // Navigate to a page that fails to load. It must result in an error page, the
488 // NEW_PAGE navigation type, and an addition to the history list.
490 FrameNavigateParamsCapturer
capturer(root
);
491 NavigateFrameToURL(root
, error_url
);
493 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
494 NavigationEntry
* entry
= controller
.GetLastCommittedEntry();
495 EXPECT_EQ(PAGE_TYPE_ERROR
, entry
->GetPageType());
496 EXPECT_EQ(2, controller
.GetEntryCount());
499 // Navigate again to the page that fails to load. It must result in an error
500 // page, the EXISTING_PAGE navigation type, and no addition to the history
501 // list. We do not use SAME_PAGE here; that case only differs in that it
502 // clears the pending entry, and there is no pending entry after a load
505 FrameNavigateParamsCapturer
capturer(root
);
506 NavigateFrameToURL(root
, error_url
);
508 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
509 NavigationEntry
* entry
= controller
.GetLastCommittedEntry();
510 EXPECT_EQ(PAGE_TYPE_ERROR
, entry
->GetPageType());
511 EXPECT_EQ(2, controller
.GetEntryCount());
514 // Make a new entry ...
515 NavigateToURL(shell(), GURL(url::kAboutBlankURL
));
516 EXPECT_EQ(3, controller
.GetEntryCount());
518 // ... and replace it with a failed load. (Note that when you set the
519 // should_replace_current_entry flag, the navigation is classified as NEW_PAGE
520 // because that is a classification of the renderer's behavior, and the flag
521 // is a browser-side flag.)
523 FrameNavigateParamsCapturer
capturer(root
);
524 NavigateToURLAndReplace(shell(), error_url
);
526 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
527 NavigationEntry
* entry
= controller
.GetLastCommittedEntry();
528 EXPECT_EQ(PAGE_TYPE_ERROR
, entry
->GetPageType());
529 EXPECT_EQ(3, controller
.GetEntryCount());
532 // Make a new web ui page to force a process swap ...
533 GURL
web_ui_page(std::string(kChromeUIScheme
) + "://" +
534 std::string(kChromeUIGpuHost
));
535 NavigateToURL(shell(), web_ui_page
);
536 EXPECT_EQ(4, controller
.GetEntryCount());
538 // ... and replace it with a failed load. (It is NEW_PAGE for the reason noted
541 FrameNavigateParamsCapturer
capturer(root
);
542 NavigateToURLAndReplace(shell(), error_url
);
544 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
545 NavigationEntry
* entry
= controller
.GetLastCommittedEntry();
546 EXPECT_EQ(PAGE_TYPE_ERROR
, entry
->GetPageType());
547 EXPECT_EQ(4, controller
.GetEntryCount());
551 // Various tests for navigation type classifications. TODO(avi): It's rather
552 // bogus that the same info is in two different enums; http://crbug.com/453555.
554 // Verify that navigations for NAVIGATION_TYPE_NEW_PAGE are correctly
556 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
557 NavigationTypeClassification_NewPage
) {
558 NavigateToURL(shell(), GURL(url::kAboutBlankURL
));
560 FrameTreeNode
* root
=
561 static_cast<WebContentsImpl
*>(shell()->web_contents())->
562 GetFrameTree()->root();
566 FrameNavigateParamsCapturer
capturer(root
);
567 GURL
frame_url(embedded_test_server()->GetURL(
568 "/navigation_controller/page_with_links.html"));
569 NavigateFrameToURL(root
, frame_url
);
571 // TODO(avi,creis): Why is this (and quite a few others below) a "link"
572 // transition? Lots of these transitions should be cleaned up.
573 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
, capturer
.params().transition
);
574 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
575 EXPECT_FALSE(capturer
.details().is_in_page
);
579 // Load via a fragment link click.
580 FrameNavigateParamsCapturer
capturer(root
);
581 std::string script
= "document.getElementById('fraglink').click()";
582 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
584 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
, capturer
.params().transition
);
585 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
586 EXPECT_TRUE(capturer
.details().is_in_page
);
590 // Load via link click.
591 FrameNavigateParamsCapturer
capturer(root
);
592 std::string script
= "document.getElementById('thelink').click()";
593 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
595 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
, capturer
.params().transition
);
596 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
597 EXPECT_FALSE(capturer
.details().is_in_page
);
601 // location.assign().
602 FrameNavigateParamsCapturer
capturer(root
);
603 GURL
frame_url(embedded_test_server()->GetURL(
604 "/navigation_controller/simple_page_2.html"));
605 std::string script
= "location.assign('" + frame_url
.spec() + "')";
606 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
608 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_CLIENT_REDIRECT
,
609 capturer
.params().transition
);
610 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
611 EXPECT_FALSE(capturer
.details().is_in_page
);
615 // history.pushState().
616 FrameNavigateParamsCapturer
capturer(root
);
618 "history.pushState({}, 'page 1', 'simple_page_1.html')";
619 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
621 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_CLIENT_REDIRECT
,
622 capturer
.params().transition
);
623 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
624 EXPECT_TRUE(capturer
.details().is_in_page
);
628 // Verify that navigations for NAVIGATION_TYPE_EXISTING_PAGE are correctly
630 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
631 NavigationTypeClassification_ExistingPage
) {
632 GURL
url1(embedded_test_server()->GetURL(
633 "/navigation_controller/simple_page_1.html"));
634 NavigateToURL(shell(), url1
);
635 GURL
url2(embedded_test_server()->GetURL(
636 "/navigation_controller/simple_page_2.html"));
637 NavigateToURL(shell(), url2
);
639 FrameTreeNode
* root
=
640 static_cast<WebContentsImpl
*>(shell()->web_contents())->
641 GetFrameTree()->root();
644 // Back from the browser side.
645 FrameNavigateParamsCapturer
capturer(root
);
646 shell()->web_contents()->GetController().GoBack();
648 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
649 | ui::PAGE_TRANSITION_FORWARD_BACK
650 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
,
651 capturer
.params().transition
);
652 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
653 EXPECT_FALSE(capturer
.details().is_in_page
);
657 // Forward from the browser side.
658 FrameNavigateParamsCapturer
capturer(root
);
659 shell()->web_contents()->GetController().GoForward();
661 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
662 | ui::PAGE_TRANSITION_FORWARD_BACK
663 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
,
664 capturer
.params().transition
);
665 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
666 EXPECT_FALSE(capturer
.details().is_in_page
);
670 // Back from the renderer side.
671 FrameNavigateParamsCapturer
capturer(root
);
672 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(),
675 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
676 | ui::PAGE_TRANSITION_FORWARD_BACK
677 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
,
678 capturer
.params().transition
);
679 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
680 EXPECT_FALSE(capturer
.details().is_in_page
);
684 // Forward from the renderer side.
685 FrameNavigateParamsCapturer
capturer(root
);
686 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(),
687 "history.forward()"));
689 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
690 | ui::PAGE_TRANSITION_FORWARD_BACK
691 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
,
692 capturer
.params().transition
);
693 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
694 EXPECT_FALSE(capturer
.details().is_in_page
);
698 // Back from the renderer side via history.go().
699 FrameNavigateParamsCapturer
capturer(root
);
700 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(),
703 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
704 | ui::PAGE_TRANSITION_FORWARD_BACK
705 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
,
706 capturer
.params().transition
);
707 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
708 EXPECT_FALSE(capturer
.details().is_in_page
);
712 // Forward from the renderer side via history.go().
713 FrameNavigateParamsCapturer
capturer(root
);
714 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(),
717 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
718 | ui::PAGE_TRANSITION_FORWARD_BACK
719 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
,
720 capturer
.params().transition
);
721 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
722 EXPECT_FALSE(capturer
.details().is_in_page
);
726 // Reload from the browser side.
727 FrameNavigateParamsCapturer
capturer(root
);
728 shell()->web_contents()->GetController().Reload(false);
730 EXPECT_EQ(ui::PAGE_TRANSITION_RELOAD
, capturer
.params().transition
);
731 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
732 EXPECT_FALSE(capturer
.details().is_in_page
);
736 // Reload from the renderer side.
737 FrameNavigateParamsCapturer
capturer(root
);
738 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(),
739 "location.reload()"));
741 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_CLIENT_REDIRECT
,
742 capturer
.params().transition
);
743 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
744 EXPECT_FALSE(capturer
.details().is_in_page
);
748 // location.replace().
749 FrameNavigateParamsCapturer
capturer(root
);
750 GURL
frame_url(embedded_test_server()->GetURL(
751 "/navigation_controller/simple_page_1.html"));
752 std::string script
= "location.replace('" + frame_url
.spec() + "')";
753 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
755 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_CLIENT_REDIRECT
,
756 capturer
.params().transition
);
757 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
758 EXPECT_FALSE(capturer
.details().is_in_page
);
761 // Now, various in-page navigations.
764 // history.replaceState().
765 FrameNavigateParamsCapturer
capturer(root
);
767 "history.replaceState({}, 'page 2', 'simple_page_2.html')";
768 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
770 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_CLIENT_REDIRECT
,
771 capturer
.params().transition
);
772 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
773 EXPECT_TRUE(capturer
.details().is_in_page
);
776 // Back and forward across a fragment navigation.
778 GURL
url_links(embedded_test_server()->GetURL(
779 "/navigation_controller/page_with_links.html"));
780 NavigateToURL(shell(), url_links
);
781 std::string script
= "document.getElementById('fraglink').click()";
782 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
783 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
787 FrameNavigateParamsCapturer
capturer(root
);
788 shell()->web_contents()->GetController().GoBack();
790 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
791 | ui::PAGE_TRANSITION_FORWARD_BACK
792 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
,
793 capturer
.params().transition
);
794 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
795 EXPECT_TRUE(capturer
.details().is_in_page
);
800 FrameNavigateParamsCapturer
capturer(root
);
801 shell()->web_contents()->GetController().GoForward();
803 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_FORWARD_BACK
,
804 capturer
.params().transition
);
805 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
806 EXPECT_TRUE(capturer
.details().is_in_page
);
809 // Back and forward across a pushState-created navigation.
811 NavigateToURL(shell(), url1
);
812 script
= "history.pushState({}, 'page 2', 'simple_page_2.html')";
813 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
814 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
818 FrameNavigateParamsCapturer
capturer(root
);
819 shell()->web_contents()->GetController().GoBack();
821 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
822 | ui::PAGE_TRANSITION_FORWARD_BACK
823 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
,
824 capturer
.params().transition
);
825 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
826 EXPECT_TRUE(capturer
.details().is_in_page
);
831 FrameNavigateParamsCapturer
capturer(root
);
832 shell()->web_contents()->GetController().GoForward();
834 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_FORWARD_BACK
,
835 capturer
.params().transition
);
836 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
837 EXPECT_TRUE(capturer
.details().is_in_page
);
841 // Verify that navigations for NAVIGATION_TYPE_SAME_PAGE are correctly
843 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
844 NavigationTypeClassification_SamePage
) {
845 GURL
url1(embedded_test_server()->GetURL(
846 "/navigation_controller/simple_page_1.html"));
847 NavigateToURL(shell(), url1
);
849 FrameTreeNode
* root
=
850 static_cast<WebContentsImpl
*>(shell()->web_contents())->
851 GetFrameTree()->root();
855 FrameNavigateParamsCapturer
capturer(root
);
856 GURL
frame_url(embedded_test_server()->GetURL(
857 "/navigation_controller/simple_page_1.html"));
858 NavigateFrameToURL(root
, frame_url
);
860 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
, capturer
.params().transition
);
861 EXPECT_EQ(NAVIGATION_TYPE_SAME_PAGE
, capturer
.details().type
);
865 // Verify that navigations for NAVIGATION_TYPE_NEW_SUBFRAME and
866 // NAVIGATION_TYPE_AUTO_SUBFRAME are properly classified.
867 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
868 NavigationTypeClassification_NewAndAutoSubframe
) {
869 GURL
main_url(embedded_test_server()->GetURL(
870 "/navigation_controller/page_with_iframe.html"));
871 NavigateToURL(shell(), main_url
);
873 // It is safe to obtain the root frame tree node here, as it doesn't change.
874 FrameTreeNode
* root
=
875 static_cast<WebContentsImpl
*>(shell()->web_contents())->
876 GetFrameTree()->root();
878 ASSERT_EQ(1U, root
->child_count());
879 ASSERT_NE(nullptr, root
->child_at(0));
883 LoadCommittedCapturer
capturer(root
->child_at(0));
884 GURL
frame_url(embedded_test_server()->GetURL(
885 "/navigation_controller/simple_page_1.html"));
886 NavigateFrameToURL(root
->child_at(0), frame_url
);
888 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
893 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
894 GURL
frame_url(embedded_test_server()->GetURL(
895 "/navigation_controller/simple_page_2.html"));
896 NavigateFrameToURL(root
->child_at(0), frame_url
);
898 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
899 capturer
.params().transition
);
900 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
905 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
906 shell()->web_contents()->GetController().GoBack();
908 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.params().transition
);
909 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME
, capturer
.details().type
);
914 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
915 shell()->web_contents()->GetController().GoForward();
917 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.params().transition
);
918 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME
, capturer
.details().type
);
923 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
924 GURL
frame_url(embedded_test_server()->GetURL(
925 "/navigation_controller/page_with_links.html"));
926 NavigateFrameToURL(root
->child_at(0), frame_url
);
928 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
929 capturer
.params().transition
);
930 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
934 // Load via a fragment link click.
935 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
936 std::string script
= "document.getElementById('fraglink').click()";
937 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
940 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
941 capturer
.params().transition
);
942 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
946 // location.assign().
947 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
948 GURL
frame_url(embedded_test_server()->GetURL(
949 "/navigation_controller/simple_page_1.html"));
950 std::string script
= "location.assign('" + frame_url
.spec() + "')";
951 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
954 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
955 capturer
.params().transition
);
956 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
960 // location.replace().
961 LoadCommittedCapturer
capturer(root
->child_at(0));
962 GURL
frame_url(embedded_test_server()->GetURL(
963 "/navigation_controller/simple_page_2.html"));
964 std::string script
= "location.replace('" + frame_url
.spec() + "')";
965 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
968 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
972 // history.pushState().
973 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
975 "history.pushState({}, 'page 1', 'simple_page_1.html')";
976 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
979 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
980 capturer
.params().transition
);
981 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
985 // history.replaceState().
986 LoadCommittedCapturer
capturer(root
->child_at(0));
988 "history.replaceState({}, 'page 2', 'simple_page_2.html')";
989 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
992 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
997 LoadCommittedCapturer
capturer(root
->child_at(0));
998 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
999 "location.reload()"));
1001 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1005 // Create an iframe.
1006 LoadCommittedCapturer
capturer(shell()->web_contents());
1007 GURL
frame_url(embedded_test_server()->GetURL(
1008 "/navigation_controller/simple_page_1.html"));
1009 std::string script
= "var iframe = document.createElement('iframe');"
1010 "iframe.src = '" + frame_url
.spec() + "';"
1011 "document.body.appendChild(iframe);";
1012 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1014 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1018 // Verify that navigations caused by client-side redirects are correctly
1020 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1021 NavigationTypeClassification_ClientSideRedirect
) {
1022 NavigateToURL(shell(), GURL(url::kAboutBlankURL
));
1023 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1025 FrameTreeNode
* root
=
1026 static_cast<WebContentsImpl
*>(shell()->web_contents())->
1027 GetFrameTree()->root();
1030 // Load the redirecting page.
1031 FrameNavigateParamsCapturer
capturer(root
);
1032 capturer
.set_navigations_remaining(2);
1033 GURL
frame_url(embedded_test_server()->GetURL(
1034 "/navigation_controller/client_redirect.html"));
1035 NavigateFrameToURL(root
, frame_url
);
1038 std::vector
<FrameNavigateParams
> params
= capturer
.all_params();
1039 std::vector
<LoadCommittedDetails
> details
= capturer
.all_details();
1040 ASSERT_EQ(2U, params
.size());
1041 ASSERT_EQ(2U, details
.size());
1042 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
, params
[0].transition
);
1043 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, details
[0].type
);
1044 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_CLIENT_REDIRECT
,
1045 params
[1].transition
);
1046 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, details
[1].type
);
1050 // Verify that the LoadCommittedDetails::is_in_page value is properly set for
1051 // non-IN_PAGE navigations. (It's tested for IN_PAGE navigations with the
1052 // NavigationTypeClassification_InPage test.)
1053 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1054 LoadCommittedDetails_IsInPage
) {
1055 GURL
links_url(embedded_test_server()->GetURL(
1056 "/navigation_controller/page_with_links.html"));
1057 NavigateToURL(shell(), links_url
);
1058 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1060 FrameTreeNode
* root
=
1061 static_cast<WebContentsImpl
*>(shell()->web_contents())->
1062 GetFrameTree()->root();
1065 // Do a fragment link click.
1066 FrameNavigateParamsCapturer
capturer(root
);
1067 std::string script
= "document.getElementById('fraglink').click()";
1068 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1070 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
, capturer
.params().transition
);
1071 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
1072 EXPECT_TRUE(capturer
.details().is_in_page
);
1076 // Do a non-fragment link click.
1077 FrameNavigateParamsCapturer
capturer(root
);
1078 std::string script
= "document.getElementById('thelink').click()";
1079 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1081 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
, capturer
.params().transition
);
1082 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
1083 EXPECT_FALSE(capturer
.details().is_in_page
);
1086 // Second verse, same as the first. (But in a subframe.)
1088 GURL
iframe_url(embedded_test_server()->GetURL(
1089 "/navigation_controller/page_with_iframe.html"));
1090 NavigateToURL(shell(), iframe_url
);
1092 root
= static_cast<WebContentsImpl
*>(shell()->web_contents())->
1093 GetFrameTree()->root();
1095 ASSERT_EQ(1U, root
->child_count());
1096 ASSERT_NE(nullptr, root
->child_at(0));
1098 NavigateFrameToURL(root
->child_at(0), links_url
);
1099 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1102 // Do a fragment link click.
1103 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1104 std::string script
= "document.getElementById('fraglink').click()";
1105 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
1108 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
1109 capturer
.params().transition
);
1110 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
1111 EXPECT_TRUE(capturer
.details().is_in_page
);
1115 // Do a non-fragment link click.
1116 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1117 std::string script
= "document.getElementById('thelink').click()";
1118 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
1121 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
1122 capturer
.params().transition
);
1123 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
1124 EXPECT_FALSE(capturer
.details().is_in_page
);
1128 // Verify the tree of FrameNavigationEntries after initial about:blank commits
1129 // in subframes, which should not count as real committed loads.
1130 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1131 FrameNavigationEntry_BlankAutoSubframe
) {
1132 GURL
about_blank_url(url::kAboutBlankURL
);
1133 GURL
main_url(embedded_test_server()->GetURL(
1134 "/navigation_controller/simple_page_1.html"));
1135 NavigateToURL(shell(), main_url
);
1136 const NavigationControllerImpl
& controller
=
1137 static_cast<const NavigationControllerImpl
&>(
1138 shell()->web_contents()->GetController());
1139 FrameTreeNode
* root
=
1140 static_cast<WebContentsImpl
*>(shell()->web_contents())->
1141 GetFrameTree()->root();
1143 // 1. Create a iframe with no URL.
1145 LoadCommittedCapturer
capturer(shell()->web_contents());
1146 std::string script
= "var iframe = document.createElement('iframe');"
1147 "document.body.appendChild(iframe);";
1148 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1150 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1153 // Check last committed NavigationEntry.
1154 EXPECT_EQ(1, controller
.GetEntryCount());
1155 NavigationEntryImpl
* entry
= controller
.GetLastCommittedEntry();
1156 EXPECT_EQ(main_url
, entry
->GetURL());
1157 FrameNavigationEntry
* root_entry
= entry
->root_node()->frame_entry
.get();
1158 EXPECT_EQ(main_url
, root_entry
->url());
1160 // Verify subframe entries if they're enabled (e.g. in --site-per-process).
1161 if (SiteIsolationPolicy::UseSubframeNavigationEntries()) {
1162 // The entry should now have one blank subframe FrameNavigationEntry, but
1163 // this does not count as committing a real load.
1164 ASSERT_EQ(1U, entry
->root_node()->children
.size());
1165 FrameNavigationEntry
* frame_entry
=
1166 entry
->root_node()->children
[0]->frame_entry
.get();
1167 EXPECT_EQ(about_blank_url
, frame_entry
->url());
1169 // There are no subframe FrameNavigationEntries by default.
1170 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1172 EXPECT_FALSE(root
->child_at(0)->has_committed_real_load());
1174 // 1a. A nested iframe with no URL should also create a subframe entry but not
1175 // count as a real load.
1177 LoadCommittedCapturer
capturer(shell()->web_contents());
1178 std::string script
= "var iframe = document.createElement('iframe');"
1179 "document.body.appendChild(iframe);";
1180 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
1183 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1186 // Verify subframe entries if they're enabled (e.g. in --site-per-process).
1187 if (SiteIsolationPolicy::UseSubframeNavigationEntries()) {
1188 // The nested entry should have one blank subframe FrameNavigationEntry, but
1189 // this does not count as committing a real load.
1190 ASSERT_EQ(1U, entry
->root_node()->children
[0]->children
.size());
1191 FrameNavigationEntry
* frame_entry
=
1192 entry
->root_node()->children
[0]->children
[0]->frame_entry
.get();
1193 EXPECT_EQ(about_blank_url
, frame_entry
->url());
1195 // There are no subframe FrameNavigationEntries by default.
1196 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1198 EXPECT_FALSE(root
->child_at(0)->child_at(0)->has_committed_real_load());
1200 // 2. Create another iframe with an explicit about:blank URL.
1202 LoadCommittedCapturer
capturer(shell()->web_contents());
1203 std::string script
= "var iframe = document.createElement('iframe');"
1204 "iframe.src = 'about:blank';"
1205 "document.body.appendChild(iframe);";
1206 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1208 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1211 // Check last committed NavigationEntry.
1212 EXPECT_EQ(1, controller
.GetEntryCount());
1213 EXPECT_EQ(entry
, controller
.GetLastCommittedEntry());
1215 // Verify subframe entries if they're enabled (e.g. in --site-per-process).
1216 if (SiteIsolationPolicy::UseSubframeNavigationEntries()) {
1217 // The new entry should have one blank subframe FrameNavigationEntry, but
1218 // this does not count as committing a real load.
1219 ASSERT_EQ(2U, entry
->root_node()->children
.size());
1220 FrameNavigationEntry
* frame_entry
=
1221 entry
->root_node()->children
[1]->frame_entry
.get();
1222 EXPECT_EQ(about_blank_url
, frame_entry
->url());
1224 // There are no subframe FrameNavigationEntries by default.
1225 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1227 EXPECT_FALSE(root
->child_at(1)->has_committed_real_load());
1229 // 3. A real same-site navigation in the nested iframe should be AUTO.
1230 GURL
frame_url(embedded_test_server()->GetURL(
1231 "/navigation_controller/simple_page_1.html"));
1233 LoadCommittedCapturer
capturer(root
->child_at(0)->child_at(0));
1234 std::string script
= "var frames = document.getElementsByTagName('iframe');"
1235 "frames[0].src = '" + frame_url
.spec() + "';";
1236 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
1239 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1242 // Check last committed NavigationEntry. It should have replaced the previous
1243 // frame entry in the original NavigationEntry.
1244 EXPECT_EQ(1, controller
.GetEntryCount());
1245 EXPECT_EQ(entry
, controller
.GetLastCommittedEntry());
1247 // Verify subframe entries if they're enabled (e.g. in --site-per-process).
1248 if (SiteIsolationPolicy::UseSubframeNavigationEntries()) {
1249 // The entry should still have one nested subframe FrameNavigationEntry.
1250 ASSERT_EQ(1U, entry
->root_node()->children
[0]->children
.size());
1251 FrameNavigationEntry
* frame_entry
=
1252 entry
->root_node()->children
[0]->children
[0]->frame_entry
.get();
1253 EXPECT_EQ(frame_url
, frame_entry
->url());
1255 // There are no subframe FrameNavigationEntries by default.
1256 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1258 EXPECT_FALSE(root
->child_at(0)->has_committed_real_load());
1259 EXPECT_TRUE(root
->child_at(0)->child_at(0)->has_committed_real_load());
1260 EXPECT_FALSE(root
->child_at(1)->has_committed_real_load());
1262 // 4. A real cross-site navigation in the second iframe should be AUTO.
1263 GURL
foo_url(embedded_test_server()->GetURL(
1264 "foo.com", "/navigation_controller/simple_page_2.html"));
1266 LoadCommittedCapturer
capturer(root
->child_at(1));
1267 std::string script
= "var frames = document.getElementsByTagName('iframe');"
1268 "frames[1].src = '" + foo_url
.spec() + "';";
1269 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1271 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1274 // Check last committed NavigationEntry.
1275 EXPECT_EQ(1, controller
.GetEntryCount());
1276 EXPECT_EQ(entry
, controller
.GetLastCommittedEntry());
1278 // Verify subframe entries if they're enabled (e.g. in --site-per-process).
1279 if (SiteIsolationPolicy::UseSubframeNavigationEntries()) {
1280 // The entry should still have two subframe FrameNavigationEntries.
1281 ASSERT_EQ(2U, entry
->root_node()->children
.size());
1282 FrameNavigationEntry
* frame_entry
=
1283 entry
->root_node()->children
[1]->frame_entry
.get();
1284 EXPECT_EQ(foo_url
, frame_entry
->url());
1286 // There are no subframe FrameNavigationEntries by default.
1287 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1289 EXPECT_FALSE(root
->child_at(0)->has_committed_real_load());
1290 EXPECT_TRUE(root
->child_at(0)->child_at(0)->has_committed_real_load());
1291 EXPECT_TRUE(root
->child_at(1)->has_committed_real_load());
1293 // 5. A new navigation to about:blank in the nested frame should count as a
1294 // real load, since that frame has already committed a real load and this is
1295 // not the initial blank page.
1297 LoadCommittedCapturer
capturer(root
->child_at(0)->child_at(0));
1298 std::string script
= "var frames = document.getElementsByTagName('iframe');"
1299 "frames[0].src = 'about:blank';";
1300 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
1303 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
, capturer
.transition_type());
1306 // This should have created a new NavigationEntry.
1307 EXPECT_EQ(2, controller
.GetEntryCount());
1308 EXPECT_NE(entry
, controller
.GetLastCommittedEntry());
1309 NavigationEntryImpl
* entry2
= controller
.GetLastCommittedEntry();
1311 // Verify subframe entries if they're enabled (e.g. in --site-per-process).
1312 if (SiteIsolationPolicy::UseSubframeNavigationEntries()) {
1313 ASSERT_EQ(2U, entry
->root_node()->children
.size());
1314 FrameNavigationEntry
* frame_entry
=
1315 entry2
->root_node()->children
[0]->children
[0]->frame_entry
.get();
1316 EXPECT_EQ(about_blank_url
, frame_entry
->url());
1318 // There are no subframe FrameNavigationEntries by default.
1319 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1321 EXPECT_FALSE(root
->child_at(0)->has_committed_real_load());
1322 EXPECT_TRUE(root
->child_at(0)->child_at(0)->has_committed_real_load());
1323 EXPECT_TRUE(root
->child_at(1)->has_committed_real_load());
1325 // Check the end result of the frame tree.
1326 if (AreAllSitesIsolatedForTesting()) {
1327 FrameTreeVisualizer visualizer
;
1329 " Site A ------------ proxies for B\n"
1330 " |--Site A ------- proxies for B\n"
1331 " | +--Site A -- proxies for B\n"
1332 " +--Site B ------- proxies for A\n"
1333 "Where A = http://127.0.0.1/\n"
1334 " B = http://foo.com/",
1335 visualizer
.DepictFrameTree(root
));
1339 // Verify the tree of FrameNavigationEntries after NAVIGATION_TYPE_AUTO_SUBFRAME
1341 // TODO(creis): Test updating entries for history auto subframe navigations.
1342 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1343 FrameNavigationEntry_AutoSubframe
) {
1344 GURL
main_url(embedded_test_server()->GetURL(
1345 "/navigation_controller/simple_page_1.html"));
1346 NavigateToURL(shell(), main_url
);
1347 const NavigationControllerImpl
& controller
=
1348 static_cast<const NavigationControllerImpl
&>(
1349 shell()->web_contents()->GetController());
1350 FrameTreeNode
* root
=
1351 static_cast<WebContentsImpl
*>(shell()->web_contents())->
1352 GetFrameTree()->root();
1354 // 1. Create a same-site iframe.
1355 GURL
frame_url(embedded_test_server()->GetURL(
1356 "/navigation_controller/simple_page_2.html"));
1358 LoadCommittedCapturer
capturer(shell()->web_contents());
1359 std::string script
= "var iframe = document.createElement('iframe');"
1360 "iframe.src = '" + frame_url
.spec() + "';"
1361 "document.body.appendChild(iframe);";
1362 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1364 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1367 // Check last committed NavigationEntry.
1368 EXPECT_EQ(1, controller
.GetEntryCount());
1369 NavigationEntryImpl
* entry
= controller
.GetLastCommittedEntry();
1370 EXPECT_EQ(main_url
, entry
->GetURL());
1371 FrameNavigationEntry
* root_entry
= entry
->root_node()->frame_entry
.get();
1372 EXPECT_EQ(main_url
, root_entry
->url());
1373 EXPECT_FALSE(controller
.GetPendingEntry());
1375 // Verify subframe entries if they're enabled (e.g. in --site-per-process).
1376 if (SiteIsolationPolicy::UseSubframeNavigationEntries()) {
1377 // The entry should now have a subframe FrameNavigationEntry.
1378 ASSERT_EQ(1U, entry
->root_node()->children
.size());
1379 FrameNavigationEntry
* frame_entry
=
1380 entry
->root_node()->children
[0]->frame_entry
.get();
1381 EXPECT_EQ(frame_url
, frame_entry
->url());
1382 EXPECT_TRUE(root
->child_at(0)->has_committed_real_load());
1384 // There are no subframe FrameNavigationEntries by default.
1385 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1388 // 2. Create a second, initially cross-site iframe.
1389 GURL
foo_url(embedded_test_server()->GetURL(
1390 "foo.com", "/navigation_controller/simple_page_1.html"));
1392 LoadCommittedCapturer
capturer(shell()->web_contents());
1393 std::string script
= "var iframe = document.createElement('iframe');"
1394 "iframe.src = '" + foo_url
.spec() + "';"
1395 "document.body.appendChild(iframe);";
1396 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1398 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1401 // The last committed NavigationEntry shouldn't have changed.
1402 EXPECT_EQ(1, controller
.GetEntryCount());
1403 entry
= controller
.GetLastCommittedEntry();
1404 EXPECT_EQ(main_url
, entry
->GetURL());
1405 root_entry
= entry
->root_node()->frame_entry
.get();
1406 EXPECT_EQ(main_url
, root_entry
->url());
1407 EXPECT_FALSE(controller
.GetPendingEntry());
1409 // Verify subframe entries if they're enabled (e.g. in --site-per-process).
1410 if (SiteIsolationPolicy::UseSubframeNavigationEntries()) {
1411 // The entry should now have 2 subframe FrameNavigationEntries.
1412 ASSERT_EQ(2U, entry
->root_node()->children
.size());
1413 FrameNavigationEntry
* frame_entry
=
1414 entry
->root_node()->children
[1]->frame_entry
.get();
1415 EXPECT_EQ(foo_url
, frame_entry
->url());
1416 EXPECT_TRUE(root
->child_at(1)->has_committed_real_load());
1418 // There are no subframe FrameNavigationEntries by default.
1419 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1422 // 3. Create a nested iframe in the second subframe.
1424 LoadCommittedCapturer
capturer(shell()->web_contents());
1425 std::string script
= "var iframe = document.createElement('iframe');"
1426 "iframe.src = '" + foo_url
.spec() + "';"
1427 "document.body.appendChild(iframe);";
1428 EXPECT_TRUE(content::ExecuteScript(root
->child_at(1)->current_frame_host(),
1431 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1434 // The last committed NavigationEntry shouldn't have changed.
1435 EXPECT_EQ(1, controller
.GetEntryCount());
1436 entry
= controller
.GetLastCommittedEntry();
1437 EXPECT_EQ(main_url
, entry
->GetURL());
1438 root_entry
= entry
->root_node()->frame_entry
.get();
1439 EXPECT_EQ(main_url
, root_entry
->url());
1441 // Verify subframe entries if they're enabled (e.g. in --site-per-process).
1442 if (SiteIsolationPolicy::UseSubframeNavigationEntries()) {
1443 // The entry should now have 2 subframe FrameNavigationEntries.
1444 ASSERT_EQ(2U, entry
->root_node()->children
.size());
1445 ASSERT_EQ(1U, entry
->root_node()->children
[1]->children
.size());
1446 FrameNavigationEntry
* frame_entry
=
1447 entry
->root_node()->children
[1]->children
[0]->frame_entry
.get();
1448 EXPECT_EQ(foo_url
, frame_entry
->url());
1450 // There are no subframe FrameNavigationEntries by default.
1451 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1454 // 4. Create a third iframe on the same site as the second. This ensures that
1455 // the commit type is correct even when the subframe process already exists.
1457 LoadCommittedCapturer
capturer(shell()->web_contents());
1458 std::string script
= "var iframe = document.createElement('iframe');"
1459 "iframe.src = '" + foo_url
.spec() + "';"
1460 "document.body.appendChild(iframe);";
1461 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1463 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1466 // The last committed NavigationEntry shouldn't have changed.
1467 EXPECT_EQ(1, controller
.GetEntryCount());
1468 entry
= controller
.GetLastCommittedEntry();
1469 EXPECT_EQ(main_url
, entry
->GetURL());
1470 root_entry
= entry
->root_node()->frame_entry
.get();
1471 EXPECT_EQ(main_url
, root_entry
->url());
1473 // Verify subframe entries if they're enabled (e.g. in --site-per-process).
1474 if (SiteIsolationPolicy::UseSubframeNavigationEntries()) {
1475 // The entry should now have 3 subframe FrameNavigationEntries.
1476 ASSERT_EQ(3U, entry
->root_node()->children
.size());
1477 FrameNavigationEntry
* frame_entry
=
1478 entry
->root_node()->children
[2]->frame_entry
.get();
1479 EXPECT_EQ(foo_url
, frame_entry
->url());
1481 // There are no subframe FrameNavigationEntries by default.
1482 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1485 // 5. Create a nested iframe on the original site (A-B-A).
1487 LoadCommittedCapturer
capturer(shell()->web_contents());
1488 std::string script
= "var iframe = document.createElement('iframe');"
1489 "iframe.src = '" + frame_url
.spec() + "';"
1490 "document.body.appendChild(iframe);";
1491 FrameTreeNode
* child
= root
->child_at(2);
1492 EXPECT_TRUE(content::ExecuteScript(child
->current_frame_host(), script
));
1494 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1497 // The last committed NavigationEntry shouldn't have changed.
1498 EXPECT_EQ(1, controller
.GetEntryCount());
1499 entry
= controller
.GetLastCommittedEntry();
1500 EXPECT_EQ(main_url
, entry
->GetURL());
1501 root_entry
= entry
->root_node()->frame_entry
.get();
1502 EXPECT_EQ(main_url
, root_entry
->url());
1504 // Verify subframe entries if they're enabled (e.g. in --site-per-process).
1505 if (SiteIsolationPolicy::UseSubframeNavigationEntries()) {
1506 // There should be a corresponding FrameNavigationEntry.
1507 ASSERT_EQ(1U, entry
->root_node()->children
[2]->children
.size());
1508 FrameNavigationEntry
* frame_entry
=
1509 entry
->root_node()->children
[2]->children
[0]->frame_entry
.get();
1510 EXPECT_EQ(frame_url
, frame_entry
->url());
1512 // There are no subframe FrameNavigationEntries by default.
1513 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1516 // Check the end result of the frame tree.
1517 if (AreAllSitesIsolatedForTesting()) {
1518 FrameTreeVisualizer visualizer
;
1520 " Site A ------------ proxies for B\n"
1521 " |--Site A ------- proxies for B\n"
1522 " |--Site B ------- proxies for A\n"
1523 " | +--Site B -- proxies for A\n"
1524 " +--Site B ------- proxies for A\n"
1525 " +--Site A -- proxies for B\n"
1526 "Where A = http://127.0.0.1/\n"
1527 " B = http://foo.com/",
1528 visualizer
.DepictFrameTree(root
));
1532 // Verify the tree of FrameNavigationEntries after NAVIGATION_TYPE_NEW_SUBFRAME
1534 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1535 FrameNavigationEntry_NewSubframe
) {
1536 GURL
main_url(embedded_test_server()->GetURL(
1537 "/navigation_controller/simple_page_1.html"));
1538 NavigateToURL(shell(), main_url
);
1539 const NavigationControllerImpl
& controller
=
1540 static_cast<const NavigationControllerImpl
&>(
1541 shell()->web_contents()->GetController());
1542 FrameTreeNode
* root
=
1543 static_cast<WebContentsImpl
*>(shell()->web_contents())->
1544 GetFrameTree()->root();
1546 // 1. Create a same-site iframe.
1547 GURL
frame_url(embedded_test_server()->GetURL(
1548 "/navigation_controller/simple_page_2.html"));
1550 LoadCommittedCapturer
capturer(shell()->web_contents());
1551 std::string script
= "var iframe = document.createElement('iframe');"
1552 "iframe.src = '" + frame_url
.spec() + "';"
1553 "document.body.appendChild(iframe);";
1554 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1557 NavigationEntryImpl
* entry
= controller
.GetLastCommittedEntry();
1559 // 2. Navigate in the subframe same-site.
1560 GURL
frame_url2(embedded_test_server()->GetURL(
1561 "/navigation_controller/page_with_links.html"));
1563 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1564 NavigateFrameToURL(root
->child_at(0), frame_url2
);
1566 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
1567 capturer
.params().transition
);
1568 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
1571 // We should have created a new NavigationEntry with the same main frame URL.
1572 EXPECT_EQ(2, controller
.GetEntryCount());
1573 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
1574 NavigationEntryImpl
* entry2
= controller
.GetLastCommittedEntry();
1575 EXPECT_NE(entry
, entry2
);
1576 EXPECT_EQ(main_url
, entry2
->GetURL());
1577 FrameNavigationEntry
* root_entry2
= entry2
->root_node()->frame_entry
.get();
1578 EXPECT_EQ(main_url
, root_entry2
->url());
1580 // Verify subframe entries if they're enabled (e.g. in --site-per-process).
1581 if (SiteIsolationPolicy::UseSubframeNavigationEntries()) {
1582 // The entry should have a new FrameNavigationEntries for the subframe.
1583 ASSERT_EQ(1U, entry2
->root_node()->children
.size());
1584 EXPECT_EQ(frame_url2
, entry2
->root_node()->children
[0]->frame_entry
->url());
1586 // There are no subframe FrameNavigationEntries by default.
1587 EXPECT_EQ(0U, entry2
->root_node()->children
.size());
1590 // 3. Create a second, initially cross-site iframe.
1591 GURL
foo_url(embedded_test_server()->GetURL(
1592 "foo.com", "/navigation_controller/simple_page_1.html"));
1594 LoadCommittedCapturer
capturer(shell()->web_contents());
1595 std::string script
= "var iframe = document.createElement('iframe');"
1596 "iframe.src = '" + foo_url
.spec() + "';"
1597 "document.body.appendChild(iframe);";
1598 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1602 // 4. Create a nested same-site iframe in the second subframe, wait for it to
1603 // commit, then navigate it again.
1605 LoadCommittedCapturer
capturer(shell()->web_contents());
1606 std::string script
= "var iframe = document.createElement('iframe');"
1607 "iframe.src = '" + foo_url
.spec() + "';"
1608 "document.body.appendChild(iframe);";
1609 EXPECT_TRUE(content::ExecuteScript(root
->child_at(1)->current_frame_host(),
1613 GURL
bar_url(embedded_test_server()->GetURL(
1614 "bar.com", "/navigation_controller/simple_page_1.html"));
1616 FrameNavigateParamsCapturer
capturer(root
->child_at(1)->child_at(0));
1617 NavigateFrameToURL(root
->child_at(1)->child_at(0), bar_url
);
1619 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
1620 capturer
.params().transition
);
1621 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
1624 // We should have created a new NavigationEntry with the same main frame URL.
1625 EXPECT_EQ(3, controller
.GetEntryCount());
1626 EXPECT_EQ(2, controller
.GetLastCommittedEntryIndex());
1627 NavigationEntryImpl
* entry3
= controller
.GetLastCommittedEntry();
1628 EXPECT_NE(entry
, entry3
);
1629 EXPECT_EQ(main_url
, entry3
->GetURL());
1630 FrameNavigationEntry
* root_entry3
= entry3
->root_node()->frame_entry
.get();
1631 EXPECT_EQ(main_url
, root_entry3
->url());
1633 // Verify subframe entries if they're enabled (e.g. in --site-per-process).
1634 if (SiteIsolationPolicy::UseSubframeNavigationEntries()) {
1635 // The entry should still have FrameNavigationEntries for all 3 subframes.
1636 ASSERT_EQ(2U, entry3
->root_node()->children
.size());
1637 EXPECT_EQ(frame_url2
, entry3
->root_node()->children
[0]->frame_entry
->url());
1638 EXPECT_EQ(foo_url
, entry3
->root_node()->children
[1]->frame_entry
->url());
1639 ASSERT_EQ(1U, entry3
->root_node()->children
[1]->children
.size());
1642 entry3
->root_node()->children
[1]->children
[0]->frame_entry
->url());
1644 // There are no subframe FrameNavigationEntries by default.
1645 EXPECT_EQ(0U, entry3
->root_node()->children
.size());
1648 // 6. Navigate the second subframe cross-site, clearing its existing subtree.
1649 GURL
baz_url(embedded_test_server()->GetURL(
1650 "baz.com", "/navigation_controller/simple_page_1.html"));
1652 FrameNavigateParamsCapturer
capturer(root
->child_at(1));
1653 std::string script
= "var frames = document.getElementsByTagName('iframe');"
1654 "frames[1].src = '" + baz_url
.spec() + "';";
1655 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1657 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
1658 capturer
.params().transition
);
1659 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
1662 // We should have created a new NavigationEntry with the same main frame URL.
1663 EXPECT_EQ(4, controller
.GetEntryCount());
1664 EXPECT_EQ(3, controller
.GetLastCommittedEntryIndex());
1665 NavigationEntryImpl
* entry4
= controller
.GetLastCommittedEntry();
1666 EXPECT_NE(entry
, entry4
);
1667 EXPECT_EQ(main_url
, entry4
->GetURL());
1668 FrameNavigationEntry
* root_entry4
= entry4
->root_node()->frame_entry
.get();
1669 EXPECT_EQ(main_url
, root_entry4
->url());
1671 // Verify subframe entries if they're enabled (e.g. in --site-per-process).
1672 if (SiteIsolationPolicy::UseSubframeNavigationEntries()) {
1673 // The entry should still have FrameNavigationEntries for all 3 subframes.
1674 ASSERT_EQ(2U, entry4
->root_node()->children
.size());
1675 EXPECT_EQ(frame_url2
, entry4
->root_node()->children
[0]->frame_entry
->url());
1676 EXPECT_EQ(baz_url
, entry4
->root_node()->children
[1]->frame_entry
->url());
1677 ASSERT_EQ(0U, entry4
->root_node()->children
[1]->children
.size());
1679 // There are no subframe FrameNavigationEntries by default.
1680 EXPECT_EQ(0U, entry4
->root_node()->children
.size());
1683 // Check the end result of the frame tree.
1684 if (AreAllSitesIsolatedForTesting()) {
1685 FrameTreeVisualizer visualizer
;
1687 " Site A ------------ proxies for B\n"
1688 " |--Site A ------- proxies for B\n"
1689 " +--Site B ------- proxies for A\n"
1690 "Where A = http://127.0.0.1/\n"
1691 " B = http://baz.com/",
1692 visualizer
.DepictFrameTree(root
));
1696 // Ensure that we don't crash when navigating subframes after in-page
1697 // navigations. See https://crbug.com/522193.
1698 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1699 FrameNavigationEntry_SubframeAfterInPage
) {
1700 // 1. Start on a page with a subframe.
1701 GURL
main_url(embedded_test_server()->GetURL(
1702 "/navigation_controller/page_with_iframe.html"));
1703 NavigateToURL(shell(), main_url
);
1704 FrameTreeNode
* root
=
1705 static_cast<WebContentsImpl
*>(shell()->web_contents())->
1706 GetFrameTree()->root();
1708 ASSERT_EQ(1U, root
->child_count());
1709 ASSERT_NE(nullptr, root
->child_at(0));
1711 // Navigate to a real page in the subframe, so that the next navigation will
1712 // be MANUAL_SUBFRAME.
1713 GURL
subframe_url(embedded_test_server()->GetURL(
1714 "/navigation_controller/simple_page_1.html"));
1716 LoadCommittedCapturer
capturer(root
->child_at(0));
1717 NavigateFrameToURL(root
->child_at(0), subframe_url
);
1719 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1722 // 2. In-page navigation in the main frame.
1723 std::string push_script
= "history.pushState({}, 'page 2', 'page_2.html')";
1724 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), push_script
));
1725 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1727 // TODO(creis): Verify subframe entries. https://crbug.com/522193.
1729 // 3. Add a nested subframe.
1731 LoadCommittedCapturer
capturer(shell()->web_contents());
1732 std::string script
= "var iframe = document.createElement('iframe');"
1733 "iframe.src = '" + subframe_url
.spec() + "';"
1734 "document.body.appendChild(iframe);";
1735 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
1738 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1741 // TODO(creis): Verify subframe entries. https://crbug.com/522193.
1744 // Verify the tree of FrameNavigationEntries after back/forward navigations in a
1745 // cross-site subframe.
1746 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1747 FrameNavigationEntry_SubframeBackForward
) {
1748 GURL
main_url(embedded_test_server()->GetURL(
1749 "/navigation_controller/simple_page_1.html"));
1750 NavigateToURL(shell(), main_url
);
1751 const NavigationControllerImpl
& controller
=
1752 static_cast<const NavigationControllerImpl
&>(
1753 shell()->web_contents()->GetController());
1754 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1758 // 1. Create a same-site iframe.
1759 GURL
frame_url(embedded_test_server()->GetURL(
1760 "/navigation_controller/simple_page_2.html"));
1762 LoadCommittedCapturer
capturer(shell()->web_contents());
1763 std::string script
= "var iframe = document.createElement('iframe');"
1764 "iframe.src = '" + frame_url
.spec() + "';"
1765 "document.body.appendChild(iframe);";
1766 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1769 NavigationEntryImpl
* entry1
= controller
.GetLastCommittedEntry();
1771 // 2. Navigate in the subframe cross-site.
1772 GURL
frame_url2(embedded_test_server()->GetURL(
1773 "foo.com", "/navigation_controller/page_with_links.html"));
1775 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1776 NavigateFrameToURL(root
->child_at(0), frame_url2
);
1779 EXPECT_EQ(2, controller
.GetEntryCount());
1780 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
1781 NavigationEntryImpl
* entry2
= controller
.GetLastCommittedEntry();
1783 // 3. Navigate in the subframe cross-site again.
1784 GURL
frame_url3(embedded_test_server()->GetURL(
1785 "bar.com", "/navigation_controller/page_with_links.html"));
1787 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1788 NavigateFrameToURL(root
->child_at(0), frame_url3
);
1791 EXPECT_EQ(3, controller
.GetEntryCount());
1792 EXPECT_EQ(2, controller
.GetLastCommittedEntryIndex());
1793 NavigationEntryImpl
* entry3
= controller
.GetLastCommittedEntry();
1795 // 4. Go back in the subframe.
1797 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1798 shell()->web_contents()->GetController().GoBack();
1800 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.params().transition
);
1801 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME
, capturer
.details().type
);
1803 EXPECT_EQ(3, controller
.GetEntryCount());
1804 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
1805 EXPECT_EQ(entry2
, controller
.GetLastCommittedEntry());
1807 // Verify subframe entries if they're enabled (e.g. in --site-per-process).
1808 if (SiteIsolationPolicy::UseSubframeNavigationEntries()) {
1809 // The entry should have a new FrameNavigationEntries for the subframe.
1810 ASSERT_EQ(1U, entry2
->root_node()->children
.size());
1811 EXPECT_EQ(frame_url2
, entry2
->root_node()->children
[0]->frame_entry
->url());
1813 // There are no subframe FrameNavigationEntries by default.
1814 EXPECT_EQ(0U, entry2
->root_node()->children
.size());
1817 // 5. Go back in the subframe again to the parent page's site.
1819 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1820 shell()->web_contents()->GetController().GoBack();
1822 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.params().transition
);
1823 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME
, capturer
.details().type
);
1825 EXPECT_EQ(3, controller
.GetEntryCount());
1826 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
1827 EXPECT_EQ(entry1
, controller
.GetLastCommittedEntry());
1829 // Verify subframe entries if they're enabled (e.g. in --site-per-process).
1830 if (SiteIsolationPolicy::UseSubframeNavigationEntries()) {
1831 // The entry should have a new FrameNavigationEntries for the subframe.
1832 ASSERT_EQ(1U, entry1
->root_node()->children
.size());
1833 EXPECT_EQ(frame_url
, entry1
->root_node()->children
[0]->frame_entry
->url());
1835 // There are no subframe FrameNavigationEntries by default.
1836 EXPECT_EQ(0U, entry1
->root_node()->children
.size());
1839 // 6. Go forward in the subframe cross-site.
1841 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1842 shell()->web_contents()->GetController().GoForward();
1844 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.params().transition
);
1845 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME
, capturer
.details().type
);
1847 EXPECT_EQ(3, controller
.GetEntryCount());
1848 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
1849 EXPECT_EQ(entry2
, controller
.GetLastCommittedEntry());
1851 // Verify subframe entries if they're enabled (e.g. in --site-per-process).
1852 if (SiteIsolationPolicy::UseSubframeNavigationEntries()) {
1853 // The entry should have a new FrameNavigationEntries for the subframe.
1854 ASSERT_EQ(1U, entry2
->root_node()->children
.size());
1855 EXPECT_EQ(frame_url2
, entry2
->root_node()->children
[0]->frame_entry
->url());
1857 // There are no subframe FrameNavigationEntries by default.
1858 EXPECT_EQ(0U, entry2
->root_node()->children
.size());
1861 // 7. Go forward in the subframe again, cross-site.
1863 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1864 shell()->web_contents()->GetController().GoForward();
1866 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.params().transition
);
1867 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME
, capturer
.details().type
);
1869 EXPECT_EQ(3, controller
.GetEntryCount());
1870 EXPECT_EQ(2, controller
.GetLastCommittedEntryIndex());
1871 EXPECT_EQ(entry3
, controller
.GetLastCommittedEntry());
1873 // Verify subframe entries if they're enabled (e.g. in --site-per-process).
1874 if (SiteIsolationPolicy::UseSubframeNavigationEntries()) {
1875 // The entry should have a new FrameNavigationEntries for the subframe.
1876 ASSERT_EQ(1U, entry3
->root_node()->children
.size());
1877 EXPECT_EQ(frame_url3
, entry3
->root_node()->children
[0]->frame_entry
->url());
1879 // There are no subframe FrameNavigationEntries by default.
1880 EXPECT_EQ(0U, entry3
->root_node()->children
.size());
1884 // Verifies that item sequence numbers and document sequence numbers update
1885 // properly for main frames and subframes.
1886 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1887 FrameNavigationEntry_SequenceNumbers
) {
1888 const NavigationControllerImpl
& controller
=
1889 static_cast<const NavigationControllerImpl
&>(
1890 shell()->web_contents()->GetController());
1892 // 1. Navigate the main frame.
1893 GURL
url(embedded_test_server()->GetURL(
1894 "/navigation_controller/page_with_links.html"));
1895 NavigateToURL(shell(), url
);
1896 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1900 FrameNavigationEntry
* frame_entry
=
1901 controller
.GetLastCommittedEntry()->GetFrameEntry(root
);
1902 int64 isn_1
= frame_entry
->item_sequence_number();
1903 int64 dsn_1
= frame_entry
->document_sequence_number();
1904 EXPECT_NE(-1, isn_1
);
1905 EXPECT_NE(-1, dsn_1
);
1907 // 2. Do an in-page fragment navigation.
1908 std::string script
= "document.getElementById('fraglink').click()";
1909 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1910 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1912 frame_entry
= controller
.GetLastCommittedEntry()->GetFrameEntry(root
);
1913 int64 isn_2
= frame_entry
->item_sequence_number();
1914 int64 dsn_2
= frame_entry
->document_sequence_number();
1915 EXPECT_NE(-1, isn_2
);
1916 EXPECT_NE(isn_1
, isn_2
);
1917 EXPECT_EQ(dsn_1
, dsn_2
);
1919 // Test subframe sequence numbers only if enabled, e.g. in --site-per-process.
1920 if (!SiteIsolationPolicy::UseSubframeNavigationEntries())
1923 // 3. Add a subframe, which does an AUTO_SUBFRAME navigation.
1925 LoadCommittedCapturer
capturer(shell()->web_contents());
1926 std::string script
= "var iframe = document.createElement('iframe');"
1927 "iframe.src = '" + url
.spec() + "';"
1928 "document.body.appendChild(iframe);";
1929 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1931 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1934 // The root FrameNavigationEntry hasn't changed.
1935 EXPECT_EQ(frame_entry
,
1936 controller
.GetLastCommittedEntry()->GetFrameEntry(root
));
1938 // We should have a unique ISN and DSN for the subframe entry.
1939 FrameTreeNode
* subframe
= root
->child_at(0);
1940 FrameNavigationEntry
* subframe_entry
=
1941 controller
.GetLastCommittedEntry()->GetFrameEntry(subframe
);
1942 int64 isn_3
= subframe_entry
->item_sequence_number();
1943 int64 dsn_3
= subframe_entry
->document_sequence_number();
1944 EXPECT_NE(-1, isn_2
);
1945 EXPECT_NE(isn_2
, isn_3
);
1946 EXPECT_NE(dsn_2
, dsn_3
);
1948 // 4. Do an in-page fragment navigation in the subframe.
1949 EXPECT_TRUE(content::ExecuteScript(subframe
->current_frame_host(), script
));
1950 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1952 subframe_entry
= controller
.GetLastCommittedEntry()->GetFrameEntry(subframe
);
1953 int64 isn_4
= subframe_entry
->item_sequence_number();
1954 int64 dsn_4
= subframe_entry
->document_sequence_number();
1955 EXPECT_NE(-1, isn_4
);
1956 EXPECT_NE(isn_3
, isn_4
);
1957 EXPECT_EQ(dsn_3
, dsn_4
);
1962 class HttpThrottle
: public ResourceThrottle
{
1965 void WillStartRequest(bool* defer
) override
{
1969 const char* GetNameForLogging() const override
{
1970 return "HttpThrottle";
1974 class StallDelegate
: public ResourceDispatcherHostDelegate
{
1975 // ResourceDispatcherHostDelegate
1976 void RequestBeginning(
1977 net::URLRequest
* request
,
1978 content::ResourceContext
* resource_context
,
1979 content::AppCacheService
* appcache_service
,
1980 ResourceType resource_type
,
1981 ScopedVector
<content::ResourceThrottle
>* throttles
) override
{
1982 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1983 throttles
->push_back(new HttpThrottle
);
1987 // Loads |start_url|, then loads |stalled_url| which stalls. While the page is
1988 // stalled, an in-page navigation happens. Make sure that all the navigations
1989 // are properly classified.
1990 void DoReplaceStateWhilePending(Shell
* shell
,
1991 const GURL
& start_url
,
1992 const GURL
& stalled_url
,
1993 const std::string
& replace_state_filename
) {
1994 NavigationControllerImpl
& controller
=
1995 static_cast<NavigationControllerImpl
&>(
1996 shell
->web_contents()->GetController());
1998 FrameTreeNode
* root
=
1999 static_cast<WebContentsImpl
*>(shell
->web_contents())->
2000 GetFrameTree()->root();
2002 // Start with one page.
2003 EXPECT_TRUE(NavigateToURL(shell
, start_url
));
2005 // Have the user decide to go to a different page which is very slow.
2006 StallDelegate stall_delegate
;
2007 ResourceDispatcherHost::Get()->SetDelegate(&stall_delegate
);
2009 stalled_url
, Referrer(), ui::PAGE_TRANSITION_LINK
, std::string());
2011 // That should be the pending entry.
2012 NavigationEntryImpl
* entry
= controller
.GetPendingEntry();
2013 ASSERT_NE(nullptr, entry
);
2014 EXPECT_EQ(stalled_url
, entry
->GetURL());
2017 // Now the existing page uses history.replaceState().
2018 FrameNavigateParamsCapturer
capturer(root
);
2019 capturer
.set_wait_for_load(false);
2020 std::string script
=
2021 "history.replaceState({}, '', '" + replace_state_filename
+ "')";
2022 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
2025 // The fact that there was a pending entry shouldn't interfere with the
2027 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
2028 EXPECT_TRUE(capturer
.details().is_in_page
);
2031 ResourceDispatcherHost::Get()->SetDelegate(nullptr);
2036 IN_PROC_BROWSER_TEST_F(
2037 NavigationControllerBrowserTest
,
2038 NavigationTypeClassification_On1InPageToXWhile2Pending
) {
2039 GURL
url1(embedded_test_server()->GetURL(
2040 "/navigation_controller/simple_page_1.html"));
2041 GURL
url2(embedded_test_server()->GetURL(
2042 "/navigation_controller/simple_page_2.html"));
2043 DoReplaceStateWhilePending(shell(), url1
, url2
, "x");
2046 IN_PROC_BROWSER_TEST_F(
2047 NavigationControllerBrowserTest
,
2048 NavigationTypeClassification_On1InPageTo2While2Pending
) {
2049 GURL
url1(embedded_test_server()->GetURL(
2050 "/navigation_controller/simple_page_1.html"));
2051 GURL
url2(embedded_test_server()->GetURL(
2052 "/navigation_controller/simple_page_2.html"));
2053 DoReplaceStateWhilePending(shell(), url1
, url2
, "simple_page_2.html");
2056 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
2057 NavigationTypeClassification_On1InPageToXWhile1Pending
) {
2058 GURL
url(embedded_test_server()->GetURL(
2059 "/navigation_controller/simple_page_1.html"));
2060 DoReplaceStateWhilePending(shell(), url
, url
, "x");
2063 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
2064 NavigationTypeClassification_On1InPageTo1While1Pending
) {
2065 GURL
url(embedded_test_server()->GetURL(
2066 "/navigation_controller/simple_page_1.html"));
2067 DoReplaceStateWhilePending(shell(), url
, url
, "simple_page_1.html");
2070 // Ensure the renderer process does not get confused about the current entry
2071 // due to subframes and replaced entries. See https://crbug.com/480201.
2072 // TODO(creis): Re-enable for Site Isolation FYI bots: https://crbug.com/502317.
2073 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
2074 PreventSpoofFromSubframeAndReplace
) {
2075 // Start at an initial URL.
2076 GURL
url1(embedded_test_server()->GetURL(
2077 "/navigation_controller/simple_page_1.html"));
2078 NavigateToURL(shell(), url1
);
2080 // Now go to a page with a real iframe.
2081 GURL
url2(embedded_test_server()->GetURL(
2082 "/navigation_controller/page_with_data_iframe.html"));
2083 NavigateToURL(shell(), url2
);
2085 // It is safe to obtain the root frame tree node here, as it doesn't change.
2086 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
2089 ASSERT_EQ(1U, root
->child_count());
2090 ASSERT_NE(nullptr, root
->child_at(0));
2093 // Navigate in the iframe.
2094 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
2095 GURL
frame_url(embedded_test_server()->GetURL(
2096 "/navigation_controller/simple_page_2.html"));
2097 NavigateFrameToURL(root
->child_at(0), frame_url
);
2099 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
2103 // Go back in the iframe.
2104 TestNavigationObserver
back_load_observer(shell()->web_contents());
2105 shell()->web_contents()->GetController().GoBack();
2106 back_load_observer
.Wait();
2110 // Go forward in the iframe.
2111 TestNavigationObserver
forward_load_observer(shell()->web_contents());
2112 shell()->web_contents()->GetController().GoForward();
2113 forward_load_observer
.Wait();
2116 GURL
url3(embedded_test_server()->GetURL(
2117 "/navigation_controller/page_with_iframe.html"));
2119 // location.replace() to cause an inert commit.
2120 TestNavigationObserver
replace_load_observer(shell()->web_contents());
2121 std::string script
= "location.replace('" + url3
.spec() + "')";
2122 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
2123 replace_load_observer
.Wait();
2128 TestNavigationObserver
back_load_observer(shell()->web_contents());
2129 shell()->web_contents()->GetController().GoBack();
2130 back_load_observer
.Wait();
2132 // Make sure the URL is correct for both the entry and the main frame, and
2133 // that the process hasn't been killed for showing a spoof.
2134 EXPECT_TRUE(root
->current_frame_host()->IsRenderFrameLive());
2135 EXPECT_EQ(url2
, shell()->web_contents()->GetLastCommittedURL());
2136 EXPECT_EQ(url2
, root
->current_url());
2140 // Go back to reset main frame entirely.
2141 TestNavigationObserver
back_load_observer(shell()->web_contents());
2142 shell()->web_contents()->GetController().GoBack();
2143 back_load_observer
.Wait();
2144 EXPECT_EQ(url1
, shell()->web_contents()->GetLastCommittedURL());
2145 EXPECT_EQ(url1
, root
->current_url());
2150 TestNavigationObserver
back_load_observer(shell()->web_contents());
2151 shell()->web_contents()->GetController().GoForward();
2152 back_load_observer
.Wait();
2153 EXPECT_EQ(url2
, shell()->web_contents()->GetLastCommittedURL());
2154 EXPECT_EQ(url2
, root
->current_url());
2158 // Go forward to the replaced URL.
2159 TestNavigationObserver
forward_load_observer(shell()->web_contents());
2160 shell()->web_contents()->GetController().GoForward();
2161 forward_load_observer
.Wait();
2163 // Make sure the URL is correct for both the entry and the main frame, and
2164 // that the process hasn't been killed for showing a spoof.
2165 EXPECT_TRUE(root
->current_frame_host()->IsRenderFrameLive());
2166 EXPECT_EQ(url3
, shell()->web_contents()->GetLastCommittedURL());
2167 EXPECT_EQ(url3
, root
->current_url());
2171 // Ensure the renderer process does not get killed if the main frame URL's path
2172 // changes when going back in a subframe, since this is currently possible after
2173 // a replaceState in the main frame (thanks to https://crbug.com/373041).
2174 // See https:///crbug.com/486916.
2175 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
2176 SubframeBackFromReplaceState
) {
2177 // Start at a page with a real iframe.
2178 GURL
url1(embedded_test_server()->GetURL(
2179 "/navigation_controller/page_with_data_iframe.html"));
2180 NavigateToURL(shell(), url1
);
2182 // It is safe to obtain the root frame tree node here, as it doesn't change.
2183 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
2186 ASSERT_EQ(1U, root
->child_count());
2187 ASSERT_NE(nullptr, root
->child_at(0));
2190 // Navigate in the iframe.
2191 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
2192 GURL
frame_url(embedded_test_server()->GetURL(
2193 "/navigation_controller/simple_page_2.html"));
2194 NavigateFrameToURL(root
->child_at(0), frame_url
);
2196 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
2200 // history.replaceState().
2201 FrameNavigateParamsCapturer
capturer(root
);
2202 std::string script
=
2203 "history.replaceState({}, 'replaced', 'replaced')";
2204 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
2209 // Go back in the iframe.
2210 TestNavigationObserver
back_load_observer(shell()->web_contents());
2211 shell()->web_contents()->GetController().GoBack();
2212 back_load_observer
.Wait();
2215 // For now, we expect the main frame's URL to revert. This won't happen once
2216 // https://crbug.com/373041 is fixed.
2217 EXPECT_EQ(url1
, shell()->web_contents()->GetLastCommittedURL());
2219 // Make sure the renderer process has not been killed.
2220 EXPECT_TRUE(root
->current_frame_host()->IsRenderFrameLive());
2225 class FailureWatcher
: public WebContentsObserver
{
2227 // Observes failure for the specified |node|.
2228 explicit FailureWatcher(FrameTreeNode
* node
)
2229 : WebContentsObserver(
2230 node
->current_frame_host()->delegate()->GetAsWebContents()),
2231 frame_tree_node_id_(node
->frame_tree_node_id()),
2232 message_loop_runner_(new MessageLoopRunner
) {}
2235 message_loop_runner_
->Run();
2239 void DidFailLoad(RenderFrameHost
* render_frame_host
,
2240 const GURL
& validated_url
,
2242 const base::string16
& error_description
,
2243 bool was_ignored_by_handler
) override
{
2244 RenderFrameHostImpl
* rfh
=
2245 static_cast<RenderFrameHostImpl
*>(render_frame_host
);
2246 if (rfh
->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_
)
2249 message_loop_runner_
->Quit();
2252 void DidFailProvisionalLoad(
2253 RenderFrameHost
* render_frame_host
,
2254 const GURL
& validated_url
,
2256 const base::string16
& error_description
,
2257 bool was_ignored_by_handler
) override
{
2258 RenderFrameHostImpl
* rfh
=
2259 static_cast<RenderFrameHostImpl
*>(render_frame_host
);
2260 if (rfh
->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_
)
2263 message_loop_runner_
->Quit();
2266 // The id of the FrameTreeNode whose navigations to observe.
2267 int frame_tree_node_id_
;
2269 // The MessageLoopRunner used to spin the message loop.
2270 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
2275 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
2276 StopCausesFailureDespiteJavaScriptURL
) {
2277 NavigationControllerImpl
& controller
=
2278 static_cast<NavigationControllerImpl
&>(
2279 shell()->web_contents()->GetController());
2281 FrameTreeNode
* root
=
2282 static_cast<WebContentsImpl
*>(shell()->web_contents())->
2283 GetFrameTree()->root();
2285 // Start with a normal page.
2286 GURL
url1(embedded_test_server()->GetURL(
2287 "/navigation_controller/simple_page_1.html"));
2288 EXPECT_TRUE(NavigateToURL(shell(), url1
));
2290 // Have the user decide to go to a different page which is very slow.
2291 StallDelegate stall_delegate
;
2292 ResourceDispatcherHost::Get()->SetDelegate(&stall_delegate
);
2293 GURL
url2(embedded_test_server()->GetURL(
2294 "/navigation_controller/simple_page_2.html"));
2295 controller
.LoadURL(url2
, Referrer(), ui::PAGE_TRANSITION_LINK
, std::string());
2297 // That should be the pending entry.
2298 NavigationEntryImpl
* entry
= controller
.GetPendingEntry();
2299 ASSERT_NE(nullptr, entry
);
2300 EXPECT_EQ(url2
, entry
->GetURL());
2302 // Loading a JavaScript URL shouldn't affect the ability to stop.
2304 FailureWatcher
watcher(root
);
2305 GURL
js("javascript:(function(){})()");
2306 controller
.LoadURL(js
, Referrer(), ui::PAGE_TRANSITION_LINK
, std::string());
2307 // This LoadURL ends up purging the pending entry, which is why this is
2309 EXPECT_EQ(nullptr, controller
.GetPendingEntry());
2310 shell()->web_contents()->Stop();
2314 ResourceDispatcherHost::Get()->SetDelegate(nullptr);
2318 class RenderProcessKilledObserver
: public WebContentsObserver
{
2320 RenderProcessKilledObserver(WebContents
* web_contents
)
2321 : WebContentsObserver(web_contents
) {}
2322 ~RenderProcessKilledObserver() override
{}
2324 void RenderProcessGone(base::TerminationStatus status
) override
{
2326 base::TerminationStatus::TERMINATION_STATUS_PROCESS_WAS_KILLED
);
2331 // This tests a race in ReloadOriginalRequest, where a cross-origin reload was
2332 // causing an in-flight replaceState to look like a cross-origin navigation,
2333 // even though it's in-page. (The reload should not modify the underlying last
2334 // committed entry.) Not crashing means that the test is successful.
2335 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
, ReloadOriginalRequest
) {
2336 GURL
original_url(embedded_test_server()->GetURL(
2337 "/navigation_controller/simple_page_1.html"));
2338 NavigateToURL(shell(), original_url
);
2339 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
2342 RenderProcessKilledObserver
kill_observer(shell()->web_contents());
2344 // Redirect so that we can use ReloadOriginalRequest.
2345 GURL
redirect_url(embedded_test_server()->GetURL(
2346 "foo.com", "/navigation_controller/simple_page_1.html"));
2348 std::string script
= "location.replace('" + redirect_url
.spec() + "');";
2349 FrameNavigateParamsCapturer
capturer(root
);
2350 EXPECT_TRUE(ExecuteScript(shell()->web_contents(), script
));
2352 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_CLIENT_REDIRECT
,
2353 capturer
.params().transition
);
2354 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
2357 // Modify an entry in the session history and reload the original request.
2359 // We first send a replaceState() to the renderer, which will cause the
2360 // renderer to send back a DidCommitProvisionalLoad. Immediately after,
2361 // we send a ReloadOriginalRequest (which in this case is a different
2362 // origin) and will also cause the renderer to commit the frame. In the
2363 // end we verify that both navigations committed and that the URLs are
2365 std::string script
= "history.replaceState({}, '', 'foo');";
2366 root
->render_manager()
2367 ->current_frame_host()
2368 ->ExecuteJavaScriptWithUserGestureForTests(base::UTF8ToUTF16(script
));
2369 EXPECT_FALSE(shell()->web_contents()->IsLoading());
2370 shell()->web_contents()->GetController().ReloadOriginalRequestURL(false);
2371 EXPECT_TRUE(shell()->web_contents()->IsLoading());
2372 EXPECT_EQ(redirect_url
, shell()->web_contents()->GetLastCommittedURL());
2374 // Wait until there's no more navigations.
2375 GURL
modified_url(embedded_test_server()->GetURL(
2376 "foo.com", "/navigation_controller/foo"));
2377 FrameNavigateParamsCapturer
capturer(root
);
2378 capturer
.set_wait_for_load(false);
2379 capturer
.set_navigations_remaining(2);
2381 EXPECT_EQ(2U, capturer
.all_details().size());
2382 EXPECT_EQ(modified_url
, capturer
.all_params()[0].url
);
2383 EXPECT_EQ(original_url
, capturer
.all_params()[1].url
);
2384 EXPECT_EQ(original_url
, shell()->web_contents()->GetLastCommittedURL());
2387 // Make sure the renderer is still alive.
2389 ExecuteScript(shell()->web_contents(), "console.log('Success');"));
2392 } // namespace content