[safe-browsing] Database full hash matches like prefix match.
[chromium-blink-merge.git] / chrome / browser / errorpage_browsertest.cc
blobb34c1a5539eece64aa9e9b2e72861e7007705cda
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/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;
58 namespace {
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);",
69 text.c_str());
70 bool result = false;
71 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
72 browser->tab_strip_model()->GetActiveWebContents(), command, &result));
73 return 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
119 // code.
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 {
149 public:
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()
159 // accessors.
160 void AddUrlHandler() {
161 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
162 scoped_ptr<URLRequestJobFactory::ProtocolHandler> scoped_handler(this);
163 net::URLRequestFilter::GetInstance()->AddUrlProtocolHandler(
164 url_,
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());
173 requests_++;
174 if (failures_ < requests_to_fail_) {
175 failures_++;
176 // Note: net::ERR_CONNECTION_RESET does not summon the Link Doctor; see
177 // NetErrorHelperCore::GetErrorPageURL.
178 return new URLRequestFailedJob(request,
179 network_delegate,
180 net::ERR_CONNECTION_RESET);
181 } else {
182 return new URLRequestTestJob(request, network_delegate,
183 URLRequestTestJob::test_headers(),
184 URLRequestTestJob::test_data_1(),
185 true);
189 int requests() const { return requests_; }
190 int failures() const { return failures_; }
192 private:
193 const GURL url_;
194 // These are mutable because MaybeCreateJob is const but we want this state
195 // for testing.
196 mutable int requests_;
197 mutable int failures_;
198 int requests_to_fail_;
201 class ErrorPageTest : public InProcessBrowserTest {
202 public:
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(
211 browser(),
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,
236 num_navigations,
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,
245 num_navigations,
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 =
262 "try {\n"
263 " domAutomationController.send(\n"
264 " 'staleLoadButton' in templateData ? 'yes' : 'no');\n"
265 "} catch (e) {\n"
266 " domAutomationController.send(e.message);\n"
267 "}\n";
269 std::string result;
270 bool ret =
271 content::ExecuteScriptAndExtractString(
272 browser()->tab_strip_model()->GetActiveWebContents(),
273 js_cache_probe,
274 &result);
275 if (!ret) {
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 =
288 "try {\n"
289 " document.getElementById('stale-load-button').click();\n"
290 " domAutomationController.send('success');\n"
291 "} catch (e) {\n"
292 " domAutomationController.send(e.message);\n"
293 "}\n";
295 std::string result;
296 bool ret = content::ExecuteScriptAndExtractString(
297 browser()->tab_strip_model()->GetActiveWebContents(),
298 js_reload_script,
299 &result);
300 EXPECT_TRUE(ret);
301 if (!ret)
302 return testing::AssertionFailure();
303 return ("success" == result ? testing::AssertionSuccess() :
304 (testing::AssertionFailure() << "Exception message is " << result));
307 protected:
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);
330 private:
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,
334 int num_navigations,
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(),
350 num_navigations);
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);
355 } else {
356 FAIL();
358 test_navigation_observer.Wait();
362 class TestFailProvisionalLoadObserver : public content::WebContentsObserver {
363 public:
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(
370 int64 frame_id,
371 const base::string16& frame_unique_name,
372 bool is_main_frame,
373 const GURL& validated_url,
374 int error_code,
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_; }
382 private:
383 GURL fail_url_;
385 DISALLOW_COPY_AND_ASSIGN(TestFailProvisionalLoadObserver);
388 void InterceptNetworkTransactions(net::URLRequestContextGetter* getter,
389 net::Error error) {
390 DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::IO));
391 net::HttpCache* cache(
392 getter->GetURLRequestContext()->http_transaction_factory()->GetCache());
393 DCHECK(cache);
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
404 #else
405 #define MAYBE_DNSError_Basic DNSError_Basic
406 #endif
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
410 // page.
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
419 #else
420 #define MAYBE_DNSError_GoBack1 DNSError_GoBack1
421 #endif
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
436 #else
437 #define MAYBE_DNSError_GoBack2 DNSError_GoBack2
438 #endif
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
459 #else
460 #define MAYBE_DNSError_GoBack2AndForward DNSError_GoBack2AndForward
461 #endif
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
485 #else
486 #define MAYBE_DNSError_GoBack2Forward2 DNSError_GoBack2Forward2
487 #endif
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
513 #else
514 #define MAYBE_DNSError_DoSearch DNSError_DoSearch
515 #endif
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
519 // page.
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();"));
534 nav_observer.Wait();
535 EXPECT_EQ(base::ASCIIToUTF16("Title Of More Awesomeness"),
536 title_watcher.WaitAndGetTitle());
538 // Check the path and query string.
539 std::string url;
540 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
541 browser()->tab_strip_model()->GetActiveWebContents(),
542 "domAutomationController.send(window.location.href);",
543 &url));
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"))),
558 "Blah",
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".
562 EXPECT_EQ(2,
563 browser()->tab_strip_model()->GetActiveWebContents()->
564 GetController().GetEntryCount());
567 // This test fails regularly on win_rel trybots. See crbug.com/121540
568 #if defined(OS_WIN)
569 #define MAYBE_IFrameDNSError_GoBack DISABLED_IFrameDNSError_GoBack
570 #else
571 #define MAYBE_IFrameDNSError_GoBack IFrameDNSError_GoBack
572 #endif
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
586 #else
587 #define MAYBE_IFrameDNSError_GoBackAndForward IFrameDNSError_GoBackAndForward
588 #endif
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();
605 GURL fail_url =
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
630 // entries.
631 EXPECT_EQ(2, wc->GetController().GetEntryCount());
634 // Do the same test, but with an iframe that doesn't have initial URL
635 // assigned.
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
663 // 404 page.
664 IN_PROC_BROWSER_TEST_F(ErrorPageTest, Page404) {
665 NavigateToURLAndWaitForTitle(
666 content::URLRequestMockHTTPJob::GetMockUrl(
667 base::FilePath(FILE_PATH_LITERAL("page404.html"))),
668 "SUCCESS",
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
678 // cache.
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,
689 net::ERR_FAILED));
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 {
720 public:
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(
727 url,
728 requests_to_fail);
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_;
756 private:
757 void AddFilters() {
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
762 // invalid.
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 {
785 public:
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,
794 network_delegate,
795 net::ERR_ADDRESS_UNREACHABLE);
798 private:
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 {
807 public:
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));
821 private:
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(
847 browser(),
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
858 // above.
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
863 // cache.
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 {
903 public:
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,
912 std::string());
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));
924 private:
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."
940 "\\u0440\\u0444";
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(
946 browser(),
947 URLRequestFailedJob::GetMockHttpUrlForHostname(net::ERR_UNSAFE_PORT,
948 kHostname),
951 ToggleHelpBox(browser());
952 EXPECT_TRUE(IsDisplayingText(browser(), kHostnameJSUnicode));
955 } // namespace