1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/bind.h"
6 #include "base/command_line.h"
7 #include "base/compiler_specific.h"
8 #include "base/logging.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/memory/weak_ptr.h"
11 #include "base/path_service.h"
12 #include "base/prefs/pref_service.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/synchronization/lock.h"
16 #include "chrome/browser/browsing_data/browsing_data_helper.h"
17 #include "chrome/browser/browsing_data/browsing_data_remover.h"
18 #include "chrome/browser/google/google_profile_helper.h"
19 #include "chrome/browser/net/url_request_mock_util.h"
20 #include "chrome/browser/profiles/profile.h"
21 #include "chrome/browser/ui/browser.h"
22 #include "chrome/browser/ui/browser_commands.h"
23 #include "chrome/browser/ui/tabs/tab_strip_model.h"
24 #include "chrome/common/chrome_paths.h"
25 #include "chrome/common/chrome_switches.h"
26 #include "chrome/common/pref_names.h"
27 #include "chrome/test/base/in_process_browser_test.h"
28 #include "chrome/test/base/ui_test_utils.h"
29 #include "components/google/core/browser/google_util.h"
30 #include "content/public/browser/browser_thread.h"
31 #include "content/public/browser/notification_service.h"
32 #include "content/public/browser/notification_types.h"
33 #include "content/public/browser/render_frame_host.h"
34 #include "content/public/browser/render_view_host.h"
35 #include "content/public/browser/web_contents.h"
36 #include "content/public/browser/web_contents_observer.h"
37 #include "content/public/test/browser_test_utils.h"
38 #include "content/public/test/test_navigation_observer.h"
39 #include "content/test/net/url_request_failed_job.h"
40 #include "content/test/net/url_request_mock_http_job.h"
41 #include "grit/generated_resources.h"
42 #include "net/base/net_errors.h"
43 #include "net/base/net_util.h"
44 #include "net/http/failing_http_transaction_factory.h"
45 #include "net/http/http_cache.h"
46 #include "net/test/spawned_test_server/spawned_test_server.h"
47 #include "net/url_request/url_request_context.h"
48 #include "net/url_request/url_request_context_getter.h"
49 #include "net/url_request/url_request_filter.h"
50 #include "net/url_request/url_request_interceptor.h"
51 #include "net/url_request/url_request_job.h"
52 #include "net/url_request/url_request_test_job.h"
53 #include "net/url_request/url_request_test_util.h"
54 #include "ui/base/l10n/l10n_util.h"
55
56 using content::BrowserThread;
57 using content::NavigationController;
58 using content::URLRequestFailedJob;
59 using net::URLRequestTestJob;
60
61 namespace {
62
63 // Returns true if |text| is displayed on the page |browser| is currently
64 // displaying. Uses "innerText", so will miss hidden text, and whitespace
65 // space handling may be weird.
IsDisplayingText(Browser * browser,const std::string & text)66 bool WARN_UNUSED_RESULT IsDisplayingText(Browser* browser,
67 const std::string& text) {
68 std::string command = base::StringPrintf(
69 "var textContent = document.body.innerText;"
70 "var hasText = textContent.indexOf('%s') >= 0;"
71 "domAutomationController.send(hasText);",
72 text.c_str());
73 bool result = false;
74 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
75 browser->tab_strip_model()->GetActiveWebContents(), command, &result));
76 return result;
77 }
78
79 // Expands the more box on the currently displayed error page.
ToggleHelpBox(Browser * browser)80 void ToggleHelpBox(Browser* browser) {
81 EXPECT_TRUE(content::ExecuteScript(
82 browser->tab_strip_model()->GetActiveWebContents(),
83 "document.getElementById('more-less-button').click();"));
84 }
85
86 // Returns true if |browser| is displaying the text representation of
87 // |error_code| on the current page.
IsDisplayingNetError(Browser * browser,net::Error error_code)88 bool WARN_UNUSED_RESULT IsDisplayingNetError(Browser* browser,
89 net::Error error_code) {
90 // Get the error as a string, and remove the leading "net::", which is not
91 // included on error pages.
92 std::string error_string(net::ErrorToString(error_code));
93 DCHECK(StartsWithASCII(error_string, "net::", true));
94 error_string.erase(0, 5);
95
96 return IsDisplayingText(browser, error_string);
97 }
98
99 // Checks that the local error page is being displayed, without remotely
100 // retrieved navigation corrections, and with the specified error code.
ExpectDisplayingLocalErrorPage(Browser * browser,net::Error error_code)101 void ExpectDisplayingLocalErrorPage(Browser* browser, net::Error error_code) {
102 // Expand the help box so innerText will include text below the fold.
103 ToggleHelpBox(browser);
104
105 EXPECT_TRUE(IsDisplayingNetError(browser, error_code));
106
107 // Locally generated error pages should not have navigation corrections.
108 EXPECT_FALSE(IsDisplayingText(browser, "http://correction1/"));
109 EXPECT_FALSE(IsDisplayingText(browser, "http://correction2/"));
110
111 // Locally generated error pages should not have a populated search box.
112 bool search_box_populated = false;
113 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
114 browser->tab_strip_model()->GetActiveWebContents(),
115 "var searchText = document.getElementById('search-box').value;"
116 "domAutomationController.send(searchText == 'search query');",
117 &search_box_populated));
118 EXPECT_FALSE(search_box_populated);
119 }
120
121 // Checks that an error page with information retrieved from the navigation
122 // correction service is being displayed, with the specified specified error
123 // code.
ExpectDisplayingNavigationCorrections(Browser * browser,net::Error error_code)124 void ExpectDisplayingNavigationCorrections(Browser* browser,
125 net::Error error_code) {
126 // Expand the help box so innerText will include text below the fold.
127 ToggleHelpBox(browser);
128
129 EXPECT_TRUE(IsDisplayingNetError(browser, error_code));
130
131 // Check that the mock navigation corrections are displayed.
132 EXPECT_TRUE(IsDisplayingText(browser, "http://correction1/"));
133 EXPECT_TRUE(IsDisplayingText(browser, "http://correction2/"));
134
135 // Check that the search box is populated correctly.
136 bool search_box_populated = false;
137 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
138 browser->tab_strip_model()->GetActiveWebContents(),
139 "var searchText = document.getElementById('search-box').value;"
140 "domAutomationController.send(searchText == 'search query');",
141 &search_box_populated));
142 EXPECT_TRUE(search_box_populated);
143 }
144
GetLoadStaleButtonLabel()145 std::string GetLoadStaleButtonLabel() {
146 return l10n_util::GetStringUTF8(IDS_ERRORPAGES_BUTTON_LOAD_STALE);
147 }
148
AddInterceptorForURL(const GURL & url,scoped_ptr<net::URLRequestInterceptor> handler)149 void AddInterceptorForURL(
150 const GURL& url,
151 scoped_ptr<net::URLRequestInterceptor> handler) {
152 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
153 net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
154 url, handler.Pass());
155 }
156
157 // An interceptor that fails a configurable number of requests, then succeeds
158 // all requests after that, keeping count of failures and successes.
159 class FailFirstNRequestsInterceptor : public net::URLRequestInterceptor {
160 public:
FailFirstNRequestsInterceptor(int requests_to_fail)161 explicit FailFirstNRequestsInterceptor(int requests_to_fail)
162 : requests_(0), failures_(0), requests_to_fail_(requests_to_fail) {}
~FailFirstNRequestsInterceptor()163 virtual ~FailFirstNRequestsInterceptor() {}
164
165 // net::URLRequestInterceptor implementation
MaybeInterceptRequest(net::URLRequest * request,net::NetworkDelegate * network_delegate) const166 virtual net::URLRequestJob* MaybeInterceptRequest(
167 net::URLRequest* request,
168 net::NetworkDelegate* network_delegate) const OVERRIDE {
169 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
170 requests_++;
171 if (failures_ < requests_to_fail_) {
172 failures_++;
173 // Note: net::ERR_CONNECTION_RESET does not summon the Link Doctor; see
174 // NetErrorHelperCore::GetErrorPageURL.
175 return new URLRequestFailedJob(request,
176 network_delegate,
177 net::ERR_CONNECTION_RESET);
178 } else {
179 return new URLRequestTestJob(request, network_delegate,
180 URLRequestTestJob::test_headers(),
181 URLRequestTestJob::test_data_1(),
182 true);
183 }
184 }
185
requests() const186 int requests() const { return requests_; }
failures() const187 int failures() const { return failures_; }
188
189 private:
190 // These are mutable because MaybeCreateJob is const but we want this state
191 // for testing.
192 mutable int requests_;
193 mutable int failures_;
194 int requests_to_fail_;
195
196 DISALLOW_COPY_AND_ASSIGN(FailFirstNRequestsInterceptor);
197 };
198
199 // An interceptor that serves LinkDoctor responses. It also allows waiting
200 // until a certain number of requests have been sent.
201 // TODO(mmenke): Wait until responses have been received instead.
202 class LinkDoctorInterceptor : public net::URLRequestInterceptor {
203 public:
LinkDoctorInterceptor()204 LinkDoctorInterceptor() : num_requests_(0),
205 requests_to_wait_for_(-1),
206 weak_factory_(this) {
207 }
208
~LinkDoctorInterceptor()209 virtual ~LinkDoctorInterceptor() {}
210
211 // net::URLRequestInterceptor implementation
MaybeInterceptRequest(net::URLRequest * request,net::NetworkDelegate * network_delegate) const212 virtual net::URLRequestJob* MaybeInterceptRequest(
213 net::URLRequest* request,
214 net::NetworkDelegate* network_delegate) const OVERRIDE {
215 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
216
217 BrowserThread::PostTask(
218 BrowserThread::UI, FROM_HERE,
219 base::Bind(&LinkDoctorInterceptor::RequestCreated,
220 weak_factory_.GetWeakPtr()));
221
222 base::FilePath root_http;
223 PathService::Get(chrome::DIR_TEST_DATA, &root_http);
224 return new content::URLRequestMockHTTPJob(
225 request, network_delegate,
226 root_http.AppendASCII("mock-link-doctor.json"));
227 }
228
WaitForRequests(int requests_to_wait_for)229 void WaitForRequests(int requests_to_wait_for) {
230 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
231 DCHECK_EQ(-1, requests_to_wait_for_);
232 DCHECK(!run_loop_);
233
234 if (requests_to_wait_for >= num_requests_)
235 return;
236
237 requests_to_wait_for_ = requests_to_wait_for;
238 run_loop_.reset(new base::RunLoop());
239 run_loop_->Run();
240 run_loop_.reset();
241 requests_to_wait_for_ = -1;
242 EXPECT_EQ(num_requests_, requests_to_wait_for);
243 }
244
245 // It is up to the caller to wait until all relevant requests has been
246 // created, either through calling WaitForRequests or some other manner,
247 // before calling this method.
num_requests() const248 int num_requests() const {
249 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
250 return num_requests_;
251 }
252
253 private:
RequestCreated()254 void RequestCreated() {
255 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
256
257 num_requests_++;
258 if (num_requests_ == requests_to_wait_for_)
259 run_loop_->Quit();
260 }
261
262 // These are only used on the UI thread.
263 int num_requests_;
264 int requests_to_wait_for_;
265 scoped_ptr<base::RunLoop> run_loop_;
266
267 // This prevents any risk of flake if any test doesn't wait for a request
268 // it sent. Mutable so it can be accessed from a const function.
269 mutable base::WeakPtrFactory<LinkDoctorInterceptor> weak_factory_;
270
271 DISALLOW_COPY_AND_ASSIGN(LinkDoctorInterceptor);
272 };
273
InstallMockInterceptors(const GURL & search_url,scoped_ptr<net::URLRequestInterceptor> link_doctor_interceptor)274 void InstallMockInterceptors(
275 const GURL& search_url,
276 scoped_ptr<net::URLRequestInterceptor> link_doctor_interceptor) {
277 chrome_browser_net::SetUrlRequestMocksEnabled(true);
278
279 AddInterceptorForURL(google_util::LinkDoctorBaseURL(),
280 link_doctor_interceptor.Pass());
281
282 // Add a mock for the search engine the error page will use.
283 base::FilePath root_http;
284 PathService::Get(chrome::DIR_TEST_DATA, &root_http);
285 content::URLRequestMockHTTPJob::AddHostnameToFileHandler(
286 search_url.host(), root_http.AppendASCII("title3.html"));
287 }
288
289 class ErrorPageTest : public InProcessBrowserTest {
290 public:
291 enum HistoryNavigationDirection {
292 HISTORY_NAVIGATE_BACK,
293 HISTORY_NAVIGATE_FORWARD,
294 };
295
ErrorPageTest()296 ErrorPageTest() : link_doctor_interceptor_(NULL) {}
~ErrorPageTest()297 virtual ~ErrorPageTest() {}
298
299 // Navigates the active tab to a mock url created for the file at |file_path|.
300 // Needed for StaleCacheStatus and StaleCacheStatusFailedCorrections tests.
SetUpCommandLine(CommandLine * command_line)301 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
302 command_line->AppendSwitch(switches::kEnableOfflineLoadStaleCache);
303 }
304
305 // Navigates the active tab to a mock url created for the file at |file_path|.
NavigateToFileURL(const base::FilePath::StringType & file_path)306 void NavigateToFileURL(const base::FilePath::StringType& file_path) {
307 ui_test_utils::NavigateToURL(
308 browser(),
309 content::URLRequestMockHTTPJob::GetMockUrl(base::FilePath(file_path)));
310 }
311
312 // Navigates to the given URL and waits for |num_navigations| to occur, and
313 // the title to change to |expected_title|.
NavigateToURLAndWaitForTitle(const GURL & url,const std::string & expected_title,int num_navigations)314 void NavigateToURLAndWaitForTitle(const GURL& url,
315 const std::string& expected_title,
316 int num_navigations) {
317 content::TitleWatcher title_watcher(
318 browser()->tab_strip_model()->GetActiveWebContents(),
319 base::ASCIIToUTF16(expected_title));
320
321 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
322 browser(), url, num_navigations);
323
324 EXPECT_EQ(base::ASCIIToUTF16(expected_title),
325 title_watcher.WaitAndGetTitle());
326 }
327
328 // Navigates back in the history and waits for |num_navigations| to occur, and
329 // the title to change to |expected_title|.
GoBackAndWaitForTitle(const std::string & expected_title,int num_navigations)330 void GoBackAndWaitForTitle(const std::string& expected_title,
331 int num_navigations) {
332 NavigateHistoryAndWaitForTitle(expected_title,
333 num_navigations,
334 HISTORY_NAVIGATE_BACK);
335 }
336
337 // Navigates forward in the history and waits for |num_navigations| to occur,
338 // and the title to change to |expected_title|.
GoForwardAndWaitForTitle(const std::string & expected_title,int num_navigations)339 void GoForwardAndWaitForTitle(const std::string& expected_title,
340 int num_navigations) {
341 NavigateHistoryAndWaitForTitle(expected_title,
342 num_navigations,
343 HISTORY_NAVIGATE_FORWARD);
344 }
345
GoBackAndWaitForNavigations(int num_navigations)346 void GoBackAndWaitForNavigations(int num_navigations) {
347 NavigateHistory(num_navigations, HISTORY_NAVIGATE_BACK);
348 }
349
GoForwardAndWaitForNavigations(int num_navigations)350 void GoForwardAndWaitForNavigations(int num_navigations) {
351 NavigateHistory(num_navigations, HISTORY_NAVIGATE_FORWARD);
352 }
353
354 // Confirms that the javascript variable indicating whether or not we have
355 // a stale copy in the cache has been set to |expected|, and that the
356 // stale load button is or isn't there based on the same expectation.
ProbeStaleCopyValue(bool expected)357 testing::AssertionResult ProbeStaleCopyValue(bool expected) {
358 const char* js_cache_probe =
359 "try {\n"
360 " domAutomationController.send(\n"
361 " 'staleLoadButton' in templateData ? 'yes' : 'no');\n"
362 "} catch (e) {\n"
363 " domAutomationController.send(e.message);\n"
364 "}\n";
365
366 std::string result;
367 bool ret =
368 content::ExecuteScriptAndExtractString(
369 browser()->tab_strip_model()->GetActiveWebContents(),
370 js_cache_probe,
371 &result);
372 if (!ret) {
373 return testing::AssertionFailure()
374 << "Failing return from ExecuteScriptAndExtractString.";
375 }
376
377 if ((expected && "yes" == result) || (!expected && "no" == result))
378 return testing::AssertionSuccess();
379
380 return testing::AssertionFailure() << "Cache probe result is " << result;
381 }
382
ReloadStaleCopyFromCache()383 testing::AssertionResult ReloadStaleCopyFromCache() {
384 const char* js_reload_script =
385 "try {\n"
386 " document.getElementById('stale-load-button').click();\n"
387 " domAutomationController.send('success');\n"
388 "} catch (e) {\n"
389 " domAutomationController.send(e.message);\n"
390 "}\n";
391
392 std::string result;
393 bool ret = content::ExecuteScriptAndExtractString(
394 browser()->tab_strip_model()->GetActiveWebContents(),
395 js_reload_script,
396 &result);
397 EXPECT_TRUE(ret);
398 if (!ret)
399 return testing::AssertionFailure();
400 return ("success" == result ? testing::AssertionSuccess() :
401 (testing::AssertionFailure() << "Exception message is " << result));
402 }
403
link_doctor_interceptor()404 LinkDoctorInterceptor* link_doctor_interceptor() {
405 return link_doctor_interceptor_;
406 }
407
408 protected:
SetUpOnMainThread()409 virtual void SetUpOnMainThread() OVERRIDE {
410 link_doctor_interceptor_ = new LinkDoctorInterceptor();
411 scoped_ptr<net::URLRequestInterceptor> owned_interceptor(
412 link_doctor_interceptor_);
413 // Ownership of the |interceptor_| is passed to an object the IO thread, but
414 // a pointer is kept in the test fixture. As soon as anything calls
415 // URLRequestFilter::ClearHandlers(), |interceptor_| can become invalid.
416 BrowserThread::PostTask(
417 BrowserThread::IO, FROM_HERE,
418 base::Bind(&InstallMockInterceptors,
419 google_util::GetGoogleSearchURL(
420 google_profile_helper::GetGoogleHomePageURL(
421 browser()->profile())),
422 base::Passed(&owned_interceptor)));
423 }
424
425 // Returns a GURL that results in a DNS error.
GetDnsErrorURL() const426 GURL GetDnsErrorURL() const {
427 return URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED);
428 }
429
430 private:
431 // Navigates the browser the indicated direction in the history and waits for
432 // |num_navigations| to occur and the title to change to |expected_title|.
NavigateHistoryAndWaitForTitle(const std::string & expected_title,int num_navigations,HistoryNavigationDirection direction)433 void NavigateHistoryAndWaitForTitle(const std::string& expected_title,
434 int num_navigations,
435 HistoryNavigationDirection direction) {
436 content::TitleWatcher title_watcher(
437 browser()->tab_strip_model()->GetActiveWebContents(),
438 base::ASCIIToUTF16(expected_title));
439
440 NavigateHistory(num_navigations, direction);
441
442 EXPECT_EQ(title_watcher.WaitAndGetTitle(),
443 base::ASCIIToUTF16(expected_title));
444 }
445
NavigateHistory(int num_navigations,HistoryNavigationDirection direction)446 void NavigateHistory(int num_navigations,
447 HistoryNavigationDirection direction) {
448 content::TestNavigationObserver test_navigation_observer(
449 browser()->tab_strip_model()->GetActiveWebContents(),
450 num_navigations);
451 if (direction == HISTORY_NAVIGATE_BACK) {
452 chrome::GoBack(browser(), CURRENT_TAB);
453 } else if (direction == HISTORY_NAVIGATE_FORWARD) {
454 chrome::GoForward(browser(), CURRENT_TAB);
455 } else {
456 FAIL();
457 }
458 test_navigation_observer.Wait();
459 }
460
461 LinkDoctorInterceptor* link_doctor_interceptor_;
462 };
463
464 class TestFailProvisionalLoadObserver : public content::WebContentsObserver {
465 public:
TestFailProvisionalLoadObserver(content::WebContents * contents)466 explicit TestFailProvisionalLoadObserver(content::WebContents* contents)
467 : content::WebContentsObserver(contents) {}
~TestFailProvisionalLoadObserver()468 virtual ~TestFailProvisionalLoadObserver() {}
469
470 // This method is invoked when the provisional load failed.
DidFailProvisionalLoad(int64 frame_id,const base::string16 & frame_unique_name,bool is_main_frame,const GURL & validated_url,int error_code,const base::string16 & error_description,content::RenderViewHost * render_view_host)471 virtual void DidFailProvisionalLoad(
472 int64 frame_id,
473 const base::string16& frame_unique_name,
474 bool is_main_frame,
475 const GURL& validated_url,
476 int error_code,
477 const base::string16& error_description,
478 content::RenderViewHost* render_view_host) OVERRIDE {
479 fail_url_ = validated_url;
480 }
481
fail_url() const482 const GURL& fail_url() const { return fail_url_; }
483
484 private:
485 GURL fail_url_;
486
487 DISALLOW_COPY_AND_ASSIGN(TestFailProvisionalLoadObserver);
488 };
489
InterceptNetworkTransactions(net::URLRequestContextGetter * getter,net::Error error)490 void InterceptNetworkTransactions(net::URLRequestContextGetter* getter,
491 net::Error error) {
492 DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::IO));
493 net::HttpCache* cache(
494 getter->GetURLRequestContext()->http_transaction_factory()->GetCache());
495 DCHECK(cache);
496 scoped_ptr<net::HttpTransactionFactory> factory(
497 new net::FailingHttpTransactionFactory(cache->GetSession(), error));
498 // Throw away old version; since this is a a browser test, we don't
499 // need to restore the old state.
500 cache->SetHttpNetworkTransactionFactoryForTesting(factory.Pass());
501 }
502
503 // Test that a DNS error occuring in the main frame redirects to an error page.
IN_PROC_BROWSER_TEST_F(ErrorPageTest,DNSError_Basic)504 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_Basic) {
505 // The first navigation should fail, and the second one should be the error
506 // page.
507 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
508 browser(), GetDnsErrorURL(), 2);
509 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
510 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
511 }
512
513 // Test that a DNS error occuring in the main frame does not result in an
514 // additional session history entry.
IN_PROC_BROWSER_TEST_F(ErrorPageTest,DNSError_GoBack1)515 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack1) {
516 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
517 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
518 browser(), GetDnsErrorURL(), 2);
519 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
520 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
521 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
522 }
523
524 // Test that a DNS error occuring in the main frame does not result in an
525 // additional session history entry.
IN_PROC_BROWSER_TEST_F(ErrorPageTest,DNSError_GoBack2)526 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack2) {
527 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
528
529 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
530 browser(), GetDnsErrorURL(), 2);
531 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
532 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
533
534 NavigateToFileURL(FILE_PATH_LITERAL("title3.html"));
535
536 GoBackAndWaitForNavigations(2);
537 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
538 EXPECT_EQ(2, link_doctor_interceptor()->num_requests());
539
540 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
541 EXPECT_EQ(2, link_doctor_interceptor()->num_requests());
542 }
543
544 // Test that a DNS error occuring in the main frame does not result in an
545 // additional session history entry.
IN_PROC_BROWSER_TEST_F(ErrorPageTest,DNSError_GoBack2AndForward)546 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack2AndForward) {
547 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
548
549 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
550 browser(), GetDnsErrorURL(), 2);
551 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
552 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
553
554 NavigateToFileURL(FILE_PATH_LITERAL("title3.html"));
555
556 GoBackAndWaitForNavigations(2);
557 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
558 EXPECT_EQ(2, link_doctor_interceptor()->num_requests());
559
560 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
561
562 GoForwardAndWaitForNavigations(2);
563 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
564 EXPECT_EQ(3, link_doctor_interceptor()->num_requests());
565 }
566
567 // Test that a DNS error occuring in the main frame does not result in an
568 // additional session history entry.
IN_PROC_BROWSER_TEST_F(ErrorPageTest,DNSError_GoBack2Forward2)569 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_GoBack2Forward2) {
570 NavigateToFileURL(FILE_PATH_LITERAL("title3.html"));
571
572 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
573 browser(), GetDnsErrorURL(), 2);
574 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
575 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
576
577 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
578
579 GoBackAndWaitForNavigations(2);
580 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
581 EXPECT_EQ(2, link_doctor_interceptor()->num_requests());
582
583 GoBackAndWaitForTitle("Title Of More Awesomeness", 1);
584
585 GoForwardAndWaitForNavigations(2);
586 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
587 EXPECT_EQ(3, link_doctor_interceptor()->num_requests());
588
589 GoForwardAndWaitForTitle("Title Of Awesomeness", 1);
590 EXPECT_EQ(3, link_doctor_interceptor()->num_requests());
591 }
592
593 // Test that the search button on a DNS error page works.
IN_PROC_BROWSER_TEST_F(ErrorPageTest,DNSError_DoSearch)594 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_DoSearch) {
595 // The first navigation should fail, and the second one should be the error
596 // page.
597 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
598 browser(), GetDnsErrorURL(), 2);
599 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
600 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
601
602 content::WebContents* web_contents =
603 browser()->tab_strip_model()->GetActiveWebContents();
604
605 // Do a search and make sure the browser ends up at the right page.
606 content::TestNavigationObserver nav_observer(web_contents, 1);
607 content::TitleWatcher title_watcher(
608 web_contents,
609 base::ASCIIToUTF16("Title Of More Awesomeness"));
610 // Can't use content::ExecuteScript because it waits for scripts to send
611 // notification that they've run, and scripts that trigger a navigation may
612 // not send that notification.
613 web_contents->GetMainFrame()->ExecuteJavaScript(
614 base::ASCIIToUTF16("document.getElementById('search-button').click();"));
615 nav_observer.Wait();
616 EXPECT_EQ(base::ASCIIToUTF16("Title Of More Awesomeness"),
617 title_watcher.WaitAndGetTitle());
618
619 // There should have been another Link Doctor request, for tracking purposes.
620 // Have to wait for it, since the search page does not depend on having
621 // sent the tracking request.
622 link_doctor_interceptor()->WaitForRequests(2);
623 EXPECT_EQ(2, link_doctor_interceptor()->num_requests());
624
625 // Check the path and query string.
626 std::string url;
627 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
628 browser()->tab_strip_model()->GetActiveWebContents(),
629 "domAutomationController.send(window.location.href);",
630 &url));
631 EXPECT_EQ("/search", GURL(url).path());
632 EXPECT_EQ("q=search%20query", GURL(url).query());
633
634 // Go back to the error page, to make sure the history is correct.
635 GoBackAndWaitForNavigations(2);
636 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
637 EXPECT_EQ(3, link_doctor_interceptor()->num_requests());
638 }
639
640 // Test that the reload button on a DNS error page works.
IN_PROC_BROWSER_TEST_F(ErrorPageTest,DNSError_DoReload)641 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_DoReload) {
642 // The first navigation should fail, and the second one should be the error
643 // page.
644 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
645 browser(), GetDnsErrorURL(), 2);
646 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
647 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
648
649 content::WebContents* web_contents =
650 browser()->tab_strip_model()->GetActiveWebContents();
651
652 // Clicking the reload button should load the error page again, and there
653 // should be two commits, as before.
654 content::TestNavigationObserver nav_observer(web_contents, 2);
655 // Can't use content::ExecuteScript because it waits for scripts to send
656 // notification that they've run, and scripts that trigger a navigation may
657 // not send that notification.
658 web_contents->GetMainFrame()->ExecuteJavaScript(
659 base::ASCIIToUTF16("document.getElementById('reload-button').click();"));
660 nav_observer.Wait();
661 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
662
663 // There should have two more requests to the correction service: One for the
664 // new error page, and one for tracking purposes. Have to make sure to wait
665 // for the tracking request, since the new error page does not depend on it.
666 link_doctor_interceptor()->WaitForRequests(3);
667 EXPECT_EQ(3, link_doctor_interceptor()->num_requests());
668 }
669
670 // Test that clicking links on a DNS error page works.
IN_PROC_BROWSER_TEST_F(ErrorPageTest,DNSError_DoClickLink)671 IN_PROC_BROWSER_TEST_F(ErrorPageTest, DNSError_DoClickLink) {
672 // The first navigation should fail, and the second one should be the error
673 // page.
674 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
675 browser(), GetDnsErrorURL(), 2);
676 ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED);
677 EXPECT_EQ(1, link_doctor_interceptor()->num_requests());
678
679 content::WebContents* web_contents =
680 browser()->tab_strip_model()->GetActiveWebContents();
681
682 // Simulate a click on a link.
683
684 content::TitleWatcher title_watcher(
685 web_contents,
686 base::ASCIIToUTF16("Title Of Awesomeness"));
687 std::string link_selector =
688 "document.querySelector('a[href=\"http://mock.http/title2.html\"]')";
689 // The tracking request is triggered by onmousedown, so it catches middle
690 // mouse button clicks, as well as left clicks.
691 web_contents->GetMainFrame()->ExecuteJavaScript(
692 base::ASCIIToUTF16(link_selector + ".onmousedown();"));
693 // Can't use content::ExecuteScript because it waits for scripts to send
694 // notification that they've run, and scripts that trigger a navigation may
695 // not send that notification.
696 web_contents->GetMainFrame()->ExecuteJavaScript(
697 base::ASCIIToUTF16(link_selector + ".click();"));
698 EXPECT_EQ(base::ASCIIToUTF16("Title Of Awesomeness"),
699 title_watcher.WaitAndGetTitle());
700
701 // There should have been a tracking request to the correction service. Have
702 // to make sure to wait the tracking request, since the new page does not
703 // depend on it.
704 link_doctor_interceptor()->WaitForRequests(2);
705 EXPECT_EQ(2, link_doctor_interceptor()->num_requests());
706 }
707
708 // Test that a DNS error occuring in an iframe does not result in showing
709 // navigation corrections.
IN_PROC_BROWSER_TEST_F(ErrorPageTest,IFrameDNSError_Basic)710 IN_PROC_BROWSER_TEST_F(ErrorPageTest, IFrameDNSError_Basic) {
711 NavigateToURLAndWaitForTitle(
712 content::URLRequestMockHTTPJob::GetMockUrl(
713 base::FilePath(FILE_PATH_LITERAL("iframe_dns_error.html"))),
714 "Blah",
715 1);
716 // We expect to have two history entries, since we started off with navigation
717 // to "about:blank" and then navigated to "iframe_dns_error.html".
718 EXPECT_EQ(2,
719 browser()->tab_strip_model()->GetActiveWebContents()->
720 GetController().GetEntryCount());
721 EXPECT_EQ(0, link_doctor_interceptor()->num_requests());
722 }
723
724 // This test fails regularly on win_rel trybots. See crbug.com/121540
725 #if defined(OS_WIN)
726 #define MAYBE_IFrameDNSError_GoBack DISABLED_IFrameDNSError_GoBack
727 #else
728 #define MAYBE_IFrameDNSError_GoBack IFrameDNSError_GoBack
729 #endif
730 // Test that a DNS error occuring in an iframe does not result in an
731 // additional session history entry.
IN_PROC_BROWSER_TEST_F(ErrorPageTest,MAYBE_IFrameDNSError_GoBack)732 IN_PROC_BROWSER_TEST_F(ErrorPageTest, MAYBE_IFrameDNSError_GoBack) {
733 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
734 NavigateToFileURL(FILE_PATH_LITERAL("iframe_dns_error.html"));
735 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
736 EXPECT_EQ(0, link_doctor_interceptor()->num_requests());
737 }
738
739 // This test fails regularly on win_rel trybots. See crbug.com/121540
740 //
741 // This fails on linux_aura bringup: http://crbug.com/163931
742 #if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA))
743 #define MAYBE_IFrameDNSError_GoBackAndForward DISABLED_IFrameDNSError_GoBackAndForward
744 #else
745 #define MAYBE_IFrameDNSError_GoBackAndForward IFrameDNSError_GoBackAndForward
746 #endif
747 // Test that a DNS error occuring in an iframe does not result in an
748 // additional session history entry.
IN_PROC_BROWSER_TEST_F(ErrorPageTest,MAYBE_IFrameDNSError_GoBackAndForward)749 IN_PROC_BROWSER_TEST_F(ErrorPageTest, MAYBE_IFrameDNSError_GoBackAndForward) {
750 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
751 NavigateToFileURL(FILE_PATH_LITERAL("iframe_dns_error.html"));
752 GoBackAndWaitForTitle("Title Of Awesomeness", 1);
753 GoForwardAndWaitForTitle("Blah", 1);
754 EXPECT_EQ(0, link_doctor_interceptor()->num_requests());
755 }
756
757 // Test that a DNS error occuring in an iframe, once the main document is
758 // completed loading, does not result in an additional session history entry.
759 // To ensure that the main document has completed loading, JavaScript is used to
760 // inject an iframe after loading is done.
IN_PROC_BROWSER_TEST_F(ErrorPageTest,IFrameDNSError_JavaScript)761 IN_PROC_BROWSER_TEST_F(ErrorPageTest, IFrameDNSError_JavaScript) {
762 content::WebContents* wc =
763 browser()->tab_strip_model()->GetActiveWebContents();
764 GURL fail_url =
765 URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED);
766
767 // Load a regular web page, in which we will inject an iframe.
768 NavigateToFileURL(FILE_PATH_LITERAL("title2.html"));
769
770 // We expect to have two history entries, since we started off with navigation
771 // to "about:blank" and then navigated to "title2.html".
772 EXPECT_EQ(2, wc->GetController().GetEntryCount());
773
774 std::string script = "var frame = document.createElement('iframe');"
775 "frame.src = '" + fail_url.spec() + "';"
776 "document.body.appendChild(frame);";
777 {
778 TestFailProvisionalLoadObserver fail_observer(wc);
779 content::WindowedNotificationObserver load_observer(
780 content::NOTIFICATION_LOAD_STOP,
781 content::Source<NavigationController>(&wc->GetController()));
782 wc->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(script));
783 load_observer.Wait();
784
785 // Ensure we saw the expected failure.
786 EXPECT_EQ(fail_url, fail_observer.fail_url());
787
788 // Failed initial navigation of an iframe shouldn't be adding any history
789 // entries.
790 EXPECT_EQ(2, wc->GetController().GetEntryCount());
791 }
792
793 // Do the same test, but with an iframe that doesn't have initial URL
794 // assigned.
795 script = "var frame = document.createElement('iframe');"
796 "frame.id = 'target_frame';"
797 "document.body.appendChild(frame);";
798 {
799 content::WindowedNotificationObserver load_observer(
800 content::NOTIFICATION_LOAD_STOP,
801 content::Source<NavigationController>(&wc->GetController()));
802 wc->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(script));
803 load_observer.Wait();
804 }
805
806 script = "var f = document.getElementById('target_frame');"
807 "f.src = '" + fail_url.spec() + "';";
808 {
809 TestFailProvisionalLoadObserver fail_observer(wc);
810 content::WindowedNotificationObserver load_observer(
811 content::NOTIFICATION_LOAD_STOP,
812 content::Source<NavigationController>(&wc->GetController()));
813 wc->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(script));
814 load_observer.Wait();
815
816 EXPECT_EQ(fail_url, fail_observer.fail_url());
817 EXPECT_EQ(2, wc->GetController().GetEntryCount());
818 }
819 EXPECT_EQ(0, link_doctor_interceptor()->num_requests());
820 }
821
822 // Checks that navigation corrections are not loaded when we receive an actual
823 // 404 page.
IN_PROC_BROWSER_TEST_F(ErrorPageTest,Page404)824 IN_PROC_BROWSER_TEST_F(ErrorPageTest, Page404) {
825 NavigateToURLAndWaitForTitle(
826 content::URLRequestMockHTTPJob::GetMockUrl(
827 base::FilePath(FILE_PATH_LITERAL("page404.html"))),
828 "SUCCESS",
829 1);
830 EXPECT_EQ(0, link_doctor_interceptor()->num_requests());
831 }
832
833 // Checks that when an error occurs, the stale cache status of the page
834 // is correctly transferred, and that stale cached copied can be loaded
835 // from the javascript.
IN_PROC_BROWSER_TEST_F(ErrorPageTest,StaleCacheStatus)836 IN_PROC_BROWSER_TEST_F(ErrorPageTest, StaleCacheStatus) {
837 ASSERT_TRUE(test_server()->Start());
838 // Load cache with entry with "nocache" set, to create stale
839 // cache.
840 GURL test_url(test_server()->GetURL("files/nocache.html"));
841 NavigateToURLAndWaitForTitle(test_url, "Nocache Test Page", 1);
842
843 // Reload same URL after forcing an error from the the network layer;
844 // confirm that the error page is told the cached copy exists.
845 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter =
846 browser()->profile()->GetRequestContext();
847 BrowserThread::PostTask(
848 BrowserThread::IO, FROM_HERE,
849 base::Bind(&InterceptNetworkTransactions, url_request_context_getter,
850 net::ERR_FAILED));
851
852 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
853 // With no navigation corrections to load, there's only one navigation.
854 browser(), test_url, 1);
855 EXPECT_TRUE(ProbeStaleCopyValue(true));
856 EXPECT_TRUE(IsDisplayingText(browser(), GetLoadStaleButtonLabel()));
857 EXPECT_NE(base::ASCIIToUTF16("Nocache Test Page"),
858 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
859
860 // Confirm that loading the stale copy from the cache works.
861 content::TestNavigationObserver same_tab_observer(
862 browser()->tab_strip_model()->GetActiveWebContents(), 1);
863 ASSERT_TRUE(ReloadStaleCopyFromCache());
864 same_tab_observer.Wait();
865 EXPECT_EQ(base::ASCIIToUTF16("Nocache Test Page"),
866 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
867
868 // Clear the cache and reload the same URL; confirm the error page is told
869 // that there is no cached copy.
870 BrowsingDataRemover* remover =
871 BrowsingDataRemover::CreateForUnboundedRange(browser()->profile());
872 remover->Remove(BrowsingDataRemover::REMOVE_CACHE,
873 BrowsingDataHelper::UNPROTECTED_WEB);
874 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
875 browser(), test_url, 1);
876 EXPECT_TRUE(ProbeStaleCopyValue(false));
877 EXPECT_FALSE(IsDisplayingText(browser(), GetLoadStaleButtonLabel()));
878 EXPECT_EQ(0, link_doctor_interceptor()->num_requests());
879 }
880
881 class ErrorPageAutoReloadTest : public InProcessBrowserTest {
882 public:
SetUpCommandLine(CommandLine * command_line)883 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
884 command_line->AppendSwitch(switches::kEnableOfflineAutoReload);
885 }
886
InstallInterceptor(const GURL & url,int requests_to_fail)887 void InstallInterceptor(const GURL& url, int requests_to_fail) {
888 interceptor_ = new FailFirstNRequestsInterceptor(requests_to_fail);
889 scoped_ptr<net::URLRequestInterceptor> owned_interceptor(interceptor_);
890
891 // Tests don't need to wait for this task to complete before using the
892 // filter; any requests that might be affected by it will end up in the IO
893 // thread's message loop after this posted task anyway.
894 //
895 // Ownership of the interceptor is passed to an object the IO thread, but a
896 // pointer is kept in the test fixture. As soon as anything calls
897 // URLRequestFilter::ClearHandlers(), |interceptor_| can become invalid.
898 BrowserThread::PostTask(
899 BrowserThread::IO, FROM_HERE,
900 base::Bind(&AddInterceptorForURL, url,
901 base::Passed(&owned_interceptor)));
902 }
903
NavigateToURLAndWaitForTitle(const GURL & url,const std::string & expected_title,int num_navigations)904 void NavigateToURLAndWaitForTitle(const GURL& url,
905 const std::string& expected_title,
906 int num_navigations) {
907 content::TitleWatcher title_watcher(
908 browser()->tab_strip_model()->GetActiveWebContents(),
909 base::ASCIIToUTF16(expected_title));
910
911 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
912 browser(), url, num_navigations);
913
914 EXPECT_EQ(base::ASCIIToUTF16(expected_title),
915 title_watcher.WaitAndGetTitle());
916 }
917
interceptor()918 FailFirstNRequestsInterceptor* interceptor() {
919 return interceptor_;
920 }
921
922 private:
923 FailFirstNRequestsInterceptor* interceptor_;
924 };
925
IN_PROC_BROWSER_TEST_F(ErrorPageAutoReloadTest,AutoReload)926 IN_PROC_BROWSER_TEST_F(ErrorPageAutoReloadTest, AutoReload) {
927 GURL test_url("http://error.page.auto.reload");
928 const int kRequestsToFail = 2;
929 InstallInterceptor(test_url, kRequestsToFail);
930 NavigateToURLAndWaitForTitle(test_url, "Test One", kRequestsToFail + 1);
931 // Note that the interceptor updates these variables on the IO thread,
932 // but this function reads them on the main thread. The requests have to be
933 // created (on the IO thread) before NavigateToURLAndWaitForTitle returns or
934 // this becomes racey.
935 EXPECT_EQ(kRequestsToFail, interceptor()->failures());
936 EXPECT_EQ(kRequestsToFail + 1, interceptor()->requests());
937 }
938
939 // Interceptor that fails all requests with net::ERR_ADDRESS_UNREACHABLE.
940 class AddressUnreachableInterceptor : public net::URLRequestInterceptor {
941 public:
AddressUnreachableInterceptor()942 AddressUnreachableInterceptor() {}
~AddressUnreachableInterceptor()943 virtual ~AddressUnreachableInterceptor() {}
944
945 // net::URLRequestInterceptor:
MaybeInterceptRequest(net::URLRequest * request,net::NetworkDelegate * network_delegate) const946 virtual net::URLRequestJob* MaybeInterceptRequest(
947 net::URLRequest* request,
948 net::NetworkDelegate* network_delegate) const OVERRIDE {
949 return new URLRequestFailedJob(request,
950 network_delegate,
951 net::ERR_ADDRESS_UNREACHABLE);
952 }
953
954 private:
955 DISALLOW_COPY_AND_ASSIGN(AddressUnreachableInterceptor);
956 };
957
958 // A test fixture that returns ERR_ADDRESS_UNREACHABLE for all navigation
959 // correction requests. ERR_NAME_NOT_RESOLVED is more typical, but need to use
960 // a different error for the correction service and the original page to
961 // validate the right page is being displayed.
962 class ErrorPageNavigationCorrectionsFailTest : public ErrorPageTest {
963 public:
964 // InProcessBrowserTest:
SetUpOnMainThread()965 virtual void SetUpOnMainThread() OVERRIDE {
966 BrowserThread::PostTask(
967 BrowserThread::IO, FROM_HERE,
968 base::Bind(&ErrorPageNavigationCorrectionsFailTest::AddFilters));
969 }
970
CleanUpOnMainThread()971 virtual void CleanUpOnMainThread() OVERRIDE {
972 BrowserThread::PostTask(
973 BrowserThread::IO, FROM_HERE,
974 base::Bind(&ErrorPageNavigationCorrectionsFailTest::RemoveFilters));
975 }
976
977 private:
978 // Adds a filter that causes all correction service requests to fail with
979 // ERR_ADDRESS_UNREACHABLE.
980 //
981 // Also adds the content::URLRequestFailedJob filter.
AddFilters()982 static void AddFilters() {
983 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
984 content::URLRequestFailedJob::AddUrlHandler();
985
986 net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
987 google_util::LinkDoctorBaseURL(),
988 scoped_ptr<net::URLRequestInterceptor>(
989 new AddressUnreachableInterceptor()));
990 }
991
RemoveFilters()992 static void RemoveFilters() {
993 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
994 net::URLRequestFilter::GetInstance()->ClearHandlers();
995 }
996 };
997
998 // Make sure that when corrections fail to load, the network error page is
999 // successfully loaded.
IN_PROC_BROWSER_TEST_F(ErrorPageNavigationCorrectionsFailTest,FetchCorrectionsFails)1000 IN_PROC_BROWSER_TEST_F(ErrorPageNavigationCorrectionsFailTest,
1001 FetchCorrectionsFails) {
1002 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
1003 browser(),
1004 URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED),
1005 2);
1006
1007 // Verify that the expected error page is being displayed.
1008 ExpectDisplayingLocalErrorPage(browser(), net::ERR_NAME_NOT_RESOLVED);
1009 }
1010
1011 // Checks that when an error occurs and a corrections fail to load, the stale
1012 // cache status of the page is correctly transferred, and we can load the
1013 // stale copy from the javascript. Most logic copied from StaleCacheStatus
1014 // above.
IN_PROC_BROWSER_TEST_F(ErrorPageNavigationCorrectionsFailTest,StaleCacheStatusFailedCorrections)1015 IN_PROC_BROWSER_TEST_F(ErrorPageNavigationCorrectionsFailTest,
1016 StaleCacheStatusFailedCorrections) {
1017 ASSERT_TRUE(test_server()->Start());
1018 // Load cache with entry with "nocache" set, to create stale
1019 // cache.
1020 GURL test_url(test_server()->GetURL("files/nocache.html"));
1021 NavigateToURLAndWaitForTitle(test_url, "Nocache Test Page", 1);
1022
1023 // Reload same URL after forcing an error from the the network layer;
1024 // confirm that the error page is told the cached copy exists.
1025 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter =
1026 browser()->profile()->GetRequestContext();
1027 BrowserThread::PostTask(
1028 BrowserThread::IO, FROM_HERE,
1029 base::Bind(&InterceptNetworkTransactions, url_request_context_getter,
1030 net::ERR_CONNECTION_FAILED));
1031
1032 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
1033 browser(), test_url, 2);
1034 EXPECT_TRUE(IsDisplayingText(browser(), GetLoadStaleButtonLabel()));
1035 EXPECT_TRUE(ProbeStaleCopyValue(true));
1036
1037 // Confirm that loading the stale copy from the cache works.
1038 content::TestNavigationObserver same_tab_observer(
1039 browser()->tab_strip_model()->GetActiveWebContents(), 1);
1040 ASSERT_TRUE(ReloadStaleCopyFromCache());
1041 same_tab_observer.Wait();
1042 EXPECT_EQ(base::ASCIIToUTF16("Nocache Test Page"),
1043 browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
1044
1045 // Clear the cache and reload the same URL; confirm the error page is told
1046 // that there is no cached copy.
1047 BrowsingDataRemover* remover =
1048 BrowsingDataRemover::CreateForUnboundedRange(browser()->profile());
1049 remover->Remove(BrowsingDataRemover::REMOVE_CACHE,
1050 BrowsingDataHelper::UNPROTECTED_WEB);
1051 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
1052 browser(), test_url, 2);
1053 EXPECT_TRUE(ProbeStaleCopyValue(false));
1054 EXPECT_FALSE(IsDisplayingText(browser(), GetLoadStaleButtonLabel()));
1055 }
1056
1057 // A test fixture that simulates failing requests for an IDN domain name.
1058 class ErrorPageForIDNTest : public InProcessBrowserTest {
1059 public:
1060 // Target hostname in different forms.
1061 static const char kHostname[];
1062 static const char kHostnameJSUnicode[];
1063
1064 // InProcessBrowserTest:
SetUpOnMainThread()1065 virtual void SetUpOnMainThread() OVERRIDE {
1066 // Clear AcceptLanguages to force punycode decoding.
1067 browser()->profile()->GetPrefs()->SetString(prefs::kAcceptLanguages,
1068 std::string());
1069 BrowserThread::PostTask(
1070 BrowserThread::IO, FROM_HERE,
1071 base::Bind(&ErrorPageForIDNTest::AddFilters));
1072 }
1073
CleanUpOnMainThread()1074 virtual void CleanUpOnMainThread() OVERRIDE {
1075 BrowserThread::PostTask(
1076 BrowserThread::IO, FROM_HERE,
1077 base::Bind(&ErrorPageForIDNTest::RemoveFilters));
1078 }
1079
1080 private:
AddFilters()1081 static void AddFilters() {
1082 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1083 content::URLRequestFailedJob::AddUrlHandlerForHostname(kHostname);
1084 }
1085
RemoveFilters()1086 static void RemoveFilters() {
1087 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1088 net::URLRequestFilter::GetInstance()->ClearHandlers();
1089 }
1090 };
1091
1092 const char ErrorPageForIDNTest::kHostname[] =
1093 "xn--d1abbgf6aiiy.xn--p1ai";
1094 const char ErrorPageForIDNTest::kHostnameJSUnicode[] =
1095 "\\u043f\\u0440\\u0435\\u0437\\u0438\\u0434\\u0435\\u043d\\u0442."
1096 "\\u0440\\u0444";
1097
1098 // Make sure error page shows correct unicode for IDN.
IN_PROC_BROWSER_TEST_F(ErrorPageForIDNTest,IDN)1099 IN_PROC_BROWSER_TEST_F(ErrorPageForIDNTest, IDN) {
1100 // ERR_UNSAFE_PORT will not trigger navigation corrections.
1101 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
1102 browser(),
1103 URLRequestFailedJob::GetMockHttpUrlForHostname(net::ERR_UNSAFE_PORT,
1104 kHostname),
1105 1);
1106
1107 ToggleHelpBox(browser());
1108 EXPECT_TRUE(IsDisplayingText(browser(), kHostnameJSUnicode));
1109 }
1110
1111 } // namespace
1112