Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / content / browser / frame_host / navigation_controller_impl_browsertest.cc
blob541aaa584b41d1a1d7bdc3a16429f974e5decc74
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/bind.h"
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"
35 namespace content {
37 class NavigationControllerBrowserTest : public ContentBrowserTest {
38 protected:
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())
53 ->GetFrameTree()
54 ->root();
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),
69 cross_process);
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
112 // list.
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());
143 controller.GoBack();
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());
151 namespace {
153 int RendererHistoryLength(Shell* shell) {
154 int value = 0;
155 EXPECT_TRUE(ExecuteScriptAndExtractInt(
156 shell->web_contents(),
157 "domAutomationController.send(history.length)",
158 &value));
159 return value;
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))
173 return false;
174 return web_contents->GetLastCommittedURL() == url;
177 } // namespace
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()));
204 controller.GoBack();
205 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
206 controller.GoBack();
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
218 // incorrect length.
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
223 // right.
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.
248 namespace {
250 class NoNavigationsObserver : public WebContentsObserver {
251 public:
252 // Observes navigation for the specified |web_contents|.
253 explicit NoNavigationsObserver(WebContents* web_contents)
254 : WebContentsObserver(web_contents) {}
256 private:
257 void DidNavigateAnyFrame(RenderFrameHost* render_frame_host,
258 const LoadCommittedDetails& details,
259 const FrameNavigateParams& params) override {
260 FAIL() << "No navigations should occur";
264 } // namespace
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));
303 // Navigate it.
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.
311 EXPECT_EQ(nullptr,
312 new_shell->web_contents()->GetController().GetLastCommittedEntry());
315 namespace {
317 class FrameNavigateParamsCapturer : public WebContentsObserver {
318 public:
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;
336 void Wait() {
337 message_loop_runner_->Run();
340 const FrameNavigateParams& params() const {
341 EXPECT_EQ(1U, params_.size());
342 return params_[0];
345 const std::vector<FrameNavigateParams>& all_params() const {
346 return params_;
349 const LoadCommittedDetails& details() const {
350 EXPECT_EQ(1U, details_.size());
351 return details_[0];
354 const std::vector<LoadCommittedDetails>& all_details() const {
355 return details_;
358 private:
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_)
365 return;
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.
387 bool wait_for_load_;
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 {
400 public:
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
409 // |web_contents|.
410 explicit LoadCommittedCapturer(WebContents* web_contents)
411 : WebContentsObserver(web_contents),
412 frame_tree_node_id_(0),
413 message_loop_runner_(new MessageLoopRunner) {}
415 void Wait() {
416 message_loop_runner_->Run();
419 ui::PageTransition transition_type() const {
420 return transition_type_;
423 private:
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();
434 return;
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,
448 const GURL& url,
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_)
454 return;
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_;
473 } // namespace
475 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
476 ErrorPageReplacement) {
477 NavigationController& controller = shell()->web_contents()->GetController();
478 GURL error_url(
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);
494 capturer.Wait();
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
505 // failure.
507 FrameNavigateParamsCapturer capturer(root);
508 NavigateFrameToURL(root, error_url);
509 capturer.Wait();
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);
527 capturer.Wait();
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
541 // above.)
543 FrameNavigateParamsCapturer capturer(root);
544 NavigateToURLAndReplace(shell(), error_url);
545 capturer.Wait();
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
557 // classified.
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();
567 // Simple load.
568 FrameNavigateParamsCapturer capturer(root);
569 GURL frame_url(embedded_test_server()->GetURL(
570 "/navigation_controller/page_with_links.html"));
571 NavigateFrameToURL(root, frame_url);
572 capturer.Wait();
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));
585 capturer.Wait();
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));
596 capturer.Wait();
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));
609 capturer.Wait();
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);
619 std::string script =
620 "history.pushState({}, 'page 1', 'simple_page_1.html')";
621 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
622 capturer.Wait();
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
631 // classified.
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();
649 capturer.Wait();
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();
662 capturer.Wait();
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(),
675 "history.back()"));
676 capturer.Wait();
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()"));
690 capturer.Wait();
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(),
703 "history.go(-1)"));
704 capturer.Wait();
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(),
717 "history.go(1)"));
718 capturer.Wait();
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);
731 capturer.Wait();
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()"));
742 capturer.Wait();
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));
756 capturer.Wait();
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);
768 std::string script =
769 "history.replaceState({}, 'page 2', 'simple_page_2.html')";
770 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
771 capturer.Wait();
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()));
788 // Back.
789 FrameNavigateParamsCapturer capturer(root);
790 shell()->web_contents()->GetController().GoBack();
791 capturer.Wait();
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);
801 // Forward.
802 FrameNavigateParamsCapturer capturer(root);
803 shell()->web_contents()->GetController().GoForward();
804 capturer.Wait();
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()));
819 // Back.
820 FrameNavigateParamsCapturer capturer(root);
821 shell()->web_contents()->GetController().GoBack();
822 capturer.Wait();
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);
832 // Forward.
833 FrameNavigateParamsCapturer capturer(root);
834 shell()->web_contents()->GetController().GoForward();
835 capturer.Wait();
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
844 // classified.
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();
856 // Simple load.
857 FrameNavigateParamsCapturer capturer(root);
858 GURL frame_url(embedded_test_server()->GetURL(
859 "/navigation_controller/simple_page_1.html"));
860 NavigateFrameToURL(root, frame_url);
861 capturer.Wait();
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));
884 // Initial load.
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);
889 capturer.Wait();
890 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
894 // Simple load.
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);
899 capturer.Wait();
900 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME,
901 capturer.params().transition);
902 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
906 // Back.
907 FrameNavigateParamsCapturer capturer(root->child_at(0));
908 shell()->web_contents()->GetController().GoBack();
909 capturer.Wait();
910 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.params().transition);
911 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.details().type);
915 // Forward.
916 FrameNavigateParamsCapturer capturer(root->child_at(0));
917 shell()->web_contents()->GetController().GoForward();
918 capturer.Wait();
919 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.params().transition);
920 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.details().type);
924 // Simple load.
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);
929 capturer.Wait();
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(),
940 script));
941 capturer.Wait();
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(),
954 script));
955 capturer.Wait();
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(),
968 script));
969 capturer.Wait();
970 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
974 // history.pushState().
975 FrameNavigateParamsCapturer capturer(root->child_at(0));
976 std::string script =
977 "history.pushState({}, 'page 1', 'simple_page_1.html')";
978 EXPECT_TRUE(content::ExecuteScript(root->child_at(0)->current_frame_host(),
979 script));
980 capturer.Wait();
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));
989 std::string script =
990 "history.replaceState({}, 'page 2', 'simple_page_2.html')";
991 EXPECT_TRUE(content::ExecuteScript(root->child_at(0)->current_frame_host(),
992 script));
993 capturer.Wait();
994 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
998 // Reload.
999 LoadCommittedCapturer capturer(root->child_at(0));
1000 EXPECT_TRUE(content::ExecuteScript(root->child_at(0)->current_frame_host(),
1001 "location.reload()"));
1002 capturer.Wait();
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));
1015 capturer.Wait();
1016 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
1020 // Verify that navigations caused by client-side redirects are correctly
1021 // classified.
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);
1038 capturer.Wait();
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));
1071 capturer.Wait();
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));
1082 capturer.Wait();
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(),
1108 script));
1109 capturer.Wait();
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(),
1121 script));
1122 capturer.Wait();
1123 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME,
1124 capturer.params().transition);
1125 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
1126 EXPECT_FALSE(capturer.details().is_in_page);
1130 // Verify the tree of FrameNavigationEntries after initial about:blank commits
1131 // in subframes, which should not count as real committed loads.
1132 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
1133 FrameNavigationEntry_BlankAutoSubframe) {
1134 GURL about_blank_url(url::kAboutBlankURL);
1135 GURL main_url(embedded_test_server()->GetURL(
1136 "/navigation_controller/simple_page_1.html"));
1137 NavigateToURL(shell(), main_url);
1138 const NavigationControllerImpl& controller =
1139 static_cast<const NavigationControllerImpl&>(
1140 shell()->web_contents()->GetController());
1141 FrameTreeNode* root =
1142 static_cast<WebContentsImpl*>(shell()->web_contents())->
1143 GetFrameTree()->root();
1145 // 1. Create a iframe with no URL.
1147 LoadCommittedCapturer capturer(shell()->web_contents());
1148 std::string script = "var iframe = document.createElement('iframe');"
1149 "document.body.appendChild(iframe);";
1150 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
1151 capturer.Wait();
1152 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
1155 // Check last committed NavigationEntry.
1156 EXPECT_EQ(1, controller.GetEntryCount());
1157 NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
1158 EXPECT_EQ(main_url, entry->GetURL());
1159 FrameNavigationEntry* root_entry = entry->root_node()->frame_entry.get();
1160 EXPECT_EQ(main_url, root_entry->url());
1162 // Verify subframe entries if we're in --site-per-process mode.
1163 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1164 switches::kSitePerProcess)) {
1165 // The entry should now have one blank subframe FrameNavigationEntry, but
1166 // this does not count as committing a real load.
1167 ASSERT_EQ(1U, entry->root_node()->children.size());
1168 FrameNavigationEntry* frame_entry =
1169 entry->root_node()->children[0]->frame_entry.get();
1170 EXPECT_EQ(about_blank_url, frame_entry->url());
1171 } else {
1172 // There are no subframe FrameNavigationEntries by default.
1173 EXPECT_EQ(0U, entry->root_node()->children.size());
1175 EXPECT_FALSE(root->child_at(0)->has_committed_real_load());
1177 // 1a. A nested iframe with no URL should also create a subframe entry but not
1178 // count as a real load.
1180 LoadCommittedCapturer capturer(shell()->web_contents());
1181 std::string script = "var iframe = document.createElement('iframe');"
1182 "document.body.appendChild(iframe);";
1183 EXPECT_TRUE(content::ExecuteScript(root->child_at(0)->current_frame_host(),
1184 script));
1185 capturer.Wait();
1186 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
1189 // Verify subframe entries if we're in --site-per-process mode.
1190 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1191 switches::kSitePerProcess)) {
1192 // The nested entry should have one blank subframe FrameNavigationEntry, but
1193 // this does not count as committing a real load.
1194 ASSERT_EQ(1U, entry->root_node()->children[0]->children.size());
1195 FrameNavigationEntry* frame_entry =
1196 entry->root_node()->children[0]->children[0]->frame_entry.get();
1197 EXPECT_EQ(about_blank_url, frame_entry->url());
1198 } else {
1199 // There are no subframe FrameNavigationEntries by default.
1200 EXPECT_EQ(0U, entry->root_node()->children.size());
1202 EXPECT_FALSE(root->child_at(0)->child_at(0)->has_committed_real_load());
1204 // 2. Create another iframe with an explicit about:blank URL.
1206 LoadCommittedCapturer capturer(shell()->web_contents());
1207 std::string script = "var iframe = document.createElement('iframe');"
1208 "iframe.src = 'about:blank';"
1209 "document.body.appendChild(iframe);";
1210 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
1211 capturer.Wait();
1212 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
1215 // Check last committed NavigationEntry.
1216 EXPECT_EQ(1, controller.GetEntryCount());
1217 EXPECT_EQ(entry, controller.GetLastCommittedEntry());
1219 // Verify subframe entries if we're in --site-per-process mode.
1220 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1221 switches::kSitePerProcess)) {
1222 // The new entry should have one blank subframe FrameNavigationEntry, but
1223 // this does not count as committing a real load.
1224 ASSERT_EQ(2U, entry->root_node()->children.size());
1225 FrameNavigationEntry* frame_entry =
1226 entry->root_node()->children[1]->frame_entry.get();
1227 EXPECT_EQ(about_blank_url, frame_entry->url());
1228 } else {
1229 // There are no subframe FrameNavigationEntries by default.
1230 EXPECT_EQ(0U, entry->root_node()->children.size());
1232 EXPECT_FALSE(root->child_at(1)->has_committed_real_load());
1234 // 3. A real same-site navigation in the nested iframe should be AUTO.
1235 GURL frame_url(embedded_test_server()->GetURL(
1236 "/navigation_controller/simple_page_1.html"));
1238 LoadCommittedCapturer capturer(root->child_at(0)->child_at(0));
1239 std::string script = "var frames = document.getElementsByTagName('iframe');"
1240 "frames[0].src = '" + frame_url.spec() + "';";
1241 EXPECT_TRUE(content::ExecuteScript(root->child_at(0)->current_frame_host(),
1242 script));
1243 capturer.Wait();
1244 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
1247 // Check last committed NavigationEntry. It should have replaced the previous
1248 // frame entry in the original NavigationEntry.
1249 EXPECT_EQ(1, controller.GetEntryCount());
1250 EXPECT_EQ(entry, controller.GetLastCommittedEntry());
1252 // Verify subframe entries if we're in --site-per-process mode.
1253 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1254 switches::kSitePerProcess)) {
1255 // The entry should still have one nested subframe FrameNavigationEntry.
1256 ASSERT_EQ(1U, entry->root_node()->children[0]->children.size());
1257 FrameNavigationEntry* frame_entry =
1258 entry->root_node()->children[0]->children[0]->frame_entry.get();
1259 EXPECT_EQ(frame_url, frame_entry->url());
1260 } else {
1261 // There are no subframe FrameNavigationEntries by default.
1262 EXPECT_EQ(0U, entry->root_node()->children.size());
1264 EXPECT_FALSE(root->child_at(0)->has_committed_real_load());
1265 EXPECT_TRUE(root->child_at(0)->child_at(0)->has_committed_real_load());
1266 EXPECT_FALSE(root->child_at(1)->has_committed_real_load());
1268 // 4. A real cross-site navigation in the second iframe should be AUTO.
1269 GURL foo_url(embedded_test_server()->GetURL(
1270 "foo.com", "/navigation_controller/simple_page_2.html"));
1272 LoadCommittedCapturer capturer(root->child_at(1));
1273 std::string script = "var frames = document.getElementsByTagName('iframe');"
1274 "frames[1].src = '" + foo_url.spec() + "';";
1275 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
1276 capturer.Wait();
1277 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
1280 // Check last committed NavigationEntry.
1281 EXPECT_EQ(1, controller.GetEntryCount());
1282 EXPECT_EQ(entry, controller.GetLastCommittedEntry());
1284 // Verify subframe entries if we're in --site-per-process mode.
1285 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1286 switches::kSitePerProcess)) {
1287 // The entry should still have two subframe FrameNavigationEntries.
1288 ASSERT_EQ(2U, entry->root_node()->children.size());
1289 FrameNavigationEntry* frame_entry =
1290 entry->root_node()->children[1]->frame_entry.get();
1291 EXPECT_EQ(foo_url, frame_entry->url());
1292 } else {
1293 // There are no subframe FrameNavigationEntries by default.
1294 EXPECT_EQ(0U, entry->root_node()->children.size());
1296 EXPECT_FALSE(root->child_at(0)->has_committed_real_load());
1297 EXPECT_TRUE(root->child_at(0)->child_at(0)->has_committed_real_load());
1298 EXPECT_TRUE(root->child_at(1)->has_committed_real_load());
1300 // 5. A new navigation to about:blank in the nested frame should count as a
1301 // real load, since that frame has already committed a real load and this is
1302 // not the initial blank page.
1304 LoadCommittedCapturer capturer(root->child_at(0)->child_at(0));
1305 std::string script = "var frames = document.getElementsByTagName('iframe');"
1306 "frames[0].src = 'about:blank';";
1307 EXPECT_TRUE(content::ExecuteScript(root->child_at(0)->current_frame_host(),
1308 script));
1309 capturer.Wait();
1310 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME, capturer.transition_type());
1313 // This should have created a new NavigationEntry.
1314 EXPECT_EQ(2, controller.GetEntryCount());
1315 EXPECT_NE(entry, controller.GetLastCommittedEntry());
1316 NavigationEntryImpl* entry2 = controller.GetLastCommittedEntry();
1318 // Verify subframe entries if we're in --site-per-process mode.
1319 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1320 switches::kSitePerProcess)) {
1321 ASSERT_EQ(2U, entry->root_node()->children.size());
1322 FrameNavigationEntry* frame_entry =
1323 entry2->root_node()->children[0]->children[0]->frame_entry.get();
1324 EXPECT_EQ(about_blank_url, frame_entry->url());
1325 } else {
1326 // There are no subframe FrameNavigationEntries by default.
1327 EXPECT_EQ(0U, entry->root_node()->children.size());
1329 EXPECT_FALSE(root->child_at(0)->has_committed_real_load());
1330 EXPECT_TRUE(root->child_at(0)->child_at(0)->has_committed_real_load());
1331 EXPECT_TRUE(root->child_at(1)->has_committed_real_load());
1333 // Check the end result of the frame tree.
1334 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1335 switches::kSitePerProcess)) {
1336 FrameTreeVisualizer visualizer;
1337 EXPECT_EQ(
1338 " Site A ------------ proxies for B\n"
1339 " |--Site A ------- proxies for B\n"
1340 " | +--Site A -- proxies for B\n"
1341 " +--Site B ------- proxies for A\n"
1342 "Where A = http://127.0.0.1/\n"
1343 " B = http://foo.com/",
1344 visualizer.DepictFrameTree(root));
1348 // Verify the tree of FrameNavigationEntries after NAVIGATION_TYPE_AUTO_SUBFRAME
1349 // commits.
1350 // TODO(creis): Test updating entries for history auto subframe navigations.
1351 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
1352 FrameNavigationEntry_AutoSubframe) {
1353 GURL main_url(embedded_test_server()->GetURL(
1354 "/navigation_controller/simple_page_1.html"));
1355 NavigateToURL(shell(), main_url);
1356 const NavigationControllerImpl& controller =
1357 static_cast<const NavigationControllerImpl&>(
1358 shell()->web_contents()->GetController());
1359 FrameTreeNode* root =
1360 static_cast<WebContentsImpl*>(shell()->web_contents())->
1361 GetFrameTree()->root();
1363 // 1. Create a same-site iframe.
1364 GURL frame_url(embedded_test_server()->GetURL(
1365 "/navigation_controller/simple_page_2.html"));
1367 LoadCommittedCapturer capturer(shell()->web_contents());
1368 std::string script = "var iframe = document.createElement('iframe');"
1369 "iframe.src = '" + frame_url.spec() + "';"
1370 "document.body.appendChild(iframe);";
1371 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
1372 capturer.Wait();
1373 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
1376 // Check last committed NavigationEntry.
1377 EXPECT_EQ(1, controller.GetEntryCount());
1378 NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
1379 EXPECT_EQ(main_url, entry->GetURL());
1380 FrameNavigationEntry* root_entry = entry->root_node()->frame_entry.get();
1381 EXPECT_EQ(main_url, root_entry->url());
1382 EXPECT_FALSE(controller.GetPendingEntry());
1384 // Verify subframe entries if we're in --site-per-process mode.
1385 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1386 switches::kSitePerProcess)) {
1387 // The entry should now have a subframe FrameNavigationEntry.
1388 ASSERT_EQ(1U, entry->root_node()->children.size());
1389 FrameNavigationEntry* frame_entry =
1390 entry->root_node()->children[0]->frame_entry.get();
1391 EXPECT_EQ(frame_url, frame_entry->url());
1392 EXPECT_TRUE(root->child_at(0)->has_committed_real_load());
1393 } else {
1394 // There are no subframe FrameNavigationEntries by default.
1395 EXPECT_EQ(0U, entry->root_node()->children.size());
1398 // 2. Create a second, initially cross-site iframe.
1399 GURL foo_url(embedded_test_server()->GetURL(
1400 "foo.com", "/navigation_controller/simple_page_1.html"));
1402 LoadCommittedCapturer capturer(shell()->web_contents());
1403 std::string script = "var iframe = document.createElement('iframe');"
1404 "iframe.src = '" + foo_url.spec() + "';"
1405 "document.body.appendChild(iframe);";
1406 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
1407 capturer.Wait();
1408 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
1411 // The last committed NavigationEntry shouldn't have changed.
1412 EXPECT_EQ(1, controller.GetEntryCount());
1413 entry = controller.GetLastCommittedEntry();
1414 EXPECT_EQ(main_url, entry->GetURL());
1415 root_entry = entry->root_node()->frame_entry.get();
1416 EXPECT_EQ(main_url, root_entry->url());
1417 EXPECT_FALSE(controller.GetPendingEntry());
1419 // Verify subframe entries if we're in --site-per-process mode.
1420 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1421 switches::kSitePerProcess)) {
1422 // The entry should now have 2 subframe FrameNavigationEntries.
1423 ASSERT_EQ(2U, entry->root_node()->children.size());
1424 FrameNavigationEntry* frame_entry =
1425 entry->root_node()->children[1]->frame_entry.get();
1426 EXPECT_EQ(foo_url, frame_entry->url());
1427 EXPECT_TRUE(root->child_at(1)->has_committed_real_load());
1428 } else {
1429 // There are no subframe FrameNavigationEntries by default.
1430 EXPECT_EQ(0U, entry->root_node()->children.size());
1433 // 3. Create a nested iframe in the second subframe.
1435 LoadCommittedCapturer capturer(shell()->web_contents());
1436 std::string script = "var iframe = document.createElement('iframe');"
1437 "iframe.src = '" + foo_url.spec() + "';"
1438 "document.body.appendChild(iframe);";
1439 EXPECT_TRUE(content::ExecuteScript(root->child_at(1)->current_frame_host(),
1440 script));
1441 capturer.Wait();
1442 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
1445 // The last committed NavigationEntry shouldn't have changed.
1446 EXPECT_EQ(1, controller.GetEntryCount());
1447 entry = controller.GetLastCommittedEntry();
1448 EXPECT_EQ(main_url, entry->GetURL());
1449 root_entry = entry->root_node()->frame_entry.get();
1450 EXPECT_EQ(main_url, root_entry->url());
1452 // Verify subframe entries if we're in --site-per-process mode.
1453 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1454 switches::kSitePerProcess)) {
1455 // The entry should now have 2 subframe FrameNavigationEntries.
1456 ASSERT_EQ(2U, entry->root_node()->children.size());
1457 ASSERT_EQ(1U, entry->root_node()->children[1]->children.size());
1458 FrameNavigationEntry* frame_entry =
1459 entry->root_node()->children[1]->children[0]->frame_entry.get();
1460 EXPECT_EQ(foo_url, frame_entry->url());
1461 } else {
1462 // There are no subframe FrameNavigationEntries by default.
1463 EXPECT_EQ(0U, entry->root_node()->children.size());
1466 // 4. Create a third iframe on the same site as the second. This ensures that
1467 // the commit type is correct even when the subframe process already exists.
1469 LoadCommittedCapturer capturer(shell()->web_contents());
1470 std::string script = "var iframe = document.createElement('iframe');"
1471 "iframe.src = '" + foo_url.spec() + "';"
1472 "document.body.appendChild(iframe);";
1473 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
1474 capturer.Wait();
1475 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
1478 // The last committed NavigationEntry shouldn't have changed.
1479 EXPECT_EQ(1, controller.GetEntryCount());
1480 entry = controller.GetLastCommittedEntry();
1481 EXPECT_EQ(main_url, entry->GetURL());
1482 root_entry = entry->root_node()->frame_entry.get();
1483 EXPECT_EQ(main_url, root_entry->url());
1485 // Verify subframe entries if we're in --site-per-process mode.
1486 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1487 switches::kSitePerProcess)) {
1488 // The entry should now have 3 subframe FrameNavigationEntries.
1489 ASSERT_EQ(3U, entry->root_node()->children.size());
1490 FrameNavigationEntry* frame_entry =
1491 entry->root_node()->children[2]->frame_entry.get();
1492 EXPECT_EQ(foo_url, frame_entry->url());
1493 } else {
1494 // There are no subframe FrameNavigationEntries by default.
1495 EXPECT_EQ(0U, entry->root_node()->children.size());
1498 // 5. Create a nested iframe on the original site (A-B-A).
1500 LoadCommittedCapturer capturer(shell()->web_contents());
1501 std::string script = "var iframe = document.createElement('iframe');"
1502 "iframe.src = '" + frame_url.spec() + "';"
1503 "document.body.appendChild(iframe);";
1504 FrameTreeNode* child = root->child_at(2);
1505 EXPECT_TRUE(content::ExecuteScript(child->current_frame_host(), script));
1506 capturer.Wait();
1507 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
1510 // The last committed NavigationEntry shouldn't have changed.
1511 EXPECT_EQ(1, controller.GetEntryCount());
1512 entry = controller.GetLastCommittedEntry();
1513 EXPECT_EQ(main_url, entry->GetURL());
1514 root_entry = entry->root_node()->frame_entry.get();
1515 EXPECT_EQ(main_url, root_entry->url());
1517 // Verify subframe entries if we're in --site-per-process mode.
1518 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1519 switches::kSitePerProcess)) {
1520 // There should be a corresponding FrameNavigationEntry.
1521 ASSERT_EQ(1U, entry->root_node()->children[2]->children.size());
1522 FrameNavigationEntry* frame_entry =
1523 entry->root_node()->children[2]->children[0]->frame_entry.get();
1524 EXPECT_EQ(frame_url, frame_entry->url());
1525 } else {
1526 // There are no subframe FrameNavigationEntries by default.
1527 EXPECT_EQ(0U, entry->root_node()->children.size());
1530 // Check the end result of the frame tree.
1531 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1532 switches::kSitePerProcess)) {
1533 FrameTreeVisualizer visualizer;
1534 EXPECT_EQ(
1535 " Site A ------------ proxies for B\n"
1536 " |--Site A ------- proxies for B\n"
1537 " |--Site B ------- proxies for A\n"
1538 " | +--Site B -- proxies for A\n"
1539 " +--Site B ------- proxies for A\n"
1540 " +--Site A -- proxies for B\n"
1541 "Where A = http://127.0.0.1/\n"
1542 " B = http://foo.com/",
1543 visualizer.DepictFrameTree(root));
1547 // Verify the tree of FrameNavigationEntries after NAVIGATION_TYPE_NEW_SUBFRAME
1548 // commits.
1549 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
1550 FrameNavigationEntry_NewSubframe) {
1551 GURL main_url(embedded_test_server()->GetURL(
1552 "/navigation_controller/simple_page_1.html"));
1553 NavigateToURL(shell(), main_url);
1554 const NavigationControllerImpl& controller =
1555 static_cast<const NavigationControllerImpl&>(
1556 shell()->web_contents()->GetController());
1557 FrameTreeNode* root =
1558 static_cast<WebContentsImpl*>(shell()->web_contents())->
1559 GetFrameTree()->root();
1561 // 1. Create a same-site iframe.
1562 GURL frame_url(embedded_test_server()->GetURL(
1563 "/navigation_controller/simple_page_2.html"));
1565 LoadCommittedCapturer capturer(shell()->web_contents());
1566 std::string script = "var iframe = document.createElement('iframe');"
1567 "iframe.src = '" + frame_url.spec() + "';"
1568 "document.body.appendChild(iframe);";
1569 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
1570 capturer.Wait();
1572 NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
1574 // 2. Navigate in the subframe same-site.
1575 GURL frame_url2(embedded_test_server()->GetURL(
1576 "/navigation_controller/page_with_links.html"));
1578 FrameNavigateParamsCapturer capturer(root->child_at(0));
1579 NavigateFrameToURL(root->child_at(0), frame_url2);
1580 capturer.Wait();
1581 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME,
1582 capturer.params().transition);
1583 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
1586 // We should have created a new NavigationEntry with the same main frame URL.
1587 EXPECT_EQ(2, controller.GetEntryCount());
1588 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
1589 NavigationEntryImpl* entry2 = controller.GetLastCommittedEntry();
1590 EXPECT_NE(entry, entry2);
1591 EXPECT_EQ(main_url, entry2->GetURL());
1592 FrameNavigationEntry* root_entry2 = entry2->root_node()->frame_entry.get();
1593 EXPECT_EQ(main_url, root_entry2->url());
1595 // Verify subframe entries if we're in --site-per-process mode.
1596 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1597 switches::kSitePerProcess)) {
1598 // The entry should have a new FrameNavigationEntries for the subframe.
1599 ASSERT_EQ(1U, entry2->root_node()->children.size());
1600 EXPECT_EQ(frame_url2, entry2->root_node()->children[0]->frame_entry->url());
1601 } else {
1602 // There are no subframe FrameNavigationEntries by default.
1603 EXPECT_EQ(0U, entry2->root_node()->children.size());
1606 // 3. Create a second, initially cross-site iframe.
1607 GURL foo_url(embedded_test_server()->GetURL(
1608 "foo.com", "/navigation_controller/simple_page_1.html"));
1610 LoadCommittedCapturer capturer(shell()->web_contents());
1611 std::string script = "var iframe = document.createElement('iframe');"
1612 "iframe.src = '" + foo_url.spec() + "';"
1613 "document.body.appendChild(iframe);";
1614 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
1615 capturer.Wait();
1618 // 4. Create a nested same-site iframe in the second subframe, wait for it to
1619 // commit, then navigate it again.
1621 LoadCommittedCapturer capturer(shell()->web_contents());
1622 std::string script = "var iframe = document.createElement('iframe');"
1623 "iframe.src = '" + foo_url.spec() + "';"
1624 "document.body.appendChild(iframe);";
1625 EXPECT_TRUE(content::ExecuteScript(root->child_at(1)->current_frame_host(),
1626 script));
1627 capturer.Wait();
1629 GURL bar_url(embedded_test_server()->GetURL(
1630 "bar.com", "/navigation_controller/simple_page_1.html"));
1632 FrameNavigateParamsCapturer capturer(root->child_at(1)->child_at(0));
1633 NavigateFrameToURL(root->child_at(1)->child_at(0), bar_url);
1634 capturer.Wait();
1635 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME,
1636 capturer.params().transition);
1637 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
1640 // We should have created a new NavigationEntry with the same main frame URL.
1641 EXPECT_EQ(3, controller.GetEntryCount());
1642 EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
1643 NavigationEntryImpl* entry3 = controller.GetLastCommittedEntry();
1644 EXPECT_NE(entry, entry3);
1645 EXPECT_EQ(main_url, entry3->GetURL());
1646 FrameNavigationEntry* root_entry3 = entry3->root_node()->frame_entry.get();
1647 EXPECT_EQ(main_url, root_entry3->url());
1649 // Verify subframe entries if we're in --site-per-process mode.
1650 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1651 switches::kSitePerProcess)) {
1652 // The entry should still have FrameNavigationEntries for all 3 subframes.
1653 ASSERT_EQ(2U, entry3->root_node()->children.size());
1654 EXPECT_EQ(frame_url2, entry3->root_node()->children[0]->frame_entry->url());
1655 EXPECT_EQ(foo_url, entry3->root_node()->children[1]->frame_entry->url());
1656 ASSERT_EQ(1U, entry3->root_node()->children[1]->children.size());
1657 EXPECT_EQ(
1658 bar_url,
1659 entry3->root_node()->children[1]->children[0]->frame_entry->url());
1660 } else {
1661 // There are no subframe FrameNavigationEntries by default.
1662 EXPECT_EQ(0U, entry3->root_node()->children.size());
1665 // 6. Navigate the second subframe cross-site, clearing its existing subtree.
1666 GURL baz_url(embedded_test_server()->GetURL(
1667 "baz.com", "/navigation_controller/simple_page_1.html"));
1669 FrameNavigateParamsCapturer capturer(root->child_at(1));
1670 std::string script = "var frames = document.getElementsByTagName('iframe');"
1671 "frames[1].src = '" + baz_url.spec() + "';";
1672 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
1673 capturer.Wait();
1674 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME,
1675 capturer.params().transition);
1676 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
1679 // We should have created a new NavigationEntry with the same main frame URL.
1680 EXPECT_EQ(4, controller.GetEntryCount());
1681 EXPECT_EQ(3, controller.GetLastCommittedEntryIndex());
1682 NavigationEntryImpl* entry4 = controller.GetLastCommittedEntry();
1683 EXPECT_NE(entry, entry4);
1684 EXPECT_EQ(main_url, entry4->GetURL());
1685 FrameNavigationEntry* root_entry4 = entry4->root_node()->frame_entry.get();
1686 EXPECT_EQ(main_url, root_entry4->url());
1688 // Verify subframe entries if we're in --site-per-process mode.
1689 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1690 switches::kSitePerProcess)) {
1691 // The entry should still have FrameNavigationEntries for all 3 subframes.
1692 ASSERT_EQ(2U, entry4->root_node()->children.size());
1693 EXPECT_EQ(frame_url2, entry4->root_node()->children[0]->frame_entry->url());
1694 EXPECT_EQ(baz_url, entry4->root_node()->children[1]->frame_entry->url());
1695 ASSERT_EQ(0U, entry4->root_node()->children[1]->children.size());
1696 } else {
1697 // There are no subframe FrameNavigationEntries by default.
1698 EXPECT_EQ(0U, entry4->root_node()->children.size());
1701 // Check the end result of the frame tree.
1702 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1703 switches::kSitePerProcess)) {
1704 FrameTreeVisualizer visualizer;
1705 EXPECT_EQ(
1706 " Site A ------------ proxies for B\n"
1707 " |--Site A ------- proxies for B\n"
1708 " +--Site B ------- proxies for A\n"
1709 "Where A = http://127.0.0.1/\n"
1710 " B = http://baz.com/",
1711 visualizer.DepictFrameTree(root));
1715 // Verify the tree of FrameNavigationEntries after back/forward navigations in a
1716 // cross-site subframe.
1717 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
1718 FrameNavigationEntry_SubframeBackForward) {
1719 GURL main_url(embedded_test_server()->GetURL(
1720 "/navigation_controller/simple_page_1.html"));
1721 NavigateToURL(shell(), main_url);
1722 const NavigationControllerImpl& controller =
1723 static_cast<const NavigationControllerImpl&>(
1724 shell()->web_contents()->GetController());
1725 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1726 ->GetFrameTree()
1727 ->root();
1729 // 1. Create a same-site iframe.
1730 GURL frame_url(embedded_test_server()->GetURL(
1731 "/navigation_controller/simple_page_2.html"));
1733 LoadCommittedCapturer capturer(shell()->web_contents());
1734 std::string script = "var iframe = document.createElement('iframe');"
1735 "iframe.src = '" + frame_url.spec() + "';"
1736 "document.body.appendChild(iframe);";
1737 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
1738 capturer.Wait();
1740 NavigationEntryImpl* entry1 = controller.GetLastCommittedEntry();
1742 // 2. Navigate in the subframe cross-site.
1743 GURL frame_url2(embedded_test_server()->GetURL(
1744 "foo.com", "/navigation_controller/page_with_links.html"));
1746 FrameNavigateParamsCapturer capturer(root->child_at(0));
1747 NavigateFrameToURL(root->child_at(0), frame_url2);
1748 capturer.Wait();
1750 EXPECT_EQ(2, controller.GetEntryCount());
1751 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
1752 NavigationEntryImpl* entry2 = controller.GetLastCommittedEntry();
1754 // 3. Navigate in the subframe cross-site again.
1755 GURL frame_url3(embedded_test_server()->GetURL(
1756 "bar.com", "/navigation_controller/page_with_links.html"));
1758 FrameNavigateParamsCapturer capturer(root->child_at(0));
1759 NavigateFrameToURL(root->child_at(0), frame_url3);
1760 capturer.Wait();
1762 EXPECT_EQ(3, controller.GetEntryCount());
1763 EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
1764 NavigationEntryImpl* entry3 = controller.GetLastCommittedEntry();
1766 // 4. Go back in the subframe.
1768 FrameNavigateParamsCapturer capturer(root->child_at(0));
1769 shell()->web_contents()->GetController().GoBack();
1770 capturer.Wait();
1771 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.params().transition);
1772 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.details().type);
1774 EXPECT_EQ(3, controller.GetEntryCount());
1775 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
1776 EXPECT_EQ(entry2, controller.GetLastCommittedEntry());
1778 // Verify subframe entries if we're in --site-per-process mode.
1779 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1780 switches::kSitePerProcess)) {
1781 // The entry should have a new FrameNavigationEntries for the subframe.
1782 ASSERT_EQ(1U, entry2->root_node()->children.size());
1783 EXPECT_EQ(frame_url2, entry2->root_node()->children[0]->frame_entry->url());
1784 } else {
1785 // There are no subframe FrameNavigationEntries by default.
1786 EXPECT_EQ(0U, entry2->root_node()->children.size());
1789 // 5. Go back in the subframe again to the parent page's site.
1791 FrameNavigateParamsCapturer capturer(root->child_at(0));
1792 shell()->web_contents()->GetController().GoBack();
1793 capturer.Wait();
1794 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.params().transition);
1795 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.details().type);
1797 EXPECT_EQ(3, controller.GetEntryCount());
1798 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
1799 EXPECT_EQ(entry1, controller.GetLastCommittedEntry());
1801 // Verify subframe entries if we're in --site-per-process mode.
1802 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1803 switches::kSitePerProcess)) {
1804 // The entry should have a new FrameNavigationEntries for the subframe.
1805 ASSERT_EQ(1U, entry1->root_node()->children.size());
1806 EXPECT_EQ(frame_url, entry1->root_node()->children[0]->frame_entry->url());
1807 } else {
1808 // There are no subframe FrameNavigationEntries by default.
1809 EXPECT_EQ(0U, entry1->root_node()->children.size());
1812 // 6. Go forward in the subframe cross-site.
1814 FrameNavigateParamsCapturer capturer(root->child_at(0));
1815 shell()->web_contents()->GetController().GoForward();
1816 capturer.Wait();
1817 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.params().transition);
1818 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.details().type);
1820 EXPECT_EQ(3, controller.GetEntryCount());
1821 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex());
1822 EXPECT_EQ(entry2, controller.GetLastCommittedEntry());
1824 // Verify subframe entries if we're in --site-per-process mode.
1825 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1826 switches::kSitePerProcess)) {
1827 // The entry should have a new FrameNavigationEntries for the subframe.
1828 ASSERT_EQ(1U, entry2->root_node()->children.size());
1829 EXPECT_EQ(frame_url2, entry2->root_node()->children[0]->frame_entry->url());
1830 } else {
1831 // There are no subframe FrameNavigationEntries by default.
1832 EXPECT_EQ(0U, entry2->root_node()->children.size());
1835 // 7. Go forward in the subframe again, cross-site.
1837 FrameNavigateParamsCapturer capturer(root->child_at(0));
1838 shell()->web_contents()->GetController().GoForward();
1839 capturer.Wait();
1840 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.params().transition);
1841 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.details().type);
1843 EXPECT_EQ(3, controller.GetEntryCount());
1844 EXPECT_EQ(2, controller.GetLastCommittedEntryIndex());
1845 EXPECT_EQ(entry3, controller.GetLastCommittedEntry());
1847 // Verify subframe entries if we're in --site-per-process mode.
1848 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1849 switches::kSitePerProcess)) {
1850 // The entry should have a new FrameNavigationEntries for the subframe.
1851 ASSERT_EQ(1U, entry3->root_node()->children.size());
1852 EXPECT_EQ(frame_url3, entry3->root_node()->children[0]->frame_entry->url());
1853 } else {
1854 // There are no subframe FrameNavigationEntries by default.
1855 EXPECT_EQ(0U, entry3->root_node()->children.size());
1859 // Verifies that item sequence numbers and document sequence numbers update
1860 // properly for main frames and subframes.
1861 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
1862 FrameNavigationEntry_SequenceNumbers) {
1863 const NavigationControllerImpl& controller =
1864 static_cast<const NavigationControllerImpl&>(
1865 shell()->web_contents()->GetController());
1867 // 1. Navigate the main frame.
1868 GURL url(embedded_test_server()->GetURL(
1869 "/navigation_controller/page_with_links.html"));
1870 NavigateToURL(shell(), url);
1871 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1872 ->GetFrameTree()
1873 ->root();
1875 FrameNavigationEntry* frame_entry =
1876 controller.GetLastCommittedEntry()->GetFrameEntry(root);
1877 int64 isn_1 = frame_entry->item_sequence_number();
1878 int64 dsn_1 = frame_entry->document_sequence_number();
1879 EXPECT_NE(-1, isn_1);
1880 EXPECT_NE(-1, dsn_1);
1882 // 2. Do an in-page fragment navigation.
1883 std::string script = "document.getElementById('fraglink').click()";
1884 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
1885 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1887 frame_entry = controller.GetLastCommittedEntry()->GetFrameEntry(root);
1888 int64 isn_2 = frame_entry->item_sequence_number();
1889 int64 dsn_2 = frame_entry->document_sequence_number();
1890 EXPECT_NE(-1, isn_2);
1891 EXPECT_NE(isn_1, isn_2);
1892 EXPECT_EQ(dsn_1, dsn_2);
1894 // Also test subframe sequence numbers, but only in --site-per-proces mode.
1895 // (We do not create subframe FrameNavigationEntries in default mode yet.)
1896 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
1897 switches::kSitePerProcess))
1898 return;
1900 // 3. Add a subframe, which does an AUTO_SUBFRAME navigation.
1902 LoadCommittedCapturer capturer(shell()->web_contents());
1903 std::string script = "var iframe = document.createElement('iframe');"
1904 "iframe.src = '" + url.spec() + "';"
1905 "document.body.appendChild(iframe);";
1906 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
1907 capturer.Wait();
1908 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
1911 // The root FrameNavigationEntry hasn't changed.
1912 EXPECT_EQ(frame_entry,
1913 controller.GetLastCommittedEntry()->GetFrameEntry(root));
1915 // We should have a unique ISN and DSN for the subframe entry.
1916 FrameTreeNode* subframe = root->child_at(0);
1917 FrameNavigationEntry* subframe_entry =
1918 controller.GetLastCommittedEntry()->GetFrameEntry(subframe);
1919 int64 isn_3 = subframe_entry->item_sequence_number();
1920 int64 dsn_3 = subframe_entry->document_sequence_number();
1921 EXPECT_NE(-1, isn_2);
1922 EXPECT_NE(isn_2, isn_3);
1923 EXPECT_NE(dsn_2, dsn_3);
1925 // 4. Do an in-page fragment navigation in the subframe.
1926 EXPECT_TRUE(content::ExecuteScript(subframe->current_frame_host(), script));
1927 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1929 subframe_entry = controller.GetLastCommittedEntry()->GetFrameEntry(subframe);
1930 int64 isn_4 = subframe_entry->item_sequence_number();
1931 int64 dsn_4 = subframe_entry->document_sequence_number();
1932 EXPECT_NE(-1, isn_4);
1933 EXPECT_NE(isn_3, isn_4);
1934 EXPECT_EQ(dsn_3, dsn_4);
1937 namespace {
1939 class HttpThrottle : public ResourceThrottle {
1940 public:
1941 // ResourceThrottle
1942 void WillStartRequest(bool* defer) override {
1943 *defer = true;
1946 const char* GetNameForLogging() const override {
1947 return "HttpThrottle";
1951 class StallDelegate : public ResourceDispatcherHostDelegate {
1952 // ResourceDispatcherHostDelegate
1953 void RequestBeginning(
1954 net::URLRequest* request,
1955 content::ResourceContext* resource_context,
1956 content::AppCacheService* appcache_service,
1957 ResourceType resource_type,
1958 ScopedVector<content::ResourceThrottle>* throttles) override {
1959 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1960 throttles->push_back(new HttpThrottle);
1964 // Loads |start_url|, then loads |stalled_url| which stalls. While the page is
1965 // stalled, an in-page navigation happens. Make sure that all the navigations
1966 // are properly classified.
1967 void DoReplaceStateWhilePending(Shell* shell,
1968 const GURL& start_url,
1969 const GURL& stalled_url,
1970 const std::string& replace_state_filename) {
1971 NavigationControllerImpl& controller =
1972 static_cast<NavigationControllerImpl&>(
1973 shell->web_contents()->GetController());
1975 FrameTreeNode* root =
1976 static_cast<WebContentsImpl*>(shell->web_contents())->
1977 GetFrameTree()->root();
1979 // Start with one page.
1980 EXPECT_TRUE(NavigateToURL(shell, start_url));
1982 // Have the user decide to go to a different page which is very slow.
1983 StallDelegate stall_delegate;
1984 ResourceDispatcherHost::Get()->SetDelegate(&stall_delegate);
1985 controller.LoadURL(
1986 stalled_url, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
1988 // That should be the pending entry.
1989 NavigationEntryImpl* entry = controller.GetPendingEntry();
1990 ASSERT_NE(nullptr, entry);
1991 EXPECT_EQ(stalled_url, entry->GetURL());
1994 // Now the existing page uses history.replaceState().
1995 FrameNavigateParamsCapturer capturer(root);
1996 capturer.set_wait_for_load(false);
1997 std::string script =
1998 "history.replaceState({}, '', '" + replace_state_filename + "')";
1999 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
2000 capturer.Wait();
2002 // The fact that there was a pending entry shouldn't interfere with the
2003 // classification.
2004 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.details().type);
2005 EXPECT_TRUE(capturer.details().is_in_page);
2008 ResourceDispatcherHost::Get()->SetDelegate(nullptr);
2011 } // namespace
2013 IN_PROC_BROWSER_TEST_F(
2014 NavigationControllerBrowserTest,
2015 NavigationTypeClassification_On1InPageToXWhile2Pending) {
2016 GURL url1(embedded_test_server()->GetURL(
2017 "/navigation_controller/simple_page_1.html"));
2018 GURL url2(embedded_test_server()->GetURL(
2019 "/navigation_controller/simple_page_2.html"));
2020 DoReplaceStateWhilePending(shell(), url1, url2, "x");
2023 IN_PROC_BROWSER_TEST_F(
2024 NavigationControllerBrowserTest,
2025 NavigationTypeClassification_On1InPageTo2While2Pending) {
2026 GURL url1(embedded_test_server()->GetURL(
2027 "/navigation_controller/simple_page_1.html"));
2028 GURL url2(embedded_test_server()->GetURL(
2029 "/navigation_controller/simple_page_2.html"));
2030 DoReplaceStateWhilePending(shell(), url1, url2, "simple_page_2.html");
2033 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
2034 NavigationTypeClassification_On1InPageToXWhile1Pending) {
2035 GURL url(embedded_test_server()->GetURL(
2036 "/navigation_controller/simple_page_1.html"));
2037 DoReplaceStateWhilePending(shell(), url, url, "x");
2040 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
2041 NavigationTypeClassification_On1InPageTo1While1Pending) {
2042 GURL url(embedded_test_server()->GetURL(
2043 "/navigation_controller/simple_page_1.html"));
2044 DoReplaceStateWhilePending(shell(), url, url, "simple_page_1.html");
2047 // Ensure the renderer process does not get confused about the current entry
2048 // due to subframes and replaced entries. See https://crbug.com/480201.
2049 // TODO(creis): Re-enable for Site Isolation FYI bots: https://crbug.com/502317.
2050 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
2051 PreventSpoofFromSubframeAndReplace) {
2052 // Start at an initial URL.
2053 GURL url1(embedded_test_server()->GetURL(
2054 "/navigation_controller/simple_page_1.html"));
2055 NavigateToURL(shell(), url1);
2057 // Now go to a page with a real iframe.
2058 GURL url2(embedded_test_server()->GetURL(
2059 "/navigation_controller/page_with_data_iframe.html"));
2060 NavigateToURL(shell(), url2);
2062 // It is safe to obtain the root frame tree node here, as it doesn't change.
2063 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2064 ->GetFrameTree()
2065 ->root();
2066 ASSERT_EQ(1U, root->child_count());
2067 ASSERT_NE(nullptr, root->child_at(0));
2070 // Navigate in the iframe.
2071 FrameNavigateParamsCapturer capturer(root->child_at(0));
2072 GURL frame_url(embedded_test_server()->GetURL(
2073 "/navigation_controller/simple_page_2.html"));
2074 NavigateFrameToURL(root->child_at(0), frame_url);
2075 capturer.Wait();
2076 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
2080 // Go back in the iframe.
2081 TestNavigationObserver back_load_observer(shell()->web_contents());
2082 shell()->web_contents()->GetController().GoBack();
2083 back_load_observer.Wait();
2087 // Go forward in the iframe.
2088 TestNavigationObserver forward_load_observer(shell()->web_contents());
2089 shell()->web_contents()->GetController().GoForward();
2090 forward_load_observer.Wait();
2093 GURL url3(embedded_test_server()->GetURL(
2094 "/navigation_controller/page_with_iframe.html"));
2096 // location.replace() to cause an inert commit.
2097 TestNavigationObserver replace_load_observer(shell()->web_contents());
2098 std::string script = "location.replace('" + url3.spec() + "')";
2099 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
2100 replace_load_observer.Wait();
2104 // Go back to url2.
2105 TestNavigationObserver back_load_observer(shell()->web_contents());
2106 shell()->web_contents()->GetController().GoBack();
2107 back_load_observer.Wait();
2109 // Make sure the URL is correct for both the entry and the main frame, and
2110 // that the process hasn't been killed for showing a spoof.
2111 EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
2112 EXPECT_EQ(url2, shell()->web_contents()->GetLastCommittedURL());
2113 EXPECT_EQ(url2, root->current_url());
2117 // Go back to reset main frame entirely.
2118 TestNavigationObserver back_load_observer(shell()->web_contents());
2119 shell()->web_contents()->GetController().GoBack();
2120 back_load_observer.Wait();
2121 EXPECT_EQ(url1, shell()->web_contents()->GetLastCommittedURL());
2122 EXPECT_EQ(url1, root->current_url());
2126 // Go forward.
2127 TestNavigationObserver back_load_observer(shell()->web_contents());
2128 shell()->web_contents()->GetController().GoForward();
2129 back_load_observer.Wait();
2130 EXPECT_EQ(url2, shell()->web_contents()->GetLastCommittedURL());
2131 EXPECT_EQ(url2, root->current_url());
2135 // Go forward to the replaced URL.
2136 TestNavigationObserver forward_load_observer(shell()->web_contents());
2137 shell()->web_contents()->GetController().GoForward();
2138 forward_load_observer.Wait();
2140 // Make sure the URL is correct for both the entry and the main frame, and
2141 // that the process hasn't been killed for showing a spoof.
2142 EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
2143 EXPECT_EQ(url3, shell()->web_contents()->GetLastCommittedURL());
2144 EXPECT_EQ(url3, root->current_url());
2148 // Ensure the renderer process does not get killed if the main frame URL's path
2149 // changes when going back in a subframe, since this is currently possible after
2150 // a replaceState in the main frame (thanks to https://crbug.com/373041).
2151 // See https:///crbug.com/486916.
2152 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
2153 SubframeBackFromReplaceState) {
2154 // Start at a page with a real iframe.
2155 GURL url1(embedded_test_server()->GetURL(
2156 "/navigation_controller/page_with_data_iframe.html"));
2157 NavigateToURL(shell(), url1);
2159 // It is safe to obtain the root frame tree node here, as it doesn't change.
2160 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2161 ->GetFrameTree()
2162 ->root();
2163 ASSERT_EQ(1U, root->child_count());
2164 ASSERT_NE(nullptr, root->child_at(0));
2167 // Navigate in the iframe.
2168 FrameNavigateParamsCapturer capturer(root->child_at(0));
2169 GURL frame_url(embedded_test_server()->GetURL(
2170 "/navigation_controller/simple_page_2.html"));
2171 NavigateFrameToURL(root->child_at(0), frame_url);
2172 capturer.Wait();
2173 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
2177 // history.replaceState().
2178 FrameNavigateParamsCapturer capturer(root);
2179 std::string script =
2180 "history.replaceState({}, 'replaced', 'replaced')";
2181 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
2182 capturer.Wait();
2186 // Go back in the iframe.
2187 TestNavigationObserver back_load_observer(shell()->web_contents());
2188 shell()->web_contents()->GetController().GoBack();
2189 back_load_observer.Wait();
2192 // For now, we expect the main frame's URL to revert. This won't happen once
2193 // https://crbug.com/373041 is fixed.
2194 EXPECT_EQ(url1, shell()->web_contents()->GetLastCommittedURL());
2196 // Make sure the renderer process has not been killed.
2197 EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
2200 namespace {
2202 class FailureWatcher : public WebContentsObserver {
2203 public:
2204 // Observes failure for the specified |node|.
2205 explicit FailureWatcher(FrameTreeNode* node)
2206 : WebContentsObserver(
2207 node->current_frame_host()->delegate()->GetAsWebContents()),
2208 frame_tree_node_id_(node->frame_tree_node_id()),
2209 message_loop_runner_(new MessageLoopRunner) {}
2211 void Wait() {
2212 message_loop_runner_->Run();
2215 private:
2216 void DidFailLoad(RenderFrameHost* render_frame_host,
2217 const GURL& validated_url,
2218 int error_code,
2219 const base::string16& error_description,
2220 bool was_ignored_by_handler) override {
2221 RenderFrameHostImpl* rfh =
2222 static_cast<RenderFrameHostImpl*>(render_frame_host);
2223 if (rfh->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_)
2224 return;
2226 message_loop_runner_->Quit();
2229 void DidFailProvisionalLoad(
2230 RenderFrameHost* render_frame_host,
2231 const GURL& validated_url,
2232 int error_code,
2233 const base::string16& error_description,
2234 bool was_ignored_by_handler) override {
2235 RenderFrameHostImpl* rfh =
2236 static_cast<RenderFrameHostImpl*>(render_frame_host);
2237 if (rfh->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_)
2238 return;
2240 message_loop_runner_->Quit();
2243 // The id of the FrameTreeNode whose navigations to observe.
2244 int frame_tree_node_id_;
2246 // The MessageLoopRunner used to spin the message loop.
2247 scoped_refptr<MessageLoopRunner> message_loop_runner_;
2250 } // namespace
2252 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
2253 StopCausesFailureDespiteJavaScriptURL) {
2254 NavigationControllerImpl& controller =
2255 static_cast<NavigationControllerImpl&>(
2256 shell()->web_contents()->GetController());
2258 FrameTreeNode* root =
2259 static_cast<WebContentsImpl*>(shell()->web_contents())->
2260 GetFrameTree()->root();
2262 // Start with a normal page.
2263 GURL url1(embedded_test_server()->GetURL(
2264 "/navigation_controller/simple_page_1.html"));
2265 EXPECT_TRUE(NavigateToURL(shell(), url1));
2267 // Have the user decide to go to a different page which is very slow.
2268 StallDelegate stall_delegate;
2269 ResourceDispatcherHost::Get()->SetDelegate(&stall_delegate);
2270 GURL url2(embedded_test_server()->GetURL(
2271 "/navigation_controller/simple_page_2.html"));
2272 controller.LoadURL(url2, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
2274 // That should be the pending entry.
2275 NavigationEntryImpl* entry = controller.GetPendingEntry();
2276 ASSERT_NE(nullptr, entry);
2277 EXPECT_EQ(url2, entry->GetURL());
2279 // Loading a JavaScript URL shouldn't affect the ability to stop.
2281 FailureWatcher watcher(root);
2282 GURL js("javascript:(function(){})()");
2283 controller.LoadURL(js, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
2284 // This LoadURL ends up purging the pending entry, which is why this is
2285 // tricky.
2286 EXPECT_EQ(nullptr, controller.GetPendingEntry());
2287 shell()->web_contents()->Stop();
2288 watcher.Wait();
2291 ResourceDispatcherHost::Get()->SetDelegate(nullptr);
2294 namespace {
2295 class RenderProcessKilledObserver : public WebContentsObserver {
2296 public:
2297 RenderProcessKilledObserver(WebContents* web_contents)
2298 : WebContentsObserver(web_contents) {}
2299 ~RenderProcessKilledObserver() override {}
2301 void RenderProcessGone(base::TerminationStatus status) override {
2302 CHECK_NE(status,
2303 base::TerminationStatus::TERMINATION_STATUS_PROCESS_WAS_KILLED);
2308 // This tests a race in ReloadOriginalRequest, where a cross-origin reload was
2309 // causing an in-flight replaceState to look like a cross-origin navigation,
2310 // even though it's in-page. (The reload should not modify the underlying last
2311 // committed entry.) Not crashing means that the test is successful.
2312 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, ReloadOriginalRequest) {
2313 GURL original_url(embedded_test_server()->GetURL(
2314 "/navigation_controller/simple_page_1.html"));
2315 NavigateToURL(shell(), original_url);
2316 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2317 ->GetFrameTree()
2318 ->root();
2319 RenderProcessKilledObserver kill_observer(shell()->web_contents());
2321 // Redirect so that we can use ReloadOriginalRequest.
2322 GURL redirect_url(embedded_test_server()->GetURL(
2323 "foo.com", "/navigation_controller/simple_page_1.html"));
2325 std::string script = "location.replace('" + redirect_url.spec() + "');";
2326 FrameNavigateParamsCapturer capturer(root);
2327 EXPECT_TRUE(ExecuteScript(shell()->web_contents(), script));
2328 capturer.Wait();
2329 EXPECT_EQ(ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_CLIENT_REDIRECT,
2330 capturer.params().transition);
2331 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.details().type);
2334 // Modify an entry in the session history and reload the original request.
2336 // We first send a replaceState() to the renderer, which will cause the
2337 // renderer to send back a DidCommitProvisionalLoad. Immediately after,
2338 // we send a ReloadOriginalRequest (which in this case is a different
2339 // origin) and will also cause the renderer to commit the frame. In the
2340 // end we verify that both navigations committed and that the URLs are
2341 // correct.
2342 std::string script = "history.replaceState({}, '', 'foo');";
2343 root->render_manager()
2344 ->current_frame_host()
2345 ->ExecuteJavaScriptWithUserGestureForTests(base::UTF8ToUTF16(script));
2346 EXPECT_FALSE(shell()->web_contents()->IsLoading());
2347 shell()->web_contents()->GetController().ReloadOriginalRequestURL(false);
2348 EXPECT_TRUE(shell()->web_contents()->IsLoading());
2349 EXPECT_EQ(redirect_url, shell()->web_contents()->GetLastCommittedURL());
2351 // Wait until there's no more navigations.
2352 GURL modified_url(embedded_test_server()->GetURL(
2353 "foo.com", "/navigation_controller/foo"));
2354 FrameNavigateParamsCapturer capturer(root);
2355 capturer.set_wait_for_load(false);
2356 capturer.set_navigations_remaining(2);
2357 capturer.Wait();
2358 EXPECT_EQ(2U, capturer.all_details().size());
2359 EXPECT_EQ(modified_url, capturer.all_params()[0].url);
2360 EXPECT_EQ(original_url, capturer.all_params()[1].url);
2361 EXPECT_EQ(original_url, shell()->web_contents()->GetLastCommittedURL());
2364 // Make sure the renderer is still alive.
2365 EXPECT_TRUE(
2366 ExecuteScript(shell()->web_contents(), "console.log('Success');"));
2369 } // namespace content