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.
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/path_service.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "chrome/browser/browsing_data/browsing_data_helper.h"
15 #include "chrome/browser/browsing_data/browsing_data_remover.h"
16 #include "chrome/browser/google/google_util.h"
17 #include "chrome/browser/net/url_request_mock_util.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/ui/browser.h"
20 #include "chrome/browser/ui/browser_commands.h"
21 #include "chrome/browser/ui/tabs/tab_strip_model.h"
22 #include "chrome/common/chrome_paths.h"
23 #include "chrome/common/chrome_switches.h"
24 #include "chrome/common/pref_names.h"
25 #include "chrome/test/base/in_process_browser_test.h"
26 #include "chrome/test/base/ui_test_utils.h"
27 #include "content/public/browser/browser_thread.h"
28 #include "content/public/browser/notification_service.h"
29 #include "content/public/browser/render_frame_host.h"
30 #include "content/public/browser/render_view_host.h"
31 #include "content/public/browser/web_contents.h"
32 #include "content/public/browser/web_contents_observer.h"
33 #include "content/public/test/browser_test_utils.h"
34 #include "content/public/test/test_navigation_observer.h"
35 #include "content/test/net/url_request_failed_job.h"
36 #include "content/test/net/url_request_mock_http_job.h"
37 #include "grit/generated_resources.h"
38 #include "net/base/net_errors.h"
39 #include "net/base/net_util.h"
40 #include "net/http/failing_http_transaction_factory.h"
41 #include "net/http/http_cache.h"
42 #include "net/test/spawned_test_server/spawned_test_server.h"
43 #include "net/url_request/url_request_context.h"
44 #include "net/url_request/url_request_context_getter.h"
45 #include "net/url_request/url_request_filter.h"
46 #include "net/url_request/url_request_job.h"
47 #include "net/url_request/url_request_job_factory.h"
48 #include "net/url_request/url_request_test_job.h"
49 #include "net/url_request/url_request_test_util.h"
50 #include "ui/base/l10n/l10n_util.h"
52 using content::BrowserThread
;
53 using content::NavigationController
;
54 using content::URLRequestFailedJob
;
55 using net::URLRequestJobFactory
;
56 using net::URLRequestTestJob
;
60 // Returns true if |text| is displayed on the page |browser| is currently
61 // displaying. Uses "innerText", so will miss hidden text, and whitespace
62 // space handling may be weird.
63 bool WARN_UNUSED_RESULT
IsDisplayingText(Browser
* browser
,
64 const std::string
& text
) {
65 std::string command
= base::StringPrintf(
66 "var textContent = document.body.innerText;"
67 "var hasText = textContent.indexOf('%s') >= 0;"
68 "domAutomationController.send(hasText);",
71 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
72 browser
->tab_strip_model()->GetActiveWebContents(), command
, &result
));
76 // Expands the more box on the currently displayed error page.
77 void ToggleHelpBox(Browser
* browser
) {
78 EXPECT_TRUE(content::ExecuteScript(
79 browser
->tab_strip_model()->GetActiveWebContents(),
80 "document.getElementById('more-less-button').click();"));
83 // Returns true if |browser| is displaying the text representation of
84 // |error_code| on the current page.
85 bool WARN_UNUSED_RESULT
IsDisplayingNetError(Browser
* browser
,
86 net::Error error_code
) {
87 // Get the error as a string, and remove the leading "net::", which is not
88 // included on error pages.
89 std::string error_string
= net::ErrorToString(error_code
);
90 base::RemoveChars(error_string
, "net:", &error_string
);
92 return IsDisplayingText(browser
, error_string
);
95 // Checks that the local error page is being displayed, without remotely
96 // retrieved navigation corrections, and with the specified error code.
97 void ExpectDisplayingLocalErrorPage(Browser
* browser
, net::Error error_code
) {
98 // Expand the help box so innerText will include text below the fold.
99 ToggleHelpBox(browser
);
101 EXPECT_TRUE(IsDisplayingNetError(browser
, error_code
));
103 // Locally generated error pages should not have navigation corrections.
104 EXPECT_FALSE(IsDisplayingText(browser
, "http://correction1/"));
105 EXPECT_FALSE(IsDisplayingText(browser
, "http://correction2/"));
107 // Locally generated error pages should not have a populated search box.
108 bool search_box_populated
= false;
109 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
110 browser
->tab_strip_model()->GetActiveWebContents(),
111 "var searchText = document.getElementById('search-box').value;"
112 "domAutomationController.send(searchText == 'search query');",
113 &search_box_populated
));
114 EXPECT_FALSE(search_box_populated
);
117 // Checks that an error page with information retrieved from the navigation
118 // correction service is being displayed, with the specified specified error
120 void ExpectDisplayingNavigationCorrections(Browser
* browser
,
121 net::Error error_code
) {
122 // Expand the help box so innerText will include text below the fold.
123 ToggleHelpBox(browser
);
125 EXPECT_TRUE(IsDisplayingNetError(browser
, error_code
));
127 // Check that the mock navigation corrections are displayed.
128 EXPECT_TRUE(IsDisplayingText(browser
, "http://correction1/"));
129 EXPECT_TRUE(IsDisplayingText(browser
, "http://correction2/"));
131 // Check that the search box is populated correctly.
132 bool search_box_populated
= false;
133 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
134 browser
->tab_strip_model()->GetActiveWebContents(),
135 "var searchText = document.getElementById('search-box').value;"
136 "domAutomationController.send(searchText == 'search query');",
137 &search_box_populated
));
138 EXPECT_TRUE(search_box_populated
);
141 std::string
GetLoadStaleButtonLabel() {
142 return l10n_util::GetStringUTF8(IDS_ERRORPAGES_BUTTON_LOAD_STALE
);
145 // A protocol handler that fails a configurable number of requests, then
146 // succeeds all requests after that, keeping count of failures and successes.
147 class FailFirstNRequestsProtocolHandler
148 : public URLRequestJobFactory::ProtocolHandler
{
150 FailFirstNRequestsProtocolHandler(const GURL
& url
, int requests_to_fail
)
151 : url_(url
), requests_(0), failures_(0),
152 requests_to_fail_(requests_to_fail
) {}
153 virtual ~FailFirstNRequestsProtocolHandler() {}
155 // This method deliberately violates pointer ownership rules:
156 // AddUrlProtocolHandler() takes a scoped_ptr, taking ownership of the
157 // supplied ProtocolHandler (i.e., |this|), but also having the caller retain
158 // a pointer to |this| so the caller can use the requests() and failures()
160 void AddUrlHandler() {
161 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
162 scoped_ptr
<URLRequestJobFactory::ProtocolHandler
> scoped_handler(this);
163 net::URLRequestFilter::GetInstance()->AddUrlProtocolHandler(
165 scoped_handler
.Pass());
168 // net::URLRequestJobFactory::ProtocolHandler implementation
169 virtual net::URLRequestJob
* MaybeCreateJob(
170 net::URLRequest
* request
,
171 net::NetworkDelegate
* network_delegate
) const OVERRIDE
{
172 DCHECK_EQ(url_
, request
->url());
174 if (failures_
< requests_to_fail_
) {
176 // Note: net::ERR_CONNECTION_RESET does not summon the Link Doctor; see
177 // NetErrorHelperCore::GetErrorPageURL.
178 return new URLRequestFailedJob(request
,
180 net::ERR_CONNECTION_RESET
);
182 return new URLRequestTestJob(request
, network_delegate
,
183 URLRequestTestJob::test_headers(),
184 URLRequestTestJob::test_data_1(),
189 int requests() const { return requests_
; }
190 int failures() const { return failures_
; }
194 // These are mutable because MaybeCreateJob is const but we want this state
196 mutable int requests_
;
197 mutable int failures_
;
198 int requests_to_fail_
;
201 class ErrorPageTest
: public InProcessBrowserTest
{
203 enum HistoryNavigationDirection
{
204 HISTORY_NAVIGATE_BACK
,
205 HISTORY_NAVIGATE_FORWARD
,
208 // Navigates the active tab to a mock url created for the file at |file_path|.
209 void NavigateToFileURL(const base::FilePath::StringType
& file_path
) {
210 ui_test_utils::NavigateToURL(
212 content::URLRequestMockHTTPJob::GetMockUrl(base::FilePath(file_path
)));
215 // Navigates to the given URL and waits for |num_navigations| to occur, and
216 // the title to change to |expected_title|.
217 void NavigateToURLAndWaitForTitle(const GURL
& url
,
218 const std::string
& expected_title
,
219 int num_navigations
) {
220 content::TitleWatcher
title_watcher(
221 browser()->tab_strip_model()->GetActiveWebContents(),
222 base::ASCIIToUTF16(expected_title
));
224 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
225 browser(), url
, num_navigations
);
227 EXPECT_EQ(base::ASCIIToUTF16(expected_title
),
228 title_watcher
.WaitAndGetTitle());
231 // Navigates back in the history and waits for |num_navigations| to occur, and
232 // the title to change to |expected_title|.
233 void GoBackAndWaitForTitle(const std::string
& expected_title
,
234 int num_navigations
) {
235 NavigateHistoryAndWaitForTitle(expected_title
,
237 HISTORY_NAVIGATE_BACK
);
240 // Navigates forward in the history and waits for |num_navigations| to occur,
241 // and the title to change to |expected_title|.
242 void GoForwardAndWaitForTitle(const std::string
& expected_title
,
243 int num_navigations
) {
244 NavigateHistoryAndWaitForTitle(expected_title
,
246 HISTORY_NAVIGATE_FORWARD
);
249 void GoBackAndWaitForNavigations(int num_navigations
) {
250 NavigateHistory(num_navigations
, HISTORY_NAVIGATE_BACK
);
253 void GoForwardAndWaitForNavigations(int num_navigations
) {
254 NavigateHistory(num_navigations
, HISTORY_NAVIGATE_FORWARD
);
257 // Confirms that the javascript variable indicating whether or not we have
258 // a stale copy in the cache has been set to |expected|, and that the
259 // stale load button is or isn't there based on the same expectation.
260 testing::AssertionResult
ProbeStaleCopyValue(bool expected
) {
261 const char* js_cache_probe
=
263 " domAutomationController.send(\n"
264 " 'staleLoadButton' in templateData ? 'yes' : 'no');\n"
266 " domAutomationController.send(e.message);\n"
271 content::ExecuteScriptAndExtractString(
272 browser()->tab_strip_model()->GetActiveWebContents(),
276 return testing::AssertionFailure()
277 << "Failing return from ExecuteScriptAndExtractString.";
280 if ((expected
&& "yes" == result
) || (!expected
&& "no" == result
))
281 return testing::AssertionSuccess();
283 return testing::AssertionFailure() << "Cache probe result is " << result
;
286 testing::AssertionResult
ReloadStaleCopyFromCache() {
287 const char* js_reload_script
=
289 " document.getElementById('stale-load-button').click();\n"
290 " domAutomationController.send('success');\n"
292 " domAutomationController.send(e.message);\n"
296 bool ret
= content::ExecuteScriptAndExtractString(
297 browser()->tab_strip_model()->GetActiveWebContents(),
302 return testing::AssertionFailure();
303 return ("success" == result
? testing::AssertionSuccess() :
304 (testing::AssertionFailure() << "Exception message is " << result
));
308 static void EnableMocks(const GURL
& search_url
) {
309 chrome_browser_net::SetUrlRequestMocksEnabled(true);
311 // Add a mock for the search engine the error page will use.
312 base::FilePath root_http
;
313 PathService::Get(chrome::DIR_TEST_DATA
, &root_http
);
314 content::URLRequestMockHTTPJob::AddHostnameToFileHandler(
315 search_url
.host(), root_http
.AppendASCII("title3.html"));
318 virtual void SetUpOnMainThread() OVERRIDE
{
319 BrowserThread::PostTask(
320 BrowserThread::IO
, FROM_HERE
,
321 base::Bind(&ErrorPageTest::EnableMocks
,
322 google_util::GetGoogleSearchURL(browser()->profile())));
325 // Returns a GURL that results in a DNS error.
326 GURL
GetDnsErrorURL() const {
327 return URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED
);
331 // Navigates the browser the indicated direction in the history and waits for
332 // |num_navigations| to occur and the title to change to |expected_title|.
333 void NavigateHistoryAndWaitForTitle(const std::string
& expected_title
,
335 HistoryNavigationDirection direction
) {
336 content::TitleWatcher
title_watcher(
337 browser()->tab_strip_model()->GetActiveWebContents(),
338 base::ASCIIToUTF16(expected_title
));
340 NavigateHistory(num_navigations
, direction
);
342 EXPECT_EQ(title_watcher
.WaitAndGetTitle(),
343 base::ASCIIToUTF16(expected_title
));
346 void NavigateHistory(int num_navigations
,
347 HistoryNavigationDirection direction
) {
348 content::TestNavigationObserver
test_navigation_observer(
349 browser()->tab_strip_model()->GetActiveWebContents(),
351 if (direction
== HISTORY_NAVIGATE_BACK
) {
352 chrome::GoBack(browser(), CURRENT_TAB
);
353 } else if (direction
== HISTORY_NAVIGATE_FORWARD
) {
354 chrome::GoForward(browser(), CURRENT_TAB
);
358 test_navigation_observer
.Wait();
362 class TestFailProvisionalLoadObserver
: public content::WebContentsObserver
{
364 explicit TestFailProvisionalLoadObserver(content::WebContents
* contents
)
365 : content::WebContentsObserver(contents
) {}
366 virtual ~TestFailProvisionalLoadObserver() {}
368 // This method is invoked when the provisional load failed.
369 virtual void DidFailProvisionalLoad(
371 const base::string16
& frame_unique_name
,
373 const GURL
& validated_url
,
375 const base::string16
& error_description
,
376 content::RenderViewHost
* render_view_host
) OVERRIDE
{
377 fail_url_
= validated_url
;
380 const GURL
& fail_url() const { return fail_url_
; }
385 DISALLOW_COPY_AND_ASSIGN(TestFailProvisionalLoadObserver
);
388 void InterceptNetworkTransactions(net::URLRequestContextGetter
* getter
,
390 DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::IO
));
391 net::HttpCache
* cache(
392 getter
->GetURLRequestContext()->http_transaction_factory()->GetCache());
394 scoped_ptr
<net::HttpTransactionFactory
> factory(
395 new net::FailingHttpTransactionFactory(cache
->GetSession(), error
));
396 // Throw away old version; since this is a a browser test, we don't
397 // need to restore the old state.
398 cache
->SetHttpNetworkTransactionFactoryForTesting(factory
.Pass());
401 // See crbug.com/109669
402 #if defined(USE_AURA)
403 #define MAYBE_DNSError_Basic DISABLED_DNSError_Basic
405 #define MAYBE_DNSError_Basic DNSError_Basic
407 // Test that a DNS error occuring in the main frame redirects to an error page.
408 IN_PROC_BROWSER_TEST_F(ErrorPageTest
, MAYBE_DNSError_Basic
) {
409 // The first navigation should fail, and the second one should be the error
411 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
412 browser(), GetDnsErrorURL(), 2);
413 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED
);
416 // See crbug.com/109669
417 #if defined(USE_AURA)
418 #define MAYBE_DNSError_GoBack1 DISABLED_DNSError_GoBack1
420 #define MAYBE_DNSError_GoBack1 DNSError_GoBack1
423 // Test that a DNS error occuring in the main frame does not result in an
424 // additional session history entry.
425 IN_PROC_BROWSER_TEST_F(ErrorPageTest
, MAYBE_DNSError_GoBack1
) {
426 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
427 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
428 browser(), GetDnsErrorURL(), 2);
429 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED
);
430 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
433 // See crbug.com/109669
434 #if defined(USE_AURA)
435 #define MAYBE_DNSError_GoBack2 DISABLED_DNSError_GoBack2
437 #define MAYBE_DNSError_GoBack2 DNSError_GoBack2
439 // Test that a DNS error occuring in the main frame does not result in an
440 // additional session history entry.
441 IN_PROC_BROWSER_TEST_F(ErrorPageTest
, DNSError_GoBack2
) {
442 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
444 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
445 browser(), GetDnsErrorURL(), 2);
446 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED
);
448 NavigateToFileURL(FILE_PATH_LITERAL("title3.html"));
450 GoBackAndWaitForNavigations(2);
451 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED
);
453 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
456 // See crbug.com/109669
457 #if defined(USE_AURA)
458 #define MAYBE_DNSError_GoBack2AndForward DISABLED_DNSError_GoBack2AndForward
460 #define MAYBE_DNSError_GoBack2AndForward DNSError_GoBack2AndForward
462 // Test that a DNS error occuring in the main frame does not result in an
463 // additional session history entry.
464 IN_PROC_BROWSER_TEST_F(ErrorPageTest
, DNSError_GoBack2AndForward
) {
465 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
467 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
468 browser(), GetDnsErrorURL(), 2);
469 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED
);
471 NavigateToFileURL(FILE_PATH_LITERAL("title3.html"));
473 GoBackAndWaitForNavigations(2);
474 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED
);
476 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
478 GoForwardAndWaitForNavigations(2);
479 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED
);
482 // See crbug.com/109669
483 #if defined(USE_AURA)
484 #define MAYBE_DNSError_GoBack2Forward2 DISABLED_DNSError_GoBack2Forward2
486 #define MAYBE_DNSError_GoBack2Forward2 DNSError_GoBack2Forward2
488 // Test that a DNS error occuring in the main frame does not result in an
489 // additional session history entry.
490 IN_PROC_BROWSER_TEST_F(ErrorPageTest
, DNSError_GoBack2Forward2
) {
491 NavigateToFileURL(FILE_PATH_LITERAL("title3.html"));
493 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
494 browser(), GetDnsErrorURL(), 2);
495 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED
);
497 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
499 GoBackAndWaitForNavigations(2);
500 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED
);
502 GoBackAndWaitForTitle("Title Of More Awesomeness", 1);
504 GoForwardAndWaitForNavigations(2);
505 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED
);
507 GoForwardAndWaitForTitle("Title Of Awesomeness", 1);
510 // See crbug.com/109669
511 #if defined(USE_AURA)
512 #define MAYBE_DNSError_DoSearch DNSError_DoSearch
514 #define MAYBE_DNSError_DoSearch DNSError_DoSearch
516 // Test that the search button on a DNS error page works.
517 IN_PROC_BROWSER_TEST_F(ErrorPageTest
, MAYBE_DNSError_DoSearch
) {
518 // The first navigation should fail, and the second one should be the error
520 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
521 browser(), GetDnsErrorURL(), 2);
522 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED
);
524 // Do a search and make sure the browser ends up at the right page.
525 content::TestNavigationObserver
nav_observer(
526 browser()->tab_strip_model()->GetActiveWebContents(),
528 content::TitleWatcher
title_watcher(
529 browser()->tab_strip_model()->GetActiveWebContents(),
530 base::ASCIIToUTF16("Title Of More Awesomeness"));
531 ASSERT_TRUE(content::ExecuteScript(
532 browser()->tab_strip_model()->GetActiveWebContents(),
533 "document.getElementById('search-button').click();"));
535 EXPECT_EQ(base::ASCIIToUTF16("Title Of More Awesomeness"),
536 title_watcher
.WaitAndGetTitle());
538 // Check the path and query string.
540 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
541 browser()->tab_strip_model()->GetActiveWebContents(),
542 "domAutomationController.send(window.location.href);",
544 EXPECT_EQ("/search", GURL(url
).path());
545 EXPECT_EQ("q=search%20query", GURL(url
).query());
547 // Go back to the error page, to make sure the history is correct.
548 GoBackAndWaitForNavigations(2);
549 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED
);
552 // Test that a DNS error occuring in an iframe does not result in showing
553 // navigation corrections.
554 IN_PROC_BROWSER_TEST_F(ErrorPageTest
, IFrameDNSError_Basic
) {
555 NavigateToURLAndWaitForTitle(
556 content::URLRequestMockHTTPJob::GetMockUrl(
557 base::FilePath(FILE_PATH_LITERAL("iframe_dns_error.html"))),
560 // We expect to have two history entries, since we started off with navigation
561 // to "about:blank" and then navigated to "iframe_dns_error.html".
563 browser()->tab_strip_model()->GetActiveWebContents()->
564 GetController().GetEntryCount());
567 // This test fails regularly on win_rel trybots. See crbug.com/121540
569 #define MAYBE_IFrameDNSError_GoBack DISABLED_IFrameDNSError_GoBack
571 #define MAYBE_IFrameDNSError_GoBack IFrameDNSError_GoBack
573 // Test that a DNS error occuring in an iframe does not result in an
574 // additional session history entry.
575 IN_PROC_BROWSER_TEST_F(ErrorPageTest
, MAYBE_IFrameDNSError_GoBack
) {
576 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
577 NavigateToFileURL(FILE_PATH_LITERAL("iframe_dns_error.html"));
578 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
581 // This test fails regularly on win_rel trybots. See crbug.com/121540
583 // This fails on linux_aura bringup: http://crbug.com/163931
584 #if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA))
585 #define MAYBE_IFrameDNSError_GoBackAndForward DISABLED_IFrameDNSError_GoBackAndForward
587 #define MAYBE_IFrameDNSError_GoBackAndForward IFrameDNSError_GoBackAndForward
589 // Test that a DNS error occuring in an iframe does not result in an
590 // additional session history entry.
591 IN_PROC_BROWSER_TEST_F(ErrorPageTest
, MAYBE_IFrameDNSError_GoBackAndForward
) {
592 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
593 NavigateToFileURL(FILE_PATH_LITERAL("iframe_dns_error.html"));
594 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
595 GoForwardAndWaitForTitle("Blah", 1);
598 // Test that a DNS error occuring in an iframe, once the main document is
599 // completed loading, does not result in an additional session history entry.
600 // To ensure that the main document has completed loading, JavaScript is used to
601 // inject an iframe after loading is done.
602 IN_PROC_BROWSER_TEST_F(ErrorPageTest
, IFrameDNSError_JavaScript
) {
603 content::WebContents
* wc
=
604 browser()->tab_strip_model()->GetActiveWebContents();
606 URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED
);
608 // Load a regular web page, in which we will inject an iframe.
609 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
611 // We expect to have two history entries, since we started off with navigation
612 // to "about:blank" and then navigated to "title2.html".
613 EXPECT_EQ(2, wc
->GetController().GetEntryCount());
615 std::string script
= "var frame = document.createElement('iframe');"
616 "frame.src = '" + fail_url
.spec() + "';"
617 "document.body.appendChild(frame);";
619 TestFailProvisionalLoadObserver
fail_observer(wc
);
620 content::WindowedNotificationObserver
load_observer(
621 content::NOTIFICATION_LOAD_STOP
,
622 content::Source
<NavigationController
>(&wc
->GetController()));
623 wc
->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(script
));
624 load_observer
.Wait();
626 // Ensure we saw the expected failure.
627 EXPECT_EQ(fail_url
, fail_observer
.fail_url());
629 // Failed initial navigation of an iframe shouldn't be adding any history
631 EXPECT_EQ(2, wc
->GetController().GetEntryCount());
634 // Do the same test, but with an iframe that doesn't have initial URL
636 script
= "var frame = document.createElement('iframe');"
637 "frame.id = 'target_frame';"
638 "document.body.appendChild(frame);";
640 content::WindowedNotificationObserver
load_observer(
641 content::NOTIFICATION_LOAD_STOP
,
642 content::Source
<NavigationController
>(&wc
->GetController()));
643 wc
->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(script
));
644 load_observer
.Wait();
647 script
= "var f = document.getElementById('target_frame');"
648 "f.src = '" + fail_url
.spec() + "';";
650 TestFailProvisionalLoadObserver
fail_observer(wc
);
651 content::WindowedNotificationObserver
load_observer(
652 content::NOTIFICATION_LOAD_STOP
,
653 content::Source
<NavigationController
>(&wc
->GetController()));
654 wc
->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(script
));
655 load_observer
.Wait();
657 EXPECT_EQ(fail_url
, fail_observer
.fail_url());
658 EXPECT_EQ(2, wc
->GetController().GetEntryCount());
662 // Checks that navigation corrections are not loaded when we receive an actual
664 IN_PROC_BROWSER_TEST_F(ErrorPageTest
, Page404
) {
665 NavigateToURLAndWaitForTitle(
666 content::URLRequestMockHTTPJob::GetMockUrl(
667 base::FilePath(FILE_PATH_LITERAL("page404.html"))),
672 // Checks that when an error occurs, the stale cache status of the page
673 // is correctly transferred, and that stale cached copied can be loaded
674 // from the javascript.
675 IN_PROC_BROWSER_TEST_F(ErrorPageTest
, StaleCacheStatus
) {
676 ASSERT_TRUE(test_server()->Start());
677 // Load cache with entry with "nocache" set, to create stale
679 GURL
test_url(test_server()->GetURL("files/nocache.html"));
680 NavigateToURLAndWaitForTitle(test_url
, "Nocache Test Page", 1);
682 // Reload same URL after forcing an error from the the network layer;
683 // confirm that the error page is told the cached copy exists.
684 scoped_refptr
<net::URLRequestContextGetter
> url_request_context_getter
=
685 browser()->profile()->GetRequestContext();
686 BrowserThread::PostTask(
687 BrowserThread::IO
, FROM_HERE
,
688 base::Bind(&InterceptNetworkTransactions
, url_request_context_getter
,
691 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
692 // With no navigation corrections to load, there's only one navigation.
693 browser(), test_url
, 1);
694 EXPECT_TRUE(ProbeStaleCopyValue(true));
695 EXPECT_TRUE(IsDisplayingText(browser(), GetLoadStaleButtonLabel()));
696 EXPECT_NE(base::ASCIIToUTF16("Nocache Test Page"),
697 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
699 // Confirm that loading the stale copy from the cache works.
700 content::TestNavigationObserver
same_tab_observer(
701 browser()->tab_strip_model()->GetActiveWebContents(), 1);
702 ASSERT_TRUE(ReloadStaleCopyFromCache());
703 same_tab_observer
.Wait();
704 EXPECT_EQ(base::ASCIIToUTF16("Nocache Test Page"),
705 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
707 // Clear the cache and reload the same URL; confirm the error page is told
708 // that there is no cached copy.
709 BrowsingDataRemover
* remover
=
710 BrowsingDataRemover::CreateForUnboundedRange(browser()->profile());
711 remover
->Remove(BrowsingDataRemover::REMOVE_CACHE
,
712 BrowsingDataHelper::UNPROTECTED_WEB
);
713 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
714 browser(), test_url
, 1);
715 EXPECT_TRUE(ProbeStaleCopyValue(false));
716 EXPECT_FALSE(IsDisplayingText(browser(), GetLoadStaleButtonLabel()));
719 class ErrorPageAutoReloadTest
: public InProcessBrowserTest
{
721 virtual void SetUpCommandLine(CommandLine
* command_line
) OVERRIDE
{
722 command_line
->AppendSwitch(switches::kEnableOfflineAutoReload
);
725 void InstallProtocolHandler(const GURL
& url
, int requests_to_fail
) {
726 protocol_handler_
= new FailFirstNRequestsProtocolHandler(
729 // Tests don't need to wait for this task to complete before using the
730 // filter; any requests that might be affected by it will end up in the IO
731 // thread's message loop after this posted task anyway.
732 BrowserThread::PostTask(
733 BrowserThread::IO
, FROM_HERE
,
734 base::Bind(&ErrorPageAutoReloadTest::AddFilters
,
735 base::Unretained(this)));
738 void NavigateToURLAndWaitForTitle(const GURL
& url
,
739 const std::string
& expected_title
,
740 int num_navigations
) {
741 content::TitleWatcher
title_watcher(
742 browser()->tab_strip_model()->GetActiveWebContents(),
743 base::ASCIIToUTF16(expected_title
));
745 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
746 browser(), url
, num_navigations
);
748 EXPECT_EQ(base::ASCIIToUTF16(expected_title
),
749 title_watcher
.WaitAndGetTitle());
752 FailFirstNRequestsProtocolHandler
* protocol_handler() {
753 return protocol_handler_
;
758 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
759 // Note: in theory, AddUrlHandler gives ownership of |protocol_handler_| to
760 // URLRequestFilter. As soon as anything calls
761 // URLRequestFilter::ClearHandlers(), |protocol_handler_| can become
763 protocol_handler_
->AddUrlHandler();
766 FailFirstNRequestsProtocolHandler
* protocol_handler_
;
769 IN_PROC_BROWSER_TEST_F(ErrorPageAutoReloadTest
, AutoReload
) {
770 GURL
test_url("http://error.page.auto.reload");
771 const int kRequestsToFail
= 2;
772 InstallProtocolHandler(test_url
, kRequestsToFail
);
773 NavigateToURLAndWaitForTitle(test_url
, "Test One", kRequestsToFail
+ 1);
774 // Note that the protocol handler updates these variables on the IO thread,
775 // but this function reads them on the main thread. The requests have to be
776 // created (on the IO thread) before NavigateToURLAndWaitForTitle returns or
777 // this becomes racey.
778 EXPECT_EQ(kRequestsToFail
, protocol_handler()->failures());
779 EXPECT_EQ(kRequestsToFail
+ 1, protocol_handler()->requests());
782 // Protocol handler that fails all requests with net::ERR_ADDRESS_UNREACHABLE.
783 class AddressUnreachableProtocolHandler
784 : public net::URLRequestJobFactory::ProtocolHandler
{
786 AddressUnreachableProtocolHandler() {}
787 virtual ~AddressUnreachableProtocolHandler() {}
789 // net::URLRequestJobFactory::ProtocolHandler:
790 virtual net::URLRequestJob
* MaybeCreateJob(
791 net::URLRequest
* request
,
792 net::NetworkDelegate
* network_delegate
) const OVERRIDE
{
793 return new URLRequestFailedJob(request
,
795 net::ERR_ADDRESS_UNREACHABLE
);
799 DISALLOW_COPY_AND_ASSIGN(AddressUnreachableProtocolHandler
);
802 // A test fixture that returns ERR_ADDRESS_UNREACHABLE for all navigation
803 // correction requests. ERR_NAME_NOT_RESOLVED is more typical, but need to use
804 // a different error for the correction service and the original page to
805 // validate the right page is being displayed.
806 class ErrorPageNavigationCorrectionsFailTest
: public ErrorPageTest
{
808 // InProcessBrowserTest:
809 virtual void SetUpOnMainThread() OVERRIDE
{
810 BrowserThread::PostTask(
811 BrowserThread::IO
, FROM_HERE
,
812 base::Bind(&ErrorPageNavigationCorrectionsFailTest::AddFilters
));
815 virtual void CleanUpOnMainThread() OVERRIDE
{
816 BrowserThread::PostTask(
817 BrowserThread::IO
, FROM_HERE
,
818 base::Bind(&ErrorPageNavigationCorrectionsFailTest::RemoveFilters
));
822 // Adds a filter that causes all correction service requests to fail with
823 // ERR_ADDRESS_UNREACHABLE.
825 // Also adds the content::URLRequestFailedJob filter.
826 static void AddFilters() {
827 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
828 content::URLRequestFailedJob::AddUrlHandler();
830 net::URLRequestFilter::GetInstance()->AddUrlProtocolHandler(
831 google_util::LinkDoctorBaseURL(),
832 scoped_ptr
<net::URLRequestJobFactory::ProtocolHandler
>(
833 new AddressUnreachableProtocolHandler()));
836 static void RemoveFilters() {
837 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
838 net::URLRequestFilter::GetInstance()->ClearHandlers();
842 // Make sure that when corrections fail to load, the network error page is
843 // successfully loaded.
844 IN_PROC_BROWSER_TEST_F(ErrorPageNavigationCorrectionsFailTest
,
845 FetchCorrectionsFails
) {
846 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
848 URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED
),
851 // Verify that the expected error page is being displayed.
852 ExpectDisplayingLocalErrorPage(browser(), net::ERR_NAME_NOT_RESOLVED
);
855 // Checks that when an error occurs and a corrections fail to load, the stale
856 // cache status of the page is correctly transferred, and we can load the
857 // stale copy from the javascript. Most logic copied from StaleCacheStatus
859 IN_PROC_BROWSER_TEST_F(ErrorPageNavigationCorrectionsFailTest
,
860 StaleCacheStatusFailedCorrections
) {
861 ASSERT_TRUE(test_server()->Start());
862 // Load cache with entry with "nocache" set, to create stale
864 GURL
test_url(test_server()->GetURL("files/nocache.html"));
865 NavigateToURLAndWaitForTitle(test_url
, "Nocache Test Page", 1);
867 // Reload same URL after forcing an error from the the network layer;
868 // confirm that the error page is told the cached copy exists.
869 scoped_refptr
<net::URLRequestContextGetter
> url_request_context_getter
=
870 browser()->profile()->GetRequestContext();
871 BrowserThread::PostTask(
872 BrowserThread::IO
, FROM_HERE
,
873 base::Bind(&InterceptNetworkTransactions
, url_request_context_getter
,
874 net::ERR_CONNECTION_FAILED
));
876 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
877 browser(), test_url
, 2);
878 EXPECT_TRUE(IsDisplayingText(browser(), GetLoadStaleButtonLabel()));
879 EXPECT_TRUE(ProbeStaleCopyValue(true));
881 // Confirm that loading the stale copy from the cache works.
882 content::TestNavigationObserver
same_tab_observer(
883 browser()->tab_strip_model()->GetActiveWebContents(), 1);
884 ASSERT_TRUE(ReloadStaleCopyFromCache());
885 same_tab_observer
.Wait();
886 EXPECT_EQ(base::ASCIIToUTF16("Nocache Test Page"),
887 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
889 // Clear the cache and reload the same URL; confirm the error page is told
890 // that there is no cached copy.
891 BrowsingDataRemover
* remover
=
892 BrowsingDataRemover::CreateForUnboundedRange(browser()->profile());
893 remover
->Remove(BrowsingDataRemover::REMOVE_CACHE
,
894 BrowsingDataHelper::UNPROTECTED_WEB
);
895 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
896 browser(), test_url
, 2);
897 EXPECT_TRUE(ProbeStaleCopyValue(false));
898 EXPECT_FALSE(IsDisplayingText(browser(), GetLoadStaleButtonLabel()));
901 // A test fixture that simulates failing requests for an IDN domain name.
902 class ErrorPageForIDNTest
: public InProcessBrowserTest
{
904 // Target hostname in different forms.
905 static const char kHostname
[];
906 static const char kHostnameJSUnicode
[];
908 // InProcessBrowserTest:
909 virtual void SetUpOnMainThread() OVERRIDE
{
910 // Clear AcceptLanguages to force punycode decoding.
911 browser()->profile()->GetPrefs()->SetString(prefs::kAcceptLanguages
,
913 BrowserThread::PostTask(
914 BrowserThread::IO
, FROM_HERE
,
915 base::Bind(&ErrorPageForIDNTest::AddFilters
));
918 virtual void CleanUpOnMainThread() OVERRIDE
{
919 BrowserThread::PostTask(
920 BrowserThread::IO
, FROM_HERE
,
921 base::Bind(&ErrorPageForIDNTest::RemoveFilters
));
925 static void AddFilters() {
926 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
927 content::URLRequestFailedJob::AddUrlHandlerForHostname(kHostname
);
930 static void RemoveFilters() {
931 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
932 net::URLRequestFilter::GetInstance()->ClearHandlers();
936 const char ErrorPageForIDNTest::kHostname
[] =
937 "xn--d1abbgf6aiiy.xn--p1ai";
938 const char ErrorPageForIDNTest::kHostnameJSUnicode
[] =
939 "\\u043f\\u0440\\u0435\\u0437\\u0438\\u0434\\u0435\\u043d\\u0442."
942 // Make sure error page shows correct unicode for IDN.
943 IN_PROC_BROWSER_TEST_F(ErrorPageForIDNTest
, IDN
) {
944 // ERR_UNSAFE_PORT will not trigger navigation corrections.
945 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
947 URLRequestFailedJob::GetMockHttpUrlForHostname(net::ERR_UNSAFE_PORT
,
951 ToggleHelpBox(browser());
952 EXPECT_TRUE(IsDisplayingText(browser(), kHostnameJSUnicode
));