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/command_line.h" 7 #include "base/compiler_specific.h" 8 #include "base/logging.h" 9 #include "base/memory/scoped_ptr.h" 10 #include "base/memory/weak_ptr.h" 11 #include "base/path_service.h" 12 #include "base/prefs/pref_service.h" 13 #include "base/strings/stringprintf.h" 14 #include "base/strings/utf_string_conversions.h" 15 #include "base/synchronization/lock.h" 16 #include "chrome/browser/browsing_data/browsing_data_helper.h" 17 #include "chrome/browser/browsing_data/browsing_data_remover.h" 18 #include "chrome/browser/google/google_profile_helper.h" 19 #include "chrome/browser/net/url_request_mock_util.h" 20 #include "chrome/browser/profiles/profile.h" 21 #include "chrome/browser/ui/browser.h" 22 #include "chrome/browser/ui/browser_commands.h" 23 #include "chrome/browser/ui/tabs/tab_strip_model.h" 24 #include "chrome/common/chrome_paths.h" 25 #include "chrome/common/chrome_switches.h" 26 #include "chrome/common/pref_names.h" 27 #include "chrome/grit/generated_resources.h" 28 #include "chrome/test/base/in_process_browser_test.h" 29 #include "chrome/test/base/ui_test_utils.h" 30 #include "components/google/core/browser/google_util.h" 31 #include "content/public/browser/browser_thread.h" 32 #include "content/public/browser/notification_service.h" 33 #include "content/public/browser/notification_types.h" 34 #include "content/public/browser/render_frame_host.h" 35 #include "content/public/browser/render_view_host.h" 36 #include "content/public/browser/web_contents.h" 37 #include "content/public/browser/web_contents_observer.h" 38 #include "content/public/test/browser_test_utils.h" 39 #include "content/public/test/test_navigation_observer.h" 40 #include "net/base/net_errors.h" 41 #include "net/base/net_util.h" 42 #include "net/http/failing_http_transaction_factory.h" 43 #include "net/http/http_cache.h" 44 #include "net/test/spawned_test_server/spawned_test_server.h" 45 #include "net/test/url_request/url_request_failed_job.h" 46 #include "net/test/url_request/url_request_mock_http_job.h" 47 #include "net/url_request/url_request_context.h" 48 #include "net/url_request/url_request_context_getter.h" 49 #include "net/url_request/url_request_filter.h" 50 #include "net/url_request/url_request_interceptor.h" 51 #include "net/url_request/url_request_job.h" 52 #include "net/url_request/url_request_test_job.h" 53 #include "net/url_request/url_request_test_util.h" 54 #include "ui/base/l10n/l10n_util.h" 55 56 using content::BrowserThread; 57 using content::NavigationController; 58 using net::URLRequestFailedJob; 59 using net::URLRequestTestJob; 60 61 namespace { 62 63 // Returns true if |text| is displayed on the page |browser| is currently 64 // displaying. Uses "innerText", so will miss hidden text, and whitespace 65 // space handling may be weird. 66 bool WARN_UNUSED_RESULT IsDisplayingText(Browser* browser, 67 const std::string& text) { 68 std::string command = base::StringPrintf( 69 "var textContent = document.body.innerText;" 70 "var hasText = textContent.indexOf('%s') >= 0;" 71 "domAutomationController.send(hasText);", 72 text.c_str()); 73 bool result = false; 74 EXPECT_TRUE(content::ExecuteScriptAndExtractBool( 75 browser->tab_strip_model()->GetActiveWebContents(), command, &result)); 76 return result; 77 } 78 79 // Expands the more box on the currently displayed error page. 80 void ToggleHelpBox(Browser* browser) { 81 EXPECT_TRUE(content::ExecuteScript( 82 browser->tab_strip_model()->GetActiveWebContents(), 83 "document.getElementById('details-button').click();")); 84 } 85 86 // Returns true if |browser| is displaying the text representation of 87 // |error_code| on the current page. 88 bool WARN_UNUSED_RESULT IsDisplayingNetError(Browser* browser, 89 net::Error error_code) { 90 return IsDisplayingText(browser, net::ErrorToShortString(error_code)); 91 } 92 93 // Checks that the local error page is being displayed, without remotely 94 // retrieved navigation corrections, and with the specified error code. 95 void ExpectDisplayingLocalErrorPage(Browser* browser, net::Error error_code) { 96 // Expand the help box so innerText will include text below the fold. 97 ToggleHelpBox(browser); 98 99 EXPECT_TRUE(IsDisplayingNetError(browser, error_code)); 100 101 // Locally generated error pages should not have navigation corrections. 102 EXPECT_FALSE(IsDisplayingText(browser, "http://correction1/")); 103 EXPECT_FALSE(IsDisplayingText(browser, "http://correction2/")); 104 105 // Locally generated error pages should not have a populated search box. 106 bool search_box_populated = false; 107 ASSERT_TRUE(content::ExecuteScriptAndExtractBool( 108 browser->tab_strip_model()->GetActiveWebContents(), 109 "var searchText = document.getElementById('search-box').value;" 110 "domAutomationController.send(searchText == 'search query');", 111 &search_box_populated)); 112 EXPECT_FALSE(search_box_populated); 113 } 114 115 // Checks that an error page with information retrieved from the navigation 116 // correction service is being displayed, with the specified specified error 117 // code. 118 void ExpectDisplayingNavigationCorrections(Browser* browser, 119 net::Error error_code) { 120 // Expand the help box so innerText will include text below the fold. 121 ToggleHelpBox(browser); 122 123 EXPECT_TRUE(IsDisplayingNetError(browser, error_code)); 124 125 // Check that the mock navigation corrections are displayed. 126 EXPECT_TRUE(IsDisplayingText(browser, "http://correction1/")); 127 EXPECT_TRUE(IsDisplayingText(browser, "http://correction2/")); 128 129 // Check that the search box is populated correctly. 130 bool search_box_populated = false; 131 ASSERT_TRUE(content::ExecuteScriptAndExtractBool( 132 browser->tab_strip_model()->GetActiveWebContents(), 133 "var searchText = document.getElementById('search-box').value;" 134 "domAutomationController.send(searchText == 'search query');", 135 &search_box_populated)); 136 EXPECT_TRUE(search_box_populated); 137 } 138 139 std::string GetLoadStaleButtonLabel() { 140 return l10n_util::GetStringUTF8(IDS_ERRORPAGES_BUTTON_LOAD_STALE); 141 } 142 143 void AddInterceptorForURL( 144 const GURL& url, 145 scoped_ptr<net::URLRequestInterceptor> handler) { 146 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 147 net::URLRequestFilter::GetInstance()->AddUrlInterceptor( 148 url, handler.Pass()); 149 } 150 151 // An interceptor that fails a configurable number of requests, then succeeds 152 // all requests after that, keeping count of failures and successes. 153 class FailFirstNRequestsInterceptor : public net::URLRequestInterceptor { 154 public: 155 explicit FailFirstNRequestsInterceptor(int requests_to_fail) 156 : requests_(0), failures_(0), requests_to_fail_(requests_to_fail) {} 157 virtual ~FailFirstNRequestsInterceptor() {} 158 159 // net::URLRequestInterceptor implementation 160 virtual net::URLRequestJob* MaybeInterceptRequest( 161 net::URLRequest* request, 162 net::NetworkDelegate* network_delegate) const OVERRIDE { 163 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 164 requests_++; 165 if (failures_ < requests_to_fail_) { 166 failures_++; 167 // Note: net::ERR_CONNECTION_RESET does not summon the Link Doctor; see 168 // NetErrorHelperCore::GetErrorPageURL. 169 return new URLRequestFailedJob(request, 170 network_delegate, 171 net::ERR_CONNECTION_RESET); 172 } else { 173 return new URLRequestTestJob(request, network_delegate, 174 URLRequestTestJob::test_headers(), 175 URLRequestTestJob::test_data_1(), 176 true); 177 } 178 } 179 180 int requests() const { return requests_; } 181 int failures() const { return failures_; } 182 183 private: 184 // These are mutable because MaybeCreateJob is const but we want this state 185 // for testing. 186 mutable int requests_; 187 mutable int failures_; 188 int requests_to_fail_; 189 190 DISALLOW_COPY_AND_ASSIGN(FailFirstNRequestsInterceptor); 191 }; 192 193 // An interceptor that serves LinkDoctor responses. It also allows waiting 194 // until a certain number of requests have been sent. 195 // TODO(mmenke): Wait until responses have been received instead. 196 class LinkDoctorInterceptor : public net::URLRequestInterceptor { 197 public: 198 LinkDoctorInterceptor() : num_requests_(0), 199 requests_to_wait_for_(-1), 200 weak_factory_(this) { 201 } 202 203 virtual ~LinkDoctorInterceptor() {} 204 205 // net::URLRequestInterceptor implementation 206 virtual net::URLRequestJob* MaybeInterceptRequest( 207 net::URLRequest* request, 208 net::NetworkDelegate* network_delegate) const OVERRIDE { 209 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 210 211 BrowserThread::PostTask( 212 BrowserThread::UI, FROM_HERE, 213 base::Bind(&LinkDoctorInterceptor::RequestCreated, 214 weak_factory_.GetWeakPtr())); 215 216 base::FilePath root_http; 217 PathService::Get(chrome::DIR_TEST_DATA, &root_http); 218 return new net::URLRequestMockHTTPJob( 219 request, 220 network_delegate, 221 root_http.AppendASCII("mock-link-doctor.json"), 222 BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior( 223 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)); 224 } 225 226 void WaitForRequests(int requests_to_wait_for) { 227 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 228 DCHECK_EQ(-1, requests_to_wait_for_); 229 DCHECK(!run_loop_); 230 231 if (requests_to_wait_for >= num_requests_) 232 return; 233 234 requests_to_wait_for_ = requests_to_wait_for; 235 run_loop_.reset(new base::RunLoop()); 236 run_loop_->Run(); 237 run_loop_.reset(); 238 requests_to_wait_for_ = -1; 239 EXPECT_EQ(num_requests_, requests_to_wait_for); 240 } 241 242 // It is up to the caller to wait until all relevant requests has been 243 // created, either through calling WaitForRequests or some other manner, 244 // before calling this method. 245 int num_requests() const { 246 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 247 return num_requests_; 248 } 249 250 private: 251 void RequestCreated() { 252 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 253 254 num_requests_++; 255 if (num_requests_ == requests_to_wait_for_) 256 run_loop_->Quit(); 257 } 258 259 // These are only used on the UI thread. 260 int num_requests_; 261 int requests_to_wait_for_; 262 scoped_ptr<base::RunLoop> run_loop_; 263 264 // This prevents any risk of flake if any test doesn't wait for a request 265 // it sent. Mutable so it can be accessed from a const function. 266 mutable base::WeakPtrFactory<LinkDoctorInterceptor> weak_factory_; 267 268 DISALLOW_COPY_AND_ASSIGN(LinkDoctorInterceptor); 269 }; 270 271 void InstallMockInterceptors( 272 const GURL& search_url, 273 scoped_ptr<net::URLRequestInterceptor> link_doctor_interceptor) { 274 chrome_browser_net::SetUrlRequestMocksEnabled(true); 275 276 AddInterceptorForURL(google_util::LinkDoctorBaseURL(), 277 link_doctor_interceptor.Pass()); 278 279 // Add a mock for the search engine the error page will use. 280 base::FilePath root_http; 281 PathService::Get(chrome::DIR_TEST_DATA, &root_http); 282 net::URLRequestMockHTTPJob::AddHostnameToFileHandler( 283 search_url.host(), 284 root_http.AppendASCII("title3.html"), 285 BrowserThread::GetBlockingPool()); 286 } 287 288 class ErrorPageTest : public InProcessBrowserTest { 289 public: 290 enum HistoryNavigationDirection { 291 HISTORY_NAVIGATE_BACK, 292 HISTORY_NAVIGATE_FORWARD, 293 }; 294 295 ErrorPageTest() : link_doctor_interceptor_(NULL) {} 296 virtual ~ErrorPageTest() {} 297 298 // Navigates the active tab to a mock url created for the file at |file_path|. 299 // Needed for StaleCacheStatus and StaleCacheStatusFailedCorrections tests. 300 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 301 command_line->AppendSwitch(switches::kEnableOfflineLoadStaleCache); 302 } 303 304 // Navigates the active tab to a mock url created for the file at |file_path|. 305 void NavigateToFileURL(const base::FilePath::StringType& file_path) { 306 ui_test_utils::NavigateToURL( 307 browser(), 308 net::URLRequestMockHTTPJob::GetMockUrl(base::FilePath(file_path))); 309 } 310 311 // Navigates to the given URL and waits for |num_navigations| to occur, and 312 // the title to change to |expected_title|. 313 void NavigateToURLAndWaitForTitle(const GURL& url, 314 const std::string& expected_title, 315 int num_navigations) { 316 content::TitleWatcher title_watcher( 317 browser()->tab_strip_model()->GetActiveWebContents(), 318 base::ASCIIToUTF16(expected_title)); 319 320 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( 321 browser(), url, num_navigations); 322 323 EXPECT_EQ(base::ASCIIToUTF16(expected_title), 324 title_watcher.WaitAndGetTitle()); 325 } 326 327 // Navigates back in the history and waits for |num_navigations| to occur, and 328 // the title to change to |expected_title|. 329 void GoBackAndWaitForTitle(const std::string& expected_title, 330 int num_navigations) { 331 NavigateHistoryAndWaitForTitle(expected_title, 332 num_navigations, 333 HISTORY_NAVIGATE_BACK); 334 } 335 336 // Navigates forward in the history and waits for |num_navigations| to occur, 337 // and the title to change to |expected_title|. 338 void GoForwardAndWaitForTitle(const std::string& expected_title, 339 int num_navigations) { 340 NavigateHistoryAndWaitForTitle(expected_title, 341 num_navigations, 342 HISTORY_NAVIGATE_FORWARD); 343 } 344 345 void GoBackAndWaitForNavigations(int num_navigations) { 346 NavigateHistory(num_navigations, HISTORY_NAVIGATE_BACK); 347 } 348 349 void GoForwardAndWaitForNavigations(int num_navigations) { 350 NavigateHistory(num_navigations, HISTORY_NAVIGATE_FORWARD); 351 } 352 353 // Confirms that the javascript variable indicating whether or not we have 354 // a stale copy in the cache has been set to |expected|, and that the 355 // stale load button is or isn't there based on the same expectation. 356 testing::AssertionResult ProbeStaleCopyValue(bool expected) { 357 const char* js_cache_probe = 358 "try {\n" 359 " domAutomationController.send(\n" 360 " 'staleLoadButton' in templateData ? 'yes' : 'no');\n" 361 "} catch (e) {\n" 362 " domAutomationController.send(e.message);\n" 363 "}\n"; 364 365 std::string result; 366 bool ret = 367 content::ExecuteScriptAndExtractString( 368 browser()->tab_strip_model()->GetActiveWebContents(), 369 js_cache_probe, 370 &result); 371 if (!ret) { 372 return testing::AssertionFailure() 373 << "Failing return from ExecuteScriptAndExtractString."; 374 } 375 376 if ((expected && "yes" == result) || (!expected && "no" == result)) 377 return testing::AssertionSuccess(); 378 379 return testing::AssertionFailure() << "Cache probe result is " << result; 380 } 381 382 testing::AssertionResult ReloadStaleCopyFromCache() { 383 const char* js_reload_script = 384 "try {\n" 385 " document.getElementById('stale-load-button').click();\n" 386 " domAutomationController.send('success');\n" 387 "} catch (e) {\n" 388 " domAutomationController.send(e.message);\n" 389 "}\n"; 390 391 std::string result; 392 bool ret = content::ExecuteScriptAndExtractString( 393 browser()->tab_strip_model()->GetActiveWebContents(), 394 js_reload_script, 395 &result); 396 EXPECT_TRUE(ret); 397 if (!ret) 398 return testing::AssertionFailure(); 399 return ("success" == result ? testing::AssertionSuccess() : 400 (testing::AssertionFailure() << "Exception message is " << result)); 401 } 402 403 LinkDoctorInterceptor* link_doctor_interceptor() { 404 return link_doctor_interceptor_; 405 } 406 407 protected: 408 virtual void SetUpOnMainThread() OVERRIDE { 409 link_doctor_interceptor_ = new LinkDoctorInterceptor(); 410 scoped_ptr<net::URLRequestInterceptor> owned_interceptor( 411 link_doctor_interceptor_); 412 // Ownership of the |interceptor_| is passed to an object the IO thread, but 413 // a pointer is kept in the test fixture. As soon as anything calls 414 // URLRequestFilter::ClearHandlers(), |interceptor_| can become invalid. 415 BrowserThread::PostTask( 416 BrowserThread::IO, FROM_HERE, 417 base::Bind(&InstallMockInterceptors, 418 google_util::GetGoogleSearchURL( 419 google_profile_helper::GetGoogleHomePageURL( 420 browser()->profile())), 421 base::Passed(&owned_interceptor))); 422 } 423 424 // Returns a GURL that results in a DNS error. 425 GURL GetDnsErrorURL() const { 426 return URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED); 427 } 428 429 private: 430 // Navigates the browser the indicated direction in the history and waits for 431 // |num_navigations| to occur and the title to change to |expected_title|. 432 void NavigateHistoryAndWaitForTitle(const std::string& expected_title, 433 int num_navigations, 434 HistoryNavigationDirection direction) { 435 content::TitleWatcher title_watcher( 436 browser()->tab_strip_model()->GetActiveWebContents(), 437 base::ASCIIToUTF16(expected_title)); 438 439 NavigateHistory(num_navigations, direction); 440 441 EXPECT_EQ(title_watcher.WaitAndGetTitle(), 442 base::ASCIIToUTF16(expected_title)); 443 } 444 445 void NavigateHistory(int num_navigations, 446 HistoryNavigationDirection direction) { 447 content::TestNavigationObserver test_navigation_observer( 448 browser()->tab_strip_model()->GetActiveWebContents(), 449 num_navigations); 450 if (direction == HISTORY_NAVIGATE_BACK) { 451 chrome::GoBack(browser(), CURRENT_TAB); 452 } else if (direction == HISTORY_NAVIGATE_FORWARD) { 453 chrome::GoForward(browser(), CURRENT_TAB); 454 } else { 455 FAIL(); 456 } 457 test_navigation_observer.Wait(); 458 } 459 460 LinkDoctorInterceptor* link_doctor_interceptor_; 461 }; 462 463 class TestFailProvisionalLoadObserver : public content::WebContentsObserver { 464 public: 465 explicit TestFailProvisionalLoadObserver(content::WebContents* contents) 466 : content::WebContentsObserver(contents) {} 467 virtual ~TestFailProvisionalLoadObserver() {} 468 469 // This method is invoked when the provisional load failed. 470 virtual void DidFailProvisionalLoad( 471 content::RenderFrameHost* render_frame_host, 472 const GURL& validated_url, 473 int error_code, 474 const base::string16& error_description) OVERRIDE { 475 fail_url_ = validated_url; 476 } 477 478 const GURL& fail_url() const { return fail_url_; } 479 480 private: 481 GURL fail_url_; 482 483 DISALLOW_COPY_AND_ASSIGN(TestFailProvisionalLoadObserver); 484 }; 485 486 void InterceptNetworkTransactions(net::URLRequestContextGetter* getter, 487 net::Error error) { 488 DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::IO)); 489 net::HttpCache* cache( 490 getter->GetURLRequestContext()->http_transaction_factory()->GetCache()); 491 DCHECK(cache); 492 scoped_ptr<net::HttpTransactionFactory> factory( 493 new net::FailingHttpTransactionFactory(cache->GetSession(), error)); 494 // Throw away old version; since this is a a browser test, we don't 495 // need to restore the old state. 496 cache->SetHttpNetworkTransactionFactoryForTesting(factory.Pass()); 497 } 498 499 // Test that a DNS error occuring in the main frame redirects to an error page. 500 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_Basic) { 501 // The first navigation should fail, and the second one should be the error 502 // page. 503 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( 504 browser(), GetDnsErrorURL(), 2); 505 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); 506 EXPECT_EQ(1, link_doctor_interceptor()->num_requests()); 507 } 508 509 // Test that a DNS error occuring in the main frame does not result in an 510 // additional session history entry. 511 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack1) { 512 NavigateToFileURL(FILE_PATH_LITERAL("title2.html")); 513 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( 514 browser(), GetDnsErrorURL(), 2); 515 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); 516 GoBackAndWaitForTitle("Title Of Awesomeness", 1); 517 EXPECT_EQ(1, link_doctor_interceptor()->num_requests()); 518 } 519 520 // Test that a DNS error occuring in the main frame does not result in an 521 // additional session history entry. 522 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack2) { 523 NavigateToFileURL(FILE_PATH_LITERAL("title2.html")); 524 525 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( 526 browser(), GetDnsErrorURL(), 2); 527 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); 528 EXPECT_EQ(1, link_doctor_interceptor()->num_requests()); 529 530 NavigateToFileURL(FILE_PATH_LITERAL("title3.html")); 531 532 GoBackAndWaitForNavigations(2); 533 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); 534 EXPECT_EQ(2, link_doctor_interceptor()->num_requests()); 535 536 GoBackAndWaitForTitle("Title Of Awesomeness", 1); 537 EXPECT_EQ(2, link_doctor_interceptor()->num_requests()); 538 } 539 540 // Test that a DNS error occuring in the main frame does not result in an 541 // additional session history entry. 542 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack2AndForward) { 543 NavigateToFileURL(FILE_PATH_LITERAL("title2.html")); 544 545 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( 546 browser(), GetDnsErrorURL(), 2); 547 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); 548 EXPECT_EQ(1, link_doctor_interceptor()->num_requests()); 549 550 NavigateToFileURL(FILE_PATH_LITERAL("title3.html")); 551 552 GoBackAndWaitForNavigations(2); 553 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); 554 EXPECT_EQ(2, link_doctor_interceptor()->num_requests()); 555 556 GoBackAndWaitForTitle("Title Of Awesomeness", 1); 557 558 GoForwardAndWaitForNavigations(2); 559 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); 560 EXPECT_EQ(3, link_doctor_interceptor()->num_requests()); 561 } 562 563 // Test that a DNS error occuring in the main frame does not result in an 564 // additional session history entry. 565 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack2Forward2) { 566 NavigateToFileURL(FILE_PATH_LITERAL("title3.html")); 567 568 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( 569 browser(), GetDnsErrorURL(), 2); 570 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); 571 EXPECT_EQ(1, link_doctor_interceptor()->num_requests()); 572 573 NavigateToFileURL(FILE_PATH_LITERAL("title2.html")); 574 575 GoBackAndWaitForNavigations(2); 576 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); 577 EXPECT_EQ(2, link_doctor_interceptor()->num_requests()); 578 579 GoBackAndWaitForTitle("Title Of More Awesomeness", 1); 580 581 GoForwardAndWaitForNavigations(2); 582 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); 583 EXPECT_EQ(3, link_doctor_interceptor()->num_requests()); 584 585 GoForwardAndWaitForTitle("Title Of Awesomeness", 1); 586 EXPECT_EQ(3, link_doctor_interceptor()->num_requests()); 587 } 588 589 // Test that the search button on a DNS error page works. 590 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_DoSearch) { 591 // The first navigation should fail, and the second one should be the error 592 // page. 593 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( 594 browser(), GetDnsErrorURL(), 2); 595 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); 596 EXPECT_EQ(1, link_doctor_interceptor()->num_requests()); 597 598 content::WebContents* web_contents = 599 browser()->tab_strip_model()->GetActiveWebContents(); 600 601 // Do a search and make sure the browser ends up at the right page. 602 content::TestNavigationObserver nav_observer(web_contents, 1); 603 content::TitleWatcher title_watcher( 604 web_contents, 605 base::ASCIIToUTF16("Title Of More Awesomeness")); 606 // Can't use content::ExecuteScript because it waits for scripts to send 607 // notification that they've run, and scripts that trigger a navigation may 608 // not send that notification. 609 web_contents->GetMainFrame()->ExecuteJavaScript( 610 base::ASCIIToUTF16("document.getElementById('search-button').click();")); 611 nav_observer.Wait(); 612 EXPECT_EQ(base::ASCIIToUTF16("Title Of More Awesomeness"), 613 title_watcher.WaitAndGetTitle()); 614 615 // There should have been another Link Doctor request, for tracking purposes. 616 // Have to wait for it, since the search page does not depend on having 617 // sent the tracking request. 618 link_doctor_interceptor()->WaitForRequests(2); 619 EXPECT_EQ(2, link_doctor_interceptor()->num_requests()); 620 621 // Check the path and query string. 622 std::string url; 623 ASSERT_TRUE(content::ExecuteScriptAndExtractString( 624 browser()->tab_strip_model()->GetActiveWebContents(), 625 "domAutomationController.send(window.location.href);", 626 &url)); 627 EXPECT_EQ("/search", GURL(url).path()); 628 EXPECT_EQ("q=search%20query", GURL(url).query()); 629 630 // Go back to the error page, to make sure the history is correct. 631 GoBackAndWaitForNavigations(2); 632 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); 633 EXPECT_EQ(3, link_doctor_interceptor()->num_requests()); 634 } 635 636 // Test that the reload button on a DNS error page works. 637 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_DoReload) { 638 // The first navigation should fail, and the second one should be the error 639 // page. 640 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( 641 browser(), GetDnsErrorURL(), 2); 642 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); 643 EXPECT_EQ(1, link_doctor_interceptor()->num_requests()); 644 645 content::WebContents* web_contents = 646 browser()->tab_strip_model()->GetActiveWebContents(); 647 648 // Clicking the reload button should load the error page again, and there 649 // should be two commits, as before. 650 content::TestNavigationObserver nav_observer(web_contents, 2); 651 // Can't use content::ExecuteScript because it waits for scripts to send 652 // notification that they've run, and scripts that trigger a navigation may 653 // not send that notification. 654 web_contents->GetMainFrame()->ExecuteJavaScript( 655 base::ASCIIToUTF16("document.getElementById('reload-button').click();")); 656 nav_observer.Wait(); 657 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); 658 659 // There should have two more requests to the correction service: One for the 660 // new error page, and one for tracking purposes. Have to make sure to wait 661 // for the tracking request, since the new error page does not depend on it. 662 link_doctor_interceptor()->WaitForRequests(3); 663 EXPECT_EQ(3, link_doctor_interceptor()->num_requests()); 664 } 665 666 // Test that clicking links on a DNS error page works. 667 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_DoClickLink) { 668 // The first navigation should fail, and the second one should be the error 669 // page. 670 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( 671 browser(), GetDnsErrorURL(), 2); 672 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); 673 EXPECT_EQ(1, link_doctor_interceptor()->num_requests()); 674 675 content::WebContents* web_contents = 676 browser()->tab_strip_model()->GetActiveWebContents(); 677 678 // Simulate a click on a link. 679 680 content::TitleWatcher title_watcher( 681 web_contents, 682 base::ASCIIToUTF16("Title Of Awesomeness")); 683 std::string link_selector = 684 "document.querySelector('a[href=\"http://mock.http/title2.html\"]')"; 685 // The tracking request is triggered by onmousedown, so it catches middle 686 // mouse button clicks, as well as left clicks. 687 web_contents->GetMainFrame()->ExecuteJavaScript( 688 base::ASCIIToUTF16(link_selector + ".onmousedown();")); 689 // Can't use content::ExecuteScript because it waits for scripts to send 690 // notification that they've run, and scripts that trigger a navigation may 691 // not send that notification. 692 web_contents->GetMainFrame()->ExecuteJavaScript( 693 base::ASCIIToUTF16(link_selector + ".click();")); 694 EXPECT_EQ(base::ASCIIToUTF16("Title Of Awesomeness"), 695 title_watcher.WaitAndGetTitle()); 696 697 // There should have been a tracking request to the correction service. Have 698 // to make sure to wait the tracking request, since the new page does not 699 // depend on it. 700 link_doctor_interceptor()->WaitForRequests(2); 701 EXPECT_EQ(2, link_doctor_interceptor()->num_requests()); 702 } 703 704 // Test that a DNS error occuring in an iframe does not result in showing 705 // navigation corrections. 706 IN_PROC_BROWSER_TEST_F(ErrorPageTest, IFrameDNSError_Basic) { 707 NavigateToURLAndWaitForTitle( 708 net::URLRequestMockHTTPJob::GetMockUrl( 709 base::FilePath(FILE_PATH_LITERAL("iframe_dns_error.html"))), 710 "Blah", 711 1); 712 // We expect to have two history entries, since we started off with navigation 713 // to "about:blank" and then navigated to "iframe_dns_error.html". 714 EXPECT_EQ(2, 715 browser()->tab_strip_model()->GetActiveWebContents()-> 716 GetController().GetEntryCount()); 717 EXPECT_EQ(0, link_doctor_interceptor()->num_requests()); 718 } 719 720 // This test fails regularly on win_rel trybots. See crbug.com/121540 721 #if defined(OS_WIN) 722 #define MAYBE_IFrameDNSError_GoBack DISABLED_IFrameDNSError_GoBack 723 #else 724 #define MAYBE_IFrameDNSError_GoBack IFrameDNSError_GoBack 725 #endif 726 // Test that a DNS error occuring in an iframe does not result in an 727 // additional session history entry. 728 IN_PROC_BROWSER_TEST_F(ErrorPageTest, MAYBE_IFrameDNSError_GoBack) { 729 NavigateToFileURL(FILE_PATH_LITERAL("title2.html")); 730 NavigateToFileURL(FILE_PATH_LITERAL("iframe_dns_error.html")); 731 GoBackAndWaitForTitle("Title Of Awesomeness", 1); 732 EXPECT_EQ(0, link_doctor_interceptor()->num_requests()); 733 } 734 735 // This test fails regularly on win_rel trybots. See crbug.com/121540 736 // 737 // This fails on linux_aura bringup: http://crbug.com/163931 738 #if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)) 739 #define MAYBE_IFrameDNSError_GoBackAndForward DISABLED_IFrameDNSError_GoBackAndForward 740 #else 741 #define MAYBE_IFrameDNSError_GoBackAndForward IFrameDNSError_GoBackAndForward 742 #endif 743 // Test that a DNS error occuring in an iframe does not result in an 744 // additional session history entry. 745 IN_PROC_BROWSER_TEST_F(ErrorPageTest, MAYBE_IFrameDNSError_GoBackAndForward) { 746 NavigateToFileURL(FILE_PATH_LITERAL("title2.html")); 747 NavigateToFileURL(FILE_PATH_LITERAL("iframe_dns_error.html")); 748 GoBackAndWaitForTitle("Title Of Awesomeness", 1); 749 GoForwardAndWaitForTitle("Blah", 1); 750 EXPECT_EQ(0, link_doctor_interceptor()->num_requests()); 751 } 752 753 // Test that a DNS error occuring in an iframe, once the main document is 754 // completed loading, does not result in an additional session history entry. 755 // To ensure that the main document has completed loading, JavaScript is used to 756 // inject an iframe after loading is done. 757 IN_PROC_BROWSER_TEST_F(ErrorPageTest, IFrameDNSError_JavaScript) { 758 content::WebContents* wc = 759 browser()->tab_strip_model()->GetActiveWebContents(); 760 GURL fail_url = 761 URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED); 762 763 // Load a regular web page, in which we will inject an iframe. 764 NavigateToFileURL(FILE_PATH_LITERAL("title2.html")); 765 766 // We expect to have two history entries, since we started off with navigation 767 // to "about:blank" and then navigated to "title2.html". 768 EXPECT_EQ(2, wc->GetController().GetEntryCount()); 769 770 std::string script = "var frame = document.createElement('iframe');" 771 "frame.src = '" + fail_url.spec() + "';" 772 "document.body.appendChild(frame);"; 773 { 774 TestFailProvisionalLoadObserver fail_observer(wc); 775 content::WindowedNotificationObserver load_observer( 776 content::NOTIFICATION_LOAD_STOP, 777 content::Source<NavigationController>(&wc->GetController())); 778 wc->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(script)); 779 load_observer.Wait(); 780 781 // Ensure we saw the expected failure. 782 EXPECT_EQ(fail_url, fail_observer.fail_url()); 783 784 // Failed initial navigation of an iframe shouldn't be adding any history 785 // entries. 786 EXPECT_EQ(2, wc->GetController().GetEntryCount()); 787 } 788 789 // Do the same test, but with an iframe that doesn't have initial URL 790 // assigned. 791 script = "var frame = document.createElement('iframe');" 792 "frame.id = 'target_frame';" 793 "document.body.appendChild(frame);"; 794 { 795 content::WindowedNotificationObserver load_observer( 796 content::NOTIFICATION_LOAD_STOP, 797 content::Source<NavigationController>(&wc->GetController())); 798 wc->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(script)); 799 load_observer.Wait(); 800 } 801 802 script = "var f = document.getElementById('target_frame');" 803 "f.src = '" + fail_url.spec() + "';"; 804 { 805 TestFailProvisionalLoadObserver fail_observer(wc); 806 content::WindowedNotificationObserver load_observer( 807 content::NOTIFICATION_LOAD_STOP, 808 content::Source<NavigationController>(&wc->GetController())); 809 wc->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(script)); 810 load_observer.Wait(); 811 812 EXPECT_EQ(fail_url, fail_observer.fail_url()); 813 EXPECT_EQ(2, wc->GetController().GetEntryCount()); 814 } 815 EXPECT_EQ(0, link_doctor_interceptor()->num_requests()); 816 } 817 818 // Checks that navigation corrections are not loaded when we receive an actual 819 // 404 page. 820 IN_PROC_BROWSER_TEST_F(ErrorPageTest, Page404) { 821 NavigateToURLAndWaitForTitle( 822 net::URLRequestMockHTTPJob::GetMockUrl( 823 base::FilePath(FILE_PATH_LITERAL("page404.html"))), 824 "SUCCESS", 825 1); 826 EXPECT_EQ(0, link_doctor_interceptor()->num_requests()); 827 } 828 829 // Checks that when an error occurs, the stale cache status of the page 830 // is correctly transferred, and that stale cached copied can be loaded 831 // from the javascript. 832 IN_PROC_BROWSER_TEST_F(ErrorPageTest, StaleCacheStatus) { 833 ASSERT_TRUE(test_server()->Start()); 834 // Load cache with entry with "nocache" set, to create stale 835 // cache. 836 GURL test_url(test_server()->GetURL("files/nocache.html")); 837 NavigateToURLAndWaitForTitle(test_url, "Nocache Test Page", 1); 838 839 // Reload same URL after forcing an error from the the network layer; 840 // confirm that the error page is told the cached copy exists. 841 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter = 842 browser()->profile()->GetRequestContext(); 843 BrowserThread::PostTask( 844 BrowserThread::IO, FROM_HERE, 845 base::Bind(&InterceptNetworkTransactions, url_request_context_getter, 846 net::ERR_FAILED)); 847 848 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( 849 // With no navigation corrections to load, there's only one navigation. 850 browser(), test_url, 1); 851 EXPECT_TRUE(ProbeStaleCopyValue(true)); 852 EXPECT_TRUE(IsDisplayingText(browser(), GetLoadStaleButtonLabel())); 853 EXPECT_NE(base::ASCIIToUTF16("Nocache Test Page"), 854 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle()); 855 856 // Confirm that loading the stale copy from the cache works. 857 content::TestNavigationObserver same_tab_observer( 858 browser()->tab_strip_model()->GetActiveWebContents(), 1); 859 ASSERT_TRUE(ReloadStaleCopyFromCache()); 860 same_tab_observer.Wait(); 861 EXPECT_EQ(base::ASCIIToUTF16("Nocache Test Page"), 862 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle()); 863 864 // Clear the cache and reload the same URL; confirm the error page is told 865 // that there is no cached copy. 866 BrowsingDataRemover* remover = 867 BrowsingDataRemover::CreateForUnboundedRange(browser()->profile()); 868 remover->Remove(BrowsingDataRemover::REMOVE_CACHE, 869 BrowsingDataHelper::UNPROTECTED_WEB); 870 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( 871 browser(), test_url, 1); 872 EXPECT_TRUE(ProbeStaleCopyValue(false)); 873 EXPECT_FALSE(IsDisplayingText(browser(), GetLoadStaleButtonLabel())); 874 EXPECT_EQ(0, link_doctor_interceptor()->num_requests()); 875 } 876 877 class ErrorPageAutoReloadTest : public InProcessBrowserTest { 878 public: 879 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 880 command_line->AppendSwitch(switches::kEnableOfflineAutoReload); 881 } 882 883 void InstallInterceptor(const GURL& url, int requests_to_fail) { 884 interceptor_ = new FailFirstNRequestsInterceptor(requests_to_fail); 885 scoped_ptr<net::URLRequestInterceptor> owned_interceptor(interceptor_); 886 887 // Tests don't need to wait for this task to complete before using the 888 // filter; any requests that might be affected by it will end up in the IO 889 // thread's message loop after this posted task anyway. 890 // 891 // Ownership of the interceptor is passed to an object the IO thread, but a 892 // pointer is kept in the test fixture. As soon as anything calls 893 // URLRequestFilter::ClearHandlers(), |interceptor_| can become invalid. 894 BrowserThread::PostTask( 895 BrowserThread::IO, FROM_HERE, 896 base::Bind(&AddInterceptorForURL, url, 897 base::Passed(&owned_interceptor))); 898 } 899 900 void NavigateToURLAndWaitForTitle(const GURL& url, 901 const std::string& expected_title, 902 int num_navigations) { 903 content::TitleWatcher title_watcher( 904 browser()->tab_strip_model()->GetActiveWebContents(), 905 base::ASCIIToUTF16(expected_title)); 906 907 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( 908 browser(), url, num_navigations); 909 910 EXPECT_EQ(base::ASCIIToUTF16(expected_title), 911 title_watcher.WaitAndGetTitle()); 912 } 913 914 FailFirstNRequestsInterceptor* interceptor() { 915 return interceptor_; 916 } 917 918 private: 919 FailFirstNRequestsInterceptor* interceptor_; 920 }; 921 922 IN_PROC_BROWSER_TEST_F(ErrorPageAutoReloadTest, AutoReload) { 923 GURL test_url("http://error.page.auto.reload"); 924 const int kRequestsToFail = 2; 925 InstallInterceptor(test_url, kRequestsToFail); 926 NavigateToURLAndWaitForTitle(test_url, "Test One", kRequestsToFail + 1); 927 // Note that the interceptor updates these variables on the IO thread, 928 // but this function reads them on the main thread. The requests have to be 929 // created (on the IO thread) before NavigateToURLAndWaitForTitle returns or 930 // this becomes racey. 931 EXPECT_EQ(kRequestsToFail, interceptor()->failures()); 932 EXPECT_EQ(kRequestsToFail + 1, interceptor()->requests()); 933 } 934 935 // Interceptor that fails all requests with net::ERR_ADDRESS_UNREACHABLE. 936 class AddressUnreachableInterceptor : public net::URLRequestInterceptor { 937 public: 938 AddressUnreachableInterceptor() {} 939 virtual ~AddressUnreachableInterceptor() {} 940 941 // net::URLRequestInterceptor: 942 virtual net::URLRequestJob* MaybeInterceptRequest( 943 net::URLRequest* request, 944 net::NetworkDelegate* network_delegate) const OVERRIDE { 945 return new URLRequestFailedJob(request, 946 network_delegate, 947 net::ERR_ADDRESS_UNREACHABLE); 948 } 949 950 private: 951 DISALLOW_COPY_AND_ASSIGN(AddressUnreachableInterceptor); 952 }; 953 954 // A test fixture that returns ERR_ADDRESS_UNREACHABLE for all navigation 955 // correction requests. ERR_NAME_NOT_RESOLVED is more typical, but need to use 956 // a different error for the correction service and the original page to 957 // validate the right page is being displayed. 958 class ErrorPageNavigationCorrectionsFailTest : public ErrorPageTest { 959 public: 960 // InProcessBrowserTest: 961 virtual void SetUpOnMainThread() OVERRIDE { 962 BrowserThread::PostTask( 963 BrowserThread::IO, FROM_HERE, 964 base::Bind(&ErrorPageNavigationCorrectionsFailTest::AddFilters)); 965 } 966 967 virtual void TearDownOnMainThread() OVERRIDE { 968 BrowserThread::PostTask( 969 BrowserThread::IO, FROM_HERE, 970 base::Bind(&ErrorPageNavigationCorrectionsFailTest::RemoveFilters)); 971 } 972 973 private: 974 // Adds a filter that causes all correction service requests to fail with 975 // ERR_ADDRESS_UNREACHABLE. 976 // 977 // Also adds the net::URLRequestFailedJob filter. 978 static void AddFilters() { 979 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 980 URLRequestFailedJob::AddUrlHandler(); 981 982 net::URLRequestFilter::GetInstance()->AddUrlInterceptor( 983 google_util::LinkDoctorBaseURL(), 984 scoped_ptr<net::URLRequestInterceptor>( 985 new AddressUnreachableInterceptor())); 986 } 987 988 static void RemoveFilters() { 989 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 990 net::URLRequestFilter::GetInstance()->ClearHandlers(); 991 } 992 }; 993 994 // Make sure that when corrections fail to load, the network error page is 995 // successfully loaded. 996 IN_PROC_BROWSER_TEST_F(ErrorPageNavigationCorrectionsFailTest, 997 FetchCorrectionsFails) { 998 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( 999 browser(), 1000 URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED), 1001 2); 1002 1003 // Verify that the expected error page is being displayed. 1004 ExpectDisplayingLocalErrorPage(browser(), net::ERR_NAME_NOT_RESOLVED); 1005 } 1006 1007 // Checks that when an error occurs and a corrections fail to load, the stale 1008 // cache status of the page is correctly transferred, and we can load the 1009 // stale copy from the javascript. Most logic copied from StaleCacheStatus 1010 // above. 1011 IN_PROC_BROWSER_TEST_F(ErrorPageNavigationCorrectionsFailTest, 1012 StaleCacheStatusFailedCorrections) { 1013 ASSERT_TRUE(test_server()->Start()); 1014 // Load cache with entry with "nocache" set, to create stale 1015 // cache. 1016 GURL test_url(test_server()->GetURL("files/nocache.html")); 1017 NavigateToURLAndWaitForTitle(test_url, "Nocache Test Page", 1); 1018 1019 // Reload same URL after forcing an error from the the network layer; 1020 // confirm that the error page is told the cached copy exists. 1021 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter = 1022 browser()->profile()->GetRequestContext(); 1023 BrowserThread::PostTask( 1024 BrowserThread::IO, FROM_HERE, 1025 base::Bind(&InterceptNetworkTransactions, url_request_context_getter, 1026 net::ERR_CONNECTION_FAILED)); 1027 1028 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( 1029 browser(), test_url, 2); 1030 EXPECT_TRUE(IsDisplayingText(browser(), GetLoadStaleButtonLabel())); 1031 EXPECT_TRUE(ProbeStaleCopyValue(true)); 1032 1033 // Confirm that loading the stale copy from the cache works. 1034 content::TestNavigationObserver same_tab_observer( 1035 browser()->tab_strip_model()->GetActiveWebContents(), 1); 1036 ASSERT_TRUE(ReloadStaleCopyFromCache()); 1037 same_tab_observer.Wait(); 1038 EXPECT_EQ(base::ASCIIToUTF16("Nocache Test Page"), 1039 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle()); 1040 1041 // Clear the cache and reload the same URL; confirm the error page is told 1042 // that there is no cached copy. 1043 BrowsingDataRemover* remover = 1044 BrowsingDataRemover::CreateForUnboundedRange(browser()->profile()); 1045 remover->Remove(BrowsingDataRemover::REMOVE_CACHE, 1046 BrowsingDataHelper::UNPROTECTED_WEB); 1047 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( 1048 browser(), test_url, 2); 1049 EXPECT_TRUE(ProbeStaleCopyValue(false)); 1050 EXPECT_FALSE(IsDisplayingText(browser(), GetLoadStaleButtonLabel())); 1051 } 1052 1053 // A test fixture that simulates failing requests for an IDN domain name. 1054 class ErrorPageForIDNTest : public InProcessBrowserTest { 1055 public: 1056 // Target hostname in different forms. 1057 static const char kHostname[]; 1058 static const char kHostnameJSUnicode[]; 1059 1060 // InProcessBrowserTest: 1061 virtual void SetUpOnMainThread() OVERRIDE { 1062 // Clear AcceptLanguages to force punycode decoding. 1063 browser()->profile()->GetPrefs()->SetString(prefs::kAcceptLanguages, 1064 std::string()); 1065 BrowserThread::PostTask( 1066 BrowserThread::IO, FROM_HERE, 1067 base::Bind(&ErrorPageForIDNTest::AddFilters)); 1068 } 1069 1070 virtual void TearDownOnMainThread() OVERRIDE { 1071 BrowserThread::PostTask( 1072 BrowserThread::IO, FROM_HERE, 1073 base::Bind(&ErrorPageForIDNTest::RemoveFilters)); 1074 } 1075 1076 private: 1077 static void AddFilters() { 1078 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1079 URLRequestFailedJob::AddUrlHandlerForHostname(kHostname); 1080 } 1081 1082 static void RemoveFilters() { 1083 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1084 net::URLRequestFilter::GetInstance()->ClearHandlers(); 1085 } 1086 }; 1087 1088 const char ErrorPageForIDNTest::kHostname[] = 1089 "xn--d1abbgf6aiiy.xn--p1ai"; 1090 const char ErrorPageForIDNTest::kHostnameJSUnicode[] = 1091 "\\u043f\\u0440\\u0435\\u0437\\u0438\\u0434\\u0435\\u043d\\u0442." 1092 "\\u0440\\u0444"; 1093 1094 // Make sure error page shows correct unicode for IDN. 1095 IN_PROC_BROWSER_TEST_F(ErrorPageForIDNTest, IDN) { 1096 // ERR_UNSAFE_PORT will not trigger navigation corrections. 1097 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( 1098 browser(), 1099 URLRequestFailedJob::GetMockHttpUrlForHostname(net::ERR_UNSAFE_PORT, 1100 kHostname), 1101 1); 1102 1103 ToggleHelpBox(browser()); 1104 EXPECT_TRUE(IsDisplayingText(browser(), kHostnameJSUnicode)); 1105 } 1106 1107 } // namespace 1108