1// Copyright (c) 2012 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.
4
5#include "base/bind.h"
6#include "base/strings/string_number_conversions.h"
7#include "base/strings/utf_string_conversions.h"
8#include "chrome/app/chrome_command_ids.h"
9#include "chrome/browser/chrome_notification_types.h"
10#include "chrome/browser/tab_contents/render_view_context_menu.h"
11#include "chrome/browser/tab_contents/render_view_context_menu_browsertest_util.h"
12#include "chrome/browser/ui/browser.h"
13#include "chrome/browser/ui/browser_commands.h"
14#include "chrome/browser/ui/tabs/tab_strip_model.h"
15#include "chrome/test/base/in_process_browser_test.h"
16#include "chrome/test/base/ui_test_utils.h"
17#include "content/public/browser/notification_service.h"
18#include "content/public/browser/render_view_host.h"
19#include "content/public/browser/web_contents.h"
20#include "content/public/test/browser_test_utils.h"
21#include "net/test/spawned_test_server/spawned_test_server.h"
22#include "third_party/WebKit/public/web/WebInputEvent.h"
23
24// GTK requires a X11-level mouse event to open a context menu correctly.
25#if defined(TOOLKIT_GTK)
26#define MAYBE_ContextMenuOrigin DISABLED_ContextMenuOrigin
27#define MAYBE_HttpsContextMenuOrigin DISABLED_HttpsContextMenuOrigin
28#define MAYBE_ContextMenuRedirect DISABLED_ContextMenuRedirect
29#define MAYBE_HttpsContextMenuRedirect DISABLED_HttpsContextMenuRedirect
30#else
31#define MAYBE_ContextMenuOrigin ContextMenuOrigin
32#define MAYBE_HttpsContextMenuOrigin HttpsContextMenuOrigin
33#define MAYBE_ContextMenuRedirect ContextMenuRedirect
34#define MAYBE_HttpsContextMenuRedirect HttpsContextMenuRedirect
35#endif
36
37namespace {
38
39const base::FilePath::CharType kDocRoot[] =
40    FILE_PATH_LITERAL("chrome/test/data/referrer_policy");
41
42}  // namespace
43
44class ReferrerPolicyTest : public InProcessBrowserTest {
45 public:
46   ReferrerPolicyTest() {}
47   virtual ~ReferrerPolicyTest() {}
48
49   virtual void SetUp() OVERRIDE {
50     test_server_.reset(new net::SpawnedTestServer(
51                            net::SpawnedTestServer::TYPE_HTTP,
52                            net::SpawnedTestServer::kLocalhost,
53                            base::FilePath(kDocRoot)));
54     ASSERT_TRUE(test_server_->Start());
55     ssl_test_server_.reset(new net::SpawnedTestServer(
56                                net::SpawnedTestServer::TYPE_HTTPS,
57                                net::SpawnedTestServer::kLocalhost,
58                                base::FilePath(kDocRoot)));
59     ASSERT_TRUE(ssl_test_server_->Start());
60
61     InProcessBrowserTest::SetUp();
62   }
63
64 protected:
65  enum ExpectedReferrer {
66    EXPECT_EMPTY_REFERRER,
67    EXPECT_FULL_REFERRER,
68    EXPECT_ORIGIN_AS_REFERRER
69  };
70
71  // Returns the expected title for the tab with the given (full) referrer and
72  // the expected modification of it.
73  base::string16 GetExpectedTitle(const GURL& url,
74                            ExpectedReferrer expected_referrer) {
75    std::string referrer;
76    switch (expected_referrer) {
77      case EXPECT_EMPTY_REFERRER:
78        referrer = "Referrer is empty";
79        break;
80      case EXPECT_FULL_REFERRER:
81        referrer = "Referrer is " + url.spec();
82        break;
83      case EXPECT_ORIGIN_AS_REFERRER:
84        referrer = "Referrer is " + url.GetWithEmptyPath().spec();
85        break;
86    }
87    return ASCIIToUTF16(referrer);
88  }
89
90  // Adds all possible titles to the TitleWatcher, so we don't time out
91  // waiting for the title if the test fails.
92  void AddAllPossibleTitles(const GURL& url,
93                            content::TitleWatcher* title_watcher) {
94    title_watcher->AlsoWaitForTitle(
95        GetExpectedTitle(url, EXPECT_EMPTY_REFERRER));
96    title_watcher->AlsoWaitForTitle(
97        GetExpectedTitle(url, EXPECT_FULL_REFERRER));
98    title_watcher->AlsoWaitForTitle(
99        GetExpectedTitle(url, EXPECT_ORIGIN_AS_REFERRER));
100  }
101
102  // Navigates from a page with a given |referrer_policy| and checks that the
103  // reported referrer matches the expectation.
104  // Parameters:
105  //  referrer_policy:   The referrer policy to test ("default", "always",
106  //                     "origin", "never")
107  //  start_on_https:    True if the test should start on an HTTPS page.
108  //  target_blank:      True if the link that is generated should have the
109  //                     attribute target=_blank
110  //  redirect:          True if the link target should first do a server
111  //                     redirect before evaluating the passed referrer.
112  //  opens_new_tab:     True if this test opens a new tab.
113  //  button:            If not WebMouseEvent::ButtonNone, click on the
114  //                     link with the specified mouse button.
115  //  expected_referrer: The kind of referrer to expect.
116  //
117  // Returns:
118  //  The URL of the first page navigated to.
119  GURL RunReferrerTest(const std::string referrer_policy,
120                       bool start_on_https,
121                       bool target_blank,
122                       bool redirect,
123                       bool opens_new_tab,
124                       blink::WebMouseEvent::Button button,
125                       ExpectedReferrer expected_referrer) {
126    GURL start_url;
127    net::SpawnedTestServer* start_server =
128        start_on_https ? ssl_test_server_.get() : test_server_.get();
129    start_url = start_server->GetURL(
130        std::string("files/referrer-policy-start.html?") +
131        "policy=" + referrer_policy +
132        "&port=" + base::IntToString(test_server_->host_port_pair().port()) +
133        "&ssl_port=" +
134            base::IntToString(ssl_test_server_->host_port_pair().port()) +
135        "&redirect=" + (redirect ? "true" : "false") +
136        "&link=" +
137            (button == blink::WebMouseEvent::ButtonNone ? "false" : "true") +
138        "&target=" + (target_blank ? "_blank" : ""));
139
140    ui_test_utils::WindowedTabAddedNotificationObserver tab_added_observer(
141        content::NotificationService::AllSources());
142
143    base::string16 expected_title =
144        GetExpectedTitle(start_url, expected_referrer);
145    content::WebContents* tab =
146        browser()->tab_strip_model()->GetActiveWebContents();
147    content::TitleWatcher title_watcher(tab, expected_title);
148
149    // Watch for all possible outcomes to avoid timeouts if something breaks.
150    AddAllPossibleTitles(start_url, &title_watcher);
151
152    ui_test_utils::NavigateToURL(browser(), start_url);
153
154    if (button != blink::WebMouseEvent::ButtonNone) {
155      blink::WebMouseEvent mouse_event;
156      mouse_event.type = blink::WebInputEvent::MouseDown;
157      mouse_event.button = button;
158      mouse_event.x = 15;
159      mouse_event.y = 15;
160      mouse_event.clickCount = 1;
161      tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
162      mouse_event.type = blink::WebInputEvent::MouseUp;
163      tab->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
164    }
165
166    if (opens_new_tab) {
167      tab_added_observer.Wait();
168      tab = tab_added_observer.GetTab();
169      EXPECT_TRUE(tab);
170      content::WaitForLoadStop(tab);
171      EXPECT_EQ(expected_title, tab->GetTitle());
172    } else {
173      EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
174    }
175
176    return start_url;
177  }
178
179  scoped_ptr<net::SpawnedTestServer> test_server_;
180  scoped_ptr<net::SpawnedTestServer> ssl_test_server_;
181};
182
183// The basic behavior of referrer policies is covered by layout tests in
184// http/tests/security/referrer-policy-*. These tests cover (hopefully) all
185// code paths chrome uses to navigate. To keep the number of combinations down,
186// we only test the "origin" policy here.
187//
188// Some tests are marked as FAILS, see http://crbug.com/124750
189
190// Content initiated navigation, from HTTP to HTTP.
191IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, Origin) {
192  RunReferrerTest("origin", false, false, false, false,
193                  blink::WebMouseEvent::ButtonNone,
194                  EXPECT_ORIGIN_AS_REFERRER);
195}
196
197// Content initiated navigation, from HTTPS to HTTP.
198IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, HttpsDefault) {
199  RunReferrerTest("origin", true, false, false, false,
200                  blink::WebMouseEvent::ButtonNone,
201                  EXPECT_ORIGIN_AS_REFERRER);
202}
203
204// User initiated navigation, from HTTP to HTTP.
205IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, LeftClickOrigin) {
206  RunReferrerTest("origin", false, false, false, false,
207                  blink::WebMouseEvent::ButtonLeft,
208                  EXPECT_ORIGIN_AS_REFERRER);
209}
210
211// User initiated navigation, from HTTPS to HTTP.
212IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, HttpsLeftClickOrigin) {
213  RunReferrerTest("origin", true, false, false, false,
214                  blink::WebMouseEvent::ButtonLeft,
215                  EXPECT_ORIGIN_AS_REFERRER);
216}
217
218// User initiated navigation, middle click, from HTTP to HTTP.
219IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, MiddleClickOrigin) {
220  RunReferrerTest("origin", false, false, false, true,
221                  blink::WebMouseEvent::ButtonMiddle,
222                  EXPECT_ORIGIN_AS_REFERRER);
223}
224
225// User initiated navigation, middle click, from HTTPS to HTTP.
226IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, HttpsMiddleClickOrigin) {
227  RunReferrerTest("origin", true, false, false, true,
228                  blink::WebMouseEvent::ButtonMiddle,
229                  EXPECT_ORIGIN_AS_REFERRER);
230}
231
232// User initiated navigation, target blank, from HTTP to HTTP.
233IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, TargetBlankOrigin) {
234  RunReferrerTest("origin", false, true, false, true,
235                  blink::WebMouseEvent::ButtonLeft,
236                  EXPECT_ORIGIN_AS_REFERRER);
237}
238
239// User initiated navigation, target blank, from HTTPS to HTTP.
240IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, HttpsTargetBlankOrigin) {
241  RunReferrerTest("origin", true, true, false, true,
242                  blink::WebMouseEvent::ButtonLeft,
243                  EXPECT_ORIGIN_AS_REFERRER);
244}
245
246// User initiated navigation, middle click, target blank, from HTTP to HTTP.
247IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, MiddleClickTargetBlankOrigin) {
248  RunReferrerTest("origin", false, true, false, true,
249                  blink::WebMouseEvent::ButtonMiddle,
250                  EXPECT_ORIGIN_AS_REFERRER);
251}
252
253// User initiated navigation, middle click, target blank, from HTTPS to HTTP.
254IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, HttpsMiddleClickTargetBlankOrigin) {
255  RunReferrerTest("origin", true, true, false, true,
256                  blink::WebMouseEvent::ButtonMiddle,
257                  EXPECT_ORIGIN_AS_REFERRER);
258}
259
260// Context menu, from HTTP to HTTP.
261IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, MAYBE_ContextMenuOrigin) {
262  ContextMenuNotificationObserver context_menu_observer(
263      IDC_CONTENT_CONTEXT_OPENLINKNEWTAB);
264  RunReferrerTest("origin", false, false, false, true,
265                  blink::WebMouseEvent::ButtonRight,
266                  EXPECT_ORIGIN_AS_REFERRER);
267}
268
269// Context menu, from HTTPS to HTTP.
270IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, MAYBE_HttpsContextMenuOrigin) {
271  ContextMenuNotificationObserver context_menu_observer(
272      IDC_CONTENT_CONTEXT_OPENLINKNEWTAB);
273  RunReferrerTest("origin", true, false, false, true,
274                  blink::WebMouseEvent::ButtonRight,
275                  EXPECT_ORIGIN_AS_REFERRER);
276}
277
278// Content initiated navigation, from HTTP to HTTP via server redirect.
279IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, Redirect) {
280  RunReferrerTest("origin", false, false, true, false,
281                  blink::WebMouseEvent::ButtonNone,
282                  EXPECT_ORIGIN_AS_REFERRER);
283}
284
285// Content initiated navigation, from HTTPS to HTTP via server redirect.
286IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, HttpsRedirect) {
287  RunReferrerTest("origin", true, false, true, false,
288                  blink::WebMouseEvent::ButtonNone,
289                  EXPECT_ORIGIN_AS_REFERRER);
290}
291
292// User initiated navigation, from HTTP to HTTP via server redirect.
293IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, LeftClickRedirect) {
294  RunReferrerTest("origin", false, false, true, false,
295                  blink::WebMouseEvent::ButtonLeft,
296                  EXPECT_ORIGIN_AS_REFERRER);
297}
298
299// User initiated navigation, from HTTPS to HTTP via server redirect.
300IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, HttpsLeftClickRedirect) {
301  RunReferrerTest("origin", true, false, true, false,
302                  blink::WebMouseEvent::ButtonLeft,
303                  EXPECT_ORIGIN_AS_REFERRER);
304}
305
306// User initiated navigation, middle click, from HTTP to HTTP via server
307// redirect.
308IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, MiddleClickRedirect) {
309  RunReferrerTest("origin", false, false, true, true,
310                  blink::WebMouseEvent::ButtonMiddle,
311                  EXPECT_ORIGIN_AS_REFERRER);
312}
313
314// User initiated navigation, middle click, from HTTPS to HTTP via server
315// redirect.
316IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, HttpsMiddleClickRedirect) {
317  RunReferrerTest("origin", true, false, true, true,
318                  blink::WebMouseEvent::ButtonMiddle,
319                  EXPECT_ORIGIN_AS_REFERRER);
320}
321
322// User initiated navigation, target blank, from HTTP to HTTP via server
323// redirect.
324IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, TargetBlankRedirect) {
325  RunReferrerTest("origin", false, true, true, true,
326                  blink::WebMouseEvent::ButtonLeft,
327                  EXPECT_ORIGIN_AS_REFERRER);
328}
329
330// User initiated navigation, target blank, from HTTPS to HTTP via server
331// redirect.
332IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, HttpsTargetBlankRedirect) {
333  RunReferrerTest("origin", true, true, true, true,
334                  blink::WebMouseEvent::ButtonLeft,
335                  EXPECT_ORIGIN_AS_REFERRER);
336}
337
338// User initiated navigation, middle click, target blank, from HTTP to HTTP via
339// server redirect.
340IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, MiddleClickTargetBlankRedirect) {
341  RunReferrerTest("origin", false, true, true, true,
342                  blink::WebMouseEvent::ButtonMiddle,
343                  EXPECT_ORIGIN_AS_REFERRER);
344}
345
346// User initiated navigation, middle click, target blank, from HTTPS to HTTP
347// via server redirect.
348IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest,
349                       HttpsMiddleClickTargetBlankRedirect) {
350  RunReferrerTest("origin", true, true, true, true,
351                  blink::WebMouseEvent::ButtonMiddle,
352                  EXPECT_ORIGIN_AS_REFERRER);
353}
354
355// Context menu, from HTTP to HTTP via server redirect.
356IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, MAYBE_ContextMenuRedirect) {
357  ContextMenuNotificationObserver context_menu_observer(
358      IDC_CONTENT_CONTEXT_OPENLINKNEWTAB);
359  RunReferrerTest("origin", false, false, true, true,
360                  blink::WebMouseEvent::ButtonRight,
361                  EXPECT_ORIGIN_AS_REFERRER);
362}
363
364// Context menu, from HTTPS to HTTP via server redirect.
365IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, MAYBE_HttpsContextMenuRedirect) {
366  ContextMenuNotificationObserver context_menu_observer(
367      IDC_CONTENT_CONTEXT_OPENLINKNEWTAB);
368  RunReferrerTest("origin", true, false, true, true,
369                  blink::WebMouseEvent::ButtonRight,
370                  EXPECT_ORIGIN_AS_REFERRER);
371}
372
373// Tests history navigation actions: Navigate from A to B with a referrer
374// policy, then navigate to C, back to B, and reload.
375IN_PROC_BROWSER_TEST_F(ReferrerPolicyTest, History) {
376  // Navigate from A to B.
377  GURL start_url = RunReferrerTest("origin", true, false, true, false,
378                                   blink::WebMouseEvent::ButtonLeft,
379                                   EXPECT_ORIGIN_AS_REFERRER);
380
381  // Navigate to C.
382  ui_test_utils::NavigateToURL(browser(), test_server_->GetURL(std::string()));
383
384  base::string16 expected_title =
385      GetExpectedTitle(start_url, EXPECT_ORIGIN_AS_REFERRER);
386  content::WebContents* tab =
387      browser()->tab_strip_model()->GetActiveWebContents();
388  scoped_ptr<content::TitleWatcher> title_watcher(
389      new content::TitleWatcher(tab, expected_title));
390
391  // Watch for all possible outcomes to avoid timeouts if something breaks.
392  AddAllPossibleTitles(start_url, title_watcher.get());
393
394  // Go back to B.
395  chrome::GoBack(browser(), CURRENT_TAB);
396  EXPECT_EQ(expected_title, title_watcher->WaitAndGetTitle());
397
398  title_watcher.reset(new content::TitleWatcher(tab, expected_title));
399  AddAllPossibleTitles(start_url, title_watcher.get());
400
401  // Reload to B.
402  chrome::Reload(browser(), CURRENT_TAB);
403  EXPECT_EQ(expected_title, title_watcher->WaitAndGetTitle());
404
405  title_watcher.reset(new content::TitleWatcher(tab, expected_title));
406  AddAllPossibleTitles(start_url, title_watcher.get());
407
408  // Shift-reload to B.
409  chrome::ReloadIgnoringCache(browser(), CURRENT_TAB);
410  EXPECT_EQ(expected_title, title_watcher->WaitAndGetTitle());
411}
412