errorpage_browsertest.cc revision b2df76ea8fec9e32f6f3718986dba0d95315b29c
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/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 23using content::BrowserThread; 24using content::NavigationController; 25using content::URLRequestFailedJob; 26 27namespace { 28 29class 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 content::Source<NavigationController>( 100 &browser()->tab_strip_model()->GetActiveWebContents()-> 101 GetController()), 102 num_navigations); 103 if (direction == HISTORY_NAVIGATE_BACK) { 104 chrome::GoBack(browser(), CURRENT_TAB); 105 } else if (direction == HISTORY_NAVIGATE_FORWARD) { 106 chrome::GoForward(browser(), CURRENT_TAB); 107 } else { 108 FAIL(); 109 } 110 test_navigation_observer.WaitForObservation( 111 base::Bind(&content::RunMessageLoop), 112 base::Bind(&MessageLoop::Quit, 113 base::Unretained(MessageLoopForUI::current()))); 114 115 EXPECT_EQ(title_watcher.WaitAndGetTitle(), ASCIIToUTF16(expected_title)); 116 } 117}; 118 119// See crbug.com/109669 120#if defined(USE_AURA) || defined(OS_WIN) || defined(OS_MACOSX) 121#define MAYBE_DNSError_Basic DISABLED_DNSError_Basic 122#else 123#define MAYBE_DNSError_Basic DNSError_Basic 124#endif 125// Test that a DNS error occuring in the main frame redirects to an error page. 126IN_PROC_BROWSER_TEST_F(ErrorPageTest, MAYBE_DNSError_Basic) { 127 // The first navigation should fail, and the second one should be the error 128 // page. 129 NavigateToURLAndWaitForTitle(GetDnsErrorURL(), "Mock Link Doctor", 2); 130} 131 132// See crbug.com/109669 133#if defined(USE_AURA) || defined(OS_WIN) || defined(OS_MACOSX) 134#define MAYBE_DNSError_GoBack1 DISABLED_DNSError_GoBack1 135#else 136#define MAYBE_DNSError_GoBack1 DNSError_GoBack1 137#endif 138 139// Test that a DNS error occuring in the main frame does not result in an 140// additional session history entry. 141IN_PROC_BROWSER_TEST_F(ErrorPageTest, MAYBE_DNSError_GoBack1) { 142 NavigateToFileURL(FILE_PATH_LITERAL("title2.html")); 143 NavigateToURLAndWaitForTitle(GetDnsErrorURL(), "Mock Link Doctor", 2); 144 GoBackAndWaitForTitle("Title Of Awesomeness", 1); 145} 146 147// See crbug.com/109669 148#if defined(USE_AURA) || defined(OS_WIN) || defined(OS_MACOSX) 149#define MAYBE_DNSError_GoBack2 DISABLED_DNSError_GoBack2 150#else 151#define MAYBE_DNSError_GoBack2 DNSError_GoBack2 152#endif 153// Test that a DNS error occuring in the main frame does not result in an 154// additional session history entry. 155IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack2) { 156 NavigateToFileURL(FILE_PATH_LITERAL("title2.html")); 157 158 NavigateToURLAndWaitForTitle(GetDnsErrorURL(), "Mock Link Doctor", 2); 159 NavigateToFileURL(FILE_PATH_LITERAL("title3.html")); 160 161 GoBackAndWaitForTitle("Mock Link Doctor", 2); 162 GoBackAndWaitForTitle("Title Of Awesomeness", 1); 163} 164 165// See crbug.com/109669 166#if defined(USE_AURA) || defined(OS_WIN) || defined(OS_MACOSX) 167#define MAYBE_DNSError_GoBack2AndForward DISABLED_DNSError_GoBack2AndForward 168#else 169#define MAYBE_DNSError_GoBack2AndForward DNSError_GoBack2AndForward 170#endif 171// Test that a DNS error occuring in the main frame does not result in an 172// additional session history entry. 173IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack2AndForward) { 174 NavigateToFileURL(FILE_PATH_LITERAL("title2.html")); 175 176 NavigateToURLAndWaitForTitle(GetDnsErrorURL(), "Mock Link Doctor", 2); 177 NavigateToFileURL(FILE_PATH_LITERAL("title3.html")); 178 179 GoBackAndWaitForTitle("Mock Link Doctor", 2); 180 GoBackAndWaitForTitle("Title Of Awesomeness", 1); 181 182 GoForwardAndWaitForTitle("Mock Link Doctor", 2); 183} 184 185// See crbug.com/109669 186#if defined(USE_AURA) || defined(OS_WIN) || defined(OS_MACOSX) 187#define MAYBE_DNSError_GoBack2Forward2 DISABLED_DNSError_GoBack2Forward2 188#else 189#define MAYBE_DNSError_GoBack2Forward2 DNSError_GoBack2Forward2 190#endif 191// Test that a DNS error occuring in the main frame does not result in an 192// additional session history entry. 193IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack2Forward2) { 194 NavigateToFileURL(FILE_PATH_LITERAL("title3.html")); 195 196 NavigateToURLAndWaitForTitle(GetDnsErrorURL(), "Mock Link Doctor", 2); 197 NavigateToFileURL(FILE_PATH_LITERAL("title2.html")); 198 199 GoBackAndWaitForTitle("Mock Link Doctor", 2); 200 GoBackAndWaitForTitle("Title Of More Awesomeness", 1); 201 202 GoForwardAndWaitForTitle("Mock Link Doctor", 2); 203 GoForwardAndWaitForTitle("Title Of Awesomeness", 1); 204} 205 206// Test that a DNS error occuring in an iframe. 207IN_PROC_BROWSER_TEST_F(ErrorPageTest, IFrameDNSError_Basic) { 208 NavigateToURLAndWaitForTitle( 209 content::URLRequestMockHTTPJob::GetMockUrl( 210 base::FilePath(FILE_PATH_LITERAL("iframe_dns_error.html"))), 211 "Blah", 212 1); 213} 214 215// This test fails regularly on win_rel trybots. See crbug.com/121540 216#if defined(OS_WIN) 217#define MAYBE_IFrameDNSError_GoBack DISABLED_IFrameDNSError_GoBack 218#else 219#define MAYBE_IFrameDNSError_GoBack IFrameDNSError_GoBack 220#endif 221// Test that a DNS error occuring in an iframe does not result in an 222// additional session history entry. 223IN_PROC_BROWSER_TEST_F(ErrorPageTest, MAYBE_IFrameDNSError_GoBack) { 224 NavigateToFileURL(FILE_PATH_LITERAL("title2.html")); 225 NavigateToFileURL(FILE_PATH_LITERAL("iframe_dns_error.html")); 226 GoBackAndWaitForTitle("Title Of Awesomeness", 1); 227} 228 229// This test fails regularly on win_rel trybots. See crbug.com/121540 230#if defined(OS_WIN) 231#define MAYBE_IFrameDNSError_GoBackAndForward DISABLED_IFrameDNSError_GoBackAndForward 232#else 233#define MAYBE_IFrameDNSError_GoBackAndForward IFrameDNSError_GoBackAndForward 234#endif 235// Test that a DNS error occuring in an iframe does not result in an 236// additional session history entry. 237IN_PROC_BROWSER_TEST_F(ErrorPageTest, MAYBE_IFrameDNSError_GoBackAndForward) { 238 NavigateToFileURL(FILE_PATH_LITERAL("title2.html")); 239 NavigateToFileURL(FILE_PATH_LITERAL("iframe_dns_error.html")); 240 GoBackAndWaitForTitle("Title Of Awesomeness", 1); 241 GoForwardAndWaitForTitle("Blah", 1); 242} 243 244// Checks that the Link Doctor is not loaded when we receive an actual 404 page. 245IN_PROC_BROWSER_TEST_F(ErrorPageTest, Page404) { 246 NavigateToURLAndWaitForTitle( 247 content::URLRequestMockHTTPJob::GetMockUrl( 248 base::FilePath(FILE_PATH_LITERAL("page404.html"))), 249 "SUCCESS", 250 1); 251} 252 253// Protocol handler that fails all requests with net::ERR_ADDRESS_UNREACHABLE. 254class AddressUnreachableProtocolHandler 255 : public net::URLRequestJobFactory::ProtocolHandler { 256 public: 257 AddressUnreachableProtocolHandler() {} 258 virtual ~AddressUnreachableProtocolHandler() {} 259 260 // net::URLRequestJobFactory::ProtocolHandler: 261 virtual net::URLRequestJob* MaybeCreateJob( 262 net::URLRequest* request, 263 net::NetworkDelegate* network_delegate) const OVERRIDE { 264 return new URLRequestFailedJob(request, 265 network_delegate, 266 net::ERR_ADDRESS_UNREACHABLE); 267 } 268 269 private: 270 DISALLOW_COPY_AND_ASSIGN(AddressUnreachableProtocolHandler); 271}; 272 273// A test fixture that returns ERR_ADDRESS_UNREACHABLE for all Link Doctor 274// requests. ERR_NAME_NOT_RESOLVED is more typical, but need to use a different 275// error for the Link Doctor and the original page to validate the right page 276// is being displayed. 277class ErrorPageLinkDoctorFailTest : public InProcessBrowserTest { 278 public: 279 // InProcessBrowserTest: 280 virtual void SetUpOnMainThread() OVERRIDE { 281 BrowserThread::PostTask( 282 BrowserThread::IO, FROM_HERE, 283 base::Bind(&ErrorPageLinkDoctorFailTest::AddFilters)); 284 } 285 286 virtual void CleanUpOnMainThread() OVERRIDE { 287 BrowserThread::PostTask( 288 BrowserThread::IO, FROM_HERE, 289 base::Bind(&ErrorPageLinkDoctorFailTest::RemoveFilters)); 290 } 291 292 private: 293 // Adds a filter that causes all requests for the Link Doctor's scheme and 294 // host to fail with ERR_ADDRESS_UNREACHABLE. Since the Link Doctor adds 295 // query strings, it's not enough to just fail exact matches. 296 // 297 // Also adds the content::URLRequestFailedJob filter. 298 static void AddFilters() { 299 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 300 content::URLRequestFailedJob::AddUrlHandler(); 301 302 net::URLRequestFilter::GetInstance()->AddHostnameProtocolHandler( 303 google_util::LinkDoctorBaseURL().scheme(), 304 google_util::LinkDoctorBaseURL().host(), 305 scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>( 306 new AddressUnreachableProtocolHandler())); 307 } 308 309 static void RemoveFilters() { 310 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 311 net::URLRequestFilter::GetInstance()->ClearHandlers(); 312 } 313}; 314 315// Make sure that when the Link Doctor fails to load, the network error page is 316// successfully loaded. 317IN_PROC_BROWSER_TEST_F(ErrorPageLinkDoctorFailTest, LinkDoctorFail) { 318 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( 319 browser(), 320 URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED), 321 2); 322 323 // Verify that the expected error page is being displayed. Do this by making 324 // sure the original error code (ERR_NAME_NOT_RESOLVED) is displayed. 325 bool result = false; 326 EXPECT_TRUE(content::ExecuteScriptAndExtractBool( 327 browser()->tab_strip_model()->GetActiveWebContents(), 328 "var textContent = document.body.textContent;" 329 "var hasError = textContent.indexOf('ERR_NAME_NOT_RESOLVED') >= 0;" 330 "domAutomationController.send(hasError);", 331 &result)); 332 EXPECT_TRUE(result); 333} 334 335} // namespace 336