// 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());
}