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 56using content::BrowserThread; 57using content::NavigationController; 58using net::URLRequestFailedJob; 59using net::URLRequestTestJob; 60 61namespace { 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. 66bool 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. 80void 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. 88bool 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. 95void 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. 118void 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 139std::string GetLoadStaleButtonLabel() { 140 return l10n_util::GetStringUTF8(IDS_ERRORPAGES_BUTTON_LOAD_STALE); 141} 142 143void 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. 153class 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. 196class 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 271void 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 288class 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 463class 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 486void 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. 500IN_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. 511IN_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. 522IN_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. 542IN_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. 565IN_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. 590IN_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. 637IN_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. 667IN_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. 706IN_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. 728IN_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. 745IN_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. 757IN_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. 820IN_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. 832IN_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 877class 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 922IN_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. 936class 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. 958class 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. 996IN_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. 1011IN_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. 1054class 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 1088const char ErrorPageForIDNTest::kHostname[] = 1089 "xn--d1abbgf6aiiy.xn--p1ai"; 1090const 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. 1095IN_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