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.
6 #include "base/prefs/pref_service.h"
7 #include "base/strings/stringprintf.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/browser/browsing_data/browsing_data_helper.h"
10 #include "chrome/browser/browsing_data/browsing_data_remover.h"
11 #include "chrome/browser/google/google_util.h"
12 #include "chrome/browser/net/url_request_mock_util.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/ui/browser.h"
15 #include "chrome/browser/ui/browser_commands.h"
16 #include "chrome/browser/ui/tabs/tab_strip_model.h"
17 #include "chrome/common/pref_names.h"
18 #include "chrome/test/base/in_process_browser_test.h"
19 #include "chrome/test/base/ui_test_utils.h"
20 #include "content/public/browser/notification_service.h"
21 #include "content/public/browser/render_view_host.h"
22 #include "content/public/browser/web_contents.h"
23 #include "content/public/browser/web_contents_observer.h"
24 #include "content/public/test/browser_test_utils.h"
25 #include "content/public/test/test_navigation_observer.h"
26 #include "content/test/net/url_request_failed_job.h"
27 #include "content/test/net/url_request_mock_http_job.h"
28 #include "net/base/net_errors.h"
29 #include "net/base/net_util.h"
30 #include "net/http/failing_http_transaction_factory.h"
31 #include "net/http/http_cache.h"
32 #include "net/test/spawned_test_server/spawned_test_server.h"
33 #include "net/url_request/url_request_context.h"
34 #include "net/url_request/url_request_context_getter.h"
35 #include "net/url_request/url_request_filter.h"
36 #include "net/url_request/url_request_job_factory.h"
38 using content::BrowserThread;
39 using content::NavigationController;
40 using content::URLRequestFailedJob;
44 class ErrorPageTest : public InProcessBrowserTest {
46 enum HistoryNavigationDirection {
47 HISTORY_NAVIGATE_BACK,
48 HISTORY_NAVIGATE_FORWARD,
51 // Navigates the active tab to a mock url created for the file at |file_path|.
52 void NavigateToFileURL(const base::FilePath::StringType& file_path) {
53 ui_test_utils::NavigateToURL(
55 content::URLRequestMockHTTPJob::GetMockUrl(base::FilePath(file_path)));
58 // Navigates to the given URL and waits for |num_navigations| to occur, and
59 // the title to change to |expected_title|.
60 void NavigateToURLAndWaitForTitle(const GURL& url,
61 const std::string& expected_title,
62 int num_navigations) {
63 content::TitleWatcher title_watcher(
64 browser()->tab_strip_model()->GetActiveWebContents(),
65 base::ASCIIToUTF16(expected_title));
67 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
68 browser(), url, num_navigations);
70 EXPECT_EQ(base::ASCIIToUTF16(expected_title),
71 title_watcher.WaitAndGetTitle());
74 // Navigates back in the history and waits for |num_navigations| to occur, and
75 // the title to change to |expected_title|.
76 void GoBackAndWaitForTitle(const std::string& expected_title,
77 int num_navigations) {
78 NavigateHistoryAndWaitForTitle(expected_title,
80 HISTORY_NAVIGATE_BACK);
83 // Navigates forward in the history and waits for |num_navigations| to occur,
84 // and the title to change to |expected_title|.
85 void GoForwardAndWaitForTitle(const std::string& expected_title,
86 int num_navigations) {
87 NavigateHistoryAndWaitForTitle(expected_title,
89 HISTORY_NAVIGATE_FORWARD);
92 // Confirms that the javascript variable indicating whether or not we have
93 // a stale copy in the cache has been set to |expected|.
94 bool ProbeStaleCopyValue(bool expected) {
95 const char* js_cache_probe =
97 " if ('staleCopyInCache' in templateData) {\n"
98 " domAutomationController.send(\n"
99 " templateData.staleCopyInCache ? 'yes' : 'no');\n"
101 " domAutomationController.send('absent');\n"
107 content::ExecuteScriptAndExtractString(
108 browser()->tab_strip_model()->GetActiveWebContents(),
114 EXPECT_EQ(expected ? "yes" : "no", result);
115 return ((expected ? "yes" : "no") == result);
119 virtual void SetUpOnMainThread() OVERRIDE {
120 BrowserThread::PostTask(
121 BrowserThread::IO, FROM_HERE,
122 base::Bind(&chrome_browser_net::SetUrlRequestMocksEnabled, true));
125 // Returns a GURL that results in a DNS error.
126 GURL GetDnsErrorURL() const {
127 return URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED);
131 // Navigates the browser the indicated direction in the history and waits for
132 // |num_navigations| to occur and the title to change to |expected_title|.
133 void NavigateHistoryAndWaitForTitle(const std::string& expected_title,
135 HistoryNavigationDirection direction) {
136 content::TitleWatcher title_watcher(
137 browser()->tab_strip_model()->GetActiveWebContents(),
138 base::ASCIIToUTF16(expected_title));
140 content::TestNavigationObserver test_navigation_observer(
141 browser()->tab_strip_model()->GetActiveWebContents(),
143 if (direction == HISTORY_NAVIGATE_BACK) {
144 chrome::GoBack(browser(), CURRENT_TAB);
145 } else if (direction == HISTORY_NAVIGATE_FORWARD) {
146 chrome::GoForward(browser(), CURRENT_TAB);
150 test_navigation_observer.Wait();
152 EXPECT_EQ(title_watcher.WaitAndGetTitle(),
153 base::ASCIIToUTF16(expected_title));
157 class TestFailProvisionalLoadObserver : public content::WebContentsObserver {
159 explicit TestFailProvisionalLoadObserver(content::WebContents* contents)
160 : content::WebContentsObserver(contents) {}
161 virtual ~TestFailProvisionalLoadObserver() {}
163 // This method is invoked when the provisional load failed.
164 virtual void DidFailProvisionalLoad(
166 const base::string16& frame_unique_name,
168 const GURL& validated_url,
170 const base::string16& error_description,
171 content::RenderViewHost* render_view_host) OVERRIDE {
172 fail_url_ = validated_url;
175 const GURL& fail_url() const { return fail_url_; }
180 DISALLOW_COPY_AND_ASSIGN(TestFailProvisionalLoadObserver);
183 void InterceptNetworkTransactions(net::URLRequestContextGetter* getter,
185 DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::IO));
186 net::HttpCache* cache(
187 getter->GetURLRequestContext()->http_transaction_factory()->GetCache());
189 scoped_ptr<net::HttpTransactionFactory> factory(
190 new net::FailingHttpTransactionFactory(cache->GetSession(), error));
191 // Throw away old version; since this is a a browser test, we don't
192 // need to restore the old state.
193 cache->SetHttpNetworkTransactionFactoryForTesting(factory.Pass());
196 // See crbug.com/109669
197 #if defined(USE_AURA) || defined(OS_WIN)
198 #define MAYBE_DNSError_Basic DISABLED_DNSError_Basic
200 #define MAYBE_DNSError_Basic DNSError_Basic
202 // Test that a DNS error occuring in the main frame redirects to an error page.
203 IN_PROC_BROWSER_TEST_F(ErrorPageTest, MAYBE_DNSError_Basic) {
204 // The first navigation should fail, and the second one should be the error
206 NavigateToURLAndWaitForTitle(GetDnsErrorURL(), "Mock Link Doctor", 2);
209 // See crbug.com/109669
210 #if defined(USE_AURA)
211 #define MAYBE_DNSError_GoBack1 DISABLED_DNSError_GoBack1
213 #define MAYBE_DNSError_GoBack1 DNSError_GoBack1
216 // Test that a DNS error occuring in the main frame does not result in an
217 // additional session history entry.
218 IN_PROC_BROWSER_TEST_F(ErrorPageTest, MAYBE_DNSError_GoBack1) {
219 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
220 NavigateToURLAndWaitForTitle(GetDnsErrorURL(), "Mock Link Doctor", 2);
221 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
224 // See crbug.com/109669
225 #if defined(USE_AURA)
226 #define MAYBE_DNSError_GoBack2 DISABLED_DNSError_GoBack2
228 #define MAYBE_DNSError_GoBack2 DNSError_GoBack2
230 // Test that a DNS error occuring in the main frame does not result in an
231 // additional session history entry.
232 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack2) {
233 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
235 NavigateToURLAndWaitForTitle(GetDnsErrorURL(), "Mock Link Doctor", 2);
236 NavigateToFileURL(FILE_PATH_LITERAL("title3.html"));
238 GoBackAndWaitForTitle("Mock Link Doctor", 2);
239 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
242 // See crbug.com/109669
243 #if defined(USE_AURA)
244 #define MAYBE_DNSError_GoBack2AndForward DISABLED_DNSError_GoBack2AndForward
246 #define MAYBE_DNSError_GoBack2AndForward DNSError_GoBack2AndForward
248 // Test that a DNS error occuring in the main frame does not result in an
249 // additional session history entry.
250 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack2AndForward) {
251 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
253 NavigateToURLAndWaitForTitle(GetDnsErrorURL(), "Mock Link Doctor", 2);
254 NavigateToFileURL(FILE_PATH_LITERAL("title3.html"));
256 GoBackAndWaitForTitle("Mock Link Doctor", 2);
257 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
259 GoForwardAndWaitForTitle("Mock Link Doctor", 2);
262 // See crbug.com/109669
263 #if defined(USE_AURA)
264 #define MAYBE_DNSError_GoBack2Forward2 DISABLED_DNSError_GoBack2Forward2
266 #define MAYBE_DNSError_GoBack2Forward2 DNSError_GoBack2Forward2
268 // Test that a DNS error occuring in the main frame does not result in an
269 // additional session history entry.
270 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack2Forward2) {
271 NavigateToFileURL(FILE_PATH_LITERAL("title3.html"));
273 NavigateToURLAndWaitForTitle(GetDnsErrorURL(), "Mock Link Doctor", 2);
274 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
276 GoBackAndWaitForTitle("Mock Link Doctor", 2);
277 GoBackAndWaitForTitle("Title Of More Awesomeness", 1);
279 GoForwardAndWaitForTitle("Mock Link Doctor", 2);
280 GoForwardAndWaitForTitle("Title Of Awesomeness", 1);
283 // Test that a DNS error occuring in an iframe.
284 IN_PROC_BROWSER_TEST_F(ErrorPageTest, IFrameDNSError_Basic) {
285 NavigateToURLAndWaitForTitle(
286 content::URLRequestMockHTTPJob::GetMockUrl(
287 base::FilePath(FILE_PATH_LITERAL("iframe_dns_error.html"))),
290 // We expect to have two history entries, since we started off with navigation
291 // to "about:blank" and then navigated to "iframe_dns_error.html".
293 browser()->tab_strip_model()->GetActiveWebContents()->
294 GetController().GetEntryCount());
297 // This test fails regularly on win_rel trybots. See crbug.com/121540
299 #define MAYBE_IFrameDNSError_GoBack DISABLED_IFrameDNSError_GoBack
301 #define MAYBE_IFrameDNSError_GoBack IFrameDNSError_GoBack
303 // Test that a DNS error occuring in an iframe does not result in an
304 // additional session history entry.
305 IN_PROC_BROWSER_TEST_F(ErrorPageTest, MAYBE_IFrameDNSError_GoBack) {
306 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
307 NavigateToFileURL(FILE_PATH_LITERAL("iframe_dns_error.html"));
308 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
311 // This test fails regularly on win_rel trybots. See crbug.com/121540
313 // This fails on linux_aura bringup: http://crbug.com/163931
314 #if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA))
315 #define MAYBE_IFrameDNSError_GoBackAndForward DISABLED_IFrameDNSError_GoBackAndForward
317 #define MAYBE_IFrameDNSError_GoBackAndForward IFrameDNSError_GoBackAndForward
319 // Test that a DNS error occuring in an iframe does not result in an
320 // additional session history entry.
321 IN_PROC_BROWSER_TEST_F(ErrorPageTest, MAYBE_IFrameDNSError_GoBackAndForward) {
322 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
323 NavigateToFileURL(FILE_PATH_LITERAL("iframe_dns_error.html"));
324 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
325 GoForwardAndWaitForTitle("Blah", 1);
328 // Test that a DNS error occuring in an iframe, once the main document is
329 // completed loading, does not result in an additional session history entry.
330 // To ensure that the main document has completed loading, JavaScript is used to
331 // inject an iframe after loading is done.
332 IN_PROC_BROWSER_TEST_F(ErrorPageTest, IFrameDNSError_JavaScript) {
333 content::WebContents* wc =
334 browser()->tab_strip_model()->GetActiveWebContents();
336 URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED);
338 // Load a regular web page, in which we will inject an iframe.
339 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
341 // We expect to have two history entries, since we started off with navigation
342 // to "about:blank" and then navigated to "title2.html".
343 EXPECT_EQ(2, wc->GetController().GetEntryCount());
345 std::string script = "var frame = document.createElement('iframe');"
346 "frame.src = '" + fail_url.spec() + "';"
347 "document.body.appendChild(frame);";
349 TestFailProvisionalLoadObserver fail_observer(wc);
350 content::WindowedNotificationObserver load_observer(
351 content::NOTIFICATION_LOAD_STOP,
352 content::Source<NavigationController>(&wc->GetController()));
353 wc->GetRenderViewHost()->ExecuteJavascriptInWebFrame(
354 base::string16(), base::ASCIIToUTF16(script));
355 load_observer.Wait();
357 // Ensure we saw the expected failure.
358 EXPECT_EQ(fail_url, fail_observer.fail_url());
360 // Failed initial navigation of an iframe shouldn't be adding any history
362 EXPECT_EQ(2, wc->GetController().GetEntryCount());
365 // Do the same test, but with an iframe that doesn't have initial URL
367 script = "var frame = document.createElement('iframe');"
368 "frame.id = 'target_frame';"
369 "document.body.appendChild(frame);";
371 content::WindowedNotificationObserver load_observer(
372 content::NOTIFICATION_LOAD_STOP,
373 content::Source<NavigationController>(&wc->GetController()));
374 wc->GetRenderViewHost()->ExecuteJavascriptInWebFrame(
375 base::string16(), base::ASCIIToUTF16(script));
376 load_observer.Wait();
379 script = "var f = document.getElementById('target_frame');"
380 "f.src = '" + fail_url.spec() + "';";
382 TestFailProvisionalLoadObserver fail_observer(wc);
383 content::WindowedNotificationObserver load_observer(
384 content::NOTIFICATION_LOAD_STOP,
385 content::Source<NavigationController>(&wc->GetController()));
386 wc->GetRenderViewHost()->ExecuteJavascriptInWebFrame(
387 base::string16(), base::ASCIIToUTF16(script));
388 load_observer.Wait();
390 EXPECT_EQ(fail_url, fail_observer.fail_url());
391 EXPECT_EQ(2, wc->GetController().GetEntryCount());
395 // Checks that the Link Doctor is not loaded when we receive an actual 404 page.
396 IN_PROC_BROWSER_TEST_F(ErrorPageTest, Page404) {
397 NavigateToURLAndWaitForTitle(
398 content::URLRequestMockHTTPJob::GetMockUrl(
399 base::FilePath(FILE_PATH_LITERAL("page404.html"))),
404 // Checks that when an error occurs, the stale cache status of the page
405 // is correctly transferred.
406 IN_PROC_BROWSER_TEST_F(ErrorPageTest, StaleCacheStatus) {
407 ASSERT_TRUE(test_server()->Start());
408 // Load cache with entry with "nocache" set, to create stale
410 GURL test_url(test_server()->GetURL("files/nocache.html"));
411 NavigateToURLAndWaitForTitle(test_url, "Nocache Test Page", 1);
413 // Reload same URL after forcing an error from the the network layer;
414 // confirm that the error page is told the cached copy exists.
415 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter =
416 browser()->profile()->GetRequestContext();
417 BrowserThread::PostTask(
418 BrowserThread::IO, FROM_HERE,
419 base::Bind(&InterceptNetworkTransactions, url_request_context_getter,
420 // Note that we can't use an error that'll invoke the link
421 // doctor. In normal network error conditions that would
422 // work (because the link doctor fetch would also fail,
423 // putting us back in the main offline path), but
424 // SetUrlRequestMocksEnabled() has also specfied a link
425 // doctor mock, which will be accessible because it
426 // won't go through the network cache.
429 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
430 // With no link doctor load, there's only one navigation.
431 browser(), test_url, 1);
432 EXPECT_TRUE(ProbeStaleCopyValue(true));
434 // Clear the cache and reload the same URL; confirm the error page is told
435 // that there is no cached copy.
436 BrowsingDataRemover* remover =
437 BrowsingDataRemover::CreateForUnboundedRange(browser()->profile());
438 remover->Remove(BrowsingDataRemover::REMOVE_CACHE,
439 BrowsingDataHelper::UNPROTECTED_WEB);
440 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
441 browser(), test_url, 1);
442 EXPECT_TRUE(ProbeStaleCopyValue(false));
445 // Returns Javascript code that executes plain text search for the page.
446 // Pass into content::ExecuteScriptAndExtractBool as |script| parameter.
447 std::string GetTextContentContainsStringScript(
448 const std::string& value_to_search) {
449 return base::StringPrintf(
450 "var textContent = document.body.textContent;"
451 "var hasError = textContent.indexOf('%s') >= 0;"
452 "domAutomationController.send(hasError);",
453 value_to_search.c_str());
456 // Protocol handler that fails all requests with net::ERR_ADDRESS_UNREACHABLE.
457 class AddressUnreachableProtocolHandler
458 : public net::URLRequestJobFactory::ProtocolHandler {
460 AddressUnreachableProtocolHandler() {}
461 virtual ~AddressUnreachableProtocolHandler() {}
463 // net::URLRequestJobFactory::ProtocolHandler:
464 virtual net::URLRequestJob* MaybeCreateJob(
465 net::URLRequest* request,
466 net::NetworkDelegate* network_delegate) const OVERRIDE {
467 return new URLRequestFailedJob(request,
469 net::ERR_ADDRESS_UNREACHABLE);
473 DISALLOW_COPY_AND_ASSIGN(AddressUnreachableProtocolHandler);
476 // A test fixture that returns ERR_ADDRESS_UNREACHABLE for all Link Doctor
477 // requests. ERR_NAME_NOT_RESOLVED is more typical, but need to use a different
478 // error for the Link Doctor and the original page to validate the right page
479 // is being displayed.
480 class ErrorPageLinkDoctorFailTest : public ErrorPageTest {
482 // InProcessBrowserTest:
483 virtual void SetUpOnMainThread() OVERRIDE {
484 BrowserThread::PostTask(
485 BrowserThread::IO, FROM_HERE,
486 base::Bind(&ErrorPageLinkDoctorFailTest::AddFilters));
489 virtual void CleanUpOnMainThread() OVERRIDE {
490 BrowserThread::PostTask(
491 BrowserThread::IO, FROM_HERE,
492 base::Bind(&ErrorPageLinkDoctorFailTest::RemoveFilters));
496 // Adds a filter that causes all requests for the Link Doctor's scheme and
497 // host to fail with ERR_ADDRESS_UNREACHABLE. Since the Link Doctor adds
498 // query strings, it's not enough to just fail exact matches.
500 // Also adds the content::URLRequestFailedJob filter.
501 static void AddFilters() {
502 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
503 content::URLRequestFailedJob::AddUrlHandler();
505 net::URLRequestFilter::GetInstance()->AddHostnameProtocolHandler(
506 google_util::LinkDoctorBaseURL().scheme(),
507 google_util::LinkDoctorBaseURL().host(),
508 scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>(
509 new AddressUnreachableProtocolHandler()));
512 static void RemoveFilters() {
513 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
514 net::URLRequestFilter::GetInstance()->ClearHandlers();
518 // Make sure that when the Link Doctor fails to load, the network error page is
519 // successfully loaded.
520 IN_PROC_BROWSER_TEST_F(ErrorPageLinkDoctorFailTest, LinkDoctorFail) {
521 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
523 URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED),
526 // Verify that the expected error page is being displayed. Do this by making
527 // sure the original error code (ERR_NAME_NOT_RESOLVED) is displayed.
529 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
530 browser()->tab_strip_model()->GetActiveWebContents(),
531 GetTextContentContainsStringScript("ERR_NAME_NOT_RESOLVED"),
536 // Checks that when an error occurs and a link doctor load fails, the stale
537 // cache status of the page is correctly transferred. Most logic copied
538 // from StaleCacheStatus above.
539 IN_PROC_BROWSER_TEST_F(ErrorPageLinkDoctorFailTest,
540 StaleCacheStatusFailedLinkDoctor) {
541 ASSERT_TRUE(test_server()->Start());
542 // Load cache with entry with "nocache" set, to create stale
544 GURL test_url(test_server()->GetURL("files/nocache.html"));
545 NavigateToURLAndWaitForTitle(test_url, "Nocache Test Page", 1);
547 // Reload same URL after forcing an error from the the network layer;
548 // confirm that the error page is told the cached copy exists.
549 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter =
550 browser()->profile()->GetRequestContext();
551 BrowserThread::PostTask(
552 BrowserThread::IO, FROM_HERE,
553 base::Bind(&InterceptNetworkTransactions, url_request_context_getter,
554 net::ERR_CONNECTION_FAILED));
556 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
557 browser(), test_url, 2);
558 ProbeStaleCopyValue(true);
560 // Clear the cache and reload the same URL; confirm the error page is told
561 // that there is no cached copy.
562 BrowsingDataRemover* remover =
563 BrowsingDataRemover::CreateForUnboundedRange(browser()->profile());
564 remover->Remove(BrowsingDataRemover::REMOVE_CACHE,
565 BrowsingDataHelper::UNPROTECTED_WEB);
566 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
567 browser(), test_url, 2);
568 ProbeStaleCopyValue(false);
571 // A test fixture that simulates failing requests for an IDN domain name.
572 class ErrorPageForIDNTest : public InProcessBrowserTest {
574 // Target hostname in different forms.
575 static const char kHostname[];
576 static const char kHostnameJSUnicode[];
578 // InProcessBrowserTest:
579 virtual void SetUpOnMainThread() OVERRIDE {
580 // Clear AcceptLanguages to force punycode decoding.
581 browser()->profile()->GetPrefs()->SetString(prefs::kAcceptLanguages,
583 BrowserThread::PostTask(
584 BrowserThread::IO, FROM_HERE,
585 base::Bind(&ErrorPageForIDNTest::AddFilters));
588 virtual void CleanUpOnMainThread() OVERRIDE {
589 BrowserThread::PostTask(
590 BrowserThread::IO, FROM_HERE,
591 base::Bind(&ErrorPageForIDNTest::RemoveFilters));
595 static void AddFilters() {
596 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
597 content::URLRequestFailedJob::AddUrlHandlerForHostname(kHostname);
600 static void RemoveFilters() {
601 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
602 net::URLRequestFilter::GetInstance()->ClearHandlers();
606 const char ErrorPageForIDNTest::kHostname[] =
607 "xn--d1abbgf6aiiy.xn--p1ai";
608 const char ErrorPageForIDNTest::kHostnameJSUnicode[] =
609 "\\u043f\\u0440\\u0435\\u0437\\u0438\\u0434\\u0435\\u043d\\u0442."
612 // Make sure error page shows correct unicode for IDN.
613 IN_PROC_BROWSER_TEST_F(ErrorPageForIDNTest, IDN) {
614 // ERR_UNSAFE_PORT will not trigger the link doctor.
615 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
617 URLRequestFailedJob::GetMockHttpUrlForHostname(net::ERR_UNSAFE_PORT,
622 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
623 browser()->tab_strip_model()->GetActiveWebContents(),
624 GetTextContentContainsStringScript(kHostnameJSUnicode),