Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / errorpage_browsertest.cc
blobe2afcbf59b7c601ef1b81187426d68a6d2e86b55
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.
5 #include "base/bind.h"
6 #include "base/prefs/pref_service.h"
7 #include "base/strings/stringprintf.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/browser/google/google_util.h"
10 #include "chrome/browser/net/url_request_mock_util.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/ui/browser.h"
13 #include "chrome/browser/ui/browser_commands.h"
14 #include "chrome/browser/ui/tabs/tab_strip_model.h"
15 #include "chrome/common/pref_names.h"
16 #include "chrome/test/base/in_process_browser_test.h"
17 #include "chrome/test/base/ui_test_utils.h"
18 #include "content/public/browser/notification_service.h"
19 #include "content/public/browser/render_view_host.h"
20 #include "content/public/browser/web_contents.h"
21 #include "content/public/browser/web_contents_observer.h"
22 #include "content/public/test/browser_test_utils.h"
23 #include "content/public/test/test_navigation_observer.h"
24 #include "content/test/net/url_request_failed_job.h"
25 #include "content/test/net/url_request_mock_http_job.h"
26 #include "net/base/net_errors.h"
27 #include "net/base/net_util.h"
28 #include "net/url_request/url_request_filter.h"
29 #include "net/url_request/url_request_job_factory.h"
31 using content::BrowserThread;
32 using content::NavigationController;
33 using content::URLRequestFailedJob;
35 namespace {
37 class ErrorPageTest : public InProcessBrowserTest {
38 public:
39 enum HistoryNavigationDirection {
40 HISTORY_NAVIGATE_BACK,
41 HISTORY_NAVIGATE_FORWARD,
44 // Navigates the active tab to a mock url created for the file at |file_path|.
45 void NavigateToFileURL(const base::FilePath::StringType& file_path) {
46 ui_test_utils::NavigateToURL(
47 browser(),
48 content::URLRequestMockHTTPJob::GetMockUrl(base::FilePath(file_path)));
51 // Navigates to the given URL and waits for |num_navigations| to occur, and
52 // the title to change to |expected_title|.
53 void NavigateToURLAndWaitForTitle(const GURL& url,
54 const std::string& expected_title,
55 int num_navigations) {
56 content::TitleWatcher title_watcher(
57 browser()->tab_strip_model()->GetActiveWebContents(),
58 base::ASCIIToUTF16(expected_title));
60 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
61 browser(), url, num_navigations);
63 EXPECT_EQ(base::ASCIIToUTF16(expected_title),
64 title_watcher.WaitAndGetTitle());
67 // Navigates back in the history and waits for |num_navigations| to occur, and
68 // the title to change to |expected_title|.
69 void GoBackAndWaitForTitle(const std::string& expected_title,
70 int num_navigations) {
71 NavigateHistoryAndWaitForTitle(expected_title,
72 num_navigations,
73 HISTORY_NAVIGATE_BACK);
76 // Navigates forward in the history and waits for |num_navigations| to occur,
77 // and the title to change to |expected_title|.
78 void GoForwardAndWaitForTitle(const std::string& expected_title,
79 int num_navigations) {
80 NavigateHistoryAndWaitForTitle(expected_title,
81 num_navigations,
82 HISTORY_NAVIGATE_FORWARD);
85 protected:
86 virtual void SetUpOnMainThread() OVERRIDE {
87 BrowserThread::PostTask(
88 BrowserThread::IO, FROM_HERE,
89 base::Bind(&chrome_browser_net::SetUrlRequestMocksEnabled, true));
92 // Returns a GURL that results in a DNS error.
93 GURL GetDnsErrorURL() const {
94 return URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED);
97 private:
98 // Navigates the browser the indicated direction in the history and waits for
99 // |num_navigations| to occur and the title to change to |expected_title|.
100 void NavigateHistoryAndWaitForTitle(const std::string& expected_title,
101 int num_navigations,
102 HistoryNavigationDirection direction) {
103 content::TitleWatcher title_watcher(
104 browser()->tab_strip_model()->GetActiveWebContents(),
105 base::ASCIIToUTF16(expected_title));
107 content::TestNavigationObserver test_navigation_observer(
108 browser()->tab_strip_model()->GetActiveWebContents(),
109 num_navigations);
110 if (direction == HISTORY_NAVIGATE_BACK) {
111 chrome::GoBack(browser(), CURRENT_TAB);
112 } else if (direction == HISTORY_NAVIGATE_FORWARD) {
113 chrome::GoForward(browser(), CURRENT_TAB);
114 } else {
115 FAIL();
117 test_navigation_observer.Wait();
119 EXPECT_EQ(title_watcher.WaitAndGetTitle(),
120 base::ASCIIToUTF16(expected_title));
125 class TestFailProvisionalLoadObserver : public content::WebContentsObserver {
126 public:
127 explicit TestFailProvisionalLoadObserver(content::WebContents* contents)
128 : content::WebContentsObserver(contents) {}
129 virtual ~TestFailProvisionalLoadObserver() {}
131 // This method is invoked when the provisional load failed.
132 virtual void DidFailProvisionalLoad(
133 int64 frame_id,
134 const base::string16& frame_unique_name,
135 bool is_main_frame,
136 const GURL& validated_url,
137 int error_code,
138 const base::string16& error_description,
139 content::RenderViewHost* render_view_host) OVERRIDE {
140 fail_url_ = validated_url;
143 const GURL& fail_url() const { return fail_url_; }
145 private:
146 GURL fail_url_;
148 DISALLOW_COPY_AND_ASSIGN(TestFailProvisionalLoadObserver);
151 // See crbug.com/109669
152 #if defined(USE_AURA) || defined(OS_WIN)
153 #define MAYBE_DNSError_Basic DISABLED_DNSError_Basic
154 #else
155 #define MAYBE_DNSError_Basic DNSError_Basic
156 #endif
157 // Test that a DNS error occuring in the main frame redirects to an error page.
158 IN_PROC_BROWSER_TEST_F(ErrorPageTest, MAYBE_DNSError_Basic) {
159 // The first navigation should fail, and the second one should be the error
160 // page.
161 NavigateToURLAndWaitForTitle(GetDnsErrorURL(), "Mock Link Doctor", 2);
164 // See crbug.com/109669
165 #if defined(USE_AURA)
166 #define MAYBE_DNSError_GoBack1 DISABLED_DNSError_GoBack1
167 #else
168 #define MAYBE_DNSError_GoBack1 DNSError_GoBack1
169 #endif
171 // Test that a DNS error occuring in the main frame does not result in an
172 // additional session history entry.
173 IN_PROC_BROWSER_TEST_F(ErrorPageTest, MAYBE_DNSError_GoBack1) {
174 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
175 NavigateToURLAndWaitForTitle(GetDnsErrorURL(), "Mock Link Doctor", 2);
176 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
179 // See crbug.com/109669
180 #if defined(USE_AURA)
181 #define MAYBE_DNSError_GoBack2 DISABLED_DNSError_GoBack2
182 #else
183 #define MAYBE_DNSError_GoBack2 DNSError_GoBack2
184 #endif
185 // Test that a DNS error occuring in the main frame does not result in an
186 // additional session history entry.
187 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack2) {
188 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
190 NavigateToURLAndWaitForTitle(GetDnsErrorURL(), "Mock Link Doctor", 2);
191 NavigateToFileURL(FILE_PATH_LITERAL("title3.html"));
193 GoBackAndWaitForTitle("Mock Link Doctor", 2);
194 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
197 // See crbug.com/109669
198 #if defined(USE_AURA)
199 #define MAYBE_DNSError_GoBack2AndForward DISABLED_DNSError_GoBack2AndForward
200 #else
201 #define MAYBE_DNSError_GoBack2AndForward DNSError_GoBack2AndForward
202 #endif
203 // Test that a DNS error occuring in the main frame does not result in an
204 // additional session history entry.
205 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack2AndForward) {
206 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
208 NavigateToURLAndWaitForTitle(GetDnsErrorURL(), "Mock Link Doctor", 2);
209 NavigateToFileURL(FILE_PATH_LITERAL("title3.html"));
211 GoBackAndWaitForTitle("Mock Link Doctor", 2);
212 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
214 GoForwardAndWaitForTitle("Mock Link Doctor", 2);
217 // See crbug.com/109669
218 #if defined(USE_AURA)
219 #define MAYBE_DNSError_GoBack2Forward2 DISABLED_DNSError_GoBack2Forward2
220 #else
221 #define MAYBE_DNSError_GoBack2Forward2 DNSError_GoBack2Forward2
222 #endif
223 // Test that a DNS error occuring in the main frame does not result in an
224 // additional session history entry.
225 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack2Forward2) {
226 NavigateToFileURL(FILE_PATH_LITERAL("title3.html"));
228 NavigateToURLAndWaitForTitle(GetDnsErrorURL(), "Mock Link Doctor", 2);
229 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
231 GoBackAndWaitForTitle("Mock Link Doctor", 2);
232 GoBackAndWaitForTitle("Title Of More Awesomeness", 1);
234 GoForwardAndWaitForTitle("Mock Link Doctor", 2);
235 GoForwardAndWaitForTitle("Title Of Awesomeness", 1);
238 // Test that a DNS error occuring in an iframe.
239 IN_PROC_BROWSER_TEST_F(ErrorPageTest, IFrameDNSError_Basic) {
240 NavigateToURLAndWaitForTitle(
241 content::URLRequestMockHTTPJob::GetMockUrl(
242 base::FilePath(FILE_PATH_LITERAL("iframe_dns_error.html"))),
243 "Blah",
245 // We expect to have two history entries, since we started off with navigation
246 // to "about:blank" and then navigated to "iframe_dns_error.html".
247 EXPECT_EQ(2,
248 browser()->tab_strip_model()->GetActiveWebContents()->
249 GetController().GetEntryCount());
252 // This test fails regularly on win_rel trybots. See crbug.com/121540
253 #if defined(OS_WIN)
254 #define MAYBE_IFrameDNSError_GoBack DISABLED_IFrameDNSError_GoBack
255 #else
256 #define MAYBE_IFrameDNSError_GoBack IFrameDNSError_GoBack
257 #endif
258 // Test that a DNS error occuring in an iframe does not result in an
259 // additional session history entry.
260 IN_PROC_BROWSER_TEST_F(ErrorPageTest, MAYBE_IFrameDNSError_GoBack) {
261 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
262 NavigateToFileURL(FILE_PATH_LITERAL("iframe_dns_error.html"));
263 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
266 // This test fails regularly on win_rel trybots. See crbug.com/121540
268 // This fails on linux_aura bringup: http://crbug.com/163931
269 #if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA))
270 #define MAYBE_IFrameDNSError_GoBackAndForward DISABLED_IFrameDNSError_GoBackAndForward
271 #else
272 #define MAYBE_IFrameDNSError_GoBackAndForward IFrameDNSError_GoBackAndForward
273 #endif
274 // Test that a DNS error occuring in an iframe does not result in an
275 // additional session history entry.
276 IN_PROC_BROWSER_TEST_F(ErrorPageTest, MAYBE_IFrameDNSError_GoBackAndForward) {
277 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
278 NavigateToFileURL(FILE_PATH_LITERAL("iframe_dns_error.html"));
279 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
280 GoForwardAndWaitForTitle("Blah", 1);
283 // Test that a DNS error occuring in an iframe, once the main document is
284 // completed loading, does not result in an additional session history entry.
285 // To ensure that the main document has completed loading, JavaScript is used to
286 // inject an iframe after loading is done.
287 IN_PROC_BROWSER_TEST_F(ErrorPageTest, IFrameDNSError_JavaScript) {
288 content::WebContents* wc =
289 browser()->tab_strip_model()->GetActiveWebContents();
290 GURL fail_url =
291 URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED);
293 // Load a regular web page, in which we will inject an iframe.
294 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
296 // We expect to have two history entries, since we started off with navigation
297 // to "about:blank" and then navigated to "title2.html".
298 EXPECT_EQ(2, wc->GetController().GetEntryCount());
300 std::string script = "var frame = document.createElement('iframe');"
301 "frame.src = '" + fail_url.spec() + "';"
302 "document.body.appendChild(frame);";
304 TestFailProvisionalLoadObserver fail_observer(wc);
305 content::WindowedNotificationObserver load_observer(
306 content::NOTIFICATION_LOAD_STOP,
307 content::Source<NavigationController>(&wc->GetController()));
308 wc->GetRenderViewHost()->ExecuteJavascriptInWebFrame(
309 base::string16(), base::ASCIIToUTF16(script));
310 load_observer.Wait();
312 // Ensure we saw the expected failure.
313 EXPECT_EQ(fail_url, fail_observer.fail_url());
315 // Failed initial navigation of an iframe shouldn't be adding any history
316 // entries.
317 EXPECT_EQ(2, wc->GetController().GetEntryCount());
320 // Do the same test, but with an iframe that doesn't have initial URL
321 // assigned.
322 script = "var frame = document.createElement('iframe');"
323 "frame.id = 'target_frame';"
324 "document.body.appendChild(frame);";
326 content::WindowedNotificationObserver load_observer(
327 content::NOTIFICATION_LOAD_STOP,
328 content::Source<NavigationController>(&wc->GetController()));
329 wc->GetRenderViewHost()->ExecuteJavascriptInWebFrame(
330 base::string16(), base::ASCIIToUTF16(script));
331 load_observer.Wait();
334 script = "var f = document.getElementById('target_frame');"
335 "f.src = '" + fail_url.spec() + "';";
337 TestFailProvisionalLoadObserver fail_observer(wc);
338 content::WindowedNotificationObserver load_observer(
339 content::NOTIFICATION_LOAD_STOP,
340 content::Source<NavigationController>(&wc->GetController()));
341 wc->GetRenderViewHost()->ExecuteJavascriptInWebFrame(
342 base::string16(), base::ASCIIToUTF16(script));
343 load_observer.Wait();
345 EXPECT_EQ(fail_url, fail_observer.fail_url());
346 EXPECT_EQ(2, wc->GetController().GetEntryCount());
350 // Checks that the Link Doctor is not loaded when we receive an actual 404 page.
351 IN_PROC_BROWSER_TEST_F(ErrorPageTest, Page404) {
352 NavigateToURLAndWaitForTitle(
353 content::URLRequestMockHTTPJob::GetMockUrl(
354 base::FilePath(FILE_PATH_LITERAL("page404.html"))),
355 "SUCCESS",
359 // Returns Javascript code that executes plain text search for the page.
360 // Pass into content::ExecuteScriptAndExtractBool as |script| parameter.
361 std::string GetTextContentContainsStringScript(
362 const std::string& value_to_search) {
363 return base::StringPrintf(
364 "var textContent = document.body.textContent;"
365 "var hasError = textContent.indexOf('%s') >= 0;"
366 "domAutomationController.send(hasError);",
367 value_to_search.c_str());
370 // Protocol handler that fails all requests with net::ERR_ADDRESS_UNREACHABLE.
371 class AddressUnreachableProtocolHandler
372 : public net::URLRequestJobFactory::ProtocolHandler {
373 public:
374 AddressUnreachableProtocolHandler() {}
375 virtual ~AddressUnreachableProtocolHandler() {}
377 // net::URLRequestJobFactory::ProtocolHandler:
378 virtual net::URLRequestJob* MaybeCreateJob(
379 net::URLRequest* request,
380 net::NetworkDelegate* network_delegate) const OVERRIDE {
381 return new URLRequestFailedJob(request,
382 network_delegate,
383 net::ERR_ADDRESS_UNREACHABLE);
386 private:
387 DISALLOW_COPY_AND_ASSIGN(AddressUnreachableProtocolHandler);
390 // A test fixture that returns ERR_ADDRESS_UNREACHABLE for all Link Doctor
391 // requests. ERR_NAME_NOT_RESOLVED is more typical, but need to use a different
392 // error for the Link Doctor and the original page to validate the right page
393 // is being displayed.
394 class ErrorPageLinkDoctorFailTest : public InProcessBrowserTest {
395 public:
396 // InProcessBrowserTest:
397 virtual void SetUpOnMainThread() OVERRIDE {
398 BrowserThread::PostTask(
399 BrowserThread::IO, FROM_HERE,
400 base::Bind(&ErrorPageLinkDoctorFailTest::AddFilters));
403 virtual void CleanUpOnMainThread() OVERRIDE {
404 BrowserThread::PostTask(
405 BrowserThread::IO, FROM_HERE,
406 base::Bind(&ErrorPageLinkDoctorFailTest::RemoveFilters));
409 private:
410 // Adds a filter that causes all requests for the Link Doctor's scheme and
411 // host to fail with ERR_ADDRESS_UNREACHABLE. Since the Link Doctor adds
412 // query strings, it's not enough to just fail exact matches.
414 // Also adds the content::URLRequestFailedJob filter.
415 static void AddFilters() {
416 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
417 content::URLRequestFailedJob::AddUrlHandler();
419 net::URLRequestFilter::GetInstance()->AddHostnameProtocolHandler(
420 google_util::LinkDoctorBaseURL().scheme(),
421 google_util::LinkDoctorBaseURL().host(),
422 scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>(
423 new AddressUnreachableProtocolHandler()));
426 static void RemoveFilters() {
427 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
428 net::URLRequestFilter::GetInstance()->ClearHandlers();
432 // Make sure that when the Link Doctor fails to load, the network error page is
433 // successfully loaded.
434 IN_PROC_BROWSER_TEST_F(ErrorPageLinkDoctorFailTest, LinkDoctorFail) {
435 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
436 browser(),
437 URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED),
440 // Verify that the expected error page is being displayed. Do this by making
441 // sure the original error code (ERR_NAME_NOT_RESOLVED) is displayed.
442 bool result = false;
443 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
444 browser()->tab_strip_model()->GetActiveWebContents(),
445 GetTextContentContainsStringScript("ERR_NAME_NOT_RESOLVED"),
446 &result));
447 EXPECT_TRUE(result);
450 // A test fixture that simulates failing requests for an IDN domain name.
451 class ErrorPageForIDNTest : public InProcessBrowserTest {
452 public:
453 // Target hostname in different forms.
454 static const char kHostname[];
455 static const char kHostnameJSUnicode[];
457 // InProcessBrowserTest:
458 virtual void SetUpOnMainThread() OVERRIDE {
459 // Clear AcceptLanguages to force punycode decoding.
460 browser()->profile()->GetPrefs()->SetString(prefs::kAcceptLanguages,
461 std::string());
462 BrowserThread::PostTask(
463 BrowserThread::IO, FROM_HERE,
464 base::Bind(&ErrorPageForIDNTest::AddFilters));
467 virtual void CleanUpOnMainThread() OVERRIDE {
468 BrowserThread::PostTask(
469 BrowserThread::IO, FROM_HERE,
470 base::Bind(&ErrorPageForIDNTest::RemoveFilters));
473 private:
474 static void AddFilters() {
475 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
476 content::URLRequestFailedJob::AddUrlHandlerForHostname(kHostname);
479 static void RemoveFilters() {
480 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
481 net::URLRequestFilter::GetInstance()->ClearHandlers();
485 const char ErrorPageForIDNTest::kHostname[] =
486 "xn--d1abbgf6aiiy.xn--p1ai";
487 const char ErrorPageForIDNTest::kHostnameJSUnicode[] =
488 "\\u043f\\u0440\\u0435\\u0437\\u0438\\u0434\\u0435\\u043d\\u0442."
489 "\\u0440\\u0444";
491 // Make sure error page shows correct unicode for IDN.
492 IN_PROC_BROWSER_TEST_F(ErrorPageForIDNTest, IDN) {
493 // ERR_UNSAFE_PORT will not trigger the link doctor.
494 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
495 browser(),
496 URLRequestFailedJob::GetMockHttpUrlForHostname(net::ERR_UNSAFE_PORT,
497 kHostname),
500 bool result = false;
501 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
502 browser()->tab_strip_model()->GetActiveWebContents(),
503 GetTextContentContainsStringScript(kHostnameJSUnicode),
504 &result));
505 EXPECT_TRUE(result);
508 } // namespace