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 30 using content::BrowserThread; 31 32 namespace { 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. 42 class 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 63 class 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 CancelableRequestConsumerTSimple<int> request_consumer; 90 scoped_refptr<history::HistoryDBTask> task(new WaitForHistoryTask()); 91 HistoryService* history = 92 HistoryServiceFactory::GetForProfile(GetProfile(), 93 Profile::EXPLICIT_ACCESS); 94 history->HistoryService::ScheduleDBTask(task.get(), &request_consumer); 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(ASCIIToUTF16("OK")); 105 content::TitleWatcher title_watcher( 106 browser()->tab_strip_model()->GetActiveWebContents(), expected_title); 107 title_watcher.AlsoWaitForTitle(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). 121 IN_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. 144 IN_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. 163 IN_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. 193 IN_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 216 IN_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 222 IN_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 228 IN_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 238 IN_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 255 IN_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 273 IN_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 ASCIIToUTF16("<img"), true, 283 true, NULL, NULL); 284 EXPECT_GT(num, 0); 285 EXPECT_EQ(ASCIIToUTF16("History"), 286 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle()); 287 } 288 289 // Verify that history persists after session restart. 290 IN_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 297 IN_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. 304 IN_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. 313 IN_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. 319 IN_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. 325 IN_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. 334 IN_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. 362 IN_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. 371 IN_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. 389 IN_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. 404 IN_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. 431 IN_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. 458 IN_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(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. 484 IN_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(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(), GURL(content::kAboutBlankURL), NEW_FOREGROUND_TAB, 498 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); 499 chrome::ExecuteCommand(browser(), IDC_SHOW_HISTORY); 500 501 content::WebContents* active_web_contents = 502 browser()->tab_strip_model()->GetActiveWebContents(); 503 ASSERT_EQ(web_contents, active_web_contents); 504 ASSERT_EQ(history_url, active_web_contents->GetURL()); 505 506 content::WebContents* second_tab = 507 browser()->tab_strip_model()->GetWebContentsAt(1); 508 ASSERT_NE(history_url, second_tab->GetURL()); 509 } 510