// Copyright (c) 2012 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/bind.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/tab_contents/render_view_context_menu.h" #include "chrome/browser/tab_contents/render_view_context_menu_browsertest_util.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" #include "content/public/test/browser_test_utils.h" #include "net/test/spawned_test_server/spawned_test_server.h" #include "third_party/WebKit/public/web/WebInputEvent.h" // GTK requires a X11-level mouse event to open a context menu correctly. #if defined(TOOLKIT_GTK) #define MAYBE_ContextMenuOrigin DISABLED_ContextMenuOrigin #define MAYBE_HttpsContextMenuOrigin DISABLED_HttpsContextMenuOrigin #define MAYBE_ContextMenuRedirect DISABLED_ContextMenuRedirect #define MAYBE_HttpsContextMenuRedirect DISABLED_HttpsContextMenuRedirect #else #define MAYBE_ContextMenuOrigin ContextMenuOrigin #define MAYBE_HttpsContextMenuOrigin HttpsContextMenuOrigin #define MAYBE_ContextMenuRedirect ContextMenuRedirect #define MAYBE_HttpsContextMenuRedirect HttpsContextMenuRedirect #endif namespace { const base::FilePath::CharType kDocRoot[] = FILE_PATH_LITERAL("chrome/test/data/referrer_policy"); } // namespace class ReferrerPolicyTest : public InProcessBrowserTest { public: ReferrerPolicyTest() {} virtual ~ReferrerPolicyTest() {} virtual void SetUp() OVERRIDE { test_server_.reset(new net::SpawnedTestServer( net::SpawnedTestServer::TYPE_HTTP, net::SpawnedTestServer::kLocalhost, base::FilePath(kDocRoot))); ASSERT_TRUE(test_server_->Start()); ssl_test_server_.reset(new net::SpawnedTestServer( net::SpawnedTestServer::TYPE_HTTPS, net::SpawnedTestServer::kLocalhost, base::FilePath(kDocRoot))); ASSERT_TRUE(ssl_test_server_->Start()); InProcessBrowserTest::SetUp(); } protected: enum ExpectedReferrer { EXPECT_EMPTY_REFERRER, EXPECT_FULL_REFERRER, EXPECT_ORIGIN_AS_REFERRER }; // Returns the expected title for the tab with the given (full) referrer and // the expected modification of it. base::string16 GetExpectedTitle(const GURL& url, ExpectedReferrer expected_referrer) { std::string referrer; switch (expected_referrer) { case EXPECT_EMPTY_REFERRER: referrer = "Referrer is empty"; break; case EXPECT_FULL_REFERRER: referrer = "Referrer is " + url.spec(); break; case EXPECT_ORIGIN_AS_REFERRER: referrer = "Referrer is " + url.GetWithEmptyPath().spec(); break; } return ASCIIToUTF16(referrer); } // Adds all possible titles to the TitleWatcher, so we don't time out // waiting for the title if the test fails. void AddAllPossibleTitles(const GURL& url, content::TitleWatcher* title_watcher) { title_watcher->AlsoWaitForTitle( GetExpectedTitle(url, EXPECT_EMPTY_REFERRER)); title_watcher->AlsoWaitForTitle( GetExpectedTitle(url, EXPECT_FULL_REFERRER)); title_watcher->AlsoWaitForTitle( GetExpectedTitle(url, EXPECT_ORIGIN_AS_REFERRER)); } // Navigates from a page with a given |referrer_policy| and checks that the // reported referrer matches the expectation. // Parameters: // referrer_policy: The referrer policy to test ("default", "always", // "origin", "never") // start_on_https: True if the test should start on an HTTPS page. // target_blank: True if the link that is generated should have the // attribute target=_blank // redirect: True if the link target should first do a server // redirect before evaluating the passed referrer. // opens_new_tab: True if this test opens a new tab. // button: If not WebMouseEvent::ButtonNone, click on the // link with the specified mouse button. // expected_referrer: The kind of referrer to expect. // // Returns: // The URL of the first page navigated to. GURL RunReferrerTest(const std::string referrer_policy, bool start_on_https, bool target_blank, bool redirect, bool opens_new_tab, blink::WebMouseEvent::Button button, ExpectedReferrer expected_referrer) { GURL start_url; net::SpawnedTestServer* start_server = start_on_https ? ssl_test_server_.get() : test_server_.get(); start_url = start_server->GetURL( std::string("files/referrer-policy-start.html?") + "policy=" + referrer_policy + "&port=" + base::IntToString(test_server_->host_port_pair().port()) + "&ssl_port=" + base::IntToString(ssl_test_server_->host_port_pair().port()) + "&redirect=" + (redirect ? "true" : "false") + "&link=" + (button == blink::WebMouseEvent::ButtonNone ? "false" : "true") + "&target=" + (target_blank ? "_blank" : "")); ui_test_utils::WindowedTabAddedNotificationObserver tab_added_observer( content::NotificationService::AllSources()); base::string16 expected_title = GetExpectedTitle(start_url, expected_referrer); content::WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); content::TitleWatcher title_watcher(tab, expected_title); // Watch for all possible outcomes to avoid timeouts if something breaks. AddAllPossibleTitles(start_url, &title_watcher); ui_test_utils::NavigateToURL(browser(), start_url); if (button != blink::WebMouseEvent::ButtonNone) { blink::WebMouseEvent mouse_event; mouse_event.type = blink::WebInputEvent::MouseDown; mouse_event.button = button; mouse_event.x = 15; mouse_event.y = 15; mouse_event.clickCount = 1; tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event); mouse_event.type = blink::WebInputEvent::MouseUp; tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event); } if (opens_new_tab) { tab_added_observer.Wait(); tab = tab_added_observer.GetTab(); EXPECT_TRUE(tab); content::WaitForLoadStop(tab); EXPECT_EQ(expected_title, tab->GetTitle()); } else { EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); } return start_url; } scoped_ptr<net::SpawnedTestServer> test_server_; scoped_ptr<net::SpawnedTestServer> ssl_test_server_; }; // The basic behavior of referrer policies is covered by layout tests in // http/tests/security/referrer-policy-*. These tests cover (hopefully) all // code paths chrome uses to navigate. To keep the number of combinations down, // we only test the "origin" policy here. // // Some tests are marked as FAILS, see http://crbug.com/124750 // Content initiated navigation, from HTTP to HTTP. IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, Origin) { RunReferrerTest("origin", false, false, false, false, blink::WebMouseEvent::ButtonNone, EXPECT_ORIGIN_AS_REFERRER); } // Content initiated navigation, from HTTPS to HTTP. IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, HttpsDefault) { RunReferrerTest("origin", true, false, false, false, blink::WebMouseEvent::ButtonNone, EXPECT_ORIGIN_AS_REFERRER); } // User initiated navigation, from HTTP to HTTP. IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, LeftClickOrigin) { RunReferrerTest("origin", false, false, false, false, blink::WebMouseEvent::ButtonLeft, EXPECT_ORIGIN_AS_REFERRER); } // User initiated navigation, from HTTPS to HTTP. IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, HttpsLeftClickOrigin) { RunReferrerTest("origin", true, false, false, false, blink::WebMouseEvent::ButtonLeft, EXPECT_ORIGIN_AS_REFERRER); } // User initiated navigation, middle click, from HTTP to HTTP. IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, MiddleClickOrigin) { RunReferrerTest("origin", false, false, false, true, blink::WebMouseEvent::ButtonMiddle, EXPECT_ORIGIN_AS_REFERRER); } // User initiated navigation, middle click, from HTTPS to HTTP. IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, HttpsMiddleClickOrigin) { RunReferrerTest("origin", true, false, false, true, blink::WebMouseEvent::ButtonMiddle, EXPECT_ORIGIN_AS_REFERRER); } // User initiated navigation, target blank, from HTTP to HTTP. IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, TargetBlankOrigin) { RunReferrerTest("origin", false, true, false, true, blink::WebMouseEvent::ButtonLeft, EXPECT_ORIGIN_AS_REFERRER); } // User initiated navigation, target blank, from HTTPS to HTTP. IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, HttpsTargetBlankOrigin) { RunReferrerTest("origin", true, true, false, true, blink::WebMouseEvent::ButtonLeft, EXPECT_ORIGIN_AS_REFERRER); } // User initiated navigation, middle click, target blank, from HTTP to HTTP. IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, MiddleClickTargetBlankOrigin) { RunReferrerTest("origin", false, true, false, true, blink::WebMouseEvent::ButtonMiddle, EXPECT_ORIGIN_AS_REFERRER); } // User initiated navigation, middle click, target blank, from HTTPS to HTTP. IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, HttpsMiddleClickTargetBlankOrigin) { RunReferrerTest("origin", true, true, false, true, blink::WebMouseEvent::ButtonMiddle, EXPECT_ORIGIN_AS_REFERRER); } // Context menu, from HTTP to HTTP. IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, MAYBE_ContextMenuOrigin) { ContextMenuNotificationObserver context_menu_observer( IDC_CONTENT_CONTEXT_OPENLINKNEWTAB); RunReferrerTest("origin", false, false, false, true, blink::WebMouseEvent::ButtonRight, EXPECT_ORIGIN_AS_REFERRER); } // Context menu, from HTTPS to HTTP. IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, MAYBE_HttpsContextMenuOrigin) { ContextMenuNotificationObserver context_menu_observer( IDC_CONTENT_CONTEXT_OPENLINKNEWTAB); RunReferrerTest("origin", true, false, false, true, blink::WebMouseEvent::ButtonRight, EXPECT_ORIGIN_AS_REFERRER); } // Content initiated navigation, from HTTP to HTTP via server redirect. IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, Redirect) { RunReferrerTest("origin", false, false, true, false, blink::WebMouseEvent::ButtonNone, EXPECT_ORIGIN_AS_REFERRER); } // Content initiated navigation, from HTTPS to HTTP via server redirect. IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, HttpsRedirect) { RunReferrerTest("origin", true, false, true, false, blink::WebMouseEvent::ButtonNone, EXPECT_ORIGIN_AS_REFERRER); } // User initiated navigation, from HTTP to HTTP via server redirect. IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, LeftClickRedirect) { RunReferrerTest("origin", false, false, true, false, blink::WebMouseEvent::ButtonLeft, EXPECT_ORIGIN_AS_REFERRER); } // User initiated navigation, from HTTPS to HTTP via server redirect. IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, HttpsLeftClickRedirect) { RunReferrerTest("origin", true, false, true, false, blink::WebMouseEvent::ButtonLeft, EXPECT_ORIGIN_AS_REFERRER); } // User initiated navigation, middle click, from HTTP to HTTP via server // redirect. IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, MiddleClickRedirect) { RunReferrerTest("origin", false, false, true, true, blink::WebMouseEvent::ButtonMiddle, EXPECT_ORIGIN_AS_REFERRER); } // User initiated navigation, middle click, from HTTPS to HTTP via server // redirect. IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, HttpsMiddleClickRedirect) { RunReferrerTest("origin", true, false, true, true, blink::WebMouseEvent::ButtonMiddle, EXPECT_ORIGIN_AS_REFERRER); } // User initiated navigation, target blank, from HTTP to HTTP via server // redirect. IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, TargetBlankRedirect) { RunReferrerTest("origin", false, true, true, true, blink::WebMouseEvent::ButtonLeft, EXPECT_ORIGIN_AS_REFERRER); } // User initiated navigation, target blank, from HTTPS to HTTP via server // redirect. IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, HttpsTargetBlankRedirect) { RunReferrerTest("origin", true, true, true, true, blink::WebMouseEvent::ButtonLeft, EXPECT_ORIGIN_AS_REFERRER); } // User initiated navigation, middle click, target blank, from HTTP to HTTP via // server redirect. IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, MiddleClickTargetBlankRedirect) { RunReferrerTest("origin", false, true, true, true, blink::WebMouseEvent::ButtonMiddle, EXPECT_ORIGIN_AS_REFERRER); } // User initiated navigation, middle click, target blank, from HTTPS to HTTP // via server redirect. IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, HttpsMiddleClickTargetBlankRedirect) { RunReferrerTest("origin", true, true, true, true, blink::WebMouseEvent::ButtonMiddle, EXPECT_ORIGIN_AS_REFERRER); } // Context menu, from HTTP to HTTP via server redirect. IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, MAYBE_ContextMenuRedirect) { ContextMenuNotificationObserver context_menu_observer( IDC_CONTENT_CONTEXT_OPENLINKNEWTAB); RunReferrerTest("origin", false, false, true, true, blink::WebMouseEvent::ButtonRight, EXPECT_ORIGIN_AS_REFERRER); } // Context menu, from HTTPS to HTTP via server redirect. IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, MAYBE_HttpsContextMenuRedirect) { ContextMenuNotificationObserver context_menu_observer( IDC_CONTENT_CONTEXT_OPENLINKNEWTAB); RunReferrerTest("origin", true, false, true, true, blink::WebMouseEvent::ButtonRight, EXPECT_ORIGIN_AS_REFERRER); } // Tests history navigation actions: Navigate from A to B with a referrer // policy, then navigate to C, back to B, and reload. IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, History) { // Navigate from A to B. GURL start_url = RunReferrerTest("origin", true, false, true, false, blink::WebMouseEvent::ButtonLeft, EXPECT_ORIGIN_AS_REFERRER); // Navigate to C. ui_test_utils::NavigateToURL(browser(), test_server_->GetURL(std::string())); base::string16 expected_title = GetExpectedTitle(start_url, EXPECT_ORIGIN_AS_REFERRER); content::WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); scoped_ptr<content::TitleWatcher> title_watcher( new content::TitleWatcher(tab, expected_title)); // Watch for all possible outcomes to avoid timeouts if something breaks. AddAllPossibleTitles(start_url, title_watcher.get()); // Go back to B. chrome::GoBack(browser(), CURRENT_TAB); EXPECT_EQ(expected_title, title_watcher->WaitAndGetTitle()); title_watcher.reset(new content::TitleWatcher(tab, expected_title)); AddAllPossibleTitles(start_url, title_watcher.get()); // Reload to B. chrome::Reload(browser(), CURRENT_TAB); EXPECT_EQ(expected_title, title_watcher->WaitAndGetTitle()); title_watcher.reset(new content::TitleWatcher(tab, expected_title)); AddAllPossibleTitles(start_url, title_watcher.get()); // Shift-reload to B. chrome::ReloadIgnoringCache(browser(), CURRENT_TAB); EXPECT_EQ(expected_title, title_watcher->WaitAndGetTitle()); }