// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/basictypes.h" #include "base/command_line.h" #include "base/strings/stringprintf.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/web_contents.h" #include "content/public/common/content_switches.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/content_browser_test.h" #include "content/public/test/content_browser_test_utils.h" #include "content/public/test/test_navigation_observer.h" #include "content/shell/browser/shell.h" #include "net/dns/mock_host_resolver.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/url_request/url_request_failed_job.h" #include "url/gurl.h" namespace content { class BrowserSideNavigationBrowserTest : public ContentBrowserTest { public: BrowserSideNavigationBrowserTest() {} protected: void SetUpCommandLine(base::CommandLine* command_line) override { command_line->AppendSwitch(switches::kEnableBrowserSideNavigation); } void SetUpOnMainThread() override { host_resolver()->AddRule("*", "127.0.0.1"); ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); } }; // Ensure that browser initiated basic navigations work with browser side // navigation. IN_PROC_BROWSER_TEST_F(BrowserSideNavigationBrowserTest, BrowserInitiatedNavigations) { // Perform a navigation with no live renderer. { TestNavigationObserver observer(shell()->web_contents()); GURL url(embedded_test_server()->GetURL("/title1.html")); NavigateToURL(shell(), url); EXPECT_EQ(url, observer.last_navigation_url()); EXPECT_TRUE(observer.last_navigation_succeeded()); } RenderFrameHost* initial_rfh = static_cast(shell()->web_contents()) ->GetFrameTree()->root()->current_frame_host(); // Perform a same site navigation. { TestNavigationObserver observer(shell()->web_contents()); GURL url(embedded_test_server()->GetURL("/title2.html")); NavigateToURL(shell(), url); EXPECT_EQ(url, observer.last_navigation_url()); EXPECT_TRUE(observer.last_navigation_succeeded()); } // The RenderFrameHost should not have changed. EXPECT_EQ(initial_rfh, static_cast(shell()->web_contents()) ->GetFrameTree()->root()->current_frame_host()); // Perform a cross-site navigation. { TestNavigationObserver observer(shell()->web_contents()); GURL url = embedded_test_server()->GetURL("foo.com", "/title3.html"); NavigateToURL(shell(), url); EXPECT_EQ(url, observer.last_navigation_url()); EXPECT_TRUE(observer.last_navigation_succeeded()); } // The RenderFrameHost should have changed. EXPECT_NE(initial_rfh, static_cast(shell()->web_contents()) ->GetFrameTree()->root()->current_frame_host()); } // Ensure that renderer initiated same-site navigations work with browser side // navigation. IN_PROC_BROWSER_TEST_F(BrowserSideNavigationBrowserTest, RendererInitiatedSameSiteNavigation) { // Perform a navigation with no live renderer. { TestNavigationObserver observer(shell()->web_contents()); GURL url(embedded_test_server()->GetURL("/simple_links.html")); NavigateToURL(shell(), url); EXPECT_EQ(url, observer.last_navigation_url()); EXPECT_TRUE(observer.last_navigation_succeeded()); } RenderFrameHost* initial_rfh = static_cast(shell()->web_contents()) ->GetFrameTree()->root()->current_frame_host(); // Simulate clicking on a same-site link. { TestNavigationObserver observer(shell()->web_contents()); GURL url(embedded_test_server()->GetURL("/title2.html")); bool success = false; EXPECT_TRUE(ExecuteScriptAndExtractBool( shell()->web_contents(), "window.domAutomationController.send(clickSameSiteLink());", &success)); EXPECT_TRUE(success); EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); EXPECT_EQ(url, observer.last_navigation_url()); EXPECT_TRUE(observer.last_navigation_succeeded()); } // The RenderFrameHost should not have changed. EXPECT_EQ(initial_rfh, static_cast(shell()->web_contents()) ->GetFrameTree()->root()->current_frame_host()); } // Ensure that renderer initiated cross-site navigations work with browser side // navigation. IN_PROC_BROWSER_TEST_F(BrowserSideNavigationBrowserTest, RendererInitiatedCrossSiteNavigation) { // Perform a navigation with no live renderer. { TestNavigationObserver observer(shell()->web_contents()); GURL url(embedded_test_server()->GetURL("/simple_links.html")); NavigateToURL(shell(), url); EXPECT_EQ(url, observer.last_navigation_url()); EXPECT_TRUE(observer.last_navigation_succeeded()); } RenderFrameHost* initial_rfh = static_cast(shell()->web_contents()) ->GetFrameTree()->root()->current_frame_host(); // Simulate clicking on a cross-site link. { TestNavigationObserver observer(shell()->web_contents()); const char kReplacePortNumber[] = "window.domAutomationController.send(setPortNumber(%d));"; uint16 port_number = embedded_test_server()->port(); GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html"); bool success = false; EXPECT_TRUE(ExecuteScriptAndExtractBool( shell()->web_contents(), base::StringPrintf(kReplacePortNumber, port_number), &success)); success = false; EXPECT_TRUE(ExecuteScriptAndExtractBool( shell()->web_contents(), "window.domAutomationController.send(clickCrossSiteLink());", &success)); EXPECT_TRUE(success); EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); EXPECT_EQ(url, observer.last_navigation_url()); EXPECT_TRUE(observer.last_navigation_succeeded()); } // The RenderFrameHost should not have changed. EXPECT_EQ(initial_rfh, static_cast(shell()->web_contents()) ->GetFrameTree()->root()->current_frame_host()); } // Ensure that browser side navigation handles navigation failures. IN_PROC_BROWSER_TEST_F(BrowserSideNavigationBrowserTest, FailedNavigation) { // Perform a navigation with no live renderer. { TestNavigationObserver observer(shell()->web_contents()); GURL url(embedded_test_server()->GetURL("/title1.html")); NavigateToURL(shell(), url); EXPECT_EQ(url, observer.last_navigation_url()); EXPECT_TRUE(observer.last_navigation_succeeded()); } // Now navigate to an unreachable url. { TestNavigationObserver observer(shell()->web_contents()); GURL error_url( net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_RESET)); net::URLRequestFailedJob::AddUrlHandler(); NavigateToURL(shell(), error_url); EXPECT_EQ(error_url, observer.last_navigation_url()); NavigationEntry* entry = shell()->web_contents()->GetController().GetLastCommittedEntry(); EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType()); } } } // namespace content