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