1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 #include "base/command_line.h"
7 #include "base/strings/stringprintf.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "content/browser/frame_host/frame_navigation_entry.h"
10 #include "content/browser/frame_host/frame_tree.h"
11 #include "content/browser/frame_host/navigation_controller_impl.h"
12 #include "content/browser/frame_host/navigation_entry_impl.h"
13 #include "content/browser/web_contents/web_contents_impl.h"
14 #include "content/public/browser/render_view_host.h"
15 #include "content/public/browser/resource_controller.h"
16 #include "content/public/browser/resource_dispatcher_host.h"
17 #include "content/public/browser/resource_dispatcher_host_delegate.h"
18 #include "content/public/browser/resource_throttle.h"
19 #include "content/public/browser/web_contents.h"
20 #include "content/public/browser/web_contents_observer.h"
21 #include "content/public/common/bindings_policy.h"
22 #include "content/public/common/content_switches.h"
23 #include "content/public/common/url_constants.h"
24 #include "content/public/test/browser_test_utils.h"
25 #include "content/public/test/content_browser_test.h"
26 #include "content/public/test/content_browser_test_utils.h"
27 #include "content/public/test/test_navigation_observer.h"
28 #include "content/public/test/test_utils.h"
29 #include "content/shell/browser/shell.h"
30 #include "content/test/content_browser_test_utils_internal.h"
31 #include "net/dns/mock_host_resolver.h"
32 #include "net/test/embedded_test_server/embedded_test_server.h"
33 #include "net/test/url_request/url_request_failed_job.h"
37 class NavigationControllerBrowserTest
: public ContentBrowserTest
{
39 void SetUpOnMainThread() override
{
40 host_resolver()->AddRule("*", "127.0.0.1");
41 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
45 // Ensure that tests can navigate subframes cross-site in both default mode and
46 // --site-per-process, but that they only go cross-process in the latter.
47 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
, LoadCrossSiteSubframe
) {
48 // Load a main frame with a subframe.
49 GURL
main_url(embedded_test_server()->GetURL(
50 "/navigation_controller/page_with_iframe.html"));
51 NavigateToURL(shell(), main_url
);
52 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
55 ASSERT_EQ(1U, root
->child_count());
56 ASSERT_NE(nullptr, root
->child_at(0));
58 // Use NavigateFrameToURL to go cross-site in the subframe.
59 GURL
foo_url(embedded_test_server()->GetURL(
60 "foo.com", "/navigation_controller/simple_page_1.html"));
61 NavigateFrameToURL(root
->child_at(0), foo_url
);
62 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
64 // We should only have swapped processes in --site-per-process.
65 bool cross_process
= root
->current_frame_host()->GetProcess() !=
66 root
->child_at(0)->current_frame_host()->GetProcess();
67 EXPECT_EQ(base::CommandLine::ForCurrentProcess()->HasSwitch(
68 switches::kSitePerProcess
),
72 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
, LoadDataWithBaseURL
) {
73 const GURL
base_url("http://baseurl");
74 const GURL
history_url("http://historyurl");
75 const std::string data
= "<html><body>foo</body></html>";
77 const NavigationController
& controller
=
78 shell()->web_contents()->GetController();
79 // Load data. Blocks until it is done.
80 content::LoadDataWithBaseURL(shell(), history_url
, data
, base_url
);
82 // We should use history_url instead of the base_url as the original url of
83 // this navigation entry, because base_url is only used for resolving relative
84 // paths in the data, or enforcing same origin policy.
85 EXPECT_EQ(controller
.GetVisibleEntry()->GetOriginalRequestURL(), history_url
);
88 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
, UniqueIDs
) {
89 const NavigationControllerImpl
& controller
=
90 static_cast<const NavigationControllerImpl
&>(
91 shell()->web_contents()->GetController());
93 GURL
main_url(embedded_test_server()->GetURL(
94 "/navigation_controller/page_with_link_to_load_iframe.html"));
95 NavigateToURL(shell(), main_url
);
96 ASSERT_EQ(1, controller
.GetEntryCount());
98 // Use JavaScript to click the link and load the iframe.
99 std::string script
= "document.getElementById('link').click()";
100 EXPECT_TRUE(content::ExecuteScript(shell()->web_contents(), script
));
101 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
102 ASSERT_EQ(2, controller
.GetEntryCount());
104 // Unique IDs should... um... be unique.
105 ASSERT_NE(controller
.GetEntryAtIndex(0)->GetUniqueID(),
106 controller
.GetEntryAtIndex(1)->GetUniqueID());
109 // This test used to make sure that a scheme used to prevent spoofs didn't ever
110 // interfere with navigations. We switched to a different scheme, so now this is
111 // just a test to make sure we can still navigate once we prune the history
113 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
114 DontIgnoreBackAfterNavEntryLimit
) {
115 NavigationController
& controller
=
116 shell()->web_contents()->GetController();
118 const int kMaxEntryCount
=
119 static_cast<int>(NavigationControllerImpl::max_entry_count());
121 // Load up to the max count, all entries should be there.
122 for (int url_index
= 0; url_index
< kMaxEntryCount
; ++url_index
) {
123 GURL
url(base::StringPrintf("data:text/html,page%d", url_index
));
124 EXPECT_TRUE(NavigateToURL(shell(), url
));
127 EXPECT_EQ(controller
.GetEntryCount(), kMaxEntryCount
);
129 // Navigate twice more more.
130 for (int url_index
= kMaxEntryCount
;
131 url_index
< kMaxEntryCount
+ 2; ++url_index
) {
132 GURL
url(base::StringPrintf("data:text/html,page%d", url_index
));
133 EXPECT_TRUE(NavigateToURL(shell(), url
));
136 // We expect page0 and page1 to be gone.
137 EXPECT_EQ(kMaxEntryCount
, controller
.GetEntryCount());
138 EXPECT_EQ(GURL("data:text/html,page2"),
139 controller
.GetEntryAtIndex(0)->GetURL());
141 // Now try to go back. This should not hang.
142 ASSERT_TRUE(controller
.CanGoBack());
144 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
146 // This should have successfully gone back.
147 EXPECT_EQ(GURL(base::StringPrintf("data:text/html,page%d", kMaxEntryCount
)),
148 controller
.GetLastCommittedEntry()->GetURL());
153 int RendererHistoryLength(Shell
* shell
) {
155 EXPECT_TRUE(ExecuteScriptAndExtractInt(
156 shell
->web_contents(),
157 "domAutomationController.send(history.length)",
162 // Similar to the ones from content_browser_test_utils.
163 bool NavigateToURLAndReplace(Shell
* shell
, const GURL
& url
) {
164 WebContents
* web_contents
= shell
->web_contents();
165 WaitForLoadStop(web_contents
);
166 TestNavigationObserver
same_tab_observer(web_contents
, 1);
167 NavigationController::LoadURLParams
params(url
);
168 params
.should_replace_current_entry
= true;
169 web_contents
->GetController().LoadURLWithParams(params
);
170 web_contents
->Focus();
171 same_tab_observer
.Wait();
172 if (!IsLastCommittedEntryOfPageType(web_contents
, PAGE_TYPE_NORMAL
))
174 return web_contents
->GetLastCommittedURL() == url
;
179 // When loading a new page to replace an old page in the history list, make sure
180 // that the browser and renderer agree, and that both get it right.
181 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
182 CorrectLengthWithCurrentItemReplacement
) {
183 NavigationController
& controller
=
184 shell()->web_contents()->GetController();
186 EXPECT_TRUE(NavigateToURL(shell(), GURL("data:text/html,page1")));
187 EXPECT_EQ(1, controller
.GetEntryCount());
188 EXPECT_EQ(1, RendererHistoryLength(shell()));
190 EXPECT_TRUE(NavigateToURLAndReplace(shell(), GURL("data:text/html,page1a")));
191 EXPECT_EQ(1, controller
.GetEntryCount());
192 EXPECT_EQ(1, RendererHistoryLength(shell()));
194 // Now create two more entries and go back, to test replacing an entry without
195 // pruning the forward history.
196 EXPECT_TRUE(NavigateToURL(shell(), GURL("data:text/html,page2")));
197 EXPECT_EQ(2, controller
.GetEntryCount());
198 EXPECT_EQ(2, RendererHistoryLength(shell()));
200 EXPECT_TRUE(NavigateToURL(shell(), GURL("data:text/html,page3")));
201 EXPECT_EQ(3, controller
.GetEntryCount());
202 EXPECT_EQ(3, RendererHistoryLength(shell()));
205 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
207 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
208 EXPECT_TRUE(controller
.CanGoForward());
210 EXPECT_TRUE(NavigateToURLAndReplace(shell(), GURL("data:text/html,page1b")));
211 EXPECT_EQ(3, controller
.GetEntryCount());
212 EXPECT_EQ(3, RendererHistoryLength(shell()));
213 EXPECT_TRUE(controller
.CanGoForward());
215 // Note that there's no way to access the renderer's notion of the history
216 // offset via JavaScript. Checking just the history length, though, is enough;
217 // if the replacement failed, there would be a new history entry and thus an
221 // When spawning a new page from a WebUI page, make sure that the browser and
222 // renderer agree about the length of the history list, and that both get it
224 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
225 CorrectLengthWithNewTabNavigatingFromWebUI
) {
226 GURL
web_ui_page(std::string(kChromeUIScheme
) + "://" +
227 std::string(kChromeUIGpuHost
));
228 EXPECT_TRUE(NavigateToURL(shell(), web_ui_page
));
229 EXPECT_EQ(BINDINGS_POLICY_WEB_UI
,
230 shell()->web_contents()->GetRenderViewHost()->GetEnabledBindings());
232 ShellAddedObserver observer
;
233 std::string page_url
= embedded_test_server()->GetURL(
234 "/navigation_controller/simple_page_1.html").spec();
235 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
236 "window.open('" + page_url
+ "', '_blank')"));
237 Shell
* shell2
= observer
.GetShell();
238 EXPECT_TRUE(WaitForLoadStop(shell2
->web_contents()));
240 EXPECT_EQ(1, shell2
->web_contents()->GetController().GetEntryCount());
241 EXPECT_EQ(1, RendererHistoryLength(shell2
));
243 // Again, as above, there's no way to access the renderer's notion of the
244 // history offset via JavaScript. Checking just the history length, again,
245 // will have to suffice.
250 class NoNavigationsObserver
: public WebContentsObserver
{
252 // Observes navigation for the specified |web_contents|.
253 explicit NoNavigationsObserver(WebContents
* web_contents
)
254 : WebContentsObserver(web_contents
) {}
257 void DidNavigateAnyFrame(RenderFrameHost
* render_frame_host
,
258 const LoadCommittedDetails
& details
,
259 const FrameNavigateParams
& params
) override
{
260 FAIL() << "No navigations should occur";
266 // Some pages create a popup, then write an iframe into it. This causes a
267 // subframe navigation without having any committed entry. Such navigations
268 // just get thrown on the ground, but we shouldn't crash.
270 // This test actually hits NAVIGATION_TYPE_NAV_IGNORE three times. Two of them,
271 // the initial window.open() and the iframe creation, don't try to create
272 // navigation entries, and the third, the new navigation, tries to.
273 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
, SubframeOnEmptyPage
) {
274 NavigateToURL(shell(), GURL(url::kAboutBlankURL
));
275 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
277 FrameTreeNode
* root
=
278 static_cast<WebContentsImpl
*>(shell()->web_contents())->
279 GetFrameTree()->root();
281 // Pop open a new window.
282 ShellAddedObserver new_shell_observer
;
283 std::string script
= "window.open()";
284 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
285 Shell
* new_shell
= new_shell_observer
.GetShell();
286 ASSERT_NE(new_shell
->web_contents(), shell()->web_contents());
287 FrameTreeNode
* new_root
=
288 static_cast<WebContentsImpl
*>(new_shell
->web_contents())->
289 GetFrameTree()->root();
291 // Make a new iframe in it.
292 NoNavigationsObserver
observer(new_shell
->web_contents());
293 script
= "var iframe = document.createElement('iframe');"
294 "iframe.src = 'data:text/html,<p>some page</p>';"
295 "document.body.appendChild(iframe);";
296 EXPECT_TRUE(content::ExecuteScript(new_root
->current_frame_host(), script
));
297 // The success check is of the last-committed entry, and there is none.
298 WaitForLoadStopWithoutSuccessCheck(new_shell
->web_contents());
300 ASSERT_EQ(1U, new_root
->child_count());
301 ASSERT_NE(nullptr, new_root
->child_at(0));
304 GURL frame_url
= embedded_test_server()->GetURL(
305 "/navigation_controller/simple_page_2.html");
306 script
= "location.assign('" + frame_url
.spec() + "')";
307 EXPECT_TRUE(content::ExecuteScript(
308 new_root
->child_at(0)->current_frame_host(), script
));
310 // Success is not crashing, and not navigating.
312 new_shell
->web_contents()->GetController().GetLastCommittedEntry());
317 class FrameNavigateParamsCapturer
: public WebContentsObserver
{
319 // Observes navigation for the specified |node|.
320 explicit FrameNavigateParamsCapturer(FrameTreeNode
* node
)
321 : WebContentsObserver(
322 node
->current_frame_host()->delegate()->GetAsWebContents()),
323 frame_tree_node_id_(node
->frame_tree_node_id()),
324 navigations_remaining_(1),
325 wait_for_load_(true),
326 message_loop_runner_(new MessageLoopRunner
) {}
328 void set_navigations_remaining(int count
) {
329 navigations_remaining_
= count
;
332 void set_wait_for_load(bool ignore
) {
333 wait_for_load_
= ignore
;
337 message_loop_runner_
->Run();
340 const FrameNavigateParams
& params() const {
341 EXPECT_EQ(1U, params_
.size());
345 const std::vector
<FrameNavigateParams
>& all_params() const {
349 const LoadCommittedDetails
& details() const {
350 EXPECT_EQ(1U, details_
.size());
354 const std::vector
<LoadCommittedDetails
>& all_details() const {
359 void DidNavigateAnyFrame(RenderFrameHost
* render_frame_host
,
360 const LoadCommittedDetails
& details
,
361 const FrameNavigateParams
& params
) override
{
362 RenderFrameHostImpl
* rfh
=
363 static_cast<RenderFrameHostImpl
*>(render_frame_host
);
364 if (rfh
->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_
)
367 --navigations_remaining_
;
368 params_
.push_back(params
);
369 details_
.push_back(details
);
370 if (!navigations_remaining_
&&
371 (!web_contents()->IsLoading() || !wait_for_load_
))
372 message_loop_runner_
->Quit();
375 void DidStopLoading() override
{
376 if (!navigations_remaining_
)
377 message_loop_runner_
->Quit();
380 // The id of the FrameTreeNode whose navigations to observe.
381 int frame_tree_node_id_
;
383 // How many navigations remain to capture.
384 int navigations_remaining_
;
386 // Whether to also wait for the load to complete.
389 // The params of the navigations.
390 std::vector
<FrameNavigateParams
> params_
;
392 // The details of the navigations.
393 std::vector
<LoadCommittedDetails
> details_
;
395 // The MessageLoopRunner used to spin the message loop.
396 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
399 class LoadCommittedCapturer
: public WebContentsObserver
{
401 // Observes the load commit for the specified |node|.
402 explicit LoadCommittedCapturer(FrameTreeNode
* node
)
403 : WebContentsObserver(
404 node
->current_frame_host()->delegate()->GetAsWebContents()),
405 frame_tree_node_id_(node
->frame_tree_node_id()),
406 message_loop_runner_(new MessageLoopRunner
) {}
408 // Observes the load commit for the next created frame in the specified
410 explicit LoadCommittedCapturer(WebContents
* web_contents
)
411 : WebContentsObserver(web_contents
),
412 frame_tree_node_id_(0),
413 message_loop_runner_(new MessageLoopRunner
) {}
416 message_loop_runner_
->Run();
419 ui::PageTransition
transition_type() const {
420 return transition_type_
;
424 void RenderFrameCreated(RenderFrameHost
* render_frame_host
) override
{
425 RenderFrameHostImpl
* rfh
=
426 static_cast<RenderFrameHostImpl
*>(render_frame_host
);
428 // Don't pay attention to swapped out RenderFrameHosts in the main frame.
429 // TODO(nasko): Remove once swappedout:// is gone.
430 // See https://crbug.com/357747.
431 if (!RenderFrameHostImpl::IsRFHStateActive(rfh
->rfh_state())) {
432 DLOG(INFO
) << "Skipping swapped out RFH: "
433 << rfh
->GetSiteInstance()->GetSiteURL();
437 // If this object was not created with a specified frame tree node, then use
438 // the first created active RenderFrameHost. Once a node is selected, there
439 // shouldn't be any other frames being created.
440 int frame_tree_node_id
= rfh
->frame_tree_node()->frame_tree_node_id();
441 DCHECK(frame_tree_node_id_
== 0 ||
442 frame_tree_node_id_
== frame_tree_node_id
);
443 frame_tree_node_id_
= frame_tree_node_id
;
446 void DidCommitProvisionalLoadForFrame(
447 RenderFrameHost
* render_frame_host
,
449 ui::PageTransition transition_type
) override
{
450 DCHECK_NE(0, frame_tree_node_id_
);
451 RenderFrameHostImpl
* rfh
=
452 static_cast<RenderFrameHostImpl
*>(render_frame_host
);
453 if (rfh
->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_
)
456 transition_type_
= transition_type
;
457 if (!web_contents()->IsLoading())
458 message_loop_runner_
->Quit();
461 void DidStopLoading() override
{ message_loop_runner_
->Quit(); }
463 // The id of the FrameTreeNode whose navigations to observe.
464 int frame_tree_node_id_
;
466 // The transition_type of the last navigation.
467 ui::PageTransition transition_type_
;
469 // The MessageLoopRunner used to spin the message loop.
470 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
475 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
476 ErrorPageReplacement
) {
477 NavigationController
& controller
= shell()->web_contents()->GetController();
479 net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_RESET
));
480 net::URLRequestFailedJob::AddUrlHandler();
482 NavigateToURL(shell(), GURL(url::kAboutBlankURL
));
483 EXPECT_EQ(1, controller
.GetEntryCount());
485 FrameTreeNode
* root
=
486 static_cast<WebContentsImpl
*>(shell()->web_contents())->
487 GetFrameTree()->root();
489 // Navigate to a page that fails to load. It must result in an error page, the
490 // NEW_PAGE navigation type, and an addition to the history list.
492 FrameNavigateParamsCapturer
capturer(root
);
493 NavigateFrameToURL(root
, error_url
);
495 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
496 NavigationEntry
* entry
= controller
.GetLastCommittedEntry();
497 EXPECT_EQ(PAGE_TYPE_ERROR
, entry
->GetPageType());
498 EXPECT_EQ(2, controller
.GetEntryCount());
501 // Navigate again to the page that fails to load. It must result in an error
502 // page, the EXISTING_PAGE navigation type, and no addition to the history
503 // list. We do not use SAME_PAGE here; that case only differs in that it
504 // clears the pending entry, and there is no pending entry after a load
507 FrameNavigateParamsCapturer
capturer(root
);
508 NavigateFrameToURL(root
, error_url
);
510 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
511 NavigationEntry
* entry
= controller
.GetLastCommittedEntry();
512 EXPECT_EQ(PAGE_TYPE_ERROR
, entry
->GetPageType());
513 EXPECT_EQ(2, controller
.GetEntryCount());
516 // Make a new entry ...
517 NavigateToURL(shell(), GURL(url::kAboutBlankURL
));
518 EXPECT_EQ(3, controller
.GetEntryCount());
520 // ... and replace it with a failed load. (Note that when you set the
521 // should_replace_current_entry flag, the navigation is classified as NEW_PAGE
522 // because that is a classification of the renderer's behavior, and the flag
523 // is a browser-side flag.)
525 FrameNavigateParamsCapturer
capturer(root
);
526 NavigateToURLAndReplace(shell(), error_url
);
528 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
529 NavigationEntry
* entry
= controller
.GetLastCommittedEntry();
530 EXPECT_EQ(PAGE_TYPE_ERROR
, entry
->GetPageType());
531 EXPECT_EQ(3, controller
.GetEntryCount());
534 // Make a new web ui page to force a process swap ...
535 GURL
web_ui_page(std::string(kChromeUIScheme
) + "://" +
536 std::string(kChromeUIGpuHost
));
537 NavigateToURL(shell(), web_ui_page
);
538 EXPECT_EQ(4, controller
.GetEntryCount());
540 // ... and replace it with a failed load. (It is NEW_PAGE for the reason noted
543 FrameNavigateParamsCapturer
capturer(root
);
544 NavigateToURLAndReplace(shell(), error_url
);
546 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
547 NavigationEntry
* entry
= controller
.GetLastCommittedEntry();
548 EXPECT_EQ(PAGE_TYPE_ERROR
, entry
->GetPageType());
549 EXPECT_EQ(4, controller
.GetEntryCount());
553 // Various tests for navigation type classifications. TODO(avi): It's rather
554 // bogus that the same info is in two different enums; http://crbug.com/453555.
556 // Verify that navigations for NAVIGATION_TYPE_NEW_PAGE are correctly
558 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
559 NavigationTypeClassification_NewPage
) {
560 NavigateToURL(shell(), GURL(url::kAboutBlankURL
));
562 FrameTreeNode
* root
=
563 static_cast<WebContentsImpl
*>(shell()->web_contents())->
564 GetFrameTree()->root();
568 FrameNavigateParamsCapturer
capturer(root
);
569 GURL
frame_url(embedded_test_server()->GetURL(
570 "/navigation_controller/page_with_links.html"));
571 NavigateFrameToURL(root
, frame_url
);
573 // TODO(avi,creis): Why is this (and quite a few others below) a "link"
574 // transition? Lots of these transitions should be cleaned up.
575 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
, capturer
.params().transition
);
576 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
577 EXPECT_FALSE(capturer
.details().is_in_page
);
581 // Load via a fragment link click.
582 FrameNavigateParamsCapturer
capturer(root
);
583 std::string script
= "document.getElementById('fraglink').click()";
584 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
586 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
, capturer
.params().transition
);
587 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
588 EXPECT_TRUE(capturer
.details().is_in_page
);
592 // Load via link click.
593 FrameNavigateParamsCapturer
capturer(root
);
594 std::string script
= "document.getElementById('thelink').click()";
595 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
597 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
, capturer
.params().transition
);
598 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
599 EXPECT_FALSE(capturer
.details().is_in_page
);
603 // location.assign().
604 FrameNavigateParamsCapturer
capturer(root
);
605 GURL
frame_url(embedded_test_server()->GetURL(
606 "/navigation_controller/simple_page_2.html"));
607 std::string script
= "location.assign('" + frame_url
.spec() + "')";
608 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
610 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_CLIENT_REDIRECT
,
611 capturer
.params().transition
);
612 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
613 EXPECT_FALSE(capturer
.details().is_in_page
);
617 // history.pushState().
618 FrameNavigateParamsCapturer
capturer(root
);
620 "history.pushState({}, 'page 1', 'simple_page_1.html')";
621 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
623 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_CLIENT_REDIRECT
,
624 capturer
.params().transition
);
625 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
626 EXPECT_TRUE(capturer
.details().is_in_page
);
630 // Verify that navigations for NAVIGATION_TYPE_EXISTING_PAGE are correctly
632 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
633 NavigationTypeClassification_ExistingPage
) {
634 GURL
url1(embedded_test_server()->GetURL(
635 "/navigation_controller/simple_page_1.html"));
636 NavigateToURL(shell(), url1
);
637 GURL
url2(embedded_test_server()->GetURL(
638 "/navigation_controller/simple_page_2.html"));
639 NavigateToURL(shell(), url2
);
641 FrameTreeNode
* root
=
642 static_cast<WebContentsImpl
*>(shell()->web_contents())->
643 GetFrameTree()->root();
646 // Back from the browser side.
647 FrameNavigateParamsCapturer
capturer(root
);
648 shell()->web_contents()->GetController().GoBack();
650 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
651 | ui::PAGE_TRANSITION_FORWARD_BACK
652 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
,
653 capturer
.params().transition
);
654 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
655 EXPECT_FALSE(capturer
.details().is_in_page
);
659 // Forward from the browser side.
660 FrameNavigateParamsCapturer
capturer(root
);
661 shell()->web_contents()->GetController().GoForward();
663 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
664 | ui::PAGE_TRANSITION_FORWARD_BACK
665 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
,
666 capturer
.params().transition
);
667 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
668 EXPECT_FALSE(capturer
.details().is_in_page
);
672 // Back from the renderer side.
673 FrameNavigateParamsCapturer
capturer(root
);
674 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(),
677 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
678 | ui::PAGE_TRANSITION_FORWARD_BACK
679 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
,
680 capturer
.params().transition
);
681 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
682 EXPECT_FALSE(capturer
.details().is_in_page
);
686 // Forward from the renderer side.
687 FrameNavigateParamsCapturer
capturer(root
);
688 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(),
689 "history.forward()"));
691 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
692 | ui::PAGE_TRANSITION_FORWARD_BACK
693 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
,
694 capturer
.params().transition
);
695 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
696 EXPECT_FALSE(capturer
.details().is_in_page
);
700 // Back from the renderer side via history.go().
701 FrameNavigateParamsCapturer
capturer(root
);
702 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(),
705 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
706 | ui::PAGE_TRANSITION_FORWARD_BACK
707 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
,
708 capturer
.params().transition
);
709 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
710 EXPECT_FALSE(capturer
.details().is_in_page
);
714 // Forward from the renderer side via history.go().
715 FrameNavigateParamsCapturer
capturer(root
);
716 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(),
719 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
720 | ui::PAGE_TRANSITION_FORWARD_BACK
721 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
,
722 capturer
.params().transition
);
723 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
724 EXPECT_FALSE(capturer
.details().is_in_page
);
728 // Reload from the browser side.
729 FrameNavigateParamsCapturer
capturer(root
);
730 shell()->web_contents()->GetController().Reload(false);
732 EXPECT_EQ(ui::PAGE_TRANSITION_RELOAD
, capturer
.params().transition
);
733 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
734 EXPECT_FALSE(capturer
.details().is_in_page
);
738 // Reload from the renderer side.
739 FrameNavigateParamsCapturer
capturer(root
);
740 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(),
741 "location.reload()"));
743 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_CLIENT_REDIRECT
,
744 capturer
.params().transition
);
745 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
746 EXPECT_FALSE(capturer
.details().is_in_page
);
750 // location.replace().
751 FrameNavigateParamsCapturer
capturer(root
);
752 GURL
frame_url(embedded_test_server()->GetURL(
753 "/navigation_controller/simple_page_1.html"));
754 std::string script
= "location.replace('" + frame_url
.spec() + "')";
755 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
757 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_CLIENT_REDIRECT
,
758 capturer
.params().transition
);
759 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
760 EXPECT_FALSE(capturer
.details().is_in_page
);
763 // Now, various in-page navigations.
766 // history.replaceState().
767 FrameNavigateParamsCapturer
capturer(root
);
769 "history.replaceState({}, 'page 2', 'simple_page_2.html')";
770 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
772 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_CLIENT_REDIRECT
,
773 capturer
.params().transition
);
774 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
775 EXPECT_TRUE(capturer
.details().is_in_page
);
778 // Back and forward across a fragment navigation.
780 GURL
url_links(embedded_test_server()->GetURL(
781 "/navigation_controller/page_with_links.html"));
782 NavigateToURL(shell(), url_links
);
783 std::string script
= "document.getElementById('fraglink').click()";
784 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
785 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
789 FrameNavigateParamsCapturer
capturer(root
);
790 shell()->web_contents()->GetController().GoBack();
792 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
793 | ui::PAGE_TRANSITION_FORWARD_BACK
794 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
,
795 capturer
.params().transition
);
796 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
797 EXPECT_TRUE(capturer
.details().is_in_page
);
802 FrameNavigateParamsCapturer
capturer(root
);
803 shell()->web_contents()->GetController().GoForward();
805 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_FORWARD_BACK
,
806 capturer
.params().transition
);
807 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
808 EXPECT_TRUE(capturer
.details().is_in_page
);
811 // Back and forward across a pushState-created navigation.
813 NavigateToURL(shell(), url1
);
814 script
= "history.pushState({}, 'page 2', 'simple_page_2.html')";
815 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
816 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
820 FrameNavigateParamsCapturer
capturer(root
);
821 shell()->web_contents()->GetController().GoBack();
823 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
824 | ui::PAGE_TRANSITION_FORWARD_BACK
825 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
,
826 capturer
.params().transition
);
827 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
828 EXPECT_TRUE(capturer
.details().is_in_page
);
833 FrameNavigateParamsCapturer
capturer(root
);
834 shell()->web_contents()->GetController().GoForward();
836 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_FORWARD_BACK
,
837 capturer
.params().transition
);
838 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
839 EXPECT_TRUE(capturer
.details().is_in_page
);
843 // Verify that navigations for NAVIGATION_TYPE_SAME_PAGE are correctly
845 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
846 NavigationTypeClassification_SamePage
) {
847 GURL
url1(embedded_test_server()->GetURL(
848 "/navigation_controller/simple_page_1.html"));
849 NavigateToURL(shell(), url1
);
851 FrameTreeNode
* root
=
852 static_cast<WebContentsImpl
*>(shell()->web_contents())->
853 GetFrameTree()->root();
857 FrameNavigateParamsCapturer
capturer(root
);
858 GURL
frame_url(embedded_test_server()->GetURL(
859 "/navigation_controller/simple_page_1.html"));
860 NavigateFrameToURL(root
, frame_url
);
862 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
, capturer
.params().transition
);
863 EXPECT_EQ(NAVIGATION_TYPE_SAME_PAGE
, capturer
.details().type
);
867 // Verify that navigations for NAVIGATION_TYPE_NEW_SUBFRAME and
868 // NAVIGATION_TYPE_AUTO_SUBFRAME are properly classified.
869 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
870 NavigationTypeClassification_NewAndAutoSubframe
) {
871 GURL
main_url(embedded_test_server()->GetURL(
872 "/navigation_controller/page_with_iframe.html"));
873 NavigateToURL(shell(), main_url
);
875 // It is safe to obtain the root frame tree node here, as it doesn't change.
876 FrameTreeNode
* root
=
877 static_cast<WebContentsImpl
*>(shell()->web_contents())->
878 GetFrameTree()->root();
880 ASSERT_EQ(1U, root
->child_count());
881 ASSERT_NE(nullptr, root
->child_at(0));
885 LoadCommittedCapturer
capturer(root
->child_at(0));
886 GURL
frame_url(embedded_test_server()->GetURL(
887 "/navigation_controller/simple_page_1.html"));
888 NavigateFrameToURL(root
->child_at(0), frame_url
);
890 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
895 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
896 GURL
frame_url(embedded_test_server()->GetURL(
897 "/navigation_controller/simple_page_2.html"));
898 NavigateFrameToURL(root
->child_at(0), frame_url
);
900 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
901 capturer
.params().transition
);
902 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
907 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
908 shell()->web_contents()->GetController().GoBack();
910 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.params().transition
);
911 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME
, capturer
.details().type
);
916 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
917 shell()->web_contents()->GetController().GoForward();
919 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.params().transition
);
920 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME
, capturer
.details().type
);
925 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
926 GURL
frame_url(embedded_test_server()->GetURL(
927 "/navigation_controller/page_with_links.html"));
928 NavigateFrameToURL(root
->child_at(0), frame_url
);
930 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
931 capturer
.params().transition
);
932 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
936 // Load via a fragment link click.
937 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
938 std::string script
= "document.getElementById('fraglink').click()";
939 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
942 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
943 capturer
.params().transition
);
944 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
948 // location.assign().
949 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
950 GURL
frame_url(embedded_test_server()->GetURL(
951 "/navigation_controller/simple_page_1.html"));
952 std::string script
= "location.assign('" + frame_url
.spec() + "')";
953 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
956 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
957 capturer
.params().transition
);
958 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
962 // location.replace().
963 LoadCommittedCapturer
capturer(root
->child_at(0));
964 GURL
frame_url(embedded_test_server()->GetURL(
965 "/navigation_controller/simple_page_2.html"));
966 std::string script
= "location.replace('" + frame_url
.spec() + "')";
967 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
970 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
974 // history.pushState().
975 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
977 "history.pushState({}, 'page 1', 'simple_page_1.html')";
978 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
981 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
982 capturer
.params().transition
);
983 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
987 // history.replaceState().
988 LoadCommittedCapturer
capturer(root
->child_at(0));
990 "history.replaceState({}, 'page 2', 'simple_page_2.html')";
991 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
994 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
999 LoadCommittedCapturer
capturer(root
->child_at(0));
1000 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
1001 "location.reload()"));
1003 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1007 // Create an iframe.
1008 LoadCommittedCapturer
capturer(shell()->web_contents());
1009 GURL
frame_url(embedded_test_server()->GetURL(
1010 "/navigation_controller/simple_page_1.html"));
1011 std::string script
= "var iframe = document.createElement('iframe');"
1012 "iframe.src = '" + frame_url
.spec() + "';"
1013 "document.body.appendChild(iframe);";
1014 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1016 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1020 // Verify that navigations caused by client-side redirects are correctly
1022 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1023 NavigationTypeClassification_ClientSideRedirect
) {
1024 NavigateToURL(shell(), GURL(url::kAboutBlankURL
));
1025 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1027 FrameTreeNode
* root
=
1028 static_cast<WebContentsImpl
*>(shell()->web_contents())->
1029 GetFrameTree()->root();
1032 // Load the redirecting page.
1033 FrameNavigateParamsCapturer
capturer(root
);
1034 capturer
.set_navigations_remaining(2);
1035 GURL
frame_url(embedded_test_server()->GetURL(
1036 "/navigation_controller/client_redirect.html"));
1037 NavigateFrameToURL(root
, frame_url
);
1040 std::vector
<FrameNavigateParams
> params
= capturer
.all_params();
1041 std::vector
<LoadCommittedDetails
> details
= capturer
.all_details();
1042 ASSERT_EQ(2U, params
.size());
1043 ASSERT_EQ(2U, details
.size());
1044 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
, params
[0].transition
);
1045 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, details
[0].type
);
1046 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_CLIENT_REDIRECT
,
1047 params
[1].transition
);
1048 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, details
[1].type
);
1052 // Verify that the LoadCommittedDetails::is_in_page value is properly set for
1053 // non-IN_PAGE navigations. (It's tested for IN_PAGE navigations with the
1054 // NavigationTypeClassification_InPage test.)
1055 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1056 LoadCommittedDetails_IsInPage
) {
1057 GURL
links_url(embedded_test_server()->GetURL(
1058 "/navigation_controller/page_with_links.html"));
1059 NavigateToURL(shell(), links_url
);
1060 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1062 FrameTreeNode
* root
=
1063 static_cast<WebContentsImpl
*>(shell()->web_contents())->
1064 GetFrameTree()->root();
1067 // Do a fragment link click.
1068 FrameNavigateParamsCapturer
capturer(root
);
1069 std::string script
= "document.getElementById('fraglink').click()";
1070 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1072 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
, capturer
.params().transition
);
1073 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
1074 EXPECT_TRUE(capturer
.details().is_in_page
);
1078 // Do a non-fragment link click.
1079 FrameNavigateParamsCapturer
capturer(root
);
1080 std::string script
= "document.getElementById('thelink').click()";
1081 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1083 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
, capturer
.params().transition
);
1084 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE
, capturer
.details().type
);
1085 EXPECT_FALSE(capturer
.details().is_in_page
);
1088 // Second verse, same as the first. (But in a subframe.)
1090 GURL
iframe_url(embedded_test_server()->GetURL(
1091 "/navigation_controller/page_with_iframe.html"));
1092 NavigateToURL(shell(), iframe_url
);
1094 root
= static_cast<WebContentsImpl
*>(shell()->web_contents())->
1095 GetFrameTree()->root();
1097 ASSERT_EQ(1U, root
->child_count());
1098 ASSERT_NE(nullptr, root
->child_at(0));
1100 NavigateFrameToURL(root
->child_at(0), links_url
);
1101 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1104 // Do a fragment link click.
1105 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1106 std::string script
= "document.getElementById('fraglink').click()";
1107 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
1110 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
1111 capturer
.params().transition
);
1112 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
1113 EXPECT_TRUE(capturer
.details().is_in_page
);
1117 // Do a non-fragment link click.
1118 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1119 std::string script
= "document.getElementById('thelink').click()";
1120 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
1123 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
1124 capturer
.params().transition
);
1125 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
1126 EXPECT_FALSE(capturer
.details().is_in_page
);
1130 // Verify the tree of FrameNavigationEntries after initial about:blank commits
1131 // in subframes, which should not count as real committed loads.
1132 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1133 FrameNavigationEntry_BlankAutoSubframe
) {
1134 GURL
main_url(embedded_test_server()->GetURL(
1135 "/navigation_controller/simple_page_1.html"));
1136 NavigateToURL(shell(), main_url
);
1137 const NavigationControllerImpl
& controller
=
1138 static_cast<const NavigationControllerImpl
&>(
1139 shell()->web_contents()->GetController());
1140 FrameTreeNode
* root
=
1141 static_cast<WebContentsImpl
*>(shell()->web_contents())->
1142 GetFrameTree()->root();
1144 // 1. Create a iframe with no URL.
1146 LoadCommittedCapturer
capturer(shell()->web_contents());
1147 std::string script
= "var iframe = document.createElement('iframe');"
1148 "document.body.appendChild(iframe);";
1149 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1151 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1154 // Check last committed NavigationEntry.
1155 EXPECT_EQ(1, controller
.GetEntryCount());
1156 NavigationEntryImpl
* entry
= controller
.GetLastCommittedEntry();
1157 EXPECT_EQ(main_url
, entry
->GetURL());
1158 FrameNavigationEntry
* root_entry
= entry
->root_node()->frame_entry
.get();
1159 EXPECT_EQ(main_url
, root_entry
->url());
1161 // Verify no subframe entries are created.
1162 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1163 EXPECT_FALSE(controller
.HasCommittedRealLoad(root
->child_at(0)));
1165 // 1a. A nested iframe with no URL should also create no subframe entries.
1167 LoadCommittedCapturer
capturer(shell()->web_contents());
1168 std::string script
= "var iframe = document.createElement('iframe');"
1169 "document.body.appendChild(iframe);";
1170 EXPECT_TRUE(content::ExecuteScript(root
->child_at(0)->current_frame_host(),
1173 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1175 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1176 EXPECT_FALSE(controller
.HasCommittedRealLoad(root
->child_at(0)->child_at(0)));
1178 // 2. Create another iframe with an about:blank URL.
1180 LoadCommittedCapturer
capturer(shell()->web_contents());
1181 std::string script
= "var iframe = document.createElement('iframe');"
1182 "iframe.src = 'about:blank';"
1183 "document.body.appendChild(iframe);";
1184 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1186 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1189 // Check last committed NavigationEntry.
1190 EXPECT_EQ(1, controller
.GetEntryCount());
1191 EXPECT_EQ(entry
, controller
.GetLastCommittedEntry());
1193 // Verify no subframe entries are created.
1194 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1195 EXPECT_FALSE(controller
.HasCommittedRealLoad(root
->child_at(1)));
1197 // 3. A real same-site navigation in the first iframe should be AUTO.
1198 GURL
frame_url(embedded_test_server()->GetURL(
1199 "/navigation_controller/simple_page_1.html"));
1201 LoadCommittedCapturer
capturer(root
->child_at(0));
1202 std::string script
= "var frames = document.getElementsByTagName('iframe');"
1203 "frames[0].src = '" + frame_url
.spec() + "';";
1204 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1206 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1209 // Check last committed NavigationEntry.
1210 EXPECT_EQ(1, controller
.GetEntryCount());
1211 EXPECT_EQ(entry
, controller
.GetLastCommittedEntry());
1213 // Verify subframe entries if we're in --site-per-process mode.
1214 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1215 switches::kSitePerProcess
)) {
1216 // The entry should now have one subframe FrameNavigationEntry.
1217 ASSERT_EQ(1U, entry
->root_node()->children
.size());
1218 FrameNavigationEntry
* frame_entry
=
1219 entry
->root_node()->children
[0]->frame_entry
.get();
1220 EXPECT_EQ(frame_url
, frame_entry
->url());
1221 EXPECT_TRUE(controller
.HasCommittedRealLoad(root
->child_at(0)));
1222 EXPECT_FALSE(controller
.HasCommittedRealLoad(root
->child_at(1)));
1224 // There are no subframe FrameNavigationEntries by default.
1225 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1228 // 4. A real cross-site navigation in the second iframe should be AUTO.
1229 GURL
foo_url(embedded_test_server()->GetURL(
1230 "foo.com", "/navigation_controller/simple_page_2.html"));
1232 LoadCommittedCapturer
capturer(root
->child_at(1));
1233 std::string script
= "var frames = document.getElementsByTagName('iframe');"
1234 "frames[1].src = '" + foo_url
.spec() + "';";
1235 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1237 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1240 // Check last committed NavigationEntry.
1241 EXPECT_EQ(1, controller
.GetEntryCount());
1242 EXPECT_EQ(entry
, controller
.GetLastCommittedEntry());
1244 // Verify subframe entries if we're in --site-per-process mode.
1245 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1246 switches::kSitePerProcess
)) {
1247 // The entry should now have two subframe FrameNavigationEntries.
1248 ASSERT_EQ(2U, entry
->root_node()->children
.size());
1249 FrameNavigationEntry
* frame_entry
=
1250 entry
->root_node()->children
[1]->frame_entry
.get();
1251 EXPECT_EQ(foo_url
, frame_entry
->url());
1252 EXPECT_TRUE(controller
.HasCommittedRealLoad(root
->child_at(1)));
1254 // There are no subframe FrameNavigationEntries by default.
1255 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1258 // Check the end result of the frame tree.
1259 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1260 switches::kSitePerProcess
)) {
1261 FrameTreeVisualizer visualizer
;
1263 " Site A ------------ proxies for B\n"
1264 " |--Site A ------- proxies for B\n"
1265 " +--Site B ------- proxies for A\n"
1266 "Where A = http://127.0.0.1/\n"
1267 " B = http://foo.com/",
1268 visualizer
.DepictFrameTree(root
));
1272 // Verify the tree of FrameNavigationEntries after NAVIGATION_TYPE_AUTO_SUBFRAME
1274 // TODO(creis): Test updating entries for history auto subframe navigations.
1275 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1276 FrameNavigationEntry_AutoSubframe
) {
1277 GURL
main_url(embedded_test_server()->GetURL(
1278 "/navigation_controller/simple_page_1.html"));
1279 NavigateToURL(shell(), main_url
);
1280 const NavigationControllerImpl
& controller
=
1281 static_cast<const NavigationControllerImpl
&>(
1282 shell()->web_contents()->GetController());
1283 FrameTreeNode
* root
=
1284 static_cast<WebContentsImpl
*>(shell()->web_contents())->
1285 GetFrameTree()->root();
1287 // 1. Create a same-site iframe.
1288 GURL
frame_url(embedded_test_server()->GetURL(
1289 "/navigation_controller/simple_page_2.html"));
1291 LoadCommittedCapturer
capturer(shell()->web_contents());
1292 std::string script
= "var iframe = document.createElement('iframe');"
1293 "iframe.src = '" + frame_url
.spec() + "';"
1294 "document.body.appendChild(iframe);";
1295 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1297 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1300 // Check last committed NavigationEntry.
1301 EXPECT_EQ(1, controller
.GetEntryCount());
1302 NavigationEntryImpl
* entry
= controller
.GetLastCommittedEntry();
1303 EXPECT_EQ(main_url
, entry
->GetURL());
1304 FrameNavigationEntry
* root_entry
= entry
->root_node()->frame_entry
.get();
1305 EXPECT_EQ(main_url
, root_entry
->url());
1306 EXPECT_FALSE(controller
.GetPendingEntry());
1308 // Verify subframe entries if we're in --site-per-process mode.
1309 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1310 switches::kSitePerProcess
)) {
1311 // The entry should now have a subframe FrameNavigationEntry.
1312 ASSERT_EQ(1U, entry
->root_node()->children
.size());
1313 FrameNavigationEntry
* frame_entry
=
1314 entry
->root_node()->children
[0]->frame_entry
.get();
1315 EXPECT_EQ(frame_url
, frame_entry
->url());
1316 EXPECT_TRUE(controller
.HasCommittedRealLoad(root
->child_at(0)));
1318 // There are no subframe FrameNavigationEntries by default.
1319 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1322 // 2. Create a second, initially cross-site iframe.
1323 GURL
foo_url(embedded_test_server()->GetURL(
1324 "foo.com", "/navigation_controller/simple_page_1.html"));
1326 LoadCommittedCapturer
capturer(shell()->web_contents());
1327 std::string script
= "var iframe = document.createElement('iframe');"
1328 "iframe.src = '" + foo_url
.spec() + "';"
1329 "document.body.appendChild(iframe);";
1330 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1332 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1335 // The last committed NavigationEntry shouldn't have changed.
1336 EXPECT_EQ(1, controller
.GetEntryCount());
1337 entry
= controller
.GetLastCommittedEntry();
1338 EXPECT_EQ(main_url
, entry
->GetURL());
1339 root_entry
= entry
->root_node()->frame_entry
.get();
1340 EXPECT_EQ(main_url
, root_entry
->url());
1341 EXPECT_FALSE(controller
.GetPendingEntry());
1343 // Verify subframe entries if we're in --site-per-process mode.
1344 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1345 switches::kSitePerProcess
)) {
1346 // The entry should now have 2 subframe FrameNavigationEntries.
1347 ASSERT_EQ(2U, entry
->root_node()->children
.size());
1348 FrameNavigationEntry
* frame_entry
=
1349 entry
->root_node()->children
[1]->frame_entry
.get();
1350 EXPECT_EQ(foo_url
, frame_entry
->url());
1351 EXPECT_TRUE(controller
.HasCommittedRealLoad(root
->child_at(1)));
1353 // There are no subframe FrameNavigationEntries by default.
1354 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1357 // 3. Create a nested iframe in the second subframe.
1359 LoadCommittedCapturer
capturer(shell()->web_contents());
1360 std::string script
= "var iframe = document.createElement('iframe');"
1361 "iframe.src = '" + foo_url
.spec() + "';"
1362 "document.body.appendChild(iframe);";
1363 EXPECT_TRUE(content::ExecuteScript(root
->child_at(1)->current_frame_host(),
1366 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1369 // The last committed NavigationEntry shouldn't have changed.
1370 EXPECT_EQ(1, controller
.GetEntryCount());
1371 entry
= controller
.GetLastCommittedEntry();
1372 EXPECT_EQ(main_url
, entry
->GetURL());
1373 root_entry
= entry
->root_node()->frame_entry
.get();
1374 EXPECT_EQ(main_url
, root_entry
->url());
1376 // Verify subframe entries if we're in --site-per-process mode.
1377 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1378 switches::kSitePerProcess
)) {
1379 // The entry should now have 2 subframe FrameNavigationEntries.
1380 ASSERT_EQ(2U, entry
->root_node()->children
.size());
1381 ASSERT_EQ(1U, entry
->root_node()->children
[1]->children
.size());
1382 FrameNavigationEntry
* frame_entry
=
1383 entry
->root_node()->children
[1]->children
[0]->frame_entry
.get();
1384 EXPECT_EQ(foo_url
, frame_entry
->url());
1386 // There are no subframe FrameNavigationEntries by default.
1387 EXPECT_EQ(0U, entry
->root_node()->children
.size());
1390 // TODO(creis): Add tests for another subframe on B, and for a subframe on A
1391 // within it. Both are currently broken.
1393 // Check the end result of the frame tree.
1394 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1395 switches::kSitePerProcess
)) {
1396 FrameTreeVisualizer visualizer
;
1398 " Site A ------------ proxies for B\n"
1399 " |--Site A ------- proxies for B\n"
1400 " +--Site B ------- proxies for A\n"
1401 " +--Site B -- proxies for A\n"
1402 "Where A = http://127.0.0.1/\n"
1403 " B = http://foo.com/",
1404 visualizer
.DepictFrameTree(root
));
1408 // Verify the tree of FrameNavigationEntries after NAVIGATION_TYPE_NEW_SUBFRAME
1410 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1411 FrameNavigationEntry_NewSubframe
) {
1412 GURL
main_url(embedded_test_server()->GetURL(
1413 "/navigation_controller/simple_page_1.html"));
1414 NavigateToURL(shell(), main_url
);
1415 const NavigationControllerImpl
& controller
=
1416 static_cast<const NavigationControllerImpl
&>(
1417 shell()->web_contents()->GetController());
1418 FrameTreeNode
* root
=
1419 static_cast<WebContentsImpl
*>(shell()->web_contents())->
1420 GetFrameTree()->root();
1422 // 1. Create a same-site iframe.
1423 GURL
frame_url(embedded_test_server()->GetURL(
1424 "/navigation_controller/simple_page_2.html"));
1426 LoadCommittedCapturer
capturer(shell()->web_contents());
1427 std::string script
= "var iframe = document.createElement('iframe');"
1428 "iframe.src = '" + frame_url
.spec() + "';"
1429 "document.body.appendChild(iframe);";
1430 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1433 NavigationEntryImpl
* entry
= controller
.GetLastCommittedEntry();
1435 // 2. Navigate in the subframe same-site.
1436 GURL
frame_url2(embedded_test_server()->GetURL(
1437 "/navigation_controller/page_with_links.html"));
1439 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1440 NavigateFrameToURL(root
->child_at(0), frame_url2
);
1442 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
1443 capturer
.params().transition
);
1444 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
1447 // We should have created a new NavigationEntry with the same main frame URL.
1448 EXPECT_EQ(2, controller
.GetEntryCount());
1449 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
1450 NavigationEntryImpl
* entry2
= controller
.GetLastCommittedEntry();
1451 EXPECT_NE(entry
, entry2
);
1452 EXPECT_EQ(main_url
, entry2
->GetURL());
1453 FrameNavigationEntry
* root_entry2
= entry2
->root_node()->frame_entry
.get();
1454 EXPECT_EQ(main_url
, root_entry2
->url());
1456 // Verify subframe entries if we're in --site-per-process mode.
1457 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1458 switches::kSitePerProcess
)) {
1459 // The entry should have a new FrameNavigationEntries for the subframe.
1460 ASSERT_EQ(1U, entry2
->root_node()->children
.size());
1461 EXPECT_EQ(frame_url2
, entry2
->root_node()->children
[0]->frame_entry
->url());
1463 // There are no subframe FrameNavigationEntries by default.
1464 EXPECT_EQ(0U, entry2
->root_node()->children
.size());
1467 // 3. Create a second, initially cross-site iframe.
1468 GURL
foo_url(embedded_test_server()->GetURL(
1469 "foo.com", "/navigation_controller/simple_page_1.html"));
1471 LoadCommittedCapturer
capturer(shell()->web_contents());
1472 std::string script
= "var iframe = document.createElement('iframe');"
1473 "iframe.src = '" + foo_url
.spec() + "';"
1474 "document.body.appendChild(iframe);";
1475 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1479 // 4. Create a nested same-site iframe in the second subframe, wait for it to
1480 // commit, then navigate it again.
1482 LoadCommittedCapturer
capturer(shell()->web_contents());
1483 std::string script
= "var iframe = document.createElement('iframe');"
1484 "iframe.src = '" + foo_url
.spec() + "';"
1485 "document.body.appendChild(iframe);";
1486 EXPECT_TRUE(content::ExecuteScript(root
->child_at(1)->current_frame_host(),
1490 GURL
bar_url(embedded_test_server()->GetURL(
1491 "bar.com", "/navigation_controller/simple_page_1.html"));
1493 FrameNavigateParamsCapturer
capturer(root
->child_at(1)->child_at(0));
1494 NavigateFrameToURL(root
->child_at(1)->child_at(0), bar_url
);
1496 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
1497 capturer
.params().transition
);
1498 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
1501 // We should have created a new NavigationEntry with the same main frame URL.
1502 EXPECT_EQ(3, controller
.GetEntryCount());
1503 EXPECT_EQ(2, controller
.GetLastCommittedEntryIndex());
1504 NavigationEntryImpl
* entry3
= controller
.GetLastCommittedEntry();
1505 EXPECT_NE(entry
, entry3
);
1506 EXPECT_EQ(main_url
, entry3
->GetURL());
1507 FrameNavigationEntry
* root_entry3
= entry3
->root_node()->frame_entry
.get();
1508 EXPECT_EQ(main_url
, root_entry3
->url());
1510 // Verify subframe entries if we're in --site-per-process mode.
1511 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1512 switches::kSitePerProcess
)) {
1513 // The entry should still have FrameNavigationEntries for all 3 subframes.
1514 ASSERT_EQ(2U, entry3
->root_node()->children
.size());
1515 EXPECT_EQ(frame_url2
, entry3
->root_node()->children
[0]->frame_entry
->url());
1516 EXPECT_EQ(foo_url
, entry3
->root_node()->children
[1]->frame_entry
->url());
1517 ASSERT_EQ(1U, entry3
->root_node()->children
[1]->children
.size());
1520 entry3
->root_node()->children
[1]->children
[0]->frame_entry
->url());
1522 // There are no subframe FrameNavigationEntries by default.
1523 EXPECT_EQ(0U, entry3
->root_node()->children
.size());
1526 // 6. Navigate the second subframe cross-site, clearing its existing subtree.
1527 GURL
baz_url(embedded_test_server()->GetURL(
1528 "baz.com", "/navigation_controller/simple_page_1.html"));
1530 FrameNavigateParamsCapturer
capturer(root
->child_at(1));
1531 std::string script
= "var frames = document.getElementsByTagName('iframe');"
1532 "frames[1].src = '" + baz_url
.spec() + "';";
1533 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1535 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME
,
1536 capturer
.params().transition
);
1537 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
1540 // We should have created a new NavigationEntry with the same main frame URL.
1541 EXPECT_EQ(4, controller
.GetEntryCount());
1542 EXPECT_EQ(3, controller
.GetLastCommittedEntryIndex());
1543 NavigationEntryImpl
* entry4
= controller
.GetLastCommittedEntry();
1544 EXPECT_NE(entry
, entry4
);
1545 EXPECT_EQ(main_url
, entry4
->GetURL());
1546 FrameNavigationEntry
* root_entry4
= entry4
->root_node()->frame_entry
.get();
1547 EXPECT_EQ(main_url
, root_entry4
->url());
1549 // Verify subframe entries if we're in --site-per-process mode.
1550 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1551 switches::kSitePerProcess
)) {
1552 // The entry should still have FrameNavigationEntries for all 3 subframes.
1553 ASSERT_EQ(2U, entry4
->root_node()->children
.size());
1554 EXPECT_EQ(frame_url2
, entry4
->root_node()->children
[0]->frame_entry
->url());
1555 EXPECT_EQ(baz_url
, entry4
->root_node()->children
[1]->frame_entry
->url());
1556 ASSERT_EQ(0U, entry4
->root_node()->children
[1]->children
.size());
1558 // There are no subframe FrameNavigationEntries by default.
1559 EXPECT_EQ(0U, entry4
->root_node()->children
.size());
1562 // Check the end result of the frame tree.
1563 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1564 switches::kSitePerProcess
)) {
1565 FrameTreeVisualizer visualizer
;
1567 " Site A ------------ proxies for B\n"
1568 " |--Site A ------- proxies for B\n"
1569 " +--Site B ------- proxies for A\n"
1570 "Where A = http://127.0.0.1/\n"
1571 " B = http://baz.com/",
1572 visualizer
.DepictFrameTree(root
));
1576 // Verify the tree of FrameNavigationEntries after back/forward navigations in a
1577 // cross-site subframe.
1578 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1579 FrameNavigationEntry_SubframeBackForward
) {
1580 GURL
main_url(embedded_test_server()->GetURL(
1581 "/navigation_controller/simple_page_1.html"));
1582 NavigateToURL(shell(), main_url
);
1583 const NavigationControllerImpl
& controller
=
1584 static_cast<const NavigationControllerImpl
&>(
1585 shell()->web_contents()->GetController());
1586 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1590 // 1. Create a same-site iframe.
1591 GURL
frame_url(embedded_test_server()->GetURL(
1592 "/navigation_controller/simple_page_2.html"));
1594 LoadCommittedCapturer
capturer(shell()->web_contents());
1595 std::string script
= "var iframe = document.createElement('iframe');"
1596 "iframe.src = '" + frame_url
.spec() + "';"
1597 "document.body.appendChild(iframe);";
1598 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1601 NavigationEntryImpl
* entry1
= controller
.GetLastCommittedEntry();
1603 // 2. Navigate in the subframe cross-site.
1604 GURL
frame_url2(embedded_test_server()->GetURL(
1605 "foo.com", "/navigation_controller/page_with_links.html"));
1607 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1608 NavigateFrameToURL(root
->child_at(0), frame_url2
);
1611 EXPECT_EQ(2, controller
.GetEntryCount());
1612 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
1613 NavigationEntryImpl
* entry2
= controller
.GetLastCommittedEntry();
1615 // 3. Navigate in the subframe cross-site again.
1616 GURL
frame_url3(embedded_test_server()->GetURL(
1617 "bar.com", "/navigation_controller/page_with_links.html"));
1619 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1620 NavigateFrameToURL(root
->child_at(0), frame_url3
);
1623 EXPECT_EQ(3, controller
.GetEntryCount());
1624 EXPECT_EQ(2, controller
.GetLastCommittedEntryIndex());
1625 NavigationEntryImpl
* entry3
= controller
.GetLastCommittedEntry();
1627 // 4. Go back in the subframe.
1629 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1630 shell()->web_contents()->GetController().GoBack();
1632 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.params().transition
);
1633 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME
, capturer
.details().type
);
1635 EXPECT_EQ(3, controller
.GetEntryCount());
1636 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
1637 EXPECT_EQ(entry2
, controller
.GetLastCommittedEntry());
1639 // Verify subframe entries if we're in --site-per-process mode.
1640 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1641 switches::kSitePerProcess
)) {
1642 // The entry should have a new FrameNavigationEntries for the subframe.
1643 ASSERT_EQ(1U, entry2
->root_node()->children
.size());
1644 EXPECT_EQ(frame_url2
, entry2
->root_node()->children
[0]->frame_entry
->url());
1646 // There are no subframe FrameNavigationEntries by default.
1647 EXPECT_EQ(0U, entry2
->root_node()->children
.size());
1650 // 5. Go back in the subframe again to the parent page's site.
1652 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1653 shell()->web_contents()->GetController().GoBack();
1655 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.params().transition
);
1656 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME
, capturer
.details().type
);
1658 EXPECT_EQ(3, controller
.GetEntryCount());
1659 EXPECT_EQ(0, controller
.GetLastCommittedEntryIndex());
1660 EXPECT_EQ(entry1
, controller
.GetLastCommittedEntry());
1662 // Verify subframe entries if we're in --site-per-process mode.
1663 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1664 switches::kSitePerProcess
)) {
1665 // The entry should have a new FrameNavigationEntries for the subframe.
1666 ASSERT_EQ(1U, entry1
->root_node()->children
.size());
1667 EXPECT_EQ(frame_url
, entry1
->root_node()->children
[0]->frame_entry
->url());
1669 // There are no subframe FrameNavigationEntries by default.
1670 EXPECT_EQ(0U, entry1
->root_node()->children
.size());
1673 // 6. Go forward in the subframe cross-site.
1675 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1676 shell()->web_contents()->GetController().GoForward();
1678 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.params().transition
);
1679 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME
, capturer
.details().type
);
1681 EXPECT_EQ(3, controller
.GetEntryCount());
1682 EXPECT_EQ(1, controller
.GetLastCommittedEntryIndex());
1683 EXPECT_EQ(entry2
, controller
.GetLastCommittedEntry());
1685 // Verify subframe entries if we're in --site-per-process mode.
1686 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1687 switches::kSitePerProcess
)) {
1688 // The entry should have a new FrameNavigationEntries for the subframe.
1689 ASSERT_EQ(1U, entry2
->root_node()->children
.size());
1690 EXPECT_EQ(frame_url2
, entry2
->root_node()->children
[0]->frame_entry
->url());
1692 // There are no subframe FrameNavigationEntries by default.
1693 EXPECT_EQ(0U, entry2
->root_node()->children
.size());
1696 // 7. Go forward in the subframe again, cross-site.
1698 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1699 shell()->web_contents()->GetController().GoForward();
1701 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.params().transition
);
1702 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME
, capturer
.details().type
);
1704 EXPECT_EQ(3, controller
.GetEntryCount());
1705 EXPECT_EQ(2, controller
.GetLastCommittedEntryIndex());
1706 EXPECT_EQ(entry3
, controller
.GetLastCommittedEntry());
1708 // Verify subframe entries if we're in --site-per-process mode.
1709 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1710 switches::kSitePerProcess
)) {
1711 // The entry should have a new FrameNavigationEntries for the subframe.
1712 ASSERT_EQ(1U, entry3
->root_node()->children
.size());
1713 EXPECT_EQ(frame_url3
, entry3
->root_node()->children
[0]->frame_entry
->url());
1715 // There are no subframe FrameNavigationEntries by default.
1716 EXPECT_EQ(0U, entry3
->root_node()->children
.size());
1720 // Verifies that item sequence numbers and document sequence numbers update
1721 // properly for main frames and subframes.
1722 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1723 FrameNavigationEntry_SequenceNumbers
) {
1724 const NavigationControllerImpl
& controller
=
1725 static_cast<const NavigationControllerImpl
&>(
1726 shell()->web_contents()->GetController());
1728 // 1. Navigate the main frame.
1729 GURL
url(embedded_test_server()->GetURL(
1730 "/navigation_controller/page_with_links.html"));
1731 NavigateToURL(shell(), url
);
1732 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1736 FrameNavigationEntry
* frame_entry
=
1737 controller
.GetLastCommittedEntry()->GetFrameEntry(root
);
1738 int64 isn_1
= frame_entry
->item_sequence_number();
1739 int64 dsn_1
= frame_entry
->document_sequence_number();
1740 EXPECT_NE(-1, isn_1
);
1741 EXPECT_NE(-1, dsn_1
);
1743 // 2. Do an in-page fragment navigation.
1744 std::string script
= "document.getElementById('fraglink').click()";
1745 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1746 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1748 frame_entry
= controller
.GetLastCommittedEntry()->GetFrameEntry(root
);
1749 int64 isn_2
= frame_entry
->item_sequence_number();
1750 int64 dsn_2
= frame_entry
->document_sequence_number();
1751 EXPECT_NE(-1, isn_2
);
1752 EXPECT_NE(isn_1
, isn_2
);
1753 EXPECT_EQ(dsn_1
, dsn_2
);
1755 // Also test subframe sequence numbers, but only in --site-per-proces mode.
1756 // (We do not create subframe FrameNavigationEntries in default mode yet.)
1757 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
1758 switches::kSitePerProcess
))
1761 // 3. Add a subframe, which does an AUTO_SUBFRAME navigation.
1763 LoadCommittedCapturer
capturer(shell()->web_contents());
1764 std::string script
= "var iframe = document.createElement('iframe');"
1765 "iframe.src = '" + url
.spec() + "';"
1766 "document.body.appendChild(iframe);";
1767 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1769 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME
, capturer
.transition_type());
1772 // The root FrameNavigationEntry hasn't changed.
1773 EXPECT_EQ(frame_entry
,
1774 controller
.GetLastCommittedEntry()->GetFrameEntry(root
));
1776 // We should have a unique ISN and DSN for the subframe entry.
1777 FrameTreeNode
* subframe
= root
->child_at(0);
1778 FrameNavigationEntry
* subframe_entry
=
1779 controller
.GetLastCommittedEntry()->GetFrameEntry(subframe
);
1780 int64 isn_3
= subframe_entry
->item_sequence_number();
1781 int64 dsn_3
= subframe_entry
->document_sequence_number();
1782 EXPECT_NE(-1, isn_2
);
1783 EXPECT_NE(isn_2
, isn_3
);
1784 EXPECT_NE(dsn_2
, dsn_3
);
1786 // 4. Do an in-page fragment navigation in the subframe.
1787 EXPECT_TRUE(content::ExecuteScript(subframe
->current_frame_host(), script
));
1788 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1790 subframe_entry
= controller
.GetLastCommittedEntry()->GetFrameEntry(subframe
);
1791 int64 isn_4
= subframe_entry
->item_sequence_number();
1792 int64 dsn_4
= subframe_entry
->document_sequence_number();
1793 EXPECT_NE(-1, isn_4
);
1794 EXPECT_NE(isn_3
, isn_4
);
1795 EXPECT_EQ(dsn_3
, dsn_4
);
1800 class HttpThrottle
: public ResourceThrottle
{
1803 void WillStartRequest(bool* defer
) override
{
1807 const char* GetNameForLogging() const override
{
1808 return "HttpThrottle";
1812 class StallDelegate
: public ResourceDispatcherHostDelegate
{
1813 // ResourceDispatcherHostDelegate
1814 void RequestBeginning(
1815 net::URLRequest
* request
,
1816 content::ResourceContext
* resource_context
,
1817 content::AppCacheService
* appcache_service
,
1818 ResourceType resource_type
,
1819 ScopedVector
<content::ResourceThrottle
>* throttles
) override
{
1820 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
1821 throttles
->push_back(new HttpThrottle
);
1825 // Loads |start_url|, then loads |stalled_url| which stalls. While the page is
1826 // stalled, an in-page navigation happens. Make sure that all the navigations
1827 // are properly classified.
1828 void DoReplaceStateWhilePending(Shell
* shell
,
1829 const GURL
& start_url
,
1830 const GURL
& stalled_url
,
1831 const std::string
& replace_state_filename
) {
1832 NavigationControllerImpl
& controller
=
1833 static_cast<NavigationControllerImpl
&>(
1834 shell
->web_contents()->GetController());
1836 FrameTreeNode
* root
=
1837 static_cast<WebContentsImpl
*>(shell
->web_contents())->
1838 GetFrameTree()->root();
1840 // Start with one page.
1841 EXPECT_TRUE(NavigateToURL(shell
, start_url
));
1843 // Have the user decide to go to a different page which is very slow.
1844 StallDelegate stall_delegate
;
1845 ResourceDispatcherHost::Get()->SetDelegate(&stall_delegate
);
1847 stalled_url
, Referrer(), ui::PAGE_TRANSITION_LINK
, std::string());
1849 // That should be the pending entry.
1850 NavigationEntryImpl
* entry
= controller
.GetPendingEntry();
1851 ASSERT_NE(nullptr, entry
);
1852 EXPECT_EQ(stalled_url
, entry
->GetURL());
1855 // Now the existing page uses history.replaceState().
1856 FrameNavigateParamsCapturer
capturer(root
);
1857 capturer
.set_wait_for_load(false);
1858 std::string script
=
1859 "history.replaceState({}, '', '" + replace_state_filename
+ "')";
1860 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1863 // The fact that there was a pending entry shouldn't interfere with the
1865 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
1866 EXPECT_TRUE(capturer
.details().is_in_page
);
1869 ResourceDispatcherHost::Get()->SetDelegate(nullptr);
1874 IN_PROC_BROWSER_TEST_F(
1875 NavigationControllerBrowserTest
,
1876 NavigationTypeClassification_On1InPageToXWhile2Pending
) {
1877 GURL
url1(embedded_test_server()->GetURL(
1878 "/navigation_controller/simple_page_1.html"));
1879 GURL
url2(embedded_test_server()->GetURL(
1880 "/navigation_controller/simple_page_2.html"));
1881 DoReplaceStateWhilePending(shell(), url1
, url2
, "x");
1884 IN_PROC_BROWSER_TEST_F(
1885 NavigationControllerBrowserTest
,
1886 NavigationTypeClassification_On1InPageTo2While2Pending
) {
1887 GURL
url1(embedded_test_server()->GetURL(
1888 "/navigation_controller/simple_page_1.html"));
1889 GURL
url2(embedded_test_server()->GetURL(
1890 "/navigation_controller/simple_page_2.html"));
1891 DoReplaceStateWhilePending(shell(), url1
, url2
, "simple_page_2.html");
1894 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1895 NavigationTypeClassification_On1InPageToXWhile1Pending
) {
1896 GURL
url(embedded_test_server()->GetURL(
1897 "/navigation_controller/simple_page_1.html"));
1898 DoReplaceStateWhilePending(shell(), url
, url
, "x");
1901 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1902 NavigationTypeClassification_On1InPageTo1While1Pending
) {
1903 GURL
url(embedded_test_server()->GetURL(
1904 "/navigation_controller/simple_page_1.html"));
1905 DoReplaceStateWhilePending(shell(), url
, url
, "simple_page_1.html");
1908 // Ensure the renderer process does not get confused about the current entry
1909 // due to subframes and replaced entries. See https://crbug.com/480201.
1910 // TODO(creis): Re-enable for Site Isolation FYI bots: https://crbug.com/502317.
1911 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
1912 PreventSpoofFromSubframeAndReplace
) {
1913 // Start at an initial URL.
1914 GURL
url1(embedded_test_server()->GetURL(
1915 "/navigation_controller/simple_page_1.html"));
1916 NavigateToURL(shell(), url1
);
1918 // Now go to a page with a real iframe.
1919 GURL
url2(embedded_test_server()->GetURL(
1920 "/navigation_controller/page_with_data_iframe.html"));
1921 NavigateToURL(shell(), url2
);
1923 // It is safe to obtain the root frame tree node here, as it doesn't change.
1924 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1927 ASSERT_EQ(1U, root
->child_count());
1928 ASSERT_NE(nullptr, root
->child_at(0));
1931 // Navigate in the iframe.
1932 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
1933 GURL
frame_url(embedded_test_server()->GetURL(
1934 "/navigation_controller/simple_page_2.html"));
1935 NavigateFrameToURL(root
->child_at(0), frame_url
);
1937 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
1941 // Go back in the iframe.
1942 TestNavigationObserver
back_load_observer(shell()->web_contents());
1943 shell()->web_contents()->GetController().GoBack();
1944 back_load_observer
.Wait();
1948 // Go forward in the iframe.
1949 TestNavigationObserver
forward_load_observer(shell()->web_contents());
1950 shell()->web_contents()->GetController().GoForward();
1951 forward_load_observer
.Wait();
1954 GURL
url3(embedded_test_server()->GetURL(
1955 "/navigation_controller/page_with_iframe.html"));
1957 // location.replace() to cause an inert commit.
1958 TestNavigationObserver
replace_load_observer(shell()->web_contents());
1959 std::string script
= "location.replace('" + url3
.spec() + "')";
1960 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
1961 replace_load_observer
.Wait();
1966 TestNavigationObserver
back_load_observer(shell()->web_contents());
1967 shell()->web_contents()->GetController().GoBack();
1968 back_load_observer
.Wait();
1970 // Make sure the URL is correct for both the entry and the main frame, and
1971 // that the process hasn't been killed for showing a spoof.
1972 EXPECT_TRUE(root
->current_frame_host()->IsRenderFrameLive());
1973 EXPECT_EQ(url2
, shell()->web_contents()->GetLastCommittedURL());
1974 EXPECT_EQ(url2
, root
->current_url());
1978 // Go back to reset main frame entirely.
1979 TestNavigationObserver
back_load_observer(shell()->web_contents());
1980 shell()->web_contents()->GetController().GoBack();
1981 back_load_observer
.Wait();
1982 EXPECT_EQ(url1
, shell()->web_contents()->GetLastCommittedURL());
1983 EXPECT_EQ(url1
, root
->current_url());
1988 TestNavigationObserver
back_load_observer(shell()->web_contents());
1989 shell()->web_contents()->GetController().GoForward();
1990 back_load_observer
.Wait();
1991 EXPECT_EQ(url2
, shell()->web_contents()->GetLastCommittedURL());
1992 EXPECT_EQ(url2
, root
->current_url());
1996 // Go forward to the replaced URL.
1997 TestNavigationObserver
forward_load_observer(shell()->web_contents());
1998 shell()->web_contents()->GetController().GoForward();
1999 forward_load_observer
.Wait();
2001 // Make sure the URL is correct for both the entry and the main frame, and
2002 // that the process hasn't been killed for showing a spoof.
2003 EXPECT_TRUE(root
->current_frame_host()->IsRenderFrameLive());
2004 EXPECT_EQ(url3
, shell()->web_contents()->GetLastCommittedURL());
2005 EXPECT_EQ(url3
, root
->current_url());
2009 // Ensure the renderer process does not get killed if the main frame URL's path
2010 // changes when going back in a subframe, since this is currently possible after
2011 // a replaceState in the main frame (thanks to https://crbug.com/373041).
2012 // See https:///crbug.com/486916.
2013 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
2014 SubframeBackFromReplaceState
) {
2015 // Start at a page with a real iframe.
2016 GURL
url1(embedded_test_server()->GetURL(
2017 "/navigation_controller/page_with_data_iframe.html"));
2018 NavigateToURL(shell(), url1
);
2020 // It is safe to obtain the root frame tree node here, as it doesn't change.
2021 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
2024 ASSERT_EQ(1U, root
->child_count());
2025 ASSERT_NE(nullptr, root
->child_at(0));
2028 // Navigate in the iframe.
2029 FrameNavigateParamsCapturer
capturer(root
->child_at(0));
2030 GURL
frame_url(embedded_test_server()->GetURL(
2031 "/navigation_controller/simple_page_2.html"));
2032 NavigateFrameToURL(root
->child_at(0), frame_url
);
2034 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME
, capturer
.details().type
);
2038 // history.replaceState().
2039 FrameNavigateParamsCapturer
capturer(root
);
2040 std::string script
=
2041 "history.replaceState({}, 'replaced', 'replaced')";
2042 EXPECT_TRUE(content::ExecuteScript(root
->current_frame_host(), script
));
2047 // Go back in the iframe.
2048 TestNavigationObserver
back_load_observer(shell()->web_contents());
2049 shell()->web_contents()->GetController().GoBack();
2050 back_load_observer
.Wait();
2053 // For now, we expect the main frame's URL to revert. This won't happen once
2054 // https://crbug.com/373041 is fixed.
2055 EXPECT_EQ(url1
, shell()->web_contents()->GetLastCommittedURL());
2057 // Make sure the renderer process has not been killed.
2058 EXPECT_TRUE(root
->current_frame_host()->IsRenderFrameLive());
2063 class FailureWatcher
: public WebContentsObserver
{
2065 // Observes failure for the specified |node|.
2066 explicit FailureWatcher(FrameTreeNode
* node
)
2067 : WebContentsObserver(
2068 node
->current_frame_host()->delegate()->GetAsWebContents()),
2069 frame_tree_node_id_(node
->frame_tree_node_id()),
2070 message_loop_runner_(new MessageLoopRunner
) {}
2073 message_loop_runner_
->Run();
2077 void DidFailLoad(RenderFrameHost
* render_frame_host
,
2078 const GURL
& validated_url
,
2080 const base::string16
& error_description
,
2081 bool was_ignored_by_handler
) override
{
2082 RenderFrameHostImpl
* rfh
=
2083 static_cast<RenderFrameHostImpl
*>(render_frame_host
);
2084 if (rfh
->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_
)
2087 message_loop_runner_
->Quit();
2090 void DidFailProvisionalLoad(
2091 RenderFrameHost
* render_frame_host
,
2092 const GURL
& validated_url
,
2094 const base::string16
& error_description
,
2095 bool was_ignored_by_handler
) override
{
2096 RenderFrameHostImpl
* rfh
=
2097 static_cast<RenderFrameHostImpl
*>(render_frame_host
);
2098 if (rfh
->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_
)
2101 message_loop_runner_
->Quit();
2104 // The id of the FrameTreeNode whose navigations to observe.
2105 int frame_tree_node_id_
;
2107 // The MessageLoopRunner used to spin the message loop.
2108 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
2113 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
,
2114 StopCausesFailureDespiteJavaScriptURL
) {
2115 NavigationControllerImpl
& controller
=
2116 static_cast<NavigationControllerImpl
&>(
2117 shell()->web_contents()->GetController());
2119 FrameTreeNode
* root
=
2120 static_cast<WebContentsImpl
*>(shell()->web_contents())->
2121 GetFrameTree()->root();
2123 // Start with a normal page.
2124 GURL
url1(embedded_test_server()->GetURL(
2125 "/navigation_controller/simple_page_1.html"));
2126 EXPECT_TRUE(NavigateToURL(shell(), url1
));
2128 // Have the user decide to go to a different page which is very slow.
2129 StallDelegate stall_delegate
;
2130 ResourceDispatcherHost::Get()->SetDelegate(&stall_delegate
);
2131 GURL
url2(embedded_test_server()->GetURL(
2132 "/navigation_controller/simple_page_2.html"));
2133 controller
.LoadURL(url2
, Referrer(), ui::PAGE_TRANSITION_LINK
, std::string());
2135 // That should be the pending entry.
2136 NavigationEntryImpl
* entry
= controller
.GetPendingEntry();
2137 ASSERT_NE(nullptr, entry
);
2138 EXPECT_EQ(url2
, entry
->GetURL());
2140 // Loading a JavaScript URL shouldn't affect the ability to stop.
2142 FailureWatcher
watcher(root
);
2143 GURL
js("javascript:(function(){})()");
2144 controller
.LoadURL(js
, Referrer(), ui::PAGE_TRANSITION_LINK
, std::string());
2145 // This LoadURL ends up purging the pending entry, which is why this is
2147 EXPECT_EQ(nullptr, controller
.GetPendingEntry());
2148 shell()->web_contents()->Stop();
2152 ResourceDispatcherHost::Get()->SetDelegate(nullptr);
2156 class RenderProcessKilledObserver
: public WebContentsObserver
{
2158 RenderProcessKilledObserver(WebContents
* web_contents
)
2159 : WebContentsObserver(web_contents
) {}
2160 ~RenderProcessKilledObserver() override
{}
2162 void RenderProcessGone(base::TerminationStatus status
) override
{
2164 base::TerminationStatus::TERMINATION_STATUS_PROCESS_WAS_KILLED
);
2169 // This tests a race in ReloadOriginalRequest, where a cross-origin reload was
2170 // causing an in-flight replaceState to look like a cross-origin navigation,
2171 // even though it's in-page. (The reload should not modify the underlying last
2172 // committed entry.) Not crashing means that the test is successful.
2173 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest
, ReloadOriginalRequest
) {
2174 GURL
original_url(embedded_test_server()->GetURL(
2175 "/navigation_controller/simple_page_1.html"));
2176 NavigateToURL(shell(), original_url
);
2177 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
2180 RenderProcessKilledObserver
kill_observer(shell()->web_contents());
2182 // Redirect so that we can use ReloadOriginalRequest.
2183 GURL
redirect_url(embedded_test_server()->GetURL(
2184 "foo.com", "/navigation_controller/simple_page_1.html"));
2186 std::string script
= "location.replace('" + redirect_url
.spec() + "');";
2187 FrameNavigateParamsCapturer
capturer(root
);
2188 EXPECT_TRUE(ExecuteScript(shell()->web_contents(), script
));
2190 EXPECT_EQ(ui::PAGE_TRANSITION_LINK
| ui::PAGE_TRANSITION_CLIENT_REDIRECT
,
2191 capturer
.params().transition
);
2192 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE
, capturer
.details().type
);
2195 // Modify an entry in the session history and reload the original request.
2197 // We first send a replaceState() to the renderer, which will cause the
2198 // renderer to send back a DidCommitProvisionalLoad. Immediately after,
2199 // we send a ReloadOriginalRequest (which in this case is a different
2200 // origin) and will also cause the renderer to commit the frame. In the
2201 // end we verify that both navigations committed and that the URLs are
2203 std::string script
= "history.replaceState({}, '', 'foo');";
2204 root
->render_manager()
2205 ->current_frame_host()
2206 ->ExecuteJavaScriptWithUserGestureForTests(base::UTF8ToUTF16(script
));
2207 EXPECT_FALSE(shell()->web_contents()->IsLoading());
2208 shell()->web_contents()->GetController().ReloadOriginalRequestURL(false);
2209 EXPECT_TRUE(shell()->web_contents()->IsLoading());
2210 EXPECT_EQ(redirect_url
, shell()->web_contents()->GetLastCommittedURL());
2212 // Wait until there's no more navigations.
2213 GURL
modified_url(embedded_test_server()->GetURL(
2214 "foo.com", "/navigation_controller/foo"));
2215 FrameNavigateParamsCapturer
capturer(root
);
2216 capturer
.set_wait_for_load(false);
2217 capturer
.set_navigations_remaining(2);
2219 EXPECT_EQ(2U, capturer
.all_details().size());
2220 EXPECT_EQ(modified_url
, capturer
.all_params()[0].url
);
2221 EXPECT_EQ(original_url
, capturer
.all_params()[1].url
);
2222 EXPECT_EQ(original_url
, shell()->web_contents()->GetLastCommittedURL());
2225 // Make sure the renderer is still alive.
2227 ExecuteScript(shell()->web_contents(), "console.log('Success');"));
2230 } // namespace content