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