1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 #include "base/command_line.h"
7 #include "base/strings/stringprintf.h"
8 #include "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/public/browser/render_view_host.h"
14 #include "content/public/browser/resource_controller.h"
15 #include "content/public/browser/resource_dispatcher_host.h"
16 #include "content/public/browser/resource_dispatcher_host_delegate.h"
17 #include "content/public/browser/resource_throttle.h"
18 #include "content/public/browser/web_contents.h"
19 #include "content/public/browser/web_contents_observer.h"
20 #include "content/public/common/bindings_policy.h"
21 #include "content/public/common/content_switches.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 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
, LoadDataWithBaseURL
) {
45 const GURL
base_url("http://baseurl");
46 const GURL
history_url("http://historyurl");
47 const std::string data
= "<html><body>foo</body></html>";
49 const NavigationController
& controller
=
50 shell()->web_contents()->GetController();
51 // Load data. Blocks until it is done.
52 content::LoadDataWithBaseURL(shell(), history_url
, data
, base_url
);
54 // We should use history_url instead of the base_url as the original url of
55 // this navigation entry, because base_url is only used for resolving relative
56 // paths in the data, or enforcing same origin policy.
57 EXPECT_EQ(controller
.GetVisibleEntry()->GetOriginalRequestURL(), history_url
);
60 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
, UniqueIDs
) {
61 const NavigationControllerImpl
& controller
=
62 static_cast<const NavigationControllerImpl
&>(
63 shell()->web_contents()->GetController());
65 GURL
main_url(embedded_test_server()->GetURL(
66 "/navigation_controller/page_with_link_to_load_iframe.html"));
67 NavigateToURL(shell(), main_url
);
68 ASSERT_EQ(1, controller
.GetEntryCount());
70 // Use JavaScript to click the link and load the iframe.
71 std::string script
= "document.getElementById('link').click()";
72 EXPECT_TRUE(content::ExecuteScript(shell()->web_contents(), script
));
73 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
74 ASSERT_EQ(2, controller
.GetEntryCount());
76 // Unique IDs should... um... be unique.
77 ASSERT_NE(controller
.GetEntryAtIndex(0)->GetUniqueID(),
78 controller
.GetEntryAtIndex(1)->GetUniqueID());
81 // The renderer uses the position in the history list as a clue to whether a
82 // navigation is stale. In the case where the entry limit is reached and the
83 // history list is pruned, make sure that there is no mismatch that would cause
84 // it to start incorrectly rejecting navigations as stale. See
85 // http://crbug.com/89798.
86 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
87 DontIgnoreBackAfterNavEntryLimit
) {
88 NavigationController
& controller
=
89 shell()->web_contents()->GetController();
91 const int kMaxEntryCount
=
92 static_cast<int>(NavigationControllerImpl::max_entry_count());
94 // Load up to the max count, all entries should be there.
95 for (int url_index
= 0; url_index
< kMaxEntryCount
; ++url_index
) {
96 GURL
url(base::StringPrintf("data:text/html,page%d", url_index
));
97 EXPECT_TRUE(NavigateToURL(shell(), url
));
100 EXPECT_EQ(controller
.GetEntryCount(), kMaxEntryCount
);
102 // Navigate twice more more.
103 for (int url_index
= kMaxEntryCount
;
104 url_index
< kMaxEntryCount
+ 2; ++url_index
) {
105 GURL
url(base::StringPrintf("data:text/html,page%d", url_index
));
106 EXPECT_TRUE(NavigateToURL(shell(), url
));
109 // We expect page0 and page1 to be gone.
110 EXPECT_EQ(kMaxEntryCount
, controller
.GetEntryCount());
111 EXPECT_EQ(GURL("data:text/html,page2"),
112 controller
.GetEntryAtIndex(0)->GetURL());
114 // Now try to go back. This should not hang.
115 ASSERT_TRUE(controller
.CanGoBack());
117 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
119 // This should have successfully gone back.
120 EXPECT_EQ(GURL(base::StringPrintf("data:text/html,page%d", kMaxEntryCount
)),
121 controller
.GetLastCommittedEntry()->GetURL());
126 int RendererHistoryLength(Shell
* shell
) {
128 EXPECT_TRUE(ExecuteScriptAndExtractInt(
129 shell
->web_contents(),
130 "domAutomationController.send(history.length)",
135 // Similar to the ones from content_browser_test_utils.
136 bool NavigateToURLAndReplace(Shell
* shell
, const GURL
& url
) {
137 WebContents
* web_contents
= shell
->web_contents();
138 WaitForLoadStop(web_contents
);
139 TestNavigationObserver
same_tab_observer(web_contents
, 1);
140 NavigationController::LoadURLParams
params(url
);
141 params
.should_replace_current_entry
= true;
142 web_contents
->GetController().LoadURLWithParams(params
);
143 web_contents
->Focus();
144 same_tab_observer
.Wait();
145 if (!IsLastCommittedEntryOfPageType(web_contents
, PAGE_TYPE_NORMAL
))
147 return web_contents
->GetLastCommittedURL() == url
;
152 // When loading a new page to replace an old page in the history list, make sure
153 // that the browser and renderer agree, and that both get it right.
154 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
155 CorrectLengthWithCurrentItemReplacement
) {
156 NavigationController
& controller
=
157 shell()->web_contents()->GetController();
159 EXPECT_TRUE(NavigateToURL(shell(), GURL("data:text/html,page1")));
160 EXPECT_EQ(1, controller
.GetEntryCount());
161 EXPECT_EQ(1, RendererHistoryLength(shell()));
163 EXPECT_TRUE(NavigateToURLAndReplace(shell(), GURL("data:text/html,page2")));
164 EXPECT_EQ(1, controller
.GetEntryCount());
165 EXPECT_EQ(1, RendererHistoryLength(shell()));
167 // Note that there's no way to access the renderer's notion of the history
168 // offset via JavaScript. Checking just the history length, though, is enough;
169 // if the replacement failed, there would be a new history entry and thus an
173 // When spawning a new page from a WebUI page, make sure that the browser and
174 // renderer agree about the length of the history list, and that both get it
176 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
177 CorrectLengthWithNewTabNavigatingFromWebUI
) {
178 GURL
web_ui_page(std::string(kChromeUIScheme
) + "://" +
179 std::string(kChromeUIGpuHost
));
180 EXPECT_TRUE(NavigateToURL(shell(), web_ui_page
));
181 EXPECT_EQ(BINDINGS_POLICY_WEB_UI
,
182 shell()->web_contents()->GetRenderViewHost()->GetEnabledBindings());
184 ShellAddedObserver observer
;
185 std::string page_url
= embedded_test_server()->GetURL(
186 "/navigation_controller/simple_page_1.html").spec();
187 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
188 "window.open('" + page_url
+ "', '_blank')"));
189 Shell
* shell2
= observer
.GetShell();
190 EXPECT_TRUE(WaitForLoadStop(shell2
->web_contents()));
192 EXPECT_EQ(1, shell2
->web_contents()->GetController().GetEntryCount());
193 EXPECT_EQ(1, RendererHistoryLength(shell2
));
195 // Again, as above, there's no way to access the renderer's notion of the
196 // history offset via JavaScript. Checking just the history length, again,
197 // will have to suffice.
202 class NoNavigationsObserver
: public WebContentsObserver
{
204 // Observes navigation for the specified |web_contents|.
205 explicit NoNavigationsObserver(WebContents
* web_contents
)
206 : WebContentsObserver(web_contents
) {}
209 void DidNavigateAnyFrame(RenderFrameHost
* render_frame_host
,
210 const LoadCommittedDetails
& details
,
211 const FrameNavigateParams
& params
) override
{
212 FAIL() << "No navigations should occur";
218 // Some pages create a popup, then write an iframe into it. This causes a
219 // subframe navigation without having any committed entry. Such navigations
220 // just get thrown on the ground, but we shouldn't crash.
222 // This test actually hits NAVIGATION_TYPE_NAV_IGNORE three times. Two of them,
223 // the initial window.open() and the iframe creation, don't try to create
224 // navigation entries, and the third, the new navigation, tries to.
225 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
, SubframeOnEmptyPage
) {
226 NavigateToURL(shell(), GURL(url::kAboutBlankURL
));
227 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
229 FrameTreeNode
* root
=
230 static_cast<WebContentsImpl
*>(shell()->web_contents())->
231 GetFrameTree()->root();
233 // Pop open a new window.
234 ShellAddedObserver new_shell_observer
;
235 std::string script
= "window.open()";
236 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
237 Shell
* new_shell
= new_shell_observer
.GetShell();
238 ASSERT_NE(new_shell
->web_contents(), shell()->web_contents());
239 FrameTreeNode
* new_root
=
240 static_cast<WebContentsImpl
*>(new_shell
->web_contents())->
241 GetFrameTree()->root();
243 // Make a new iframe in it.
244 NoNavigationsObserver
observer(new_shell
->web_contents());
245 script
= "var iframe = document.createElement('iframe');"
246 "iframe.src = 'data:text/html,<p>some page</p>';"
247 "document.body.appendChild(iframe);";
248 EXPECT_TRUE(content::ExecuteScript(new_root
->current_frame_host(), script
));
249 // The success check is of the last-committed entry, and there is none.
250 WaitForLoadStopWithoutSuccessCheck(new_shell
->web_contents());
252 ASSERT_EQ(1U, new_root
->child_count());
253 ASSERT_NE(nullptr, new_root
->child_at(0));
256 GURL frame_url
= embedded_test_server()->GetURL(
257 "/navigation_controller/simple_page_2.html");
258 script
= "location.assign('" + frame_url
.spec() + "')";
259 EXPECT_TRUE(content::ExecuteScript(
260 new_root
->child_at(0)->current_frame_host(), script
));
262 // Success is not crashing, and not navigating.
264 new_shell
->web_contents()->GetController().GetLastCommittedEntry());
269 class FrameNavigateParamsCapturer
: public WebContentsObserver
{
271 // Observes navigation for the specified |node|.
272 explicit FrameNavigateParamsCapturer(FrameTreeNode
* node
)
273 : WebContentsObserver(
274 node
->current_frame_host()->delegate()->GetAsWebContents()),
275 frame_tree_node_id_(node
->frame_tree_node_id()),
276 navigations_remaining_(1),
277 wait_for_load_(true),
278 message_loop_runner_(new MessageLoopRunner
) {}
280 void set_navigations_remaining(int count
) {
281 navigations_remaining_
= count
;
284 void set_wait_for_load(bool ignore
) {
285 wait_for_load_
= ignore
;
289 message_loop_runner_
->Run();
292 const FrameNavigateParams
& params() const {
293 EXPECT_EQ(1U, params_
.size());
297 const std::vector
<FrameNavigateParams
>& all_params() const {
301 const LoadCommittedDetails
& details() const {
302 EXPECT_EQ(1U, details_
.size());
306 const std::vector
<LoadCommittedDetails
>& all_details() const {
311 void DidNavigateAnyFrame(RenderFrameHost
* render_frame_host
,
312 const LoadCommittedDetails
& details
,
313 const FrameNavigateParams
& params
) override
{
314 RenderFrameHostImpl
* rfh
=
315 static_cast<RenderFrameHostImpl
*>(render_frame_host
);
316 if (rfh
->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_
)
319 --navigations_remaining_
;
320 params_
.push_back(params
);
321 details_
.push_back(details
);
322 if (!navigations_remaining_
&&
323 (!web_contents()->IsLoading() || !wait_for_load_
))
324 message_loop_runner_
->Quit();
327 void DidStopLoading() override
{
328 if (!navigations_remaining_
)
329 message_loop_runner_
->Quit();
332 // The id of the FrameTreeNode whose navigations to observe.
333 int frame_tree_node_id_
;
335 // How many navigations remain to capture.
336 int navigations_remaining_
;
338 // Whether to also wait for the load to complete.
341 // The params of the navigations.
342 std::vector
<FrameNavigateParams
> params_
;
344 // The details of the navigations.
345 std::vector
<LoadCommittedDetails
> details_
;
347 // The MessageLoopRunner used to spin the message loop.
348 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
351 class LoadCommittedCapturer
: public WebContentsObserver
{
353 // Observes the load commit for the specified |node|.
354 explicit LoadCommittedCapturer(FrameTreeNode
* node
)
355 : WebContentsObserver(
356 node
->current_frame_host()->delegate()->GetAsWebContents()),
357 frame_tree_node_id_(node
->frame_tree_node_id()),
358 message_loop_runner_(new MessageLoopRunner
) {}
360 // Observes the load commit for the next created frame in the specified
362 explicit LoadCommittedCapturer(WebContents
* web_contents
)
363 : WebContentsObserver(web_contents
),
364 frame_tree_node_id_(0),
365 message_loop_runner_(new MessageLoopRunner
) {}
368 message_loop_runner_
->Run();
371 ui::PageTransition
transition_type() const {
372 return transition_type_
;
376 void RenderFrameCreated(RenderFrameHost
* render_frame_host
) override
{
377 RenderFrameHostImpl
* rfh
=
378 static_cast<RenderFrameHostImpl
*>(render_frame_host
);
380 // Don't pay attention to swapped out RenderFrameHosts in the main frame.
381 // TODO(nasko): Remove once swappedout:// is gone.
382 // See https://crbug.com/357747.
383 if (!RenderFrameHostImpl::IsRFHStateActive(rfh
->rfh_state())) {
384 DLOG(INFO
) << "Skipping swapped out RFH: "
385 << rfh
->GetSiteInstance()->GetSiteURL();
389 // If this object was not created with a specified frame tree node, then use
390 // the first created active RenderFrameHost. Once a node is selected, there
391 // shouldn't be any other frames being created.
392 int frame_tree_node_id
= rfh
->frame_tree_node()->frame_tree_node_id();
393 DCHECK(frame_tree_node_id_
== 0 ||
394 frame_tree_node_id_
== frame_tree_node_id
);
395 frame_tree_node_id_
= frame_tree_node_id
;
398 void DidCommitProvisionalLoadForFrame(
399 RenderFrameHost
* render_frame_host
,
401 ui::PageTransition transition_type
) override
{
402 DCHECK_NE(0, frame_tree_node_id_
);
403 RenderFrameHostImpl
* rfh
=
404 static_cast<RenderFrameHostImpl
*>(render_frame_host
);
405 if (rfh
->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_
)
408 transition_type_
= transition_type
;
409 if (!web_contents()->IsLoading())
410 message_loop_runner_
->Quit();
413 void DidStopLoading() override
{ message_loop_runner_
->Quit(); }
415 // The id of the FrameTreeNode whose navigations to observe.
416 int frame_tree_node_id_
;
418 // The transition_type of the last navigation.
419 ui::PageTransition transition_type_
;
421 // The MessageLoopRunner used to spin the message loop.
422 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
427 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
428 ErrorPageReplacement
) {
429 NavigationController
& controller
= shell()->web_contents()->GetController();
431 net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_RESET
));
432 net::URLRequestFailedJob::AddUrlHandler();
434 NavigateToURL(shell(), GURL(url::kAboutBlankURL
));
435 EXPECT_EQ(1, controller
.GetEntryCount());
437 FrameTreeNode
* root
=
438 static_cast<WebContentsImpl
*>(shell()->web_contents())->
439 GetFrameTree()->root();
441 // Navigate to a page that fails to load. It must result in an error page, the
442 // NEW_PAGE navigation type, and an addition to the history list.
444 FrameNavigateParamsCapturer
capturer(root
);
445 NavigateFrameToURL(root
, error_url
);
447 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
448 NavigationEntry
* entry
= controller
.GetLastCommittedEntry();
449 EXPECT_EQ(PAGE_TYPE_ERROR
, entry
->GetPageType());
450 EXPECT_EQ(2, controller
.GetEntryCount());
453 // Navigate again to the page that fails to load. It must result in an error
454 // page, the EXISTING_PAGE navigation type, and no addition to the history
455 // list. We do not use SAME_PAGE here; that case only differs in that it
456 // clears the pending entry, and there is no pending entry after a load
459 FrameNavigateParamsCapturer
capturer(root
);
460 NavigateFrameToURL(root
, error_url
);
462 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
463 NavigationEntry
* entry
= controller
.GetLastCommittedEntry();
464 EXPECT_EQ(PAGE_TYPE_ERROR
, entry
->GetPageType());
465 EXPECT_EQ(2, controller
.GetEntryCount());
468 // Make a new entry ...
469 NavigateToURL(shell(), GURL(url::kAboutBlankURL
));
470 EXPECT_EQ(3, controller
.GetEntryCount());
472 // ... and replace it with a failed load. (Note that when you set the
473 // should_replace_current_entry flag, the navigation is classified as NEW_PAGE
474 // because that is a classification of the renderer's behavior, and the flag
475 // is a browser-side flag.)
477 FrameNavigateParamsCapturer
capturer(root
);
478 NavigateToURLAndReplace(shell(), error_url
);
480 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
481 NavigationEntry
* entry
= controller
.GetLastCommittedEntry();
482 EXPECT_EQ(PAGE_TYPE_ERROR
, entry
->GetPageType());
483 EXPECT_EQ(3, controller
.GetEntryCount());
486 // Make a new web ui page to force a process swap ...
487 GURL
web_ui_page(std::string(kChromeUIScheme
) + "://" +
488 std::string(kChromeUIGpuHost
));
489 NavigateToURL(shell(), web_ui_page
);
490 EXPECT_EQ(4, controller
.GetEntryCount());
492 // ... and replace it with a failed load. (It is NEW_PAGE for the reason noted
495 FrameNavigateParamsCapturer
capturer(root
);
496 NavigateToURLAndReplace(shell(), error_url
);
498 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
499 NavigationEntry
* entry
= controller
.GetLastCommittedEntry();
500 EXPECT_EQ(PAGE_TYPE_ERROR
, entry
->GetPageType());
501 EXPECT_EQ(4, controller
.GetEntryCount());
505 // Various tests for navigation type classifications. TODO(avi): It's rather
506 // bogus that the same info is in two different enums; http://crbug.com/453555.
508 // Verify that navigations for NAVIGATION_TYPE_NEW_PAGE are correctly
510 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
511 NavigationTypeClassification_NewPage
) {
512 NavigateToURL(shell(), GURL(url::kAboutBlankURL
));
514 FrameTreeNode
* root
=
515 static_cast<WebContentsImpl
*>(shell()->web_contents())->
516 GetFrameTree()->root();
520 FrameNavigateParamsCapturer
capturer(root
);
521 GURL
frame_url(embedded_test_server()->GetURL(
522 "/navigation_controller/page_with_links.html"));
523 NavigateFrameToURL(root
, frame_url
);
525 // TODO(avi,creis): Why is this (and quite a few others below) a "link"
526 // transition? Lots of these transitions should be cleaned up.
527 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
, capturer
.params().transition
);
528 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
532 // Load via a fragment link click.
533 FrameNavigateParamsCapturer
capturer(root
);
534 std::string script
= "document.getElementById('fraglink').click()";
535 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
537 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
, capturer
.params().transition
);
538 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
542 // Load via link click.
543 FrameNavigateParamsCapturer
capturer(root
);
544 std::string script
= "document.getElementById('thelink').click()";
545 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
547 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
, capturer
.params().transition
);
548 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
552 // location.assign().
553 FrameNavigateParamsCapturer
capturer(root
);
554 GURL
frame_url(embedded_test_server()->GetURL(
555 "/navigation_controller/simple_page_2.html"));
556 std::string script
= "location.assign('" + frame_url
.spec() + "')";
557 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
559 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_CLIENT_REDIRECT
,
560 capturer
.params().transition
);
561 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
565 // history.pushState().
566 FrameNavigateParamsCapturer
capturer(root
);
568 "history.pushState({}, 'page 1', 'simple_page_1.html')";
569 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
571 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_CLIENT_REDIRECT
,
572 capturer
.params().transition
);
573 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
577 // Verify that navigations for NAVIGATION_TYPE_EXISTING_PAGE are correctly
579 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
580 NavigationTypeClassification_ExistingPage
) {
581 GURL
url1(embedded_test_server()->GetURL(
582 "/navigation_controller/simple_page_1.html"));
583 NavigateToURL(shell(), url1
);
584 GURL
url2(embedded_test_server()->GetURL(
585 "/navigation_controller/simple_page_2.html"));
586 NavigateToURL(shell(), url2
);
588 FrameTreeNode
* root
=
589 static_cast<WebContentsImpl
*>(shell()->web_contents())->
590 GetFrameTree()->root();
593 // Back from the browser side.
594 FrameNavigateParamsCapturer
capturer(root
);
595 shell()->web_contents()->GetController().GoBack();
597 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
598 | ui::PAGE_TRANSITION_FORWARD_BACK
599 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
,
600 capturer
.params().transition
);
601 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
605 // Forward from the browser side.
606 FrameNavigateParamsCapturer
capturer(root
);
607 shell()->web_contents()->GetController().GoForward();
609 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
610 | ui::PAGE_TRANSITION_FORWARD_BACK
611 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
,
612 capturer
.params().transition
);
613 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
617 // Back from the renderer side.
618 FrameNavigateParamsCapturer
capturer(root
);
619 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(),
622 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
623 | ui::PAGE_TRANSITION_FORWARD_BACK
624 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
,
625 capturer
.params().transition
);
626 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
630 // Forward from the renderer side.
631 FrameNavigateParamsCapturer
capturer(root
);
632 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(),
633 "history.forward()"));
635 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
636 | ui::PAGE_TRANSITION_FORWARD_BACK
637 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
,
638 capturer
.params().transition
);
639 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
643 // Back from the renderer side via history.go().
644 FrameNavigateParamsCapturer
capturer(root
);
645 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(),
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
);
656 // Forward from the renderer side via history.go().
657 FrameNavigateParamsCapturer
capturer(root
);
658 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(),
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
);
669 // Reload from the browser side.
670 FrameNavigateParamsCapturer
capturer(root
);
671 shell()->web_contents()->GetController().Reload(false);
673 EXPECT_EQ(ui::PAGE_TRANSITION_RELOAD
, capturer
.params().transition
);
674 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
678 // Reload from the renderer side.
679 FrameNavigateParamsCapturer
capturer(root
);
680 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(),
681 "location.reload()"));
683 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_CLIENT_REDIRECT
,
684 capturer
.params().transition
);
685 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
689 // location.replace().
690 FrameNavigateParamsCapturer
capturer(root
);
691 GURL
frame_url(embedded_test_server()->GetURL(
692 "/navigation_controller/simple_page_1.html"));
693 std::string script
= "location.replace('" + frame_url
.spec() + "')";
694 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
696 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_CLIENT_REDIRECT
,
697 capturer
.params().transition
);
698 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
702 // Verify that navigations for NAVIGATION_TYPE_SAME_PAGE are correctly
704 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
705 NavigationTypeClassification_SamePage
) {
706 GURL
url1(embedded_test_server()->GetURL(
707 "/navigation_controller/simple_page_1.html"));
708 NavigateToURL(shell(), url1
);
710 FrameTreeNode
* root
=
711 static_cast<WebContentsImpl
*>(shell()->web_contents())->
712 GetFrameTree()->root();
716 FrameNavigateParamsCapturer
capturer(root
);
717 GURL
frame_url(embedded_test_server()->GetURL(
718 "/navigation_controller/simple_page_1.html"));
719 NavigateFrameToURL(root
, frame_url
);
721 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
, capturer
.params().transition
);
722 EXPECT_EQ(NAVIGATION_TYPE_SAME_PAGE
, capturer
.details().type
);
726 // Verify that navigations for NAVIGATION_TYPE_IN_PAGE are correctly
728 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
729 NavigationTypeClassification_InPage
) {
730 GURL
url1(embedded_test_server()->GetURL(
731 "/navigation_controller/simple_page_1.html"));
732 NavigateToURL(shell(), url1
);
734 FrameTreeNode
* root
=
735 static_cast<WebContentsImpl
*>(shell()->web_contents())->
736 GetFrameTree()->root();
739 // history.replaceState().
740 FrameNavigateParamsCapturer
capturer(root
);
742 "history.replaceState({}, 'page 1', 'simple_page_2.html')";
743 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
745 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
, capturer
.params().transition
);
746 EXPECT_EQ(NAVIGATION_TYPE_IN_PAGE
, capturer
.details().type
);
747 EXPECT_TRUE(capturer
.details().is_in_page
);
750 // Back and forward across a fragment navigation.
752 GURL
url2(embedded_test_server()->GetURL(
753 "/navigation_controller/page_with_links.html"));
754 NavigateToURL(shell(), url2
);
755 std::string script
= "document.getElementById('fraglink').click()";
756 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
757 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
761 FrameNavigateParamsCapturer
capturer(root
);
762 shell()->web_contents()->GetController().GoBack();
764 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
765 | ui::PAGE_TRANSITION_FORWARD_BACK
766 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
,
767 capturer
.params().transition
);
768 EXPECT_EQ(NAVIGATION_TYPE_IN_PAGE
, capturer
.details().type
);
769 EXPECT_TRUE(capturer
.details().is_in_page
);
774 FrameNavigateParamsCapturer
capturer(root
);
775 shell()->web_contents()->GetController().GoForward();
777 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_FORWARD_BACK
,
778 capturer
.params().transition
);
779 EXPECT_EQ(NAVIGATION_TYPE_IN_PAGE
, capturer
.details().type
);
780 EXPECT_TRUE(capturer
.details().is_in_page
);
783 // Back and forward across a pushState-created navigation.
785 NavigateToURL(shell(), url1
);
786 script
= "history.pushState({}, 'page 2', 'simple_page_2.html')";
787 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
788 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
792 FrameNavigateParamsCapturer
capturer(root
);
793 shell()->web_contents()->GetController().GoBack();
795 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
796 | ui::PAGE_TRANSITION_FORWARD_BACK
797 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
,
798 capturer
.params().transition
);
799 EXPECT_EQ(NAVIGATION_TYPE_IN_PAGE
, capturer
.details().type
);
800 EXPECT_TRUE(capturer
.details().is_in_page
);
805 FrameNavigateParamsCapturer
capturer(root
);
806 shell()->web_contents()->GetController().GoForward();
808 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_FORWARD_BACK
,
809 capturer
.params().transition
);
810 EXPECT_EQ(NAVIGATION_TYPE_IN_PAGE
, capturer
.details().type
);
811 EXPECT_TRUE(capturer
.details().is_in_page
);
815 // Verify that navigations for NAVIGATION_TYPE_NEW_SUBFRAME and
816 // NAVIGATION_TYPE_AUTO_SUBFRAME are properly classified.
817 // TODO(creis): Re-enable this test when https://crbug.com/498559 is fixed.
818 IN_PROC_BROWSER_TEST_F(
819 NavigationControllerBrowserTest
,
820 DISABLED_NavigationTypeClassification_NewAndAutoSubframe
) {
821 GURL
main_url(embedded_test_server()->GetURL(
822 "/navigation_controller/page_with_iframe.html"));
823 NavigateToURL(shell(), main_url
);
825 // It is safe to obtain the root frame tree node here, as it doesn't change.
826 FrameTreeNode
* root
=
827 static_cast<WebContentsImpl
*>(shell()->web_contents())->
828 GetFrameTree()->root();
830 ASSERT_EQ(1U, root
->child_count());
831 ASSERT_NE(nullptr, root
->child_at(0));
835 LoadCommittedCapturer
capturer(root
->child_at(0));
836 GURL
frame_url(embedded_test_server()->GetURL(
837 "/navigation_controller/simple_page_1.html"));
838 NavigateFrameToURL(root
->child_at(0), frame_url
);
840 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
845 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
846 GURL
frame_url(embedded_test_server()->GetURL(
847 "/navigation_controller/simple_page_2.html"));
848 NavigateFrameToURL(root
->child_at(0), frame_url
);
850 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
851 capturer
.params().transition
);
852 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
857 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
858 shell()->web_contents()->GetController().GoBack();
860 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.params().transition
);
861 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME
, capturer
.details().type
);
866 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
867 shell()->web_contents()->GetController().GoForward();
869 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.params().transition
);
870 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME
, capturer
.details().type
);
875 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
876 GURL
frame_url(embedded_test_server()->GetURL(
877 "/navigation_controller/page_with_links.html"));
878 NavigateFrameToURL(root
->child_at(0), frame_url
);
880 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
881 capturer
.params().transition
);
882 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
886 // Load via a fragment link click.
887 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
888 std::string script
= "document.getElementById('fraglink').click()";
889 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
892 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
893 capturer
.params().transition
);
894 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
898 // location.assign().
899 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
900 GURL
frame_url(embedded_test_server()->GetURL(
901 "/navigation_controller/simple_page_1.html"));
902 std::string script
= "location.assign('" + frame_url
.spec() + "')";
903 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
906 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
907 capturer
.params().transition
);
908 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
912 // location.replace().
913 LoadCommittedCapturer
capturer(root
->child_at(0));
914 GURL
frame_url(embedded_test_server()->GetURL(
915 "/navigation_controller/simple_page_2.html"));
916 std::string script
= "location.replace('" + frame_url
.spec() + "')";
917 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
920 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
924 // history.pushState().
925 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
927 "history.pushState({}, 'page 1', 'simple_page_1.html')";
928 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
931 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
932 capturer
.params().transition
);
933 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
937 // history.replaceState().
938 LoadCommittedCapturer
capturer(root
->child_at(0));
940 "history.replaceState({}, 'page 2', 'simple_page_2.html')";
941 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
944 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
949 LoadCommittedCapturer
capturer(root
->child_at(0));
950 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
951 "location.reload()"));
953 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
958 LoadCommittedCapturer
capturer(shell()->web_contents());
959 GURL
frame_url(embedded_test_server()->GetURL(
960 "/navigation_controller/simple_page_1.html"));
961 std::string script
= "var iframe = document.createElement('iframe');"
962 "iframe.src = '" + frame_url
.spec() + "';"
963 "document.body.appendChild(iframe);";
964 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
966 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
970 // Verify that navigations caused by client-side redirects are correctly
972 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
973 NavigationTypeClassification_ClientSideRedirect
) {
974 NavigateToURL(shell(), GURL(url::kAboutBlankURL
));
975 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
977 FrameTreeNode
* root
=
978 static_cast<WebContentsImpl
*>(shell()->web_contents())->
979 GetFrameTree()->root();
982 // Load the redirecting page.
983 FrameNavigateParamsCapturer
capturer(root
);
984 capturer
.set_navigations_remaining(2);
985 GURL
frame_url(embedded_test_server()->GetURL(
986 "/navigation_controller/client_redirect.html"));
987 NavigateFrameToURL(root
, frame_url
);
990 std::vector
<FrameNavigateParams
> params
= capturer
.all_params();
991 std::vector
<LoadCommittedDetails
> details
= capturer
.all_details();
992 ASSERT_EQ(2U, params
.size());
993 ASSERT_EQ(2U, details
.size());
994 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
, params
[0].transition
);
995 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, details
[0].type
);
996 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_CLIENT_REDIRECT
,
997 params
[1].transition
);
998 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, details
[1].type
);
1002 // Verify that the LoadCommittedDetails::is_in_page value is properly set for
1003 // non-IN_PAGE navigations. (It's tested for IN_PAGE navigations with the
1004 // NavigationTypeClassification_InPage test.)
1005 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1006 LoadCommittedDetails_IsInPage
) {
1007 GURL
links_url(embedded_test_server()->GetURL(
1008 "/navigation_controller/page_with_links.html"));
1009 NavigateToURL(shell(), links_url
);
1010 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1012 FrameTreeNode
* root
=
1013 static_cast<WebContentsImpl
*>(shell()->web_contents())->
1014 GetFrameTree()->root();
1017 // Do a fragment link click.
1018 FrameNavigateParamsCapturer
capturer(root
);
1019 std::string script
= "document.getElementById('fraglink').click()";
1020 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1022 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
, capturer
.params().transition
);
1023 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
1024 EXPECT_TRUE(capturer
.details().is_in_page
);
1028 // Do a non-fragment link click.
1029 FrameNavigateParamsCapturer
capturer(root
);
1030 std::string script
= "document.getElementById('thelink').click()";
1031 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1033 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
, capturer
.params().transition
);
1034 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
1035 EXPECT_FALSE(capturer
.details().is_in_page
);
1038 // Second verse, same as the first. (But in a subframe.)
1040 GURL
iframe_url(embedded_test_server()->GetURL(
1041 "/navigation_controller/page_with_iframe.html"));
1042 NavigateToURL(shell(), iframe_url
);
1044 root
= static_cast<WebContentsImpl
*>(shell()->web_contents())->
1045 GetFrameTree()->root();
1047 ASSERT_EQ(1U, root
->child_count());
1048 ASSERT_NE(nullptr, root
->child_at(0));
1050 NavigateFrameToURL(root
->child_at(0), links_url
);
1051 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1054 // Do a fragment link click.
1055 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1056 std::string script
= "document.getElementById('fraglink').click()";
1057 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
1060 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
1061 capturer
.params().transition
);
1062 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
1063 EXPECT_TRUE(capturer
.details().is_in_page
);
1067 // Do a non-fragment link click.
1068 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1069 std::string script
= "document.getElementById('thelink').click()";
1070 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
1073 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
1074 capturer
.params().transition
);
1075 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
1076 EXPECT_FALSE(capturer
.details().is_in_page
);
1080 // Verify the tree of FrameNavigationEntries after initial about:blank commits
1081 // in subframes, which should not count as real committed loads.
1082 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1083 FrameNavigationEntry_BlankAutoSubframe
) {
1084 GURL
main_url(embedded_test_server()->GetURL(
1085 "/navigation_controller/simple_page_1.html"));
1086 NavigateToURL(shell(), main_url
);
1087 const NavigationControllerImpl
& controller
=
1088 static_cast<const NavigationControllerImpl
&>(
1089 shell()->web_contents()->GetController());
1090 FrameTreeNode
* root
=
1091 static_cast<WebContentsImpl
*>(shell()->web_contents())->
1092 GetFrameTree()->root();
1094 // 1. Create a iframe with no URL.
1096 LoadCommittedCapturer
capturer(shell()->web_contents());
1097 std::string script
= "var iframe = document.createElement('iframe');"
1098 "document.body.appendChild(iframe);";
1099 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1101 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1104 // Check last committed NavigationEntry.
1105 EXPECT_EQ(1, controller
.GetEntryCount());
1106 NavigationEntryImpl
* entry
= controller
.GetLastCommittedEntry();
1107 EXPECT_EQ(main_url
, entry
->GetURL());
1108 FrameNavigationEntry
* root_entry
= entry
->root_node()->frame_entry
.get();
1109 EXPECT_EQ(main_url
, root_entry
->url());
1111 // Verify no subframe entries are created.
1112 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1113 EXPECT_FALSE(controller
.HasCommittedRealLoad(root
->child_at(0)));
1115 // 2. Create another iframe with an about:blank URL.
1117 LoadCommittedCapturer
capturer(shell()->web_contents());
1118 std::string script
= "var iframe = document.createElement('iframe');"
1119 "iframe.src = 'about:blank';"
1120 "document.body.appendChild(iframe);";
1121 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1123 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1126 // Check last committed NavigationEntry.
1127 EXPECT_EQ(1, controller
.GetEntryCount());
1128 EXPECT_EQ(entry
, controller
.GetLastCommittedEntry());
1130 // Verify no subframe entries are created.
1131 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1132 EXPECT_FALSE(controller
.HasCommittedRealLoad(root
->child_at(1)));
1134 // 3. A real same-site navigation in the first iframe should be AUTO.
1135 GURL
frame_url(embedded_test_server()->GetURL(
1136 "/navigation_controller/simple_page_1.html"));
1138 LoadCommittedCapturer
capturer(root
->child_at(0));
1139 std::string script
= "var frames = document.getElementsByTagName('iframe');"
1140 "frames[0].src = '" + frame_url
.spec() + "';";
1141 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1143 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1146 // Check last committed NavigationEntry.
1147 EXPECT_EQ(1, controller
.GetEntryCount());
1148 EXPECT_EQ(entry
, controller
.GetLastCommittedEntry());
1150 // Verify subframe entries if we're in --site-per-process mode.
1151 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1152 switches::kSitePerProcess
)) {
1153 // The entry should now have one subframe FrameNavigationEntry.
1154 ASSERT_EQ(1U, entry
->root_node()->children
.size());
1155 FrameNavigationEntry
* frame_entry
=
1156 entry
->root_node()->children
[0]->frame_entry
.get();
1157 EXPECT_EQ(frame_url
, frame_entry
->url());
1158 EXPECT_TRUE(controller
.HasCommittedRealLoad(root
->child_at(0)));
1159 EXPECT_FALSE(controller
.HasCommittedRealLoad(root
->child_at(1)));
1161 // There are no subframe FrameNavigationEntries by default.
1162 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1165 // 4. A real cross-site navigation in the second iframe should be AUTO.
1166 GURL
foo_url(embedded_test_server()->GetURL(
1167 "foo.com", "/navigation_controller/simple_page_2.html"));
1169 LoadCommittedCapturer
capturer(root
->child_at(1));
1170 std::string script
= "var frames = document.getElementsByTagName('iframe');"
1171 "frames[1].src = '" + foo_url
.spec() + "';";
1172 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1174 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1177 // Check last committed NavigationEntry.
1178 EXPECT_EQ(1, controller
.GetEntryCount());
1179 EXPECT_EQ(entry
, controller
.GetLastCommittedEntry());
1181 // Verify subframe entries if we're in --site-per-process mode.
1182 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1183 switches::kSitePerProcess
)) {
1184 // The entry should now have two subframe FrameNavigationEntries.
1185 ASSERT_EQ(2U, entry
->root_node()->children
.size());
1186 FrameNavigationEntry
* frame_entry
=
1187 entry
->root_node()->children
[1]->frame_entry
.get();
1188 EXPECT_EQ(foo_url
, frame_entry
->url());
1189 EXPECT_TRUE(controller
.HasCommittedRealLoad(root
->child_at(1)));
1191 // There are no subframe FrameNavigationEntries by default.
1192 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1195 // Check the end result of the frame tree.
1196 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1197 switches::kSitePerProcess
)) {
1198 FrameTreeVisualizer visualizer
;
1200 " Site A ------------ proxies for B\n"
1201 " |--Site A ------- proxies for B\n"
1202 " +--Site B ------- proxies for A\n"
1203 "Where A = http://127.0.0.1/\n"
1204 " B = http://foo.com/",
1205 visualizer
.DepictFrameTree(root
));
1209 // Verify the tree of FrameNavigationEntries after NAVIGATION_TYPE_AUTO_SUBFRAME
1211 // TODO(creis): Test updating entries for history auto subframe navigations.
1212 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1213 FrameNavigationEntry_AutoSubframe
) {
1214 GURL
main_url(embedded_test_server()->GetURL(
1215 "/navigation_controller/simple_page_1.html"));
1216 NavigateToURL(shell(), main_url
);
1217 const NavigationControllerImpl
& controller
=
1218 static_cast<const NavigationControllerImpl
&>(
1219 shell()->web_contents()->GetController());
1220 FrameTreeNode
* root
=
1221 static_cast<WebContentsImpl
*>(shell()->web_contents())->
1222 GetFrameTree()->root();
1224 // 1. Create a same-site iframe.
1225 GURL
frame_url(embedded_test_server()->GetURL(
1226 "/navigation_controller/simple_page_2.html"));
1228 LoadCommittedCapturer
capturer(shell()->web_contents());
1229 std::string script
= "var iframe = document.createElement('iframe');"
1230 "iframe.src = '" + frame_url
.spec() + "';"
1231 "document.body.appendChild(iframe);";
1232 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1234 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1237 // Check last committed NavigationEntry.
1238 EXPECT_EQ(1, controller
.GetEntryCount());
1239 NavigationEntryImpl
* entry
= controller
.GetLastCommittedEntry();
1240 EXPECT_EQ(main_url
, entry
->GetURL());
1241 FrameNavigationEntry
* root_entry
= entry
->root_node()->frame_entry
.get();
1242 EXPECT_EQ(main_url
, root_entry
->url());
1243 EXPECT_FALSE(controller
.GetPendingEntry());
1245 // Verify subframe entries if we're in --site-per-process mode.
1246 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1247 switches::kSitePerProcess
)) {
1248 // The entry should now have a subframe FrameNavigationEntry.
1249 ASSERT_EQ(1U, entry
->root_node()->children
.size());
1250 FrameNavigationEntry
* frame_entry
=
1251 entry
->root_node()->children
[0]->frame_entry
.get();
1252 EXPECT_EQ(frame_url
, frame_entry
->url());
1253 EXPECT_TRUE(controller
.HasCommittedRealLoad(root
->child_at(0)));
1255 // There are no subframe FrameNavigationEntries by default.
1256 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1259 // 2. Create a second, initially cross-site iframe.
1260 GURL
foo_url(embedded_test_server()->GetURL(
1261 "foo.com", "/navigation_controller/simple_page_1.html"));
1263 LoadCommittedCapturer
capturer(shell()->web_contents());
1264 std::string script
= "var iframe = document.createElement('iframe');"
1265 "iframe.src = '" + foo_url
.spec() + "';"
1266 "document.body.appendChild(iframe);";
1267 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1269 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1272 // The last committed NavigationEntry shouldn't have changed.
1273 EXPECT_EQ(1, controller
.GetEntryCount());
1274 entry
= controller
.GetLastCommittedEntry();
1275 EXPECT_EQ(main_url
, entry
->GetURL());
1276 root_entry
= entry
->root_node()->frame_entry
.get();
1277 EXPECT_EQ(main_url
, root_entry
->url());
1278 EXPECT_FALSE(controller
.GetPendingEntry());
1280 // Verify subframe entries if we're in --site-per-process mode.
1281 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1282 switches::kSitePerProcess
)) {
1283 // The entry should now have 2 subframe FrameNavigationEntries.
1284 ASSERT_EQ(2U, entry
->root_node()->children
.size());
1285 FrameNavigationEntry
* frame_entry
=
1286 entry
->root_node()->children
[1]->frame_entry
.get();
1287 EXPECT_EQ(foo_url
, frame_entry
->url());
1288 EXPECT_TRUE(controller
.HasCommittedRealLoad(root
->child_at(1)));
1290 // There are no subframe FrameNavigationEntries by default.
1291 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1294 // 3. Create a nested iframe in the second subframe.
1296 LoadCommittedCapturer
capturer(shell()->web_contents());
1297 std::string script
= "var iframe = document.createElement('iframe');"
1298 "iframe.src = '" + foo_url
.spec() + "';"
1299 "document.body.appendChild(iframe);";
1300 EXPECT_TRUE(content::ExecuteScript(root
->child_at(1)->current_frame_host(),
1303 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1306 // The last committed NavigationEntry shouldn't have changed.
1307 EXPECT_EQ(1, controller
.GetEntryCount());
1308 entry
= controller
.GetLastCommittedEntry();
1309 EXPECT_EQ(main_url
, entry
->GetURL());
1310 root_entry
= entry
->root_node()->frame_entry
.get();
1311 EXPECT_EQ(main_url
, root_entry
->url());
1313 // Verify subframe entries if we're in --site-per-process mode.
1314 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1315 switches::kSitePerProcess
)) {
1316 // The entry should now have 2 subframe FrameNavigationEntries.
1317 ASSERT_EQ(2U, entry
->root_node()->children
.size());
1318 ASSERT_EQ(1U, entry
->root_node()->children
[1]->children
.size());
1319 FrameNavigationEntry
* frame_entry
=
1320 entry
->root_node()->children
[1]->children
[0]->frame_entry
.get();
1321 EXPECT_EQ(foo_url
, frame_entry
->url());
1323 // There are no subframe FrameNavigationEntries by default.
1324 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1327 // TODO(creis): Add tests for another subframe on B, and for a subframe on A
1328 // within it. Both are currently broken.
1330 // Check the end result of the frame tree.
1331 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1332 switches::kSitePerProcess
)) {
1333 FrameTreeVisualizer visualizer
;
1335 " Site A ------------ proxies for B\n"
1336 " |--Site A ------- proxies for B\n"
1337 " +--Site B ------- proxies for A\n"
1338 " +--Site B -- proxies for A\n"
1339 "Where A = http://127.0.0.1/\n"
1340 " B = http://foo.com/",
1341 visualizer
.DepictFrameTree(root
));
1345 // Verify the tree of FrameNavigationEntries after NAVIGATION_TYPE_NEW_SUBFRAME
1347 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1348 FrameNavigationEntry_NewSubframe
) {
1349 GURL
main_url(embedded_test_server()->GetURL(
1350 "/navigation_controller/simple_page_1.html"));
1351 NavigateToURL(shell(), main_url
);
1352 FrameTreeNode
* root
=
1353 static_cast<WebContentsImpl
*>(shell()->web_contents())->
1354 GetFrameTree()->root();
1356 // 1. Create a same-site iframe.
1357 GURL
frame_url(embedded_test_server()->GetURL(
1358 "/navigation_controller/simple_page_2.html"));
1360 LoadCommittedCapturer
capturer(shell()->web_contents());
1361 std::string script
= "var iframe = document.createElement('iframe');"
1362 "iframe.src = '" + frame_url
.spec() + "';"
1363 "document.body.appendChild(iframe);";
1364 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1368 // 2. Navigate in the first subframe same-site.
1369 GURL
frame_url2(embedded_test_server()->GetURL(
1370 "/navigation_controller/page_with_links.html"));
1372 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1373 NavigateFrameToURL(root
->child_at(0), frame_url2
);
1375 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
1376 capturer
.params().transition
);
1377 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
1380 // 3. Create a second, initially cross-site iframe.
1381 GURL
foo_url(embedded_test_server()->GetURL(
1382 "foo.com", "/navigation_controller/simple_page_1.html"));
1384 LoadCommittedCapturer
capturer(shell()->web_contents());
1385 std::string script
= "var iframe = document.createElement('iframe');"
1386 "iframe.src = '" + foo_url
.spec() + "';"
1387 "document.body.appendChild(iframe);";
1388 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1392 // 4. Navigate in the second subframe cross-site.
1393 GURL
bar_url(embedded_test_server()->GetURL(
1394 "bar.com", "/navigation_controller/simple_page_1.html"));
1396 FrameNavigateParamsCapturer
capturer(root
->child_at(1));
1397 std::string script
= "var frames = document.getElementsByTagName('iframe');"
1398 "frames[1].src = '" + bar_url
.spec() + "';";
1399 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1401 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
1402 capturer
.params().transition
);
1403 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
1406 // TODO(creis): Expand this test once we clone FrameNavigationEntries for
1407 // NEW_SUBFRAME navigations.
1409 // Check the end result of the frame tree.
1410 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1411 switches::kSitePerProcess
)) {
1412 FrameTreeVisualizer visualizer
;
1414 " Site A ------------ proxies for B\n"
1415 " |--Site A ------- proxies for B\n"
1416 " +--Site B ------- proxies for A\n"
1417 "Where A = http://127.0.0.1/\n"
1418 " B = http://bar.com/",
1419 visualizer
.DepictFrameTree(root
));
1425 class HttpThrottle
: public ResourceThrottle
{
1428 void WillStartRequest(bool* defer
) override
{
1432 const char* GetNameForLogging() const override
{
1433 return "HttpThrottle";
1437 class StallDelegate
: public ResourceDispatcherHostDelegate
{
1438 // ResourceDispatcherHostDelegate
1439 void RequestBeginning(
1440 net::URLRequest
* request
,
1441 content::ResourceContext
* resource_context
,
1442 content::AppCacheService
* appcache_service
,
1443 ResourceType resource_type
,
1444 ScopedVector
<content::ResourceThrottle
>* throttles
) override
{
1445 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1446 throttles
->push_back(new HttpThrottle
);
1450 // Loads |start_url|, then loads |stalled_url| which stalls. While the page is
1451 // stalled, an in-page navigation happens. Make sure that all the navigations
1452 // are properly classified.
1453 void DoReplaceStateWhilePending(Shell
* shell
,
1454 const GURL
& start_url
,
1455 const GURL
& stalled_url
,
1456 const std::string
& replace_state_filename
) {
1457 NavigationControllerImpl
& controller
=
1458 static_cast<NavigationControllerImpl
&>(
1459 shell
->web_contents()->GetController());
1461 FrameTreeNode
* root
=
1462 static_cast<WebContentsImpl
*>(shell
->web_contents())->
1463 GetFrameTree()->root();
1465 // Start with one page.
1466 EXPECT_TRUE(NavigateToURL(shell
, start_url
));
1468 // Have the user decide to go to a different page which is very slow.
1469 StallDelegate stall_delegate
;
1470 ResourceDispatcherHost::Get()->SetDelegate(&stall_delegate
);
1472 stalled_url
, Referrer(), ui::PAGE_TRANSITION_LINK
, std::string());
1474 // That should be the pending entry.
1475 NavigationEntryImpl
* entry
= controller
.GetPendingEntry();
1476 ASSERT_NE(nullptr, entry
);
1477 EXPECT_EQ(stalled_url
, entry
->GetURL());
1480 // Now the existing page uses history.replaceState().
1481 FrameNavigateParamsCapturer
capturer(root
);
1482 capturer
.set_wait_for_load(false);
1483 std::string script
=
1484 "history.replaceState({}, '', '" + replace_state_filename
+ "')";
1485 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1488 // The fact that there was a pending entry shouldn't interfere with the
1490 EXPECT_EQ(NAVIGATION_TYPE_IN_PAGE
, capturer
.details().type
);
1493 ResourceDispatcherHost::Get()->SetDelegate(nullptr);
1498 IN_PROC_BROWSER_TEST_F(
1499 NavigationControllerBrowserTest
,
1500 NavigationTypeClassification_On1InPageToXWhile2Pending
) {
1501 GURL
url1(embedded_test_server()->GetURL(
1502 "/navigation_controller/simple_page_1.html"));
1503 GURL
url2(embedded_test_server()->GetURL(
1504 "/navigation_controller/simple_page_2.html"));
1505 DoReplaceStateWhilePending(shell(), url1
, url2
, "x");
1508 IN_PROC_BROWSER_TEST_F(
1509 NavigationControllerBrowserTest
,
1510 NavigationTypeClassification_On1InPageTo2While2Pending
) {
1511 GURL
url1(embedded_test_server()->GetURL(
1512 "/navigation_controller/simple_page_1.html"));
1513 GURL
url2(embedded_test_server()->GetURL(
1514 "/navigation_controller/simple_page_2.html"));
1515 DoReplaceStateWhilePending(shell(), url1
, url2
, "simple_page_2.html");
1518 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1519 NavigationTypeClassification_On1InPageToXWhile1Pending
) {
1520 GURL
url(embedded_test_server()->GetURL(
1521 "/navigation_controller/simple_page_1.html"));
1522 DoReplaceStateWhilePending(shell(), url
, url
, "x");
1525 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1526 NavigationTypeClassification_On1InPageTo1While1Pending
) {
1527 GURL
url(embedded_test_server()->GetURL(
1528 "/navigation_controller/simple_page_1.html"));
1529 DoReplaceStateWhilePending(shell(), url
, url
, "simple_page_1.html");
1532 // Ensure the renderer process does not get confused about the current entry
1533 // due to subframes and replaced entries. See https://crbug.com/480201.
1534 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1535 PreventSpoofFromSubframeAndReplace
) {
1536 // Start at an initial URL.
1537 GURL
url1(embedded_test_server()->GetURL(
1538 "/navigation_controller/simple_page_1.html"));
1539 NavigateToURL(shell(), url1
);
1541 // Now go to a page with a real iframe.
1542 GURL
url2(embedded_test_server()->GetURL(
1543 "/navigation_controller/page_with_data_iframe.html"));
1544 NavigateToURL(shell(), url2
);
1546 // It is safe to obtain the root frame tree node here, as it doesn't change.
1547 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1550 ASSERT_EQ(1U, root
->child_count());
1551 ASSERT_NE(nullptr, root
->child_at(0));
1554 // Navigate in the iframe.
1555 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1556 GURL
frame_url(embedded_test_server()->GetURL(
1557 "/navigation_controller/simple_page_2.html"));
1558 NavigateFrameToURL(root
->child_at(0), frame_url
);
1560 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
1564 // Go back in the iframe.
1565 TestNavigationObserver
back_load_observer(shell()->web_contents());
1566 shell()->web_contents()->GetController().GoBack();
1567 back_load_observer
.Wait();
1571 // Go forward in the iframe.
1572 TestNavigationObserver
forward_load_observer(shell()->web_contents());
1573 shell()->web_contents()->GetController().GoForward();
1574 forward_load_observer
.Wait();
1577 GURL
url3(embedded_test_server()->GetURL(
1578 "/navigation_controller/page_with_iframe.html"));
1580 // location.replace() to cause an inert commit.
1581 TestNavigationObserver
replace_load_observer(shell()->web_contents());
1582 std::string script
= "location.replace('" + url3
.spec() + "')";
1583 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1584 replace_load_observer
.Wait();
1589 TestNavigationObserver
back_load_observer(shell()->web_contents());
1590 shell()->web_contents()->GetController().GoBack();
1591 back_load_observer
.Wait();
1593 // Make sure the URL is correct for both the entry and the main frame, and
1594 // that the process hasn't been killed for showing a spoof.
1595 EXPECT_TRUE(root
->current_frame_host()->IsRenderFrameLive());
1596 EXPECT_EQ(url2
, shell()->web_contents()->GetLastCommittedURL());
1597 EXPECT_EQ(url2
, root
->current_url());
1601 // Go back to reset main frame entirely.
1602 TestNavigationObserver
back_load_observer(shell()->web_contents());
1603 shell()->web_contents()->GetController().GoBack();
1604 back_load_observer
.Wait();
1605 EXPECT_EQ(url1
, shell()->web_contents()->GetLastCommittedURL());
1606 EXPECT_EQ(url1
, root
->current_url());
1611 TestNavigationObserver
back_load_observer(shell()->web_contents());
1612 shell()->web_contents()->GetController().GoForward();
1613 back_load_observer
.Wait();
1614 EXPECT_EQ(url2
, shell()->web_contents()->GetLastCommittedURL());
1615 EXPECT_EQ(url2
, root
->current_url());
1619 // Go forward to the replaced URL.
1620 TestNavigationObserver
forward_load_observer(shell()->web_contents());
1621 shell()->web_contents()->GetController().GoForward();
1622 forward_load_observer
.Wait();
1624 // Make sure the URL is correct for both the entry and the main frame, and
1625 // that the process hasn't been killed for showing a spoof.
1626 EXPECT_TRUE(root
->current_frame_host()->IsRenderFrameLive());
1627 EXPECT_EQ(url3
, shell()->web_contents()->GetLastCommittedURL());
1628 EXPECT_EQ(url3
, root
->current_url());
1632 // Ensure the renderer process does not get killed if the main frame URL's path
1633 // changes when going back in a subframe, since this is currently possible after
1634 // a replaceState in the main frame (thanks to https://crbug.com/373041).
1635 // See https:///crbug.com/486916.
1636 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1637 SubframeBackFromReplaceState
) {
1638 // Start at a page with a real iframe.
1639 GURL
url1(embedded_test_server()->GetURL(
1640 "/navigation_controller/page_with_data_iframe.html"));
1641 NavigateToURL(shell(), url1
);
1643 // It is safe to obtain the root frame tree node here, as it doesn't change.
1644 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1647 ASSERT_EQ(1U, root
->child_count());
1648 ASSERT_NE(nullptr, root
->child_at(0));
1651 // Navigate in the iframe.
1652 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1653 GURL
frame_url(embedded_test_server()->GetURL(
1654 "/navigation_controller/simple_page_2.html"));
1655 NavigateFrameToURL(root
->child_at(0), frame_url
);
1657 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
1661 // history.replaceState().
1662 FrameNavigateParamsCapturer
capturer(root
);
1663 std::string script
=
1664 "history.replaceState({}, 'replaced', 'replaced')";
1665 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1670 // Go back in the iframe.
1671 TestNavigationObserver
back_load_observer(shell()->web_contents());
1672 shell()->web_contents()->GetController().GoBack();
1673 back_load_observer
.Wait();
1676 // For now, we expect the main frame's URL to revert. This won't happen once
1677 // https://crbug.com/373041 is fixed.
1678 EXPECT_EQ(url1
, shell()->web_contents()->GetLastCommittedURL());
1680 // Make sure the renderer process has not been killed.
1681 EXPECT_TRUE(root
->current_frame_host()->IsRenderFrameLive());
1686 class FailureWatcher
: public WebContentsObserver
{
1688 // Observes failure for the specified |node|.
1689 explicit FailureWatcher(FrameTreeNode
* node
)
1690 : WebContentsObserver(
1691 node
->current_frame_host()->delegate()->GetAsWebContents()),
1692 frame_tree_node_id_(node
->frame_tree_node_id()),
1693 message_loop_runner_(new MessageLoopRunner
) {}
1696 message_loop_runner_
->Run();
1700 void DidFailLoad(RenderFrameHost
* render_frame_host
,
1701 const GURL
& validated_url
,
1703 const base::string16
& error_description
) override
{
1704 RenderFrameHostImpl
* rfh
=
1705 static_cast<RenderFrameHostImpl
*>(render_frame_host
);
1706 if (rfh
->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_
)
1709 message_loop_runner_
->Quit();
1712 void DidFailProvisionalLoad(
1713 RenderFrameHost
* render_frame_host
,
1714 const GURL
& validated_url
,
1716 const base::string16
& error_description
) override
{
1717 RenderFrameHostImpl
* rfh
=
1718 static_cast<RenderFrameHostImpl
*>(render_frame_host
);
1719 if (rfh
->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_
)
1722 message_loop_runner_
->Quit();
1725 // The id of the FrameTreeNode whose navigations to observe.
1726 int frame_tree_node_id_
;
1728 // The MessageLoopRunner used to spin the message loop.
1729 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
1734 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1735 StopCausesFailureDespiteJavaScriptURL
) {
1736 NavigationControllerImpl
& controller
=
1737 static_cast<NavigationControllerImpl
&>(
1738 shell()->web_contents()->GetController());
1740 FrameTreeNode
* root
=
1741 static_cast<WebContentsImpl
*>(shell()->web_contents())->
1742 GetFrameTree()->root();
1744 // Start with a normal page.
1745 GURL
url1(embedded_test_server()->GetURL(
1746 "/navigation_controller/simple_page_1.html"));
1747 EXPECT_TRUE(NavigateToURL(shell(), url1
));
1749 // Have the user decide to go to a different page which is very slow.
1750 StallDelegate stall_delegate
;
1751 ResourceDispatcherHost::Get()->SetDelegate(&stall_delegate
);
1752 GURL
url2(embedded_test_server()->GetURL(
1753 "/navigation_controller/simple_page_2.html"));
1754 controller
.LoadURL(url2
, Referrer(), ui::PAGE_TRANSITION_LINK
, std::string());
1756 // That should be the pending entry.
1757 NavigationEntryImpl
* entry
= controller
.GetPendingEntry();
1758 ASSERT_NE(nullptr, entry
);
1759 EXPECT_EQ(url2
, entry
->GetURL());
1761 // Loading a JavaScript URL shouldn't affect the ability to stop.
1763 FailureWatcher
watcher(root
);
1764 GURL
js("javascript:(function(){})()");
1765 controller
.LoadURL(js
, Referrer(), ui::PAGE_TRANSITION_LINK
, std::string());
1766 // This LoadURL ends up purging the pending entry, which is why this is
1768 EXPECT_EQ(nullptr, controller
.GetPendingEntry());
1769 shell()->web_contents()->Stop();
1773 ResourceDispatcherHost::Get()->SetDelegate(nullptr);
1776 } // namespace content