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 // Needed for StaleCacheStatus and StaleCacheStatusFailedCorrections tests.
209 virtual void SetUpCommandLine(CommandLine
* command_line
) OVERRIDE
{
210 command_line
->AppendSwitch(switches::kEnableOfflineLoadStaleCache
);
213 // Navigates the active tab to a mock url created for the file at |file_path|.
214 void NavigateToFileURL(const base::FilePath::StringType
& file_path
) {
215 ui_test_utils::NavigateToURL(
217 content::URLRequestMockHTTPJob::GetMockUrl(base::FilePath(file_path
)));
220 // Navigates to the given URL and waits for |num_navigations| to occur, and
221 // the title to change to |expected_title|.
222 void NavigateToURLAndWaitForTitle(const GURL
& url
,
223 const std::string
& expected_title
,
224 int num_navigations
) {
225 content::TitleWatcher
title_watcher(
226 browser()->tab_strip_model()->GetActiveWebContents(),
227 base::ASCIIToUTF16(expected_title
));
229 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
230 browser(), url
, num_navigations
);
232 EXPECT_EQ(base::ASCIIToUTF16(expected_title
),
233 title_watcher
.WaitAndGetTitle());
236 // Navigates back in the history and waits for |num_navigations| to occur, and
237 // the title to change to |expected_title|.
238 void GoBackAndWaitForTitle(const std::string
& expected_title
,
239 int num_navigations
) {
240 NavigateHistoryAndWaitForTitle(expected_title
,
242 HISTORY_NAVIGATE_BACK
);
245 // Navigates forward in the history and waits for |num_navigations| to occur,
246 // and the title to change to |expected_title|.
247 void GoForwardAndWaitForTitle(const std::string
& expected_title
,
248 int num_navigations
) {
249 NavigateHistoryAndWaitForTitle(expected_title
,
251 HISTORY_NAVIGATE_FORWARD
);
254 void GoBackAndWaitForNavigations(int num_navigations
) {
255 NavigateHistory(num_navigations
, HISTORY_NAVIGATE_BACK
);
258 void GoForwardAndWaitForNavigations(int num_navigations
) {
259 NavigateHistory(num_navigations
, HISTORY_NAVIGATE_FORWARD
);
262 // Confirms that the javascript variable indicating whether or not we have
263 // a stale copy in the cache has been set to |expected|, and that the
264 // stale load button is or isn't there based on the same expectation.
265 testing::AssertionResult
ProbeStaleCopyValue(bool expected
) {
266 const char* js_cache_probe
=
268 " domAutomationController.send(\n"
269 " 'staleLoadButton' in templateData ? 'yes' : 'no');\n"
271 " domAutomationController.send(e.message);\n"
276 content::ExecuteScriptAndExtractString(
277 browser()->tab_strip_model()->GetActiveWebContents(),
281 return testing::AssertionFailure()
282 << "Failing return from ExecuteScriptAndExtractString.";
285 if ((expected
&& "yes" == result
) || (!expected
&& "no" == result
))
286 return testing::AssertionSuccess();
288 return testing::AssertionFailure() << "Cache probe result is " << result
;
291 testing::AssertionResult
ReloadStaleCopyFromCache() {
292 const char* js_reload_script
=
294 " document.getElementById('stale-load-button').click();\n"
295 " domAutomationController.send('success');\n"
297 " domAutomationController.send(e.message);\n"
301 bool ret
= content::ExecuteScriptAndExtractString(
302 browser()->tab_strip_model()->GetActiveWebContents(),
307 return testing::AssertionFailure();
308 return ("success" == result
? testing::AssertionSuccess() :
309 (testing::AssertionFailure() << "Exception message is " << result
));
313 static void EnableMocks(const GURL
& search_url
) {
314 chrome_browser_net::SetUrlRequestMocksEnabled(true);
316 // Add a mock for the search engine the error page will use.
317 base::FilePath root_http
;
318 PathService::Get(chrome::DIR_TEST_DATA
, &root_http
);
319 content::URLRequestMockHTTPJob::AddHostnameToFileHandler(
320 search_url
.host(), root_http
.AppendASCII("title3.html"));
323 virtual void SetUpOnMainThread() OVERRIDE
{
324 BrowserThread::PostTask(
325 BrowserThread::IO
, FROM_HERE
,
326 base::Bind(&ErrorPageTest::EnableMocks
,
327 google_util::GetGoogleSearchURL(browser()->profile())));
330 // Returns a GURL that results in a DNS error.
331 GURL
GetDnsErrorURL() const {
332 return URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED
);
336 // Navigates the browser the indicated direction in the history and waits for
337 // |num_navigations| to occur and the title to change to |expected_title|.
338 void NavigateHistoryAndWaitForTitle(const std::string
& expected_title
,
340 HistoryNavigationDirection direction
) {
341 content::TitleWatcher
title_watcher(
342 browser()->tab_strip_model()->GetActiveWebContents(),
343 base::ASCIIToUTF16(expected_title
));
345 NavigateHistory(num_navigations
, direction
);
347 EXPECT_EQ(title_watcher
.WaitAndGetTitle(),
348 base::ASCIIToUTF16(expected_title
));
351 void NavigateHistory(int num_navigations
,
352 HistoryNavigationDirection direction
) {
353 content::TestNavigationObserver
test_navigation_observer(
354 browser()->tab_strip_model()->GetActiveWebContents(),
356 if (direction
== HISTORY_NAVIGATE_BACK
) {
357 chrome::GoBack(browser(), CURRENT_TAB
);
358 } else if (direction
== HISTORY_NAVIGATE_FORWARD
) {
359 chrome::GoForward(browser(), CURRENT_TAB
);
363 test_navigation_observer
.Wait();
367 class TestFailProvisionalLoadObserver
: public content::WebContentsObserver
{
369 explicit TestFailProvisionalLoadObserver(content::WebContents
* contents
)
370 : content::WebContentsObserver(contents
) {}
371 virtual ~TestFailProvisionalLoadObserver() {}
373 // This method is invoked when the provisional load failed.
374 virtual void DidFailProvisionalLoad(
376 const base::string16
& frame_unique_name
,
378 const GURL
& validated_url
,
380 const base::string16
& error_description
,
381 content::RenderViewHost
* render_view_host
) OVERRIDE
{
382 fail_url_
= validated_url
;
385 const GURL
& fail_url() const { return fail_url_
; }
390 DISALLOW_COPY_AND_ASSIGN(TestFailProvisionalLoadObserver
);
393 void InterceptNetworkTransactions(net::URLRequestContextGetter
* getter
,
395 DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::IO
));
396 net::HttpCache
* cache(
397 getter
->GetURLRequestContext()->http_transaction_factory()->GetCache());
399 scoped_ptr
<net::HttpTransactionFactory
> factory(
400 new net::FailingHttpTransactionFactory(cache
->GetSession(), error
));
401 // Throw away old version; since this is a a browser test, we don't
402 // need to restore the old state.
403 cache
->SetHttpNetworkTransactionFactoryForTesting(factory
.Pass());
406 // See crbug.com/109669
407 #if defined(USE_AURA)
408 #define MAYBE_DNSError_Basic DISABLED_DNSError_Basic
410 #define MAYBE_DNSError_Basic DNSError_Basic
412 // Test that a DNS error occuring in the main frame redirects to an error page.
413 IN_PROC_BROWSER_TEST_F(ErrorPageTest
, MAYBE_DNSError_Basic
) {
414 // The first navigation should fail, and the second one should be the error
416 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
417 browser(), GetDnsErrorURL(), 2);
418 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED
);
421 // See crbug.com/109669
422 #if defined(USE_AURA)
423 #define MAYBE_DNSError_GoBack1 DISABLED_DNSError_GoBack1
425 #define MAYBE_DNSError_GoBack1 DNSError_GoBack1
428 // Test that a DNS error occuring in the main frame does not result in an
429 // additional session history entry.
430 IN_PROC_BROWSER_TEST_F(ErrorPageTest
, MAYBE_DNSError_GoBack1
) {
431 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
432 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
433 browser(), GetDnsErrorURL(), 2);
434 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED
);
435 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
438 // See crbug.com/109669
439 #if defined(USE_AURA)
440 #define MAYBE_DNSError_GoBack2 DISABLED_DNSError_GoBack2
442 #define MAYBE_DNSError_GoBack2 DNSError_GoBack2
444 // Test that a DNS error occuring in the main frame does not result in an
445 // additional session history entry.
446 IN_PROC_BROWSER_TEST_F(ErrorPageTest
, DNSError_GoBack2
) {
447 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
449 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
450 browser(), GetDnsErrorURL(), 2);
451 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED
);
453 NavigateToFileURL(FILE_PATH_LITERAL("title3.html"));
455 GoBackAndWaitForNavigations(2);
456 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED
);
458 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
461 // See crbug.com/109669
462 #if defined(USE_AURA)
463 #define MAYBE_DNSError_GoBack2AndForward DISABLED_DNSError_GoBack2AndForward
465 #define MAYBE_DNSError_GoBack2AndForward DNSError_GoBack2AndForward
467 // Test that a DNS error occuring in the main frame does not result in an
468 // additional session history entry.
469 IN_PROC_BROWSER_TEST_F(ErrorPageTest
, DNSError_GoBack2AndForward
) {
470 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
472 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
473 browser(), GetDnsErrorURL(), 2);
474 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED
);
476 NavigateToFileURL(FILE_PATH_LITERAL("title3.html"));
478 GoBackAndWaitForNavigations(2);
479 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED
);
481 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
483 GoForwardAndWaitForNavigations(2);
484 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED
);
487 // See crbug.com/109669
488 #if defined(USE_AURA)
489 #define MAYBE_DNSError_GoBack2Forward2 DISABLED_DNSError_GoBack2Forward2
491 #define MAYBE_DNSError_GoBack2Forward2 DNSError_GoBack2Forward2
493 // Test that a DNS error occuring in the main frame does not result in an
494 // additional session history entry.
495 IN_PROC_BROWSER_TEST_F(ErrorPageTest
, DNSError_GoBack2Forward2
) {
496 NavigateToFileURL(FILE_PATH_LITERAL("title3.html"));
498 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
499 browser(), GetDnsErrorURL(), 2);
500 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED
);
502 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
504 GoBackAndWaitForNavigations(2);
505 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED
);
507 GoBackAndWaitForTitle("Title Of More Awesomeness", 1);
509 GoForwardAndWaitForNavigations(2);
510 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED
);
512 GoForwardAndWaitForTitle("Title Of Awesomeness", 1);
515 // See crbug.com/109669
516 #if defined(USE_AURA)
517 #define MAYBE_DNSError_DoSearch DNSError_DoSearch
519 #define MAYBE_DNSError_DoSearch DNSError_DoSearch
521 // Test that the search button on a DNS error page works.
522 IN_PROC_BROWSER_TEST_F(ErrorPageTest
, MAYBE_DNSError_DoSearch
) {
523 // The first navigation should fail, and the second one should be the error
525 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
526 browser(), GetDnsErrorURL(), 2);
527 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED
);
529 // Do a search and make sure the browser ends up at the right page.
530 content::TestNavigationObserver
nav_observer(
531 browser()->tab_strip_model()->GetActiveWebContents(),
533 content::TitleWatcher
title_watcher(
534 browser()->tab_strip_model()->GetActiveWebContents(),
535 base::ASCIIToUTF16("Title Of More Awesomeness"));
536 ASSERT_TRUE(content::ExecuteScript(
537 browser()->tab_strip_model()->GetActiveWebContents(),
538 "document.getElementById('search-button').click();"));
540 EXPECT_EQ(base::ASCIIToUTF16("Title Of More Awesomeness"),
541 title_watcher
.WaitAndGetTitle());
543 // Check the path and query string.
545 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
546 browser()->tab_strip_model()->GetActiveWebContents(),
547 "domAutomationController.send(window.location.href);",
549 EXPECT_EQ("/search", GURL(url
).path());
550 EXPECT_EQ("q=search%20query", GURL(url
).query());
552 // Go back to the error page, to make sure the history is correct.
553 GoBackAndWaitForNavigations(2);
554 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED
);
557 // Test that a DNS error occuring in an iframe does not result in showing
558 // navigation corrections.
559 IN_PROC_BROWSER_TEST_F(ErrorPageTest
, IFrameDNSError_Basic
) {
560 NavigateToURLAndWaitForTitle(
561 content::URLRequestMockHTTPJob::GetMockUrl(
562 base::FilePath(FILE_PATH_LITERAL("iframe_dns_error.html"))),
565 // We expect to have two history entries, since we started off with navigation
566 // to "about:blank" and then navigated to "iframe_dns_error.html".
568 browser()->tab_strip_model()->GetActiveWebContents()->
569 GetController().GetEntryCount());
572 // This test fails regularly on win_rel trybots. See crbug.com/121540
574 #define MAYBE_IFrameDNSError_GoBack DISABLED_IFrameDNSError_GoBack
576 #define MAYBE_IFrameDNSError_GoBack IFrameDNSError_GoBack
578 // Test that a DNS error occuring in an iframe does not result in an
579 // additional session history entry.
580 IN_PROC_BROWSER_TEST_F(ErrorPageTest
, MAYBE_IFrameDNSError_GoBack
) {
581 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
582 NavigateToFileURL(FILE_PATH_LITERAL("iframe_dns_error.html"));
583 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
586 // This test fails regularly on win_rel trybots. See crbug.com/121540
588 // This fails on linux_aura bringup: http://crbug.com/163931
589 #if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA))
590 #define MAYBE_IFrameDNSError_GoBackAndForward DISABLED_IFrameDNSError_GoBackAndForward
592 #define MAYBE_IFrameDNSError_GoBackAndForward IFrameDNSError_GoBackAndForward
594 // Test that a DNS error occuring in an iframe does not result in an
595 // additional session history entry.
596 IN_PROC_BROWSER_TEST_F(ErrorPageTest
, MAYBE_IFrameDNSError_GoBackAndForward
) {
597 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
598 NavigateToFileURL(FILE_PATH_LITERAL("iframe_dns_error.html"));
599 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
600 GoForwardAndWaitForTitle("Blah", 1);
603 // Test that a DNS error occuring in an iframe, once the main document is
604 // completed loading, does not result in an additional session history entry.
605 // To ensure that the main document has completed loading, JavaScript is used to
606 // inject an iframe after loading is done.
607 IN_PROC_BROWSER_TEST_F(ErrorPageTest
, IFrameDNSError_JavaScript
) {
608 content::WebContents
* wc
=
609 browser()->tab_strip_model()->GetActiveWebContents();
611 URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED
);
613 // Load a regular web page, in which we will inject an iframe.
614 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
616 // We expect to have two history entries, since we started off with navigation
617 // to "about:blank" and then navigated to "title2.html".
618 EXPECT_EQ(2, wc
->GetController().GetEntryCount());
620 std::string script
= "var frame = document.createElement('iframe');"
621 "frame.src = '" + fail_url
.spec() + "';"
622 "document.body.appendChild(frame);";
624 TestFailProvisionalLoadObserver
fail_observer(wc
);
625 content::WindowedNotificationObserver
load_observer(
626 content::NOTIFICATION_LOAD_STOP
,
627 content::Source
<NavigationController
>(&wc
->GetController()));
628 wc
->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(script
));
629 load_observer
.Wait();
631 // Ensure we saw the expected failure.
632 EXPECT_EQ(fail_url
, fail_observer
.fail_url());
634 // Failed initial navigation of an iframe shouldn't be adding any history
636 EXPECT_EQ(2, wc
->GetController().GetEntryCount());
639 // Do the same test, but with an iframe that doesn't have initial URL
641 script
= "var frame = document.createElement('iframe');"
642 "frame.id = 'target_frame';"
643 "document.body.appendChild(frame);";
645 content::WindowedNotificationObserver
load_observer(
646 content::NOTIFICATION_LOAD_STOP
,
647 content::Source
<NavigationController
>(&wc
->GetController()));
648 wc
->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(script
));
649 load_observer
.Wait();
652 script
= "var f = document.getElementById('target_frame');"
653 "f.src = '" + fail_url
.spec() + "';";
655 TestFailProvisionalLoadObserver
fail_observer(wc
);
656 content::WindowedNotificationObserver
load_observer(
657 content::NOTIFICATION_LOAD_STOP
,
658 content::Source
<NavigationController
>(&wc
->GetController()));
659 wc
->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(script
));
660 load_observer
.Wait();
662 EXPECT_EQ(fail_url
, fail_observer
.fail_url());
663 EXPECT_EQ(2, wc
->GetController().GetEntryCount());
667 // Checks that navigation corrections are not loaded when we receive an actual
669 IN_PROC_BROWSER_TEST_F(ErrorPageTest
, Page404
) {
670 NavigateToURLAndWaitForTitle(
671 content::URLRequestMockHTTPJob::GetMockUrl(
672 base::FilePath(FILE_PATH_LITERAL("page404.html"))),
677 // Checks that when an error occurs, the stale cache status of the page
678 // is correctly transferred, and that stale cached copied can be loaded
679 // from the javascript.
680 IN_PROC_BROWSER_TEST_F(ErrorPageTest
, StaleCacheStatus
) {
681 ASSERT_TRUE(test_server()->Start());
682 // Load cache with entry with "nocache" set, to create stale
684 GURL
test_url(test_server()->GetURL("files/nocache.html"));
685 NavigateToURLAndWaitForTitle(test_url
, "Nocache Test Page", 1);
687 // Reload same URL after forcing an error from the the network layer;
688 // confirm that the error page is told the cached copy exists.
689 scoped_refptr
<net::URLRequestContextGetter
> url_request_context_getter
=
690 browser()->profile()->GetRequestContext();
691 BrowserThread::PostTask(
692 BrowserThread::IO
, FROM_HERE
,
693 base::Bind(&InterceptNetworkTransactions
, url_request_context_getter
,
696 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
697 // With no navigation corrections to load, there's only one navigation.
698 browser(), test_url
, 1);
699 EXPECT_TRUE(ProbeStaleCopyValue(true));
700 EXPECT_TRUE(IsDisplayingText(browser(), GetLoadStaleButtonLabel()));
701 EXPECT_NE(base::ASCIIToUTF16("Nocache Test Page"),
702 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
704 // Confirm that loading the stale copy from the cache works.
705 content::TestNavigationObserver
same_tab_observer(
706 browser()->tab_strip_model()->GetActiveWebContents(), 1);
707 ASSERT_TRUE(ReloadStaleCopyFromCache());
708 same_tab_observer
.Wait();
709 EXPECT_EQ(base::ASCIIToUTF16("Nocache Test Page"),
710 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
712 // Clear the cache and reload the same URL; confirm the error page is told
713 // that there is no cached copy.
714 BrowsingDataRemover
* remover
=
715 BrowsingDataRemover::CreateForUnboundedRange(browser()->profile());
716 remover
->Remove(BrowsingDataRemover::REMOVE_CACHE
,
717 BrowsingDataHelper::UNPROTECTED_WEB
);
718 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
719 browser(), test_url
, 1);
720 EXPECT_TRUE(ProbeStaleCopyValue(false));
721 EXPECT_FALSE(IsDisplayingText(browser(), GetLoadStaleButtonLabel()));
724 class ErrorPageAutoReloadTest
: public InProcessBrowserTest
{
726 virtual void SetUpCommandLine(CommandLine
* command_line
) OVERRIDE
{
727 command_line
->AppendSwitch(switches::kEnableOfflineAutoReload
);
730 void InstallProtocolHandler(const GURL
& url
, int requests_to_fail
) {
731 protocol_handler_
= new FailFirstNRequestsProtocolHandler(
734 // Tests don't need to wait for this task to complete before using the
735 // filter; any requests that might be affected by it will end up in the IO
736 // thread's message loop after this posted task anyway.
737 BrowserThread::PostTask(
738 BrowserThread::IO
, FROM_HERE
,
739 base::Bind(&ErrorPageAutoReloadTest::AddFilters
,
740 base::Unretained(this)));
743 void NavigateToURLAndWaitForTitle(const GURL
& url
,
744 const std::string
& expected_title
,
745 int num_navigations
) {
746 content::TitleWatcher
title_watcher(
747 browser()->tab_strip_model()->GetActiveWebContents(),
748 base::ASCIIToUTF16(expected_title
));
750 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
751 browser(), url
, num_navigations
);
753 EXPECT_EQ(base::ASCIIToUTF16(expected_title
),
754 title_watcher
.WaitAndGetTitle());
757 FailFirstNRequestsProtocolHandler
* protocol_handler() {
758 return protocol_handler_
;
763 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
764 // Note: in theory, AddUrlHandler gives ownership of |protocol_handler_| to
765 // URLRequestFilter. As soon as anything calls
766 // URLRequestFilter::ClearHandlers(), |protocol_handler_| can become
768 protocol_handler_
->AddUrlHandler();
771 FailFirstNRequestsProtocolHandler
* protocol_handler_
;
774 IN_PROC_BROWSER_TEST_F(ErrorPageAutoReloadTest
, AutoReload
) {
775 GURL
test_url("http://error.page.auto.reload");
776 const int kRequestsToFail
= 2;
777 InstallProtocolHandler(test_url
, kRequestsToFail
);
778 NavigateToURLAndWaitForTitle(test_url
, "Test One", kRequestsToFail
+ 1);
779 // Note that the protocol handler updates these variables on the IO thread,
780 // but this function reads them on the main thread. The requests have to be
781 // created (on the IO thread) before NavigateToURLAndWaitForTitle returns or
782 // this becomes racey.
783 EXPECT_EQ(kRequestsToFail
, protocol_handler()->failures());
784 EXPECT_EQ(kRequestsToFail
+ 1, protocol_handler()->requests());
787 // Protocol handler that fails all requests with net::ERR_ADDRESS_UNREACHABLE.
788 class AddressUnreachableProtocolHandler
789 : public net::URLRequestJobFactory::ProtocolHandler
{
791 AddressUnreachableProtocolHandler() {}
792 virtual ~AddressUnreachableProtocolHandler() {}
794 // net::URLRequestJobFactory::ProtocolHandler:
795 virtual net::URLRequestJob
* MaybeCreateJob(
796 net::URLRequest
* request
,
797 net::NetworkDelegate
* network_delegate
) const OVERRIDE
{
798 return new URLRequestFailedJob(request
,
800 net::ERR_ADDRESS_UNREACHABLE
);
804 DISALLOW_COPY_AND_ASSIGN(AddressUnreachableProtocolHandler
);
807 // A test fixture that returns ERR_ADDRESS_UNREACHABLE for all navigation
808 // correction requests. ERR_NAME_NOT_RESOLVED is more typical, but need to use
809 // a different error for the correction service and the original page to
810 // validate the right page is being displayed.
811 class ErrorPageNavigationCorrectionsFailTest
: public ErrorPageTest
{
813 // InProcessBrowserTest:
814 virtual void SetUpOnMainThread() OVERRIDE
{
815 BrowserThread::PostTask(
816 BrowserThread::IO
, FROM_HERE
,
817 base::Bind(&ErrorPageNavigationCorrectionsFailTest::AddFilters
));
820 virtual void CleanUpOnMainThread() OVERRIDE
{
821 BrowserThread::PostTask(
822 BrowserThread::IO
, FROM_HERE
,
823 base::Bind(&ErrorPageNavigationCorrectionsFailTest::RemoveFilters
));
827 // Adds a filter that causes all correction service requests to fail with
828 // ERR_ADDRESS_UNREACHABLE.
830 // Also adds the content::URLRequestFailedJob filter.
831 static void AddFilters() {
832 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
833 content::URLRequestFailedJob::AddUrlHandler();
835 net::URLRequestFilter::GetInstance()->AddUrlProtocolHandler(
836 google_util::LinkDoctorBaseURL(),
837 scoped_ptr
<net::URLRequestJobFactory::ProtocolHandler
>(
838 new AddressUnreachableProtocolHandler()));
841 static void RemoveFilters() {
842 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
843 net::URLRequestFilter::GetInstance()->ClearHandlers();
847 // Make sure that when corrections fail to load, the network error page is
848 // successfully loaded.
849 IN_PROC_BROWSER_TEST_F(ErrorPageNavigationCorrectionsFailTest
,
850 FetchCorrectionsFails
) {
851 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
853 URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED
),
856 // Verify that the expected error page is being displayed.
857 ExpectDisplayingLocalErrorPage(browser(), net::ERR_NAME_NOT_RESOLVED
);
860 // Checks that when an error occurs and a corrections fail to load, the stale
861 // cache status of the page is correctly transferred, and we can load the
862 // stale copy from the javascript. Most logic copied from StaleCacheStatus
864 IN_PROC_BROWSER_TEST_F(ErrorPageNavigationCorrectionsFailTest
,
865 StaleCacheStatusFailedCorrections
) {
866 ASSERT_TRUE(test_server()->Start());
867 // Load cache with entry with "nocache" set, to create stale
869 GURL
test_url(test_server()->GetURL("files/nocache.html"));
870 NavigateToURLAndWaitForTitle(test_url
, "Nocache Test Page", 1);
872 // Reload same URL after forcing an error from the the network layer;
873 // confirm that the error page is told the cached copy exists.
874 scoped_refptr
<net::URLRequestContextGetter
> url_request_context_getter
=
875 browser()->profile()->GetRequestContext();
876 BrowserThread::PostTask(
877 BrowserThread::IO
, FROM_HERE
,
878 base::Bind(&InterceptNetworkTransactions
, url_request_context_getter
,
879 net::ERR_CONNECTION_FAILED
));
881 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
882 browser(), test_url
, 2);
883 EXPECT_TRUE(IsDisplayingText(browser(), GetLoadStaleButtonLabel()));
884 EXPECT_TRUE(ProbeStaleCopyValue(true));
886 // Confirm that loading the stale copy from the cache works.
887 content::TestNavigationObserver
same_tab_observer(
888 browser()->tab_strip_model()->GetActiveWebContents(), 1);
889 ASSERT_TRUE(ReloadStaleCopyFromCache());
890 same_tab_observer
.Wait();
891 EXPECT_EQ(base::ASCIIToUTF16("Nocache Test Page"),
892 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
894 // Clear the cache and reload the same URL; confirm the error page is told
895 // that there is no cached copy.
896 BrowsingDataRemover
* remover
=
897 BrowsingDataRemover::CreateForUnboundedRange(browser()->profile());
898 remover
->Remove(BrowsingDataRemover::REMOVE_CACHE
,
899 BrowsingDataHelper::UNPROTECTED_WEB
);
900 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
901 browser(), test_url
, 2);
902 EXPECT_TRUE(ProbeStaleCopyValue(false));
903 EXPECT_FALSE(IsDisplayingText(browser(), GetLoadStaleButtonLabel()));
906 // A test fixture that simulates failing requests for an IDN domain name.
907 class ErrorPageForIDNTest
: public InProcessBrowserTest
{
909 // Target hostname in different forms.
910 static const char kHostname
[];
911 static const char kHostnameJSUnicode
[];
913 // InProcessBrowserTest:
914 virtual void SetUpOnMainThread() OVERRIDE
{
915 // Clear AcceptLanguages to force punycode decoding.
916 browser()->profile()->GetPrefs()->SetString(prefs::kAcceptLanguages
,
918 BrowserThread::PostTask(
919 BrowserThread::IO
, FROM_HERE
,
920 base::Bind(&ErrorPageForIDNTest::AddFilters
));
923 virtual void CleanUpOnMainThread() OVERRIDE
{
924 BrowserThread::PostTask(
925 BrowserThread::IO
, FROM_HERE
,
926 base::Bind(&ErrorPageForIDNTest::RemoveFilters
));
930 static void AddFilters() {
931 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
932 content::URLRequestFailedJob::AddUrlHandlerForHostname(kHostname
);
935 static void RemoveFilters() {
936 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
937 net::URLRequestFilter::GetInstance()->ClearHandlers();
941 const char ErrorPageForIDNTest::kHostname
[] =
942 "xn--d1abbgf6aiiy.xn--p1ai";
943 const char ErrorPageForIDNTest::kHostnameJSUnicode
[] =
944 "\\u043f\\u0440\\u0435\\u0437\\u0438\\u0434\\u0435\\u043d\\u0442."
947 // Make sure error page shows correct unicode for IDN.
948 IN_PROC_BROWSER_TEST_F(ErrorPageForIDNTest
, IDN
) {
949 // ERR_UNSAFE_PORT will not trigger navigation corrections.
950 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
952 URLRequestFailedJob::GetMockHttpUrlForHostname(net::ERR_UNSAFE_PORT
,
956 ToggleHelpBox(browser());
957 EXPECT_TRUE(IsDisplayingText(browser(), kHostnameJSUnicode
));