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 <vector>
6
7#include "base/bind.h"
8#include "base/command_line.h"
9#include "base/message_loop/message_loop.h"
10#include "base/prefs/pref_service.h"
11#include "base/strings/utf_string_conversions.h"
12#include "chrome/app/chrome_command_ids.h"
13#include "chrome/browser/history/history_db_task.h"
14#include "chrome/browser/history/history_service.h"
15#include "chrome/browser/history/history_service_factory.h"
16#include "chrome/browser/profiles/profile.h"
17#include "chrome/browser/ui/browser.h"
18#include "chrome/browser/ui/browser_commands.h"
19#include "chrome/browser/ui/tabs/tab_strip_model.h"
20#include "chrome/common/chrome_switches.h"
21#include "chrome/common/pref_names.h"
22#include "chrome/common/url_constants.h"
23#include "chrome/test/base/in_process_browser_test.h"
24#include "chrome/test/base/ui_test_utils.h"
25#include "content/public/browser/web_contents.h"
26#include "content/public/test/browser_test_utils.h"
27#include "content/public/test/test_browser_thread.h"
28#include "url/gurl.h"
29
30using content::BrowserThread;
31
32namespace {
33
34// Note: WaitableEvent is not used for synchronization between the main thread
35// and history backend thread because the history subsystem posts tasks back
36// to the main thread. Had we tried to Signal an event in such a task
37// and Wait for it on the main thread, the task would not run at all because
38// the main thread would be blocked on the Wait call, resulting in a deadlock.
39
40// A task to be scheduled on the history backend thread.
41// Notifies the main thread after all history backend thread tasks have run.
42class WaitForHistoryTask : public history::HistoryDBTask {
43 public:
44  WaitForHistoryTask() {}
45
46  virtual bool RunOnDBThread(history::HistoryBackend* backend,
47                             history::HistoryDatabase* db) OVERRIDE {
48    return true;
49  }
50
51  virtual void DoneRunOnMainThread() OVERRIDE {
52    base::MessageLoop::current()->Quit();
53  }
54
55 private:
56  virtual ~WaitForHistoryTask() {}
57
58  DISALLOW_COPY_AND_ASSIGN(WaitForHistoryTask);
59};
60
61}  // namespace
62
63class HistoryBrowserTest : public InProcessBrowserTest {
64 protected:
65  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
66    command_line->AppendSwitch(switches::kEnableFileCookies);
67  }
68
69  PrefService* GetPrefs() {
70    return GetProfile()->GetPrefs();
71  }
72
73  Profile* GetProfile() {
74    return browser()->profile();
75  }
76
77  std::vector<GURL> GetHistoryContents() {
78    ui_test_utils::HistoryEnumerator enumerator(GetProfile());
79    return enumerator.urls();
80  }
81
82  GURL GetTestUrl() {
83    return ui_test_utils::GetTestUrl(
84        base::FilePath(base::FilePath::kCurrentDirectory),
85        base::FilePath(FILE_PATH_LITERAL("title2.html")));
86  }
87
88  void WaitForHistoryBackendToRun() {
89    base::CancelableTaskTracker task_tracker;
90    scoped_ptr<history::HistoryDBTask> task(new WaitForHistoryTask());
91    HistoryService* history =
92        HistoryServiceFactory::GetForProfile(GetProfile(),
93                                             Profile::EXPLICIT_ACCESS);
94    history->HistoryService::ScheduleDBTask(task.Pass(), &task_tracker);
95    content::RunMessageLoop();
96  }
97
98  void ExpectEmptyHistory() {
99    std::vector<GURL> urls(GetHistoryContents());
100    EXPECT_EQ(0U, urls.size());
101  }
102
103  void LoadAndWaitForURL(const GURL& url) {
104    base::string16 expected_title(base::ASCIIToUTF16("OK"));
105    content::TitleWatcher title_watcher(
106        browser()->tab_strip_model()->GetActiveWebContents(), expected_title);
107    title_watcher.AlsoWaitForTitle(base::ASCIIToUTF16("FAIL"));
108    ui_test_utils::NavigateToURL(browser(), url);
109    EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
110  }
111
112  void LoadAndWaitForFile(const char* filename) {
113    GURL url = ui_test_utils::GetTestUrl(
114        base::FilePath().AppendASCII("History"),
115        base::FilePath().AppendASCII(filename));
116    LoadAndWaitForURL(url);
117  }
118};
119
120// Test that the browser history is saved (default setting).
121IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, SavingHistoryEnabled) {
122  EXPECT_FALSE(GetPrefs()->GetBoolean(prefs::kSavingBrowserHistoryDisabled));
123
124  EXPECT_TRUE(HistoryServiceFactory::GetForProfile(
125      GetProfile(), Profile::EXPLICIT_ACCESS));
126  EXPECT_TRUE(HistoryServiceFactory::GetForProfile(
127      GetProfile(), Profile::IMPLICIT_ACCESS));
128
129  ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile(
130      browser()->profile(), Profile::EXPLICIT_ACCESS));
131  ExpectEmptyHistory();
132
133  ui_test_utils::NavigateToURL(browser(), GetTestUrl());
134  WaitForHistoryBackendToRun();
135
136  {
137    std::vector<GURL> urls(GetHistoryContents());
138    ASSERT_EQ(1U, urls.size());
139    EXPECT_EQ(GetTestUrl().spec(), urls[0].spec());
140  }
141}
142
143// Test that disabling saving browser history really works.
144IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, SavingHistoryDisabled) {
145  GetPrefs()->SetBoolean(prefs::kSavingBrowserHistoryDisabled, true);
146
147  EXPECT_TRUE(HistoryServiceFactory::GetForProfile(
148      GetProfile(), Profile::EXPLICIT_ACCESS));
149  EXPECT_FALSE(HistoryServiceFactory::GetForProfile(
150      GetProfile(), Profile::IMPLICIT_ACCESS));
151
152  ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile(
153      browser()->profile(), Profile::EXPLICIT_ACCESS));
154  ExpectEmptyHistory();
155
156  ui_test_utils::NavigateToURL(browser(), GetTestUrl());
157  WaitForHistoryBackendToRun();
158  ExpectEmptyHistory();
159}
160
161// Test that changing the pref takes effect immediately
162// when the browser is running.
163IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, SavingHistoryEnabledThenDisabled) {
164  EXPECT_FALSE(GetPrefs()->GetBoolean(prefs::kSavingBrowserHistoryDisabled));
165
166  ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile(
167      browser()->profile(), Profile::EXPLICIT_ACCESS));
168
169  ui_test_utils::NavigateToURL(browser(), GetTestUrl());
170  WaitForHistoryBackendToRun();
171
172  {
173    std::vector<GURL> urls(GetHistoryContents());
174    ASSERT_EQ(1U, urls.size());
175    EXPECT_EQ(GetTestUrl().spec(), urls[0].spec());
176  }
177
178  GetPrefs()->SetBoolean(prefs::kSavingBrowserHistoryDisabled, true);
179
180  ui_test_utils::NavigateToURL(browser(), GetTestUrl());
181  WaitForHistoryBackendToRun();
182
183  {
184    // No additional entries should be present in the history.
185    std::vector<GURL> urls(GetHistoryContents());
186    ASSERT_EQ(1U, urls.size());
187    EXPECT_EQ(GetTestUrl().spec(), urls[0].spec());
188  }
189}
190
191// Test that changing the pref takes effect immediately
192// when the browser is running.
193IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, SavingHistoryDisabledThenEnabled) {
194  GetPrefs()->SetBoolean(prefs::kSavingBrowserHistoryDisabled, true);
195
196  ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile(
197      browser()->profile(), Profile::EXPLICIT_ACCESS));
198  ExpectEmptyHistory();
199
200  ui_test_utils::NavigateToURL(browser(), GetTestUrl());
201  WaitForHistoryBackendToRun();
202  ExpectEmptyHistory();
203
204  GetPrefs()->SetBoolean(prefs::kSavingBrowserHistoryDisabled, false);
205
206  ui_test_utils::NavigateToURL(browser(), GetTestUrl());
207  WaitForHistoryBackendToRun();
208
209  {
210    std::vector<GURL> urls(GetHistoryContents());
211    ASSERT_EQ(1U, urls.size());
212    EXPECT_EQ(GetTestUrl().spec(), urls[0].spec());
213  }
214}
215
216IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, VerifyHistoryLength1) {
217  // Test the history length for the following page transitions.
218  //   -open-> Page 1.
219  LoadAndWaitForFile("history_length_test_page_1.html");
220}
221
222IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, VerifyHistoryLength2) {
223  // Test the history length for the following page transitions.
224  //   -open-> Page 2 -redirect-> Page 3.
225  LoadAndWaitForFile("history_length_test_page_2.html");
226}
227
228IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, VerifyHistoryLength3) {
229  // Test the history length for the following page transitions.
230  // -open-> Page 1 -> open Page 2 -redirect Page 3. open Page 4
231  // -navigate_backward-> Page 3 -navigate_backward->Page 1
232  // -navigate_forward-> Page 3 -navigate_forward-> Page 4
233  LoadAndWaitForFile("history_length_test_page_1.html");
234  LoadAndWaitForFile("history_length_test_page_2.html");
235  LoadAndWaitForFile("history_length_test_page_4.html");
236}
237
238IN_PROC_BROWSER_TEST_F(HistoryBrowserTest,
239                       ConsiderRedirectAfterGestureAsUserInitiated) {
240  // Test the history length for the following page transition.
241  //
242  // -open-> Page 11 -slow_redirect-> Page 12.
243  //
244  // If redirect occurs after a user gesture, e.g., mouse click, the
245  // redirect is more likely to be user-initiated rather than automatic.
246  // Therefore, Page 11 should be in the history in addition to Page 12.
247  LoadAndWaitForFile("history_length_test_page_11.html");
248
249  content::SimulateMouseClick(
250      browser()->tab_strip_model()->GetActiveWebContents(), 0,
251      blink::WebMouseEvent::ButtonLeft);
252  LoadAndWaitForFile("history_length_test_page_11.html");
253}
254
255IN_PROC_BROWSER_TEST_F(HistoryBrowserTest,
256                       ConsiderSlowRedirectAsUserInitiated) {
257  // Test the history length for the following page transition.
258  //
259  // -open-> Page 21 -redirect-> Page 22.
260  //
261  // If redirect occurs more than 5 seconds later after the page is loaded,
262  // the redirect is likely to be user-initiated.
263  // Therefore, Page 21 should be in the history in addition to Page 22.
264  LoadAndWaitForFile("history_length_test_page_21.html");
265}
266
267// http://crbug.com/22111
268#if defined(OS_LINUX)
269#define MAYBE_HistorySearchXSS DISABLED_HistorySearchXSS
270#else
271#define MAYBE_HistorySearchXSS HistorySearchXSS
272#endif
273IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, MAYBE_HistorySearchXSS) {
274  GURL url(std::string(chrome::kChromeUIHistoryURL) +
275      "#q=%3Cimg%20src%3Dx%3Ax%20onerror%3D%22document.title%3D'XSS'%22%3E");
276  ui_test_utils::NavigateToURL(browser(), url);
277  // Mainly, this is to ensure we send a synchronous message to the renderer
278  // so that we're not susceptible (less susceptible?) to a race condition.
279  // Should a race condition ever trigger, it won't result in flakiness.
280  int num = ui_test_utils::FindInPage(
281      browser()->tab_strip_model()->GetActiveWebContents(),
282      base::ASCIIToUTF16("<img"), true,
283      true, NULL, NULL);
284  EXPECT_GT(num, 0);
285  EXPECT_EQ(base::ASCIIToUTF16("History"),
286            browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
287}
288
289// Verify that history persists after session restart.
290IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, PRE_HistoryPersists) {
291  ui_test_utils::NavigateToURL(browser(), GetTestUrl());
292  std::vector<GURL> urls(GetHistoryContents());
293  ASSERT_EQ(1u, urls.size());
294  ASSERT_EQ(GetTestUrl(), urls[0]);
295}
296
297IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, HistoryPersists) {
298  std::vector<GURL> urls(GetHistoryContents());
299  ASSERT_EQ(1u, urls.size());
300  ASSERT_EQ(GetTestUrl(), urls[0]);
301}
302
303// Invalid URLs should not go in history.
304IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, InvalidURLNoHistory) {
305  GURL non_existant = ui_test_utils::GetTestUrl(
306      base::FilePath().AppendASCII("History"),
307      base::FilePath().AppendASCII("non_existant_file.html"));
308  ui_test_utils::NavigateToURL(browser(), non_existant);
309  ExpectEmptyHistory();
310}
311
312// New tab page should not show up in history.
313IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, NewTabNoHistory) {
314  ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
315  ExpectEmptyHistory();
316}
317
318// Incognito browsing should not show up in history.
319IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, IncognitoNoHistory) {
320  ui_test_utils::NavigateToURL(CreateIncognitoBrowser(), GetTestUrl());
321  ExpectEmptyHistory();
322}
323
324// Multiple navigations to the same url should have a single history.
325IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, NavigateMultiTimes) {
326  ui_test_utils::NavigateToURL(browser(), GetTestUrl());
327  ui_test_utils::NavigateToURL(browser(), GetTestUrl());
328  std::vector<GURL> urls(GetHistoryContents());
329  ASSERT_EQ(1u, urls.size());
330  ASSERT_EQ(GetTestUrl(), urls[0]);
331}
332
333// Verify history with multiple windows and tabs.
334IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, MultiTabsWindowsHistory) {
335  GURL url1 = GetTestUrl();
336  GURL url2  = ui_test_utils::GetTestUrl(
337      base::FilePath(), base::FilePath(FILE_PATH_LITERAL("title1.html")));
338  GURL url3  = ui_test_utils::GetTestUrl(
339      base::FilePath(), base::FilePath(FILE_PATH_LITERAL("title3.html")));
340  GURL url4  = ui_test_utils::GetTestUrl(
341      base::FilePath(), base::FilePath(FILE_PATH_LITERAL("simple.html")));
342
343  ui_test_utils::NavigateToURL(browser(), url1);
344  Browser* browser2 = CreateBrowser(browser()->profile());
345  ui_test_utils::NavigateToURL(browser2, url2);
346  ui_test_utils::NavigateToURLWithDisposition(
347      browser2, url3, NEW_FOREGROUND_TAB,
348      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
349  ui_test_utils::NavigateToURLWithDisposition(
350      browser2, url4, NEW_FOREGROUND_TAB,
351      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
352
353  std::vector<GURL> urls(GetHistoryContents());
354  ASSERT_EQ(4u, urls.size());
355  ASSERT_EQ(url4, urls[0]);
356  ASSERT_EQ(url3, urls[1]);
357  ASSERT_EQ(url2, urls[2]);
358  ASSERT_EQ(url1, urls[3]);
359}
360
361// Downloaded URLs should not show up in history.
362IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, DownloadNoHistory) {
363  GURL download_url = ui_test_utils::GetTestUrl(
364      base::FilePath().AppendASCII("downloads"),
365      base::FilePath().AppendASCII("a_zip_file.zip"));
366  ui_test_utils::DownloadURL(browser(), download_url);
367  ExpectEmptyHistory();
368}
369
370// HTTP meta-refresh redirects should have separate history entries.
371IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, RedirectHistory) {
372  GURL redirector = ui_test_utils::GetTestUrl(
373      base::FilePath().AppendASCII("History"),
374      base::FilePath().AppendASCII("redirector.html"));
375  GURL landing_url = ui_test_utils::GetTestUrl(
376      base::FilePath().AppendASCII("History"),
377      base::FilePath().AppendASCII("landing.html"));
378  ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
379      browser(), redirector, 2);
380  ASSERT_EQ(landing_url,
381            browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
382  std::vector<GURL> urls(GetHistoryContents());
383  ASSERT_EQ(2u, urls.size());
384  ASSERT_EQ(landing_url, urls[0]);
385  ASSERT_EQ(redirector, urls[1]);
386}
387
388// Verify that navigation brings current page to top of history list.
389IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, NavigateBringPageToTop) {
390  GURL url1 = GetTestUrl();
391  GURL url2  = ui_test_utils::GetTestUrl(
392      base::FilePath(), base::FilePath(FILE_PATH_LITERAL("title3.html")));
393
394  ui_test_utils::NavigateToURL(browser(), url1);
395  ui_test_utils::NavigateToURL(browser(), url2);
396
397  std::vector<GURL> urls(GetHistoryContents());
398  ASSERT_EQ(2u, urls.size());
399  ASSERT_EQ(url2, urls[0]);
400  ASSERT_EQ(url1, urls[1]);
401}
402
403// Verify that reloading a page brings it to top of history list.
404IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, ReloadBringPageToTop) {
405  GURL url1 = GetTestUrl();
406  GURL url2  = ui_test_utils::GetTestUrl(
407      base::FilePath(), base::FilePath(FILE_PATH_LITERAL("title3.html")));
408
409  ui_test_utils::NavigateToURL(browser(), url1);
410  ui_test_utils::NavigateToURLWithDisposition(
411      browser(), url2, NEW_BACKGROUND_TAB,
412      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
413
414  std::vector<GURL> urls(GetHistoryContents());
415  ASSERT_EQ(2u, urls.size());
416  ASSERT_EQ(url2, urls[0]);
417  ASSERT_EQ(url1, urls[1]);
418
419  content::WebContents* tab =
420      browser()->tab_strip_model()->GetActiveWebContents();
421  tab->GetController().Reload(false);
422  content::WaitForLoadStop(tab);
423
424  urls = GetHistoryContents();
425  ASSERT_EQ(2u, urls.size());
426  ASSERT_EQ(url1, urls[0]);
427  ASSERT_EQ(url2, urls[1]);
428}
429
430// Verify that back/forward brings current page to top of history list.
431IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, BackForwardBringPageToTop) {
432  GURL url1 = GetTestUrl();
433  GURL url2  = ui_test_utils::GetTestUrl(
434      base::FilePath(), base::FilePath(FILE_PATH_LITERAL("title3.html")));
435
436  ui_test_utils::NavigateToURL(browser(), url1);
437  ui_test_utils::NavigateToURL(browser(), url2);
438
439  content::WebContents* tab =
440      browser()->tab_strip_model()->GetActiveWebContents();
441  chrome::GoBack(browser(), CURRENT_TAB);
442  content::WaitForLoadStop(tab);
443
444  std::vector<GURL> urls(GetHistoryContents());
445  ASSERT_EQ(2u, urls.size());
446  ASSERT_EQ(url1, urls[0]);
447  ASSERT_EQ(url2, urls[1]);
448
449  chrome::GoForward(browser(), CURRENT_TAB);
450  content::WaitForLoadStop(tab);
451  urls = GetHistoryContents();
452  ASSERT_EQ(2u, urls.size());
453  ASSERT_EQ(url2, urls[0]);
454  ASSERT_EQ(url1, urls[1]);
455}
456
457// Verify that submitting form adds target page to history list.
458IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, SubmitFormAddsTargetPage) {
459  GURL form = ui_test_utils::GetTestUrl(
460      base::FilePath().AppendASCII("History"),
461      base::FilePath().AppendASCII("form.html"));
462  GURL target = ui_test_utils::GetTestUrl(
463      base::FilePath().AppendASCII("History"),
464      base::FilePath().AppendASCII("target.html"));
465  ui_test_utils::NavigateToURL(browser(), form);
466
467  content::WebContents* web_contents =
468      browser()->tab_strip_model()->GetActiveWebContents();
469  base::string16 expected_title(base::ASCIIToUTF16("Target Page"));
470  content::TitleWatcher title_watcher(
471      browser()->tab_strip_model()->GetActiveWebContents(), expected_title);
472  ASSERT_TRUE(content::ExecuteScript(
473      web_contents, "document.getElementById('form').submit()"));
474  EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
475
476  std::vector<GURL> urls(GetHistoryContents());
477  ASSERT_EQ(2u, urls.size());
478  ASSERT_EQ(target, urls[0]);
479  ASSERT_EQ(form, urls[1]);
480}
481
482// Verify history shortcut opens only one history tab per window.  Also, make
483// sure that existing history tab is activated.
484IN_PROC_BROWSER_TEST_F(HistoryBrowserTest, OneHistoryTabPerWindow) {
485  GURL history_url(chrome::kChromeUIHistoryURL);
486
487  // Even after navigate completes, the currently-active tab title is
488  // 'Loading...' for a brief time while the history page loads.
489  content::WebContents* web_contents =
490      browser()->tab_strip_model()->GetActiveWebContents();
491  base::string16 expected_title(base::ASCIIToUTF16("History"));
492  content::TitleWatcher title_watcher(web_contents, expected_title);
493  chrome::ExecuteCommand(browser(), IDC_SHOW_HISTORY);
494  EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
495
496  ui_test_utils::NavigateToURLWithDisposition(
497      browser(),
498      GURL(url::kAboutBlankURL),
499      NEW_FOREGROUND_TAB,
500      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
501  chrome::ExecuteCommand(browser(), IDC_SHOW_HISTORY);
502
503  content::WebContents* active_web_contents =
504      browser()->tab_strip_model()->GetActiveWebContents();
505  ASSERT_EQ(web_contents, active_web_contents);
506  ASSERT_EQ(history_url, active_web_contents->GetURL());
507
508  content::WebContents* second_tab =
509      browser()->tab_strip_model()->GetWebContentsAt(1);
510  ASSERT_NE(history_url, second_tab->GetURL());
511}
512