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/strings/utf_string_conversions.h"
      7 #include "chrome/browser/google/google_util.h"
      8 #include "chrome/browser/net/url_request_mock_util.h"
      9 #include "chrome/browser/ui/browser.h"
     10 #include "chrome/browser/ui/browser_commands.h"
     11 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     12 #include "chrome/test/base/in_process_browser_test.h"
     13 #include "chrome/test/base/ui_test_utils.h"
     14 #include "content/public/browser/web_contents.h"
     15 #include "content/public/test/browser_test_utils.h"
     16 #include "content/public/test/test_navigation_observer.h"
     17 #include "content/test/net/url_request_failed_job.h"
     18 #include "content/test/net/url_request_mock_http_job.h"
     19 #include "net/base/net_errors.h"
     20 #include "net/url_request/url_request_filter.h"
     21 #include "net/url_request/url_request_job_factory.h"
     22 
     23 using content::BrowserThread;
     24 using content::NavigationController;
     25 using content::URLRequestFailedJob;
     26 
     27 namespace {
     28 
     29 class ErrorPageTest : public InProcessBrowserTest {
     30  public:
     31   enum HistoryNavigationDirection {
     32     HISTORY_NAVIGATE_BACK,
     33     HISTORY_NAVIGATE_FORWARD,
     34   };
     35 
     36   // Navigates the active tab to a mock url created for the file at |file_path|.
     37   void NavigateToFileURL(const base::FilePath::StringType& file_path) {
     38     ui_test_utils::NavigateToURL(
     39         browser(),
     40         content::URLRequestMockHTTPJob::GetMockUrl(base::FilePath(file_path)));
     41   }
     42 
     43   // Navigates to the given URL and waits for |num_navigations| to occur, and
     44   // the title to change to |expected_title|.
     45   void NavigateToURLAndWaitForTitle(const GURL& url,
     46                                     const std::string& expected_title,
     47                                     int num_navigations) {
     48     content::TitleWatcher title_watcher(
     49         browser()->tab_strip_model()->GetActiveWebContents(),
     50         ASCIIToUTF16(expected_title));
     51 
     52     ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
     53         browser(), url, num_navigations);
     54 
     55     EXPECT_EQ(ASCIIToUTF16(expected_title), title_watcher.WaitAndGetTitle());
     56   }
     57 
     58   // Navigates back in the history and waits for |num_navigations| to occur, and
     59   // the title to change to |expected_title|.
     60   void GoBackAndWaitForTitle(const std::string& expected_title,
     61                              int num_navigations) {
     62     NavigateHistoryAndWaitForTitle(expected_title,
     63                                    num_navigations,
     64                                    HISTORY_NAVIGATE_BACK);
     65   }
     66 
     67   // Navigates forward in the history and waits for |num_navigations| to occur,
     68   // and the title to change to |expected_title|.
     69   void GoForwardAndWaitForTitle(const std::string& expected_title,
     70                                 int num_navigations) {
     71     NavigateHistoryAndWaitForTitle(expected_title,
     72                                    num_navigations,
     73                                    HISTORY_NAVIGATE_FORWARD);
     74   }
     75 
     76  protected:
     77   virtual void SetUpOnMainThread() OVERRIDE {
     78     BrowserThread::PostTask(
     79         BrowserThread::IO, FROM_HERE,
     80         base::Bind(&chrome_browser_net::SetUrlRequestMocksEnabled, true));
     81   }
     82 
     83   // Returns a GURL that results in a DNS error.
     84   GURL GetDnsErrorURL() const {
     85     return URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED);
     86   }
     87 
     88  private:
     89   // Navigates the browser the indicated direction in the history and waits for
     90   // |num_navigations| to occur and the title to change to |expected_title|.
     91   void NavigateHistoryAndWaitForTitle(const std::string& expected_title,
     92                                       int num_navigations,
     93                                       HistoryNavigationDirection direction) {
     94     content::TitleWatcher title_watcher(
     95         browser()->tab_strip_model()->GetActiveWebContents(),
     96         ASCIIToUTF16(expected_title));
     97 
     98     content::TestNavigationObserver test_navigation_observer(
     99         browser()->tab_strip_model()->GetActiveWebContents(),
    100         num_navigations);
    101     if (direction == HISTORY_NAVIGATE_BACK) {
    102       chrome::GoBack(browser(), CURRENT_TAB);
    103     } else if (direction == HISTORY_NAVIGATE_FORWARD) {
    104       chrome::GoForward(browser(), CURRENT_TAB);
    105     } else {
    106       FAIL();
    107     }
    108     test_navigation_observer.WaitForObservation(
    109         base::Bind(&content::RunMessageLoop),
    110         base::Bind(&base::MessageLoop::Quit,
    111                    base::Unretained(base::MessageLoopForUI::current())));
    112 
    113     EXPECT_EQ(title_watcher.WaitAndGetTitle(), ASCIIToUTF16(expected_title));
    114   }
    115 };
    116 
    117 // See crbug.com/109669
    118 #if defined(USE_AURA) || defined(OS_WIN)
    119 #define MAYBE_DNSError_Basic DISABLED_DNSError_Basic
    120 #else
    121 #define MAYBE_DNSError_Basic DNSError_Basic
    122 #endif
    123 // Test that a DNS error occuring in the main frame redirects to an error page.
    124 IN_PROC_BROWSER_TEST_F(ErrorPageTest, MAYBE_DNSError_Basic) {
    125   // The first navigation should fail, and the second one should be the error
    126   // page.
    127   NavigateToURLAndWaitForTitle(GetDnsErrorURL(), "Mock Link Doctor", 2);
    128 }
    129 
    130 // See crbug.com/109669
    131 #if defined(USE_AURA)
    132 #define MAYBE_DNSError_GoBack1 DISABLED_DNSError_GoBack1
    133 #else
    134 #define MAYBE_DNSError_GoBack1 DNSError_GoBack1
    135 #endif
    136 
    137 // Test that a DNS error occuring in the main frame does not result in an
    138 // additional session history entry.
    139 IN_PROC_BROWSER_TEST_F(ErrorPageTest, MAYBE_DNSError_GoBack1) {
    140   NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
    141   NavigateToURLAndWaitForTitle(GetDnsErrorURL(), "Mock Link Doctor", 2);
    142   GoBackAndWaitForTitle("Title Of Awesomeness", 1);
    143 }
    144 
    145 // See crbug.com/109669
    146 #if defined(USE_AURA)
    147 #define MAYBE_DNSError_GoBack2 DISABLED_DNSError_GoBack2
    148 #else
    149 #define MAYBE_DNSError_GoBack2 DNSError_GoBack2
    150 #endif
    151 // Test that a DNS error occuring in the main frame does not result in an
    152 // additional session history entry.
    153 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack2) {
    154   NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
    155 
    156   NavigateToURLAndWaitForTitle(GetDnsErrorURL(), "Mock Link Doctor", 2);
    157   NavigateToFileURL(FILE_PATH_LITERAL("title3.html"));
    158 
    159   GoBackAndWaitForTitle("Mock Link Doctor", 2);
    160   GoBackAndWaitForTitle("Title Of Awesomeness", 1);
    161 }
    162 
    163 // See crbug.com/109669
    164 #if defined(USE_AURA)
    165 #define MAYBE_DNSError_GoBack2AndForward DISABLED_DNSError_GoBack2AndForward
    166 #else
    167 #define MAYBE_DNSError_GoBack2AndForward DNSError_GoBack2AndForward
    168 #endif
    169 // Test that a DNS error occuring in the main frame does not result in an
    170 // additional session history entry.
    171 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack2AndForward) {
    172   NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
    173 
    174   NavigateToURLAndWaitForTitle(GetDnsErrorURL(), "Mock Link Doctor", 2);
    175   NavigateToFileURL(FILE_PATH_LITERAL("title3.html"));
    176 
    177   GoBackAndWaitForTitle("Mock Link Doctor", 2);
    178   GoBackAndWaitForTitle("Title Of Awesomeness", 1);
    179 
    180   GoForwardAndWaitForTitle("Mock Link Doctor", 2);
    181 }
    182 
    183 // See crbug.com/109669
    184 #if defined(USE_AURA)
    185 #define MAYBE_DNSError_GoBack2Forward2 DISABLED_DNSError_GoBack2Forward2
    186 #else
    187 #define MAYBE_DNSError_GoBack2Forward2 DNSError_GoBack2Forward2
    188 #endif
    189 // Test that a DNS error occuring in the main frame does not result in an
    190 // additional session history entry.
    191 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack2Forward2) {
    192   NavigateToFileURL(FILE_PATH_LITERAL("title3.html"));
    193 
    194   NavigateToURLAndWaitForTitle(GetDnsErrorURL(), "Mock Link Doctor", 2);
    195   NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
    196 
    197   GoBackAndWaitForTitle("Mock Link Doctor", 2);
    198   GoBackAndWaitForTitle("Title Of More Awesomeness", 1);
    199 
    200   GoForwardAndWaitForTitle("Mock Link Doctor", 2);
    201   GoForwardAndWaitForTitle("Title Of Awesomeness", 1);
    202 }
    203 
    204 // Test that a DNS error occuring in an iframe.
    205 IN_PROC_BROWSER_TEST_F(ErrorPageTest, IFrameDNSError_Basic) {
    206   NavigateToURLAndWaitForTitle(
    207       content::URLRequestMockHTTPJob::GetMockUrl(
    208           base::FilePath(FILE_PATH_LITERAL("iframe_dns_error.html"))),
    209       "Blah",
    210       1);
    211 }
    212 
    213 // This test fails regularly on win_rel trybots. See crbug.com/121540
    214 #if defined(OS_WIN)
    215 #define MAYBE_IFrameDNSError_GoBack DISABLED_IFrameDNSError_GoBack
    216 #else
    217 #define MAYBE_IFrameDNSError_GoBack IFrameDNSError_GoBack
    218 #endif
    219 // Test that a DNS error occuring in an iframe does not result in an
    220 // additional session history entry.
    221 IN_PROC_BROWSER_TEST_F(ErrorPageTest, MAYBE_IFrameDNSError_GoBack) {
    222   NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
    223   NavigateToFileURL(FILE_PATH_LITERAL("iframe_dns_error.html"));
    224   GoBackAndWaitForTitle("Title Of Awesomeness", 1);
    225 }
    226 
    227 // This test fails regularly on win_rel trybots. See crbug.com/121540
    228 #if defined(OS_WIN)
    229 #define MAYBE_IFrameDNSError_GoBackAndForward DISABLED_IFrameDNSError_GoBackAndForward
    230 #else
    231 #define MAYBE_IFrameDNSError_GoBackAndForward IFrameDNSError_GoBackAndForward
    232 #endif
    233 // Test that a DNS error occuring in an iframe does not result in an
    234 // additional session history entry.
    235 IN_PROC_BROWSER_TEST_F(ErrorPageTest, MAYBE_IFrameDNSError_GoBackAndForward) {
    236   NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
    237   NavigateToFileURL(FILE_PATH_LITERAL("iframe_dns_error.html"));
    238   GoBackAndWaitForTitle("Title Of Awesomeness", 1);
    239   GoForwardAndWaitForTitle("Blah", 1);
    240 }
    241 
    242 // Checks that the Link Doctor is not loaded when we receive an actual 404 page.
    243 IN_PROC_BROWSER_TEST_F(ErrorPageTest, Page404) {
    244   NavigateToURLAndWaitForTitle(
    245       content::URLRequestMockHTTPJob::GetMockUrl(
    246           base::FilePath(FILE_PATH_LITERAL("page404.html"))),
    247       "SUCCESS",
    248       1);
    249 }
    250 
    251 // Protocol handler that fails all requests with net::ERR_ADDRESS_UNREACHABLE.
    252 class AddressUnreachableProtocolHandler
    253     : public net::URLRequestJobFactory::ProtocolHandler {
    254  public:
    255   AddressUnreachableProtocolHandler() {}
    256   virtual ~AddressUnreachableProtocolHandler() {}
    257 
    258   // net::URLRequestJobFactory::ProtocolHandler:
    259   virtual net::URLRequestJob* MaybeCreateJob(
    260       net::URLRequest* request,
    261       net::NetworkDelegate* network_delegate) const OVERRIDE {
    262     return new URLRequestFailedJob(request,
    263                                    network_delegate,
    264                                    net::ERR_ADDRESS_UNREACHABLE);
    265   }
    266 
    267  private:
    268   DISALLOW_COPY_AND_ASSIGN(AddressUnreachableProtocolHandler);
    269 };
    270 
    271 // A test fixture that returns ERR_ADDRESS_UNREACHABLE for all Link Doctor
    272 // requests.  ERR_NAME_NOT_RESOLVED is more typical, but need to use a different
    273 // error for the Link Doctor and the original page to validate the right page
    274 // is being displayed.
    275 class ErrorPageLinkDoctorFailTest : public InProcessBrowserTest {
    276  public:
    277   // InProcessBrowserTest:
    278   virtual void SetUpOnMainThread() OVERRIDE {
    279     BrowserThread::PostTask(
    280         BrowserThread::IO, FROM_HERE,
    281         base::Bind(&ErrorPageLinkDoctorFailTest::AddFilters));
    282   }
    283 
    284   virtual void CleanUpOnMainThread() OVERRIDE {
    285     BrowserThread::PostTask(
    286         BrowserThread::IO, FROM_HERE,
    287         base::Bind(&ErrorPageLinkDoctorFailTest::RemoveFilters));
    288   }
    289 
    290  private:
    291   // Adds a filter that causes all requests for the Link Doctor's scheme and
    292   // host to fail with ERR_ADDRESS_UNREACHABLE.  Since the Link Doctor adds
    293   // query strings, it's not enough to just fail exact matches.
    294   //
    295   // Also adds the content::URLRequestFailedJob filter.
    296   static void AddFilters() {
    297     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    298     content::URLRequestFailedJob::AddUrlHandler();
    299 
    300     net::URLRequestFilter::GetInstance()->AddHostnameProtocolHandler(
    301         google_util::LinkDoctorBaseURL().scheme(),
    302         google_util::LinkDoctorBaseURL().host(),
    303         scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>(
    304             new AddressUnreachableProtocolHandler()));
    305   }
    306 
    307   static void RemoveFilters() {
    308     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    309     net::URLRequestFilter::GetInstance()->ClearHandlers();
    310   }
    311 };
    312 
    313 // Make sure that when the Link Doctor fails to load, the network error page is
    314 // successfully loaded.
    315 IN_PROC_BROWSER_TEST_F(ErrorPageLinkDoctorFailTest, LinkDoctorFail) {
    316   ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
    317       browser(),
    318       URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED),
    319       2);
    320 
    321   // Verify that the expected error page is being displayed.  Do this by making
    322   // sure the original error code (ERR_NAME_NOT_RESOLVED) is displayed.
    323   bool result = false;
    324   EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
    325       browser()->tab_strip_model()->GetActiveWebContents(),
    326       "var textContent = document.body.textContent;"
    327       "var hasError = textContent.indexOf('ERR_NAME_NOT_RESOLVED') >= 0;"
    328       "domAutomationController.send(hasError);",
    329       &result));
    330   EXPECT_TRUE(result);
    331 }
    332 
    333 }  // namespace
    334