Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / errorpage_browsertest.cc
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   ~FailFirstNRequestsInterceptor() override {}
158
159   // net::URLRequestInterceptor implementation
160   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   ~LinkDoctorInterceptor() override {}
204
205   // net::URLRequestInterceptor implementation
206   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   ~ErrorPageTest() override {}
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   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         "        loadTimeData.valueExists('staleLoadButton') ? '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   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   ~TestFailProvisionalLoadObserver() override {}
468
469   // This method is invoked when the provisional load failed.
470   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   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   ~AddressUnreachableInterceptor() override {}
940
941   // net::URLRequestInterceptor:
942   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   void SetUpOnMainThread() override {
962     BrowserThread::PostTask(
963         BrowserThread::IO, FROM_HERE,
964         base::Bind(&ErrorPageNavigationCorrectionsFailTest::AddFilters));
965   }
966
967   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   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   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