Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / captive_portal / captive_portal_browsertest.cc
blob72fe2bf7b665ec2e384d736a057bdc899c56a846
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 <map>
6 #include <set>
7 #include <string>
8 #include <vector>
10 #include "base/basictypes.h"
11 #include "base/bind.h"
12 #include "base/command_line.h"
13 #include "base/compiler_specific.h"
14 #include "base/files/file_path.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/message_loop/message_loop.h"
17 #include "base/path_service.h"
18 #include "base/prefs/pref_service.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "base/values.h"
21 #include "chrome/browser/captive_portal/captive_portal_service.h"
22 #include "chrome/browser/captive_portal/captive_portal_service_factory.h"
23 #include "chrome/browser/captive_portal/captive_portal_tab_helper.h"
24 #include "chrome/browser/captive_portal/captive_portal_tab_reloader.h"
25 #include "chrome/browser/chrome_notification_types.h"
26 #include "chrome/browser/interstitials/security_interstitial_page.h"
27 #include "chrome/browser/net/url_request_mock_util.h"
28 #include "chrome/browser/profiles/profile.h"
29 #include "chrome/browser/ssl/captive_portal_blocking_page.h"
30 #include "chrome/browser/ssl/ssl_blocking_page.h"
31 #include "chrome/browser/ssl/ssl_error_handler.h"
32 #include "chrome/browser/ui/browser.h"
33 #include "chrome/browser/ui/browser_commands.h"
34 #include "chrome/browser/ui/browser_finder.h"
35 #include "chrome/browser/ui/browser_navigator.h"
36 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
37 #include "chrome/browser/ui/tabs/tab_strip_model.h"
38 #include "chrome/common/chrome_paths.h"
39 #include "chrome/common/chrome_switches.h"
40 #include "chrome/common/pref_names.h"
41 #include "chrome/test/base/in_process_browser_test.h"
42 #include "chrome/test/base/ui_test_utils.h"
43 #include "content/public/browser/browser_thread.h"
44 #include "content/public/browser/interstitial_page.h"
45 #include "content/public/browser/interstitial_page_delegate.h"
46 #include "content/public/browser/navigation_controller.h"
47 #include "content/public/browser/navigation_entry.h"
48 #include "content/public/browser/notification_observer.h"
49 #include "content/public/browser/notification_registrar.h"
50 #include "content/public/browser/notification_service.h"
51 #include "content/public/browser/notification_types.h"
52 #include "content/public/browser/render_frame_host.h"
53 #include "content/public/browser/web_contents.h"
54 #include "content/public/common/url_constants.h"
55 #include "content/public/test/browser_test_utils.h"
56 #include "net/base/net_errors.h"
57 #include "net/http/transport_security_state.h"
58 #include "net/test/url_request/url_request_failed_job.h"
59 #include "net/test/url_request/url_request_mock_http_job.h"
60 #include "net/url_request/url_request.h"
61 #include "net/url_request/url_request_context.h"
62 #include "net/url_request/url_request_context_getter.h"
63 #include "net/url_request/url_request_filter.h"
64 #include "net/url_request/url_request_interceptor.h"
65 #include "net/url_request/url_request_job.h"
66 #include "net/url_request/url_request_status.h"
67 #include "testing/gtest/include/gtest/gtest.h"
69 using captive_portal::CaptivePortalResult;
70 using content::BrowserThread;
71 using content::WebContents;
72 using net::URLRequestFailedJob;
73 using net::URLRequestMockHTTPJob;
75 namespace {
77 // Path of the fake login page, when using the TestServer.
78 const char* const kTestServerLoginPath = "files/captive_portal/login.html";
80 // Path of a page with an iframe that has a mock SSL timeout, when using the
81 // TestServer.
82 const char* const kTestServerIframeTimeoutPath =
83 "files/captive_portal/iframe_timeout.html";
85 // The following URLs each have two different behaviors, depending on whether
86 // URLRequestMockCaptivePortalJobFactory is currently simulating the presence
87 // of a captive portal or not. They use different domains so that HSTS can be
88 // applied to them independently.
90 // A mock URL for the CaptivePortalService's |test_url|. When behind a captive
91 // portal, this URL returns a mock login page. When connected to the Internet,
92 // it returns a 204 response. Uses the name of the login file so that reloading
93 // it will not request a different URL.
94 const char* const kMockCaptivePortalTestUrl =
95 "http://mock.captive.portal.test/login.html";
97 // Another mock URL for the CaptivePortalService's |test_url|. When behind a
98 // captive portal, this URL returns a 511 status code and an HTML page that
99 // redirect to the above URL. When connected to the Internet, it returns a 204
100 // response.
101 const char* const kMockCaptivePortal511Url =
102 "http://mock.captive.portal.511/page511.html";
104 // When behind a captive portal, this URL hangs without committing until a call
105 // to URLRequestTimeoutOnDemandJob::FailJobs. When that function is called,
106 // the request will time out.
108 // When connected to the Internet, this URL returns a non-error page.
109 const char* const kMockHttpsUrl =
110 "https://mock.captive.portal.long.timeout/title2.html";
112 // Same as above, but different domain, so can be used to trigger cross-site
113 // navigations.
114 const char* const kMockHttpsUrl2 =
115 "https://mock.captive.portal.long.timeout2/title2.html";
117 // Same as kMockHttpsUrl, except the timeout happens instantly.
118 const char* const kMockHttpsQuickTimeoutUrl =
119 "https://mock.captive.portal.quick.timeout/title2.html";
121 // Expected title of a tab once an HTTPS load completes, when not behind a
122 // captive portal.
123 const char* const kInternetConnectedTitle = "Title Of Awesomeness";
125 // A URL request job that hangs until FailJobs() is called. Started jobs
126 // are stored in a static class variable containing a linked list so that
127 // FailJobs() can locate them.
128 class URLRequestTimeoutOnDemandJob : public net::URLRequestJob,
129 public base::NonThreadSafe {
130 public:
131 // net::URLRequestJob:
132 void Start() override;
134 // All the public static methods below can be called on any thread.
136 // Waits for exactly |num_jobs|.
137 static void WaitForJobs(int num_jobs);
139 // Fails all active URLRequestTimeoutOnDemandJobs with connection timeouts.
140 // There are expected to be exactly |expected_num_jobs| waiting for
141 // failure. The only way to guarantee this is with an earlier call to
142 // WaitForJobs, so makes sure there has been a matching WaitForJobs call.
143 static void FailJobs(int expected_num_jobs);
145 // Fails all active URLRequestTimeoutOnDemandJobs with SSL cert errors.
146 // |expected_num_jobs| behaves just as in FailJobs.
147 static void FailJobsWithCertError(int expected_num_jobs);
149 // Abandon all active URLRequestTimeoutOnDemandJobs. |expected_num_jobs|
150 // behaves just as in FailJobs.
151 static void AbandonJobs(int expected_num_jobs);
153 private:
154 friend class URLRequestMockCaptivePortalJobFactory;
156 // Operation to perform on jobs when removing them from |job_list_|.
157 enum EndJobOperation {
158 FAIL_JOBS,
159 ABANDON_JOBS,
160 FAIL_JOBS_WITH_CERT_ERROR
163 URLRequestTimeoutOnDemandJob(net::URLRequest* request,
164 net::NetworkDelegate* network_delegate);
165 ~URLRequestTimeoutOnDemandJob() override;
167 // Attempts to removes |this| from |jobs_|. Returns true if it was removed
168 // from the list.
169 bool RemoveFromList();
171 static void WaitForJobsOnIOThread(int num_jobs);
172 static void FailOrAbandonJobsOnIOThread(
173 int expected_num_jobs,
174 EndJobOperation end_job_operation);
176 // Checks if there are at least |num_jobs_to_wait_for_| jobs in
177 // |job_list_|. If so, exits the message loop on the UI thread, which
178 // should be spinning in a call to WaitForJobs. Does nothing when
179 // |num_jobs_to_wait_for_| is 0.
180 static void MaybeStopWaitingForJobsOnIOThread();
182 // All class variables are only accessed on the IO thread.
184 // Number of jobs currently being waited for, or 0 if not currently
185 // waiting for jobs.
186 static int num_jobs_to_wait_for_;
188 // The last number of jobs that were waited for. When FailJobs or
189 // AbandonJobs is called, this should match |expected_num_jobs|.
190 static int last_num_jobs_to_wait_for_;
192 // Number of jobs that have been started, but not yet waited for. If jobs
193 // are deleted unexpectedly, they're still included in this count, even though
194 // they've been removed from |job_list_|. Intended to reduce chance of stalls
195 // on regressions.
196 static int num_jobs_started_;
198 // Head of linked list of jobs that have been started and are now waiting to
199 // be timed out.
200 static URLRequestTimeoutOnDemandJob* job_list_;
202 // The next job that had been started but not yet timed out.
203 URLRequestTimeoutOnDemandJob* next_job_;
205 DISALLOW_COPY_AND_ASSIGN(URLRequestTimeoutOnDemandJob);
208 int URLRequestTimeoutOnDemandJob::num_jobs_to_wait_for_ = 0;
209 int URLRequestTimeoutOnDemandJob::last_num_jobs_to_wait_for_ = 0;
210 int URLRequestTimeoutOnDemandJob::num_jobs_started_ = 0;
211 URLRequestTimeoutOnDemandJob* URLRequestTimeoutOnDemandJob::job_list_ = NULL;
213 void URLRequestTimeoutOnDemandJob::Start() {
214 EXPECT_TRUE(CalledOnValidThread());
216 // Insert at start of the list.
217 next_job_ = job_list_;
218 job_list_ = this;
219 ++num_jobs_started_;
221 // Checks if there are at least |num_jobs_to_wait_for_| jobs in
222 // |job_list_|. If so, exits the message loop on the UI thread, which
223 // should be spinning in a call to WaitForJobs. Does nothing if
224 // |num_jobs_to_wait_for_| is 0.
225 MaybeStopWaitingForJobsOnIOThread();
228 // static
229 void URLRequestTimeoutOnDemandJob::WaitForJobs(int num_jobs) {
230 content::BrowserThread::PostTask(
231 content::BrowserThread::IO, FROM_HERE,
232 base::Bind(&URLRequestTimeoutOnDemandJob::WaitForJobsOnIOThread,
233 num_jobs));
234 content::RunMessageLoop();
237 // static
238 void URLRequestTimeoutOnDemandJob::FailJobs(int expected_num_jobs) {
239 content::BrowserThread::PostTask(
240 content::BrowserThread::IO, FROM_HERE,
241 base::Bind(&URLRequestTimeoutOnDemandJob::FailOrAbandonJobsOnIOThread,
242 expected_num_jobs,
243 FAIL_JOBS));
246 // static
247 void URLRequestTimeoutOnDemandJob::FailJobsWithCertError(
248 int expected_num_jobs) {
249 content::BrowserThread::PostTask(
250 content::BrowserThread::IO, FROM_HERE,
251 base::Bind(&URLRequestTimeoutOnDemandJob::FailOrAbandonJobsOnIOThread,
252 expected_num_jobs,
253 FAIL_JOBS_WITH_CERT_ERROR));
256 // static
257 void URLRequestTimeoutOnDemandJob::AbandonJobs(int expected_num_jobs) {
258 content::BrowserThread::PostTask(
259 content::BrowserThread::IO, FROM_HERE,
260 base::Bind(&URLRequestTimeoutOnDemandJob::FailOrAbandonJobsOnIOThread,
261 expected_num_jobs,
262 ABANDON_JOBS));
265 URLRequestTimeoutOnDemandJob::URLRequestTimeoutOnDemandJob(
266 net::URLRequest* request, net::NetworkDelegate* network_delegate)
267 : net::URLRequestJob(request, network_delegate),
268 next_job_(NULL) {
271 URLRequestTimeoutOnDemandJob::~URLRequestTimeoutOnDemandJob() {
272 // All hanging jobs should have failed or been abandoned before being
273 // destroyed.
274 EXPECT_FALSE(RemoveFromList());
277 bool URLRequestTimeoutOnDemandJob::RemoveFromList() {
278 URLRequestTimeoutOnDemandJob** job = &job_list_;
279 while (*job) {
280 if (*job == this) {
281 *job = next_job_;
282 next_job_ = NULL;
283 return true;
285 job = &next_job_;
288 // If the job wasn't in this list, |next_job_| should be NULL.
289 EXPECT_FALSE(next_job_);
290 return false;
293 // static
294 void URLRequestTimeoutOnDemandJob::WaitForJobsOnIOThread(int num_jobs) {
295 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
296 ASSERT_EQ(0, num_jobs_to_wait_for_);
297 ASSERT_LT(0, num_jobs);
298 // Number of tabs being waited on should be strictly increasing.
299 ASSERT_LE(last_num_jobs_to_wait_for_, num_jobs);
301 num_jobs_to_wait_for_ = num_jobs;
302 MaybeStopWaitingForJobsOnIOThread();
305 // static
306 void URLRequestTimeoutOnDemandJob::MaybeStopWaitingForJobsOnIOThread() {
307 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
308 if (num_jobs_to_wait_for_ == 0)
309 return;
311 // There shouldn't be any extra jobs.
312 EXPECT_LE(num_jobs_started_, num_jobs_to_wait_for_);
314 // Should never be greater, but if it is, go ahead and exit the message loop
315 // to try and avoid hanging.
316 if (num_jobs_started_ >= num_jobs_to_wait_for_) {
317 last_num_jobs_to_wait_for_ = num_jobs_to_wait_for_;
318 num_jobs_to_wait_for_ = 0;
319 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
320 base::MessageLoop::QuitClosure());
324 // static
325 void URLRequestTimeoutOnDemandJob::FailOrAbandonJobsOnIOThread(
326 int expected_num_jobs,
327 EndJobOperation end_job_operation) {
328 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
329 ASSERT_LT(0, expected_num_jobs);
330 EXPECT_EQ(last_num_jobs_to_wait_for_, expected_num_jobs);
331 last_num_jobs_to_wait_for_ = 0;
333 int num_jobs = 0;
334 while (job_list_) {
335 ++num_jobs;
336 URLRequestTimeoutOnDemandJob* job = job_list_;
337 // Since the error notification may result in the job's destruction, remove
338 // it from the job list before the error.
339 EXPECT_TRUE(job->RemoveFromList());
340 if (end_job_operation == FAIL_JOBS) {
341 job->NotifyStartError(net::URLRequestStatus(
342 net::URLRequestStatus::FAILED,
343 net::ERR_CONNECTION_TIMED_OUT));
344 } else if (end_job_operation == FAIL_JOBS_WITH_CERT_ERROR) {
345 DCHECK(job->request()->url().SchemeIsCryptographic());
346 net::SSLInfo info;
347 info.cert_status = net::CERT_STATUS_COMMON_NAME_INVALID;
348 info.cert = new net::X509Certificate(
349 "bad.host", "CA", base::Time::Max(), base::Time::Max());
350 job->NotifySSLCertificateError(info, true);
354 EXPECT_EQ(expected_num_jobs, num_jobs_started_);
355 EXPECT_EQ(expected_num_jobs, num_jobs);
357 num_jobs_started_ -= expected_num_jobs;
360 // URLRequestCaptivePortalJobFactory emulates captive portal behavior.
361 // Initially, it emulates being behind a captive portal. When
362 // SetBehindCaptivePortal(false) is called, it emulates behavior when not behind
363 // a captive portal. The class itself is never instantiated.
365 // It handles requests for kMockCaptivePortalTestUrl, kMockHttpsUrl, and
366 // kMockHttpsQuickTimeoutUrl.
367 class URLRequestMockCaptivePortalJobFactory {
368 public:
369 URLRequestMockCaptivePortalJobFactory() : behind_captive_portal_(true) {}
370 virtual ~URLRequestMockCaptivePortalJobFactory() {}
372 // Adds the testing URLs to the net::URLRequestFilter. Should only be called
373 // once.
374 void AddUrlHandlers();
376 // Sets whether or not there is a captive portal. Outstanding requests are
377 // not affected.
378 void SetBehindCaptivePortal(bool behind_captive_portal);
380 private:
381 class Interceptor : public net::URLRequestInterceptor {
382 public:
383 explicit Interceptor(bool behind_captive_portal)
384 : behind_captive_portal_(behind_captive_portal) {}
385 ~Interceptor() override {}
387 // Returns a URLRequestJob that reflects the current captive portal state
388 // for the URLs: kMockCaptivePortalTestUrl, kMockHttpsUrl, and
389 // kMockHttpsQuickTimeoutUrl. See documentation of individual URLs for
390 // actual behavior.
391 net::URLRequestJob* MaybeInterceptRequest(
392 net::URLRequest* request,
393 net::NetworkDelegate* network_delegate) const override;
395 void SetBehindCaptivePortal(bool behind_captive_portal) {
396 behind_captive_portal_ = behind_captive_portal;
399 private:
400 bool behind_captive_portal_;
402 DISALLOW_COPY_AND_ASSIGN(Interceptor);
405 // These do all the work of the corresponding public functions, with the only
406 // difference being that they must be called on the IO thread.
407 void AddUrlHandlersOnIOThread();
408 void SetBehindCaptivePortalOnIOThread(bool behind_captive_portal);
410 // Create a new Interceptor and add it to |interceptors_|, though it returns
411 // ownership.
412 scoped_ptr<net::URLRequestInterceptor> CreateInterceptor();
414 // These variables are only accessed on IO thread, though
415 // URLRequestMockCaptivePortalJobFactory is created and
416 // destroyed on the UI thread.
417 // The Interceptors are owned by URLRequestFilter and live on the IO thread;
418 // these are just references.
419 std::vector<Interceptor*> interceptors_;
420 bool behind_captive_portal_;
422 DISALLOW_COPY_AND_ASSIGN(URLRequestMockCaptivePortalJobFactory);
425 void URLRequestMockCaptivePortalJobFactory::AddUrlHandlers() {
426 content::BrowserThread::PostTask(
427 content::BrowserThread::IO, FROM_HERE,
428 base::Bind(
429 &URLRequestMockCaptivePortalJobFactory::AddUrlHandlersOnIOThread,
430 base::Unretained(this)));
433 void URLRequestMockCaptivePortalJobFactory::SetBehindCaptivePortal(
434 bool behind_captive_portal) {
435 content::BrowserThread::PostTask(
436 content::BrowserThread::IO, FROM_HERE,
437 base::Bind(&URLRequestMockCaptivePortalJobFactory::
438 SetBehindCaptivePortalOnIOThread,
439 base::Unretained(this), behind_captive_portal));
442 scoped_ptr<net::URLRequestInterceptor>
443 URLRequestMockCaptivePortalJobFactory::CreateInterceptor() {
444 EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
445 scoped_ptr<Interceptor> interceptor(new Interceptor(behind_captive_portal_));
446 interceptors_.push_back(interceptor.get());
447 return interceptor.Pass();
450 void URLRequestMockCaptivePortalJobFactory::AddUrlHandlersOnIOThread() {
451 EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
453 // Handle only exact matches, so any related requests, such as those for
454 // favicons, are not handled by the factory.
455 net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance();
456 filter->AddUrlInterceptor(GURL(kMockCaptivePortalTestUrl),
457 CreateInterceptor());
458 filter->AddUrlInterceptor(GURL(kMockCaptivePortal511Url),
459 CreateInterceptor());
460 filter->AddUrlInterceptor(GURL(kMockHttpsUrl), CreateInterceptor());
461 filter->AddUrlInterceptor(GURL(kMockHttpsUrl2), CreateInterceptor());
462 filter->AddUrlInterceptor(GURL(kMockHttpsQuickTimeoutUrl),
463 CreateInterceptor());
466 void URLRequestMockCaptivePortalJobFactory::SetBehindCaptivePortalOnIOThread(
467 bool behind_captive_portal) {
468 EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
469 behind_captive_portal_ = behind_captive_portal;
470 for (auto* interceptor : interceptors_)
471 interceptor->SetBehindCaptivePortal(behind_captive_portal);
474 net::URLRequestJob*
475 URLRequestMockCaptivePortalJobFactory::Interceptor::MaybeInterceptRequest(
476 net::URLRequest* request,
477 net::NetworkDelegate* network_delegate) const {
478 EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
480 // The PathService is threadsafe.
481 base::FilePath root_http;
482 PathService::Get(chrome::DIR_TEST_DATA, &root_http);
484 if (request->url() == GURL(kMockHttpsUrl) ||
485 request->url() == GURL(kMockHttpsUrl2)) {
486 if (behind_captive_portal_)
487 return new URLRequestTimeoutOnDemandJob(request, network_delegate);
488 // Once logged in to the portal, HTTPS requests return the page that was
489 // actually requested.
490 return new URLRequestMockHTTPJob(
491 request,
492 network_delegate,
493 root_http.Append(FILE_PATH_LITERAL("title2.html")),
494 BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior(
495 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN));
496 } else if (request->url() == GURL(kMockHttpsQuickTimeoutUrl)) {
497 if (behind_captive_portal_)
498 return new URLRequestFailedJob(
499 request, network_delegate, net::ERR_CONNECTION_TIMED_OUT);
500 // Once logged in to the portal, HTTPS requests return the page that was
501 // actually requested.
502 return new URLRequestMockHTTPJob(
503 request,
504 network_delegate,
505 root_http.Append(FILE_PATH_LITERAL("title2.html")),
506 BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior(
507 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN));
508 } else {
509 // The URL should be the captive portal test URL.
510 EXPECT_TRUE(GURL(kMockCaptivePortalTestUrl) == request->url() ||
511 GURL(kMockCaptivePortal511Url) == request->url());
513 if (behind_captive_portal_) {
514 // Prior to logging in to the portal, the HTTP test URLs are intercepted
515 // by the captive portal.
516 if (GURL(kMockCaptivePortal511Url) == request->url()) {
517 return new URLRequestMockHTTPJob(
518 request,
519 network_delegate,
520 root_http.Append(FILE_PATH_LITERAL("captive_portal/page511.html")),
521 BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior(
522 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN));
524 return new URLRequestMockHTTPJob(
525 request,
526 network_delegate,
527 root_http.Append(FILE_PATH_LITERAL("captive_portal/login.html")),
528 BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior(
529 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN));
532 // After logging in to the portal, the test URLs return a 204 response.
533 return new URLRequestMockHTTPJob(
534 request,
535 network_delegate,
536 root_http.Append(FILE_PATH_LITERAL("captive_portal/page204.html")),
537 BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior(
538 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN));
542 // Creates a server-side redirect for use with the TestServer.
543 std::string CreateServerRedirect(const std::string& dest_url) {
544 const char* const kServerRedirectBase = "server-redirect?";
545 return kServerRedirectBase + dest_url;
548 // Returns the total number of loading tabs across all Browsers, for all
549 // Profiles.
550 int NumLoadingTabs() {
551 int num_loading_tabs = 0;
552 for (TabContentsIterator it; !it.done(); it.Next()) {
553 if (it->IsLoading())
554 ++num_loading_tabs;
556 return num_loading_tabs;
559 bool IsLoginTab(WebContents* web_contents) {
560 return CaptivePortalTabHelper::FromWebContents(web_contents)->IsLoginTab();
563 // Tracks how many times each tab has been navigated since the Observer was
564 // created. The standard TestNavigationObserver can only watch specific
565 // pre-existing tabs or loads in serial for all tabs.
566 class MultiNavigationObserver : public content::NotificationObserver {
567 public:
568 MultiNavigationObserver();
569 ~MultiNavigationObserver() override;
571 // Waits for exactly |num_navigations_to_wait_for| LOAD_STOP
572 // notifications to have occurred since the construction of |this|. More
573 // navigations than expected occuring will trigger a expect failure.
574 void WaitForNavigations(int num_navigations_to_wait_for);
576 // Returns the number of LOAD_STOP events that have occurred for
577 // |web_contents| since this was constructed.
578 int NumNavigationsForTab(WebContents* web_contents) const;
580 // The number of LOAD_STOP events since |this| was created.
581 int num_navigations() const { return num_navigations_; }
583 private:
584 typedef std::map<const WebContents*, int> TabNavigationMap;
586 // content::NotificationObserver:
587 void Observe(int type,
588 const content::NotificationSource& source,
589 const content::NotificationDetails& details) override;
591 int num_navigations_;
593 // Map of how many times each tab has navigated since |this| was created.
594 TabNavigationMap tab_navigation_map_;
596 // Total number of navigations to wait for. Value only matters when
597 // |waiting_for_navigation_| is true.
598 int num_navigations_to_wait_for_;
600 // True if WaitForNavigations has been called, until
601 // |num_navigations_to_wait_for_| have been observed.
602 bool waiting_for_navigation_;
604 content::NotificationRegistrar registrar_;
606 DISALLOW_COPY_AND_ASSIGN(MultiNavigationObserver);
609 MultiNavigationObserver::MultiNavigationObserver()
610 : num_navigations_(0),
611 num_navigations_to_wait_for_(0),
612 waiting_for_navigation_(false) {
613 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
614 content::NotificationService::AllSources());
617 MultiNavigationObserver::~MultiNavigationObserver() {
620 void MultiNavigationObserver::WaitForNavigations(
621 int num_navigations_to_wait_for) {
622 // Shouldn't already be waiting for navigations.
623 EXPECT_FALSE(waiting_for_navigation_);
624 EXPECT_LT(0, num_navigations_to_wait_for);
625 if (num_navigations_ < num_navigations_to_wait_for) {
626 num_navigations_to_wait_for_ = num_navigations_to_wait_for;
627 waiting_for_navigation_ = true;
628 content::RunMessageLoop();
629 EXPECT_FALSE(waiting_for_navigation_);
631 EXPECT_EQ(num_navigations_, num_navigations_to_wait_for);
634 int MultiNavigationObserver::NumNavigationsForTab(
635 WebContents* web_contents) const {
636 TabNavigationMap::const_iterator tab_navigations =
637 tab_navigation_map_.find(web_contents);
638 if (tab_navigations == tab_navigation_map_.end())
639 return 0;
640 return tab_navigations->second;
643 void MultiNavigationObserver::Observe(
644 int type,
645 const content::NotificationSource& source,
646 const content::NotificationDetails& details) {
647 ASSERT_EQ(type, content::NOTIFICATION_LOAD_STOP);
648 content::NavigationController* controller =
649 content::Source<content::NavigationController>(source).ptr();
650 ++num_navigations_;
651 ++tab_navigation_map_[controller->GetWebContents()];
652 if (waiting_for_navigation_ &&
653 num_navigations_to_wait_for_ == num_navigations_) {
654 waiting_for_navigation_ = false;
655 base::MessageLoopForUI::current()->Quit();
659 // This observer creates a list of loading tabs, and then waits for them all
660 // to stop loading and have the kInternetConnectedTitle.
662 // This is for the specific purpose of observing tabs time out after logging in
663 // to a captive portal, which will then cause them to reload.
664 // MultiNavigationObserver is insufficient for this because there may or may not
665 // be a LOAD_STOP event between the timeout and the reload.
666 // See bug http://crbug.com/133227
667 class FailLoadsAfterLoginObserver : public content::NotificationObserver {
668 public:
669 FailLoadsAfterLoginObserver();
670 ~FailLoadsAfterLoginObserver() override;
672 void WaitForNavigations();
674 private:
675 typedef std::set<const WebContents*> TabSet;
677 // content::NotificationObserver:
678 void Observe(int type,
679 const content::NotificationSource& source,
680 const content::NotificationDetails& details) override;
682 // The set of tabs that need to be navigated. This is the set of loading
683 // tabs when the observer is created.
684 TabSet tabs_needing_navigation_;
686 // Number of tabs that have stopped navigating with the expected title. These
687 // are expected not to be navigated again.
688 TabSet tabs_navigated_to_final_destination_;
690 // True if WaitForNavigations has been called, until
691 // |tabs_navigated_to_final_destination_| equals |tabs_needing_navigation_|.
692 bool waiting_for_navigation_;
694 content::NotificationRegistrar registrar_;
696 DISALLOW_COPY_AND_ASSIGN(FailLoadsAfterLoginObserver);
699 FailLoadsAfterLoginObserver::FailLoadsAfterLoginObserver()
700 : waiting_for_navigation_(false) {
701 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
702 content::NotificationService::AllSources());
703 for (TabContentsIterator it; !it.done(); it.Next()) {
704 if (it->IsLoading())
705 tabs_needing_navigation_.insert(*it);
709 FailLoadsAfterLoginObserver::~FailLoadsAfterLoginObserver() {
712 void FailLoadsAfterLoginObserver::WaitForNavigations() {
713 // Shouldn't already be waiting for navigations.
714 EXPECT_FALSE(waiting_for_navigation_);
715 if (tabs_needing_navigation_.size() !=
716 tabs_navigated_to_final_destination_.size()) {
717 waiting_for_navigation_ = true;
718 content::RunMessageLoop();
719 EXPECT_FALSE(waiting_for_navigation_);
721 EXPECT_EQ(tabs_needing_navigation_.size(),
722 tabs_navigated_to_final_destination_.size());
725 void FailLoadsAfterLoginObserver::Observe(
726 int type,
727 const content::NotificationSource& source,
728 const content::NotificationDetails& details) {
729 ASSERT_EQ(type, content::NOTIFICATION_LOAD_STOP);
730 content::NavigationController* controller =
731 content::Source<content::NavigationController>(source).ptr();
732 WebContents* contents = controller->GetWebContents();
734 ASSERT_EQ(1u, tabs_needing_navigation_.count(contents));
735 ASSERT_EQ(0u, tabs_navigated_to_final_destination_.count(contents));
737 if (contents->GetTitle() != base::ASCIIToUTF16(kInternetConnectedTitle))
738 return;
739 tabs_navigated_to_final_destination_.insert(contents);
741 if (waiting_for_navigation_ &&
742 tabs_needing_navigation_.size() ==
743 tabs_navigated_to_final_destination_.size()) {
744 waiting_for_navigation_ = false;
745 base::MessageLoopForUI::current()->Quit();
749 // An observer for watching the CaptivePortalService. It tracks the last
750 // received result and the total number of received results.
751 class CaptivePortalObserver : public content::NotificationObserver {
752 public:
753 explicit CaptivePortalObserver(Profile* profile);
755 // Runs the message loop until exactly |update_count| captive portal
756 // results have been received, since the creation of |this|. Expects no
757 // additional captive portal results.
758 void WaitForResults(int num_results_to_wait_for);
760 int num_results_received() const { return num_results_received_; }
762 CaptivePortalResult captive_portal_result() const {
763 return captive_portal_result_;
766 private:
767 // Records results and exits the message loop, if needed.
768 void Observe(int type,
769 const content::NotificationSource& source,
770 const content::NotificationDetails& details) override;
772 // Number of times OnPortalResult has been called since construction.
773 int num_results_received_;
775 // If WaitForResults was called, the total number of updates for which to
776 // wait. Value doesn't matter when |waiting_for_result_| is false.
777 int num_results_to_wait_for_;
779 bool waiting_for_result_;
781 Profile* profile_;
783 CaptivePortalService* captive_portal_service_;
785 // Last result received.
786 CaptivePortalResult captive_portal_result_;
788 content::NotificationRegistrar registrar_;
790 DISALLOW_COPY_AND_ASSIGN(CaptivePortalObserver);
793 CaptivePortalObserver::CaptivePortalObserver(Profile* profile)
794 : num_results_received_(0),
795 num_results_to_wait_for_(0),
796 waiting_for_result_(false),
797 profile_(profile),
798 captive_portal_service_(
799 CaptivePortalServiceFactory::GetForProfile(profile)),
800 captive_portal_result_(
801 captive_portal_service_->last_detection_result()) {
802 registrar_.Add(this,
803 chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT,
804 content::Source<Profile>(profile_));
807 void CaptivePortalObserver::WaitForResults(int num_results_to_wait_for) {
808 EXPECT_LT(0, num_results_to_wait_for);
809 EXPECT_FALSE(waiting_for_result_);
810 if (num_results_received_ < num_results_to_wait_for) {
811 num_results_to_wait_for_ = num_results_to_wait_for;
812 waiting_for_result_ = true;
813 content::RunMessageLoop();
814 EXPECT_FALSE(waiting_for_result_);
816 EXPECT_EQ(num_results_to_wait_for, num_results_received_);
819 void CaptivePortalObserver::Observe(
820 int type,
821 const content::NotificationSource& source,
822 const content::NotificationDetails& details) {
823 ASSERT_EQ(type, chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT);
824 ASSERT_EQ(profile_, content::Source<Profile>(source).ptr());
826 CaptivePortalService::Results* results =
827 content::Details<CaptivePortalService::Results>(details).ptr();
829 EXPECT_EQ(captive_portal_result_, results->previous_result);
830 EXPECT_EQ(captive_portal_service_->last_detection_result(),
831 results->result);
833 captive_portal_result_ = results->result;
834 ++num_results_received_;
836 if (waiting_for_result_ &&
837 num_results_to_wait_for_ == num_results_received_) {
838 waiting_for_result_ = false;
839 base::MessageLoop::current()->Quit();
843 // This observer waits for the SSLErrorHandler to start an interstitial timer
844 // for the given web contents.
845 class SSLInterstitialTimerObserver {
846 public:
847 explicit SSLInterstitialTimerObserver(content::WebContents* web_contents);
848 ~SSLInterstitialTimerObserver();
850 // Waits until the interstitial delay timer in SSLErrorHandler is started.
851 void WaitForTimerStarted();
853 private:
854 void OnTimerStarted(content::WebContents* web_contents);
856 const content::WebContents* web_contents_;
857 SSLErrorHandler::TimerStartedCallback callback_;
859 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
861 DISALLOW_COPY_AND_ASSIGN(SSLInterstitialTimerObserver);
864 SSLInterstitialTimerObserver::SSLInterstitialTimerObserver(
865 content::WebContents* web_contents)
866 : web_contents_(web_contents),
867 message_loop_runner_(new content::MessageLoopRunner) {
868 callback_ = base::Bind(&SSLInterstitialTimerObserver::OnTimerStarted,
869 base::Unretained(this));
870 SSLErrorHandler::SetInterstitialTimerStartedCallbackForTest(&callback_);
873 SSLInterstitialTimerObserver::~SSLInterstitialTimerObserver() {
874 SSLErrorHandler::SetInterstitialTimerStartedCallbackForTest(nullptr);
877 void SSLInterstitialTimerObserver::WaitForTimerStarted() {
878 message_loop_runner_->Run();
881 void SSLInterstitialTimerObserver::OnTimerStarted(
882 content::WebContents* web_contents) {
883 if (web_contents_ == web_contents && message_loop_runner_.get())
884 message_loop_runner_->Quit();
887 // Adds an HSTS rule for |host|, so that all HTTP requests sent to it will
888 // be switched to HTTPS requests.
889 void AddHstsHost(net::URLRequestContextGetter* context_getter,
890 const std::string& host) {
891 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
892 net::TransportSecurityState* transport_security_state =
893 context_getter->GetURLRequestContext()->transport_security_state();
894 if (!transport_security_state) {
895 FAIL();
896 return;
899 base::Time expiry = base::Time::Now() + base::TimeDelta::FromDays(1000);
900 bool include_subdomains = false;
901 transport_security_state->AddHSTS(host, expiry, include_subdomains);
904 } // namespace
906 class CaptivePortalBrowserTest : public InProcessBrowserTest {
907 public:
908 CaptivePortalBrowserTest();
910 // InProcessBrowserTest:
911 void SetUpOnMainThread() override;
912 void TearDownOnMainThread() override;
913 void SetUpCommandLine(base::CommandLine* command_line) override;
915 // Sets the captive portal checking preference. Does not affect the command
916 // line flag, which is set in SetUpCommandLine.
917 void EnableCaptivePortalDetection(Profile* profile, bool enabled);
919 // Enables or disables actual captive portal probes. Should only be called
920 // after captive portal service setup is done. When disabled, probe requests
921 // are silently ignored, never receiving a response.
922 void RespondToProbeRequests(bool enabled);
924 // Sets up the captive portal service for the given profile so that
925 // all checks go to |test_url|. Also disables all timers.
926 void SetUpCaptivePortalService(Profile* profile, const GURL& test_url);
928 // Returns true if |browser|'s profile is currently running a captive portal
929 // check.
930 bool CheckPending(Browser* browser);
932 // Returns the type of the interstitial being shown.
933 content::InterstitialPageDelegate::TypeID GetInterstitialType(
934 WebContents* contents) const;
936 // Returns the CaptivePortalTabReloader::State of |web_contents|.
937 CaptivePortalTabReloader::State GetStateOfTabReloader(
938 WebContents* web_contents) const;
940 // Returns the CaptivePortalTabReloader::State of the indicated tab.
941 CaptivePortalTabReloader::State GetStateOfTabReloaderAt(Browser* browser,
942 int index) const;
944 // Returns the number of tabs with the given state, across all profiles.
945 int NumTabsWithState(CaptivePortalTabReloader::State state) const;
947 // Returns the number of tabs broken by captive portals, across all profiles.
948 int NumBrokenTabs() const;
950 // Returns the number of tabs that need to be reloaded due to having logged
951 // in to a captive portal, across all profiles.
952 int NumNeedReloadTabs() const;
954 // Navigates |browser|'s active tab to |url| and expects no captive portal
955 // test to be triggered. |expected_navigations| is the number of times the
956 // active tab will end up being navigated. It should be 1, except for the
957 // Link Doctor page, which acts like two navigations.
958 void NavigateToPageExpectNoTest(Browser* browser,
959 const GURL& url,
960 int expected_navigations);
962 // Navigates |browser|'s active tab to an SSL tab that takes a while to load,
963 // triggering a captive portal check, which is expected to give the result
964 // |expected_result|. The page finishes loading, with a timeout, after the
965 // captive portal check.
966 void SlowLoadNoCaptivePortal(Browser* browser,
967 CaptivePortalResult expected_result);
969 // Navigates |browser|'s active tab to an SSL timeout, expecting a captive
970 // portal check to be triggered and return a result which will indicates
971 // there's no detected captive portal.
972 void FastTimeoutNoCaptivePortal(Browser* browser,
973 CaptivePortalResult expected_result);
975 // Navigates the active tab to a slow loading SSL page, which will then
976 // trigger a captive portal test. The test is expected to find a captive
977 // portal. The slow loading page will continue to load after the function
978 // returns, until URLRequestTimeoutOnDemandJob::FailJobs() is called,
979 // at which point it will timeout.
981 // When |expect_open_login_tab| is false, no login tab is expected to be
982 // opened, because one already exists, and the function returns once the
983 // captive portal test is complete.
985 // If |expect_open_login_tab| is true, a login tab is then expected to be
986 // opened. It waits until both the login tab has finished loading, and two
987 // captive portal tests complete. The second test is triggered by the load of
988 // the captive portal tab completing.
990 // This function must not be called when the active tab is currently loading.
991 // Waits for the hanging request to be issued, so other functions can rely
992 // on URLRequestTimeoutOnDemandJob::WaitForJobs having been called.
993 void SlowLoadBehindCaptivePortal(Browser* browser,
994 bool expect_open_login_tab);
996 // Same as above, but takes extra parameters.
998 // |hanging_url| should either be kMockHttpsUrl or redirect to kMockHttpsUrl.
1000 // |expected_portal_checks| and |expected_login_tab_navigations| allow
1001 // client-side redirects to be tested. |expected_login_tab_navigations| is
1002 // ignored when |expect_open_login_tab| is false.
1003 void SlowLoadBehindCaptivePortal(Browser* browser,
1004 bool expect_open_login_tab,
1005 const GURL& hanging_url,
1006 int expected_portal_checks,
1007 int expected_login_tab_navigations);
1009 // Just like SlowLoadBehindCaptivePortal, except the navigated tab has
1010 // a connection timeout rather having its time trigger, and the function
1011 // waits until that timeout occurs.
1012 void FastTimeoutBehindCaptivePortal(Browser* browser,
1013 bool expect_open_login_tab);
1015 // Much as above, but accepts a URL parameter and can be used for errors that
1016 // trigger captive portal checks other than timeouts. |error_url| should
1017 // result in an error rather than hanging.
1018 // If |delay_portal_response_until_interstital| is true, captive portal probe
1019 // request are ignored until the interstitial is shown, at which point a
1020 // captive portal result is sent. This allows testing in conjunction with the
1021 // certificate error interstitial.
1022 void FastErrorBehindCaptivePortal(
1023 Browser* browser,
1024 bool expect_open_login_tab,
1025 const GURL& error_url,
1026 bool delay_portal_response_until_interstital);
1028 // Navigates the active tab to an SSL error page which triggers an
1029 // interstitial timer. Also disables captive portal checks indefinitely, so
1030 // the page appears to be hanging.
1031 void FastErrorWithInterstitialTimer(Browser* browser,
1032 const GURL& cert_error_url);
1034 // Navigates the login tab without logging in. The login tab must be the
1035 // specified browser's active tab. Expects no other tab to change state.
1036 // |num_loading_tabs| and |num_timed_out_tabs| are used as extra checks
1037 // that nothing has gone wrong prior to the function call.
1038 void NavigateLoginTab(Browser* browser,
1039 int num_loading_tabs,
1040 int num_timed_out_tabs);
1042 // Simulates a login by updating the URLRequestMockCaptivePortalJob's
1043 // behind captive portal state, and navigating the login tab. Waits for
1044 // all broken but not loading tabs to be reloaded.
1045 // |num_loading_tabs| and |num_timed_out_tabs| are used as extra checks
1046 // that nothing has gone wrong prior to the function call.
1047 void Login(Browser* browser, int num_loading_tabs, int num_timed_out_tabs);
1049 // Simulates a login when the broken tab shows an SSL or captive portal
1050 // interstitial. Can't use Login() in those cases because the interstitial
1051 // tab looks like a cross between a hung tab (Load was never committed) and a
1052 // tab at an error page (The load was stopped).
1053 void LoginCertError(Browser* browser);
1055 // Makes the slow SSL loads of all active tabs time out at once, and waits for
1056 // them to finish both that load and the automatic reload it should trigger.
1057 // There should be no timed out tabs when this is called.
1058 void FailLoadsAfterLogin(Browser* browser, int num_loading_tabs);
1060 // Makes the slow SSL loads of all active tabs time out at once, and waits for
1061 // them to finish displaying their error pages. The login tab should be the
1062 // active tab. There should be no timed out tabs when this is called.
1063 void FailLoadsWithoutLogin(Browser* browser, int num_loading_tabs);
1065 // Navigates |browser|'s active tab to |starting_url| while not behind a
1066 // captive portal. Then navigates to |interrupted_url|, which should create
1067 // a URLRequestTimeoutOnDemandJob, which is then abandoned. The load should
1068 // trigger a captive portal check, which finds a captive portal and opens a
1069 // tab.
1071 // Then the navigation is interrupted by a navigation to |timeout_url|, which
1072 // should trigger a captive portal check, and finally the test simulates
1073 // logging in.
1075 // The purpose of this test is to make sure the TabHelper triggers a captive
1076 // portal check when a load is interrupted by another load, particularly in
1077 // the case of cross-process navigations.
1078 void RunNavigateLoadingTabToTimeoutTest(Browser* browser,
1079 const GURL& starting_url,
1080 const GURL& interrupted_url,
1081 const GURL& timeout_url);
1083 // Sets the timeout used by a CaptivePortalTabReloader on slow SSL loads
1084 // before a captive portal check.
1085 void SetSlowSSLLoadTime(CaptivePortalTabReloader* tab_reloader,
1086 base::TimeDelta slow_ssl_load_time);
1088 CaptivePortalTabReloader* GetTabReloader(WebContents* web_contents) const;
1090 protected:
1091 URLRequestMockCaptivePortalJobFactory factory_;
1093 private:
1094 DISALLOW_COPY_AND_ASSIGN(CaptivePortalBrowserTest);
1097 CaptivePortalBrowserTest::CaptivePortalBrowserTest() {
1100 void CaptivePortalBrowserTest::SetUpOnMainThread() {
1101 // Enable mock requests.
1102 content::BrowserThread::PostTask(
1103 content::BrowserThread::IO, FROM_HERE,
1104 base::Bind(&chrome_browser_net::SetUrlRequestMocksEnabled, true));
1105 factory_.AddUrlHandlers();
1107 // Double-check that the captive portal service isn't enabled by default for
1108 // browser tests.
1109 EXPECT_EQ(CaptivePortalService::DISABLED_FOR_TESTING,
1110 CaptivePortalService::get_state_for_testing());
1112 CaptivePortalService::set_state_for_testing(
1113 CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING);
1114 EnableCaptivePortalDetection(browser()->profile(), true);
1116 // Set the captive portal service to use URLRequestMockCaptivePortalJob's
1117 // mock URL, by default.
1118 SetUpCaptivePortalService(browser()->profile(),
1119 GURL(kMockCaptivePortalTestUrl));
1121 // Set SSL interstitial delay long enough so that a captive portal result
1122 // is guaranteed to arrive during this window, and a captive portal
1123 // error page is displayed instead of an SSL interstitial.
1124 SSLErrorHandler::SetInterstitialDelayTypeForTest(SSLErrorHandler::LONG);
1127 void CaptivePortalBrowserTest::TearDownOnMainThread() {
1128 // No test should have a captive portal check pending on quit.
1129 EXPECT_FALSE(CheckPending(browser()));
1132 void CaptivePortalBrowserTest::SetUpCommandLine(
1133 base::CommandLine* command_line) {
1134 // Enable finch experiment for captive portal interstitials.
1135 command_line->AppendSwitchASCII(
1136 switches::kForceFieldTrials, "CaptivePortalInterstitial/Enabled/");
1139 void CaptivePortalBrowserTest::EnableCaptivePortalDetection(
1140 Profile* profile, bool enabled) {
1141 profile->GetPrefs()->SetBoolean(prefs::kAlternateErrorPagesEnabled, enabled);
1144 void CaptivePortalBrowserTest::RespondToProbeRequests(bool enabled) {
1145 if (enabled) {
1146 EXPECT_EQ(CaptivePortalService::IGNORE_REQUESTS_FOR_TESTING,
1147 CaptivePortalService::get_state_for_testing());
1148 CaptivePortalService::set_state_for_testing(
1149 CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING);
1150 } else {
1151 EXPECT_EQ(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING,
1152 CaptivePortalService::get_state_for_testing());
1153 CaptivePortalService::set_state_for_testing(
1154 CaptivePortalService::IGNORE_REQUESTS_FOR_TESTING);
1158 void CaptivePortalBrowserTest::SetUpCaptivePortalService(Profile* profile,
1159 const GURL& test_url) {
1160 CaptivePortalService* captive_portal_service =
1161 CaptivePortalServiceFactory::GetForProfile(profile);
1162 captive_portal_service->set_test_url(test_url);
1164 // Don't use any non-zero timers. Timers are checked in unit tests.
1165 CaptivePortalService::RecheckPolicy* recheck_policy =
1166 &captive_portal_service->recheck_policy();
1167 recheck_policy->initial_backoff_no_portal_ms = 0;
1168 recheck_policy->initial_backoff_portal_ms = 0;
1169 recheck_policy->backoff_policy.maximum_backoff_ms = 0;
1172 bool CaptivePortalBrowserTest::CheckPending(Browser* browser) {
1173 CaptivePortalService* captive_portal_service =
1174 CaptivePortalServiceFactory::GetForProfile(browser->profile());
1176 return captive_portal_service->DetectionInProgress() ||
1177 captive_portal_service->TimerRunning();
1180 content::InterstitialPageDelegate::TypeID
1181 CaptivePortalBrowserTest::GetInterstitialType(WebContents* contents) const {
1182 if (!contents->ShowingInterstitialPage())
1183 return nullptr;
1184 return contents->GetInterstitialPage()
1185 ->GetDelegateForTesting()
1186 ->GetTypeForTesting();
1189 CaptivePortalTabReloader::State CaptivePortalBrowserTest::GetStateOfTabReloader(
1190 WebContents* web_contents) const {
1191 return GetTabReloader(web_contents)->state();
1194 CaptivePortalTabReloader::State
1195 CaptivePortalBrowserTest::GetStateOfTabReloaderAt(Browser* browser,
1196 int index) const {
1197 return GetStateOfTabReloader(
1198 browser->tab_strip_model()->GetWebContentsAt(index));
1201 int CaptivePortalBrowserTest::NumTabsWithState(
1202 CaptivePortalTabReloader::State state) const {
1203 int num_tabs = 0;
1204 for (TabContentsIterator it; !it.done(); it.Next()) {
1205 if (GetStateOfTabReloader(*it) == state)
1206 ++num_tabs;
1208 return num_tabs;
1211 int CaptivePortalBrowserTest::NumBrokenTabs() const {
1212 return NumTabsWithState(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL);
1215 int CaptivePortalBrowserTest::NumNeedReloadTabs() const {
1216 return NumTabsWithState(CaptivePortalTabReloader::STATE_NEEDS_RELOAD);
1219 void CaptivePortalBrowserTest::NavigateToPageExpectNoTest(
1220 Browser* browser,
1221 const GURL& url,
1222 int expected_navigations) {
1223 MultiNavigationObserver navigation_observer;
1224 CaptivePortalObserver portal_observer(browser->profile());
1226 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
1227 browser, url, expected_navigations);
1229 // No captive portal checks should have ocurred or be pending, and there
1230 // should be no new tabs.
1231 EXPECT_EQ(0, portal_observer.num_results_received());
1232 EXPECT_FALSE(CheckPending(browser));
1233 EXPECT_EQ(1, browser->tab_strip_model()->count());
1234 EXPECT_EQ(expected_navigations, navigation_observer.num_navigations());
1235 EXPECT_EQ(0, NumLoadingTabs());
1236 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1237 GetStateOfTabReloaderAt(browser, 0));
1240 void CaptivePortalBrowserTest::SlowLoadNoCaptivePortal(
1241 Browser* browser,
1242 CaptivePortalResult expected_result) {
1243 CaptivePortalTabReloader* tab_reloader =
1244 GetTabReloader(browser->tab_strip_model()->GetActiveWebContents());
1245 ASSERT_TRUE(tab_reloader);
1246 SetSlowSSLLoadTime(tab_reloader, base::TimeDelta());
1248 MultiNavigationObserver navigation_observer;
1249 CaptivePortalObserver portal_observer(browser->profile());
1250 ui_test_utils::NavigateToURLWithDisposition(browser,
1251 GURL(kMockHttpsUrl),
1252 CURRENT_TAB,
1253 ui_test_utils::BROWSER_TEST_NONE);
1255 portal_observer.WaitForResults(1);
1257 ASSERT_EQ(1, browser->tab_strip_model()->count());
1258 EXPECT_EQ(expected_result, portal_observer.captive_portal_result());
1259 EXPECT_EQ(1, portal_observer.num_results_received());
1260 EXPECT_EQ(0, navigation_observer.num_navigations());
1261 EXPECT_FALSE(CheckPending(browser));
1263 // First tab should still be loading.
1264 EXPECT_EQ(1, NumLoadingTabs());
1266 // Wait for the request to be issued, then time it out.
1267 URLRequestTimeoutOnDemandJob::WaitForJobs(1);
1268 URLRequestTimeoutOnDemandJob::FailJobs(1);
1269 navigation_observer.WaitForNavigations(1);
1271 ASSERT_EQ(1, browser->tab_strip_model()->count());
1272 EXPECT_EQ(1, portal_observer.num_results_received());
1273 EXPECT_FALSE(CheckPending(browser));
1274 EXPECT_EQ(0, NumLoadingTabs());
1276 // Set a slow SSL load time to prevent the timer from triggering.
1277 SetSlowSSLLoadTime(tab_reloader, base::TimeDelta::FromDays(1));
1280 void CaptivePortalBrowserTest::FastTimeoutNoCaptivePortal(
1281 Browser* browser,
1282 CaptivePortalResult expected_result) {
1283 ASSERT_NE(expected_result, captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL);
1285 // Set the load time to be large, so the timer won't trigger. The value is
1286 // not restored at the end of the function.
1287 CaptivePortalTabReloader* tab_reloader =
1288 GetTabReloader(browser->tab_strip_model()->GetActiveWebContents());
1289 ASSERT_TRUE(tab_reloader);
1290 SetSlowSSLLoadTime(tab_reloader, base::TimeDelta::FromHours(1));
1292 MultiNavigationObserver navigation_observer;
1293 CaptivePortalObserver portal_observer(browser->profile());
1295 // Neither of these should be changed by the navigation.
1296 int active_index = browser->tab_strip_model()->active_index();
1297 int expected_tab_count = browser->tab_strip_model()->count();
1299 ui_test_utils::NavigateToURL(
1300 browser,
1301 URLRequestFailedJob::GetMockHttpsUrl(net::ERR_CONNECTION_TIMED_OUT));
1303 // An attempt to detect a captive portal should have started by now. If not,
1304 // abort early to prevent hanging.
1305 ASSERT_TRUE(portal_observer.num_results_received() > 0 ||
1306 CheckPending(browser));
1308 portal_observer.WaitForResults(1);
1309 navigation_observer.WaitForNavigations(1);
1311 // Check the result.
1312 EXPECT_EQ(1, portal_observer.num_results_received());
1313 EXPECT_EQ(expected_result, portal_observer.captive_portal_result());
1315 // Check that the right tab was navigated, and there were no extra
1316 // navigations.
1317 EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
1318 browser->tab_strip_model()->GetWebContentsAt(active_index)));
1319 EXPECT_EQ(0, NumLoadingTabs());
1321 // Check the tab's state, and verify no captive portal check is pending.
1322 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1323 GetStateOfTabReloaderAt(browser, 0));
1324 EXPECT_FALSE(CheckPending(browser));
1326 // Make sure no login tab was opened.
1327 EXPECT_EQ(expected_tab_count, browser->tab_strip_model()->count());
1330 void CaptivePortalBrowserTest::SlowLoadBehindCaptivePortal(
1331 Browser* browser,
1332 bool expect_open_login_tab) {
1333 SlowLoadBehindCaptivePortal(browser,
1334 expect_open_login_tab,
1335 GURL(kMockHttpsUrl),
1340 void CaptivePortalBrowserTest::SlowLoadBehindCaptivePortal(
1341 Browser* browser,
1342 bool expect_open_login_tab,
1343 const GURL& hanging_url,
1344 int expected_portal_checks,
1345 int expected_login_tab_navigations) {
1346 ASSERT_GE(expected_portal_checks, 1);
1347 TabStripModel* tab_strip_model = browser->tab_strip_model();
1348 // Calling this on a tab that's waiting for a load to manually be timed out
1349 // will result in a hang.
1350 ASSERT_FALSE(tab_strip_model->GetActiveWebContents()->IsLoading());
1352 // Trigger a captive portal check quickly.
1353 CaptivePortalTabReloader* tab_reloader =
1354 GetTabReloader(tab_strip_model->GetActiveWebContents());
1355 ASSERT_TRUE(tab_reloader);
1356 SetSlowSSLLoadTime(tab_reloader, base::TimeDelta());
1358 // Number of tabs expected to be open after the captive portal checks
1359 // have completed.
1360 int initial_tab_count = tab_strip_model->count();
1361 int initial_active_index = tab_strip_model->active_index();
1362 int initial_loading_tabs = NumLoadingTabs();
1363 int expected_broken_tabs = NumBrokenTabs();
1364 if (CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL !=
1365 GetStateOfTabReloader(tab_strip_model->GetActiveWebContents())) {
1366 ++expected_broken_tabs;
1369 MultiNavigationObserver navigation_observer;
1370 CaptivePortalObserver portal_observer(browser->profile());
1371 ui_test_utils::NavigateToURLWithDisposition(browser,
1372 hanging_url,
1373 CURRENT_TAB,
1374 ui_test_utils::BROWSER_TEST_NONE);
1375 portal_observer.WaitForResults(expected_portal_checks);
1377 if (expect_open_login_tab) {
1378 ASSERT_GE(expected_login_tab_navigations, 1);
1380 navigation_observer.WaitForNavigations(expected_login_tab_navigations);
1382 ASSERT_EQ(initial_tab_count + 1, tab_strip_model->count());
1383 EXPECT_EQ(initial_tab_count, tab_strip_model->active_index());
1385 EXPECT_EQ(expected_login_tab_navigations,
1386 navigation_observer.NumNavigationsForTab(
1387 tab_strip_model->GetWebContentsAt(initial_tab_count)));
1388 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1389 GetStateOfTabReloaderAt(browser, 1));
1390 EXPECT_TRUE(IsLoginTab(tab_strip_model->GetWebContentsAt(1)));
1391 } else {
1392 EXPECT_EQ(0, navigation_observer.num_navigations());
1393 EXPECT_EQ(initial_active_index, tab_strip_model->active_index());
1394 ASSERT_EQ(initial_tab_count, tab_strip_model->count());
1395 EXPECT_EQ(initial_active_index, tab_strip_model->active_index());
1398 // Wait for all the expect resource loads to actually start, so subsequent
1399 // functions can rely on them having started.
1400 URLRequestTimeoutOnDemandJob::WaitForJobs(initial_loading_tabs + 1);
1402 EXPECT_EQ(initial_loading_tabs + 1, NumLoadingTabs());
1403 EXPECT_EQ(expected_broken_tabs, NumBrokenTabs());
1404 EXPECT_EQ(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
1405 portal_observer.captive_portal_result());
1406 EXPECT_EQ(expected_portal_checks, portal_observer.num_results_received());
1407 EXPECT_FALSE(CheckPending(browser));
1409 EXPECT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
1410 GetStateOfTabReloaderAt(browser, initial_active_index));
1412 // Reset the load time to be large, so the timer won't trigger on a reload.
1413 SetSlowSSLLoadTime(tab_reloader, base::TimeDelta::FromHours(1));
1416 void CaptivePortalBrowserTest::FastTimeoutBehindCaptivePortal(
1417 Browser* browser,
1418 bool expect_open_login_tab) {
1419 FastErrorBehindCaptivePortal(browser,
1420 expect_open_login_tab,
1421 GURL(kMockHttpsQuickTimeoutUrl),
1422 false);
1425 void CaptivePortalBrowserTest::FastErrorBehindCaptivePortal(
1426 Browser* browser,
1427 bool expect_open_login_tab,
1428 const GURL& error_url,
1429 bool delay_portal_response_until_interstital) {
1430 TabStripModel* tab_strip_model = browser->tab_strip_model();
1431 // Calling this on a tab that's waiting for a load to manually be timed out
1432 // will result in a hang.
1433 ASSERT_FALSE(tab_strip_model->GetActiveWebContents()->IsLoading());
1435 // Set the load time to be large, so the timer won't trigger. The value is
1436 // not restored at the end of the function.
1437 CaptivePortalTabReloader* tab_reloader =
1438 GetTabReloader(tab_strip_model->GetActiveWebContents());
1439 ASSERT_TRUE(tab_reloader);
1440 SetSlowSSLLoadTime(tab_reloader, base::TimeDelta::FromHours(1));
1442 // Number of tabs expected to be open after the captive portal checks
1443 // have completed.
1444 int initial_tab_count = tab_strip_model->count();
1445 int initial_active_index = tab_strip_model->active_index();
1446 int initial_loading_tabs = NumLoadingTabs();
1447 int expected_broken_tabs = NumBrokenTabs();
1448 if (CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL !=
1449 GetStateOfTabReloader(tab_strip_model->GetActiveWebContents())) {
1450 ++expected_broken_tabs;
1453 CaptivePortalService* captive_portal_service =
1454 CaptivePortalServiceFactory::GetForProfile(browser->profile());
1455 if (delay_portal_response_until_interstital)
1456 RespondToProbeRequests(false);
1458 MultiNavigationObserver navigation_observer;
1459 CaptivePortalObserver portal_observer(browser->profile());
1460 ui_test_utils::NavigateToURLWithDisposition(browser,
1461 error_url,
1462 CURRENT_TAB,
1463 ui_test_utils::BROWSER_TEST_NONE);
1465 if (delay_portal_response_until_interstital) {
1466 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1467 GetStateOfTabReloaderAt(browser, initial_active_index));
1468 // Once the interstitial is attached, probe for captive portal.
1469 WaitForInterstitialAttach(tab_strip_model->GetActiveWebContents());
1470 RespondToProbeRequests(true);
1471 captive_portal_service->DetectCaptivePortal();
1474 portal_observer.WaitForResults(1);
1476 if (expect_open_login_tab) {
1477 navigation_observer.WaitForNavigations(2);
1478 ASSERT_EQ(initial_tab_count + 1, tab_strip_model->count());
1479 EXPECT_EQ(initial_tab_count, tab_strip_model->active_index());
1480 // Make sure that the originally active tab and the captive portal tab have
1481 // each loaded once.
1482 EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
1483 tab_strip_model->GetWebContentsAt(initial_active_index)));
1484 EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
1485 tab_strip_model->GetWebContentsAt(initial_tab_count)));
1486 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1487 GetStateOfTabReloaderAt(browser, 1));
1488 EXPECT_TRUE(IsLoginTab(tab_strip_model->GetWebContentsAt(1)));
1489 } else {
1490 navigation_observer.WaitForNavigations(1);
1491 EXPECT_EQ(initial_active_index, tab_strip_model->active_index());
1492 EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
1493 tab_strip_model->GetWebContentsAt(initial_active_index)));
1494 ASSERT_EQ(initial_tab_count, tab_strip_model->count());
1495 EXPECT_EQ(initial_active_index, tab_strip_model->active_index());
1498 EXPECT_EQ(initial_loading_tabs, NumLoadingTabs());
1499 EXPECT_EQ(expected_broken_tabs, NumBrokenTabs());
1500 EXPECT_EQ(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
1501 portal_observer.captive_portal_result());
1502 EXPECT_EQ(1, portal_observer.num_results_received());
1503 EXPECT_FALSE(CheckPending(browser));
1505 EXPECT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
1506 GetStateOfTabReloaderAt(browser, initial_active_index));
1509 void CaptivePortalBrowserTest::FastErrorWithInterstitialTimer(
1510 Browser* browser,
1511 const GURL& cert_error_url) {
1512 TabStripModel* tab_strip_model = browser->tab_strip_model();
1513 WebContents* broken_tab_contents = tab_strip_model->GetActiveWebContents();
1515 // Disable captive portal checks indefinitely.
1516 RespondToProbeRequests(false);
1518 SSLInterstitialTimerObserver interstitial_timer_observer(broken_tab_contents);
1519 ui_test_utils::NavigateToURLWithDisposition(browser,
1520 cert_error_url,
1521 CURRENT_TAB,
1522 ui_test_utils::BROWSER_TEST_NONE);
1523 interstitial_timer_observer.WaitForTimerStarted();
1525 // The tab should be in loading state, waiting for the interstitial timer to
1526 // expire or a captive portal result to arrive. Since captive portal checks
1527 // are disabled and timer set to expire after a very long time, the tab should
1528 // hang indefinitely.
1529 EXPECT_TRUE(broken_tab_contents->IsLoading());
1530 EXPECT_EQ(1, NumLoadingTabs());
1533 void CaptivePortalBrowserTest::NavigateLoginTab(Browser* browser,
1534 int num_loading_tabs,
1535 int num_timed_out_tabs) {
1536 MultiNavigationObserver navigation_observer;
1537 CaptivePortalObserver portal_observer(browser->profile());
1539 TabStripModel* tab_strip_model = browser->tab_strip_model();
1540 int initial_tab_count = tab_strip_model->count();
1541 EXPECT_EQ(num_loading_tabs, NumLoadingTabs());
1542 EXPECT_EQ(num_timed_out_tabs, NumBrokenTabs() - NumLoadingTabs());
1544 int login_tab_index = tab_strip_model->active_index();
1545 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1546 GetStateOfTabReloader(tab_strip_model->GetActiveWebContents()));
1547 ASSERT_TRUE(IsLoginTab(browser->tab_strip_model()->GetActiveWebContents()));
1549 // Do the navigation.
1550 EXPECT_TRUE(content::ExecuteScript(tab_strip_model->GetActiveWebContents(),
1551 "submitForm()"));
1553 portal_observer.WaitForResults(1);
1554 navigation_observer.WaitForNavigations(1);
1556 // Check the captive portal result.
1557 EXPECT_EQ(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
1558 portal_observer.captive_portal_result());
1559 EXPECT_EQ(1, portal_observer.num_results_received());
1560 EXPECT_FALSE(CheckPending(browser));
1562 // Make sure not much has changed.
1563 EXPECT_EQ(initial_tab_count, tab_strip_model->count());
1564 EXPECT_EQ(num_loading_tabs, NumLoadingTabs());
1565 EXPECT_EQ(num_loading_tabs + num_timed_out_tabs, NumBrokenTabs());
1566 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1567 GetStateOfTabReloaderAt(browser, login_tab_index));
1568 EXPECT_TRUE(IsLoginTab(tab_strip_model->GetWebContentsAt(login_tab_index)));
1570 // Make sure there were no unexpected navigations.
1571 EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
1572 tab_strip_model->GetWebContentsAt(login_tab_index)));
1575 void CaptivePortalBrowserTest::Login(Browser* browser,
1576 int num_loading_tabs,
1577 int num_timed_out_tabs) {
1578 // Simulate logging in.
1579 factory_.SetBehindCaptivePortal(false);
1581 MultiNavigationObserver navigation_observer;
1582 CaptivePortalObserver portal_observer(browser->profile());
1584 TabStripModel* tab_strip_model = browser->tab_strip_model();
1585 int initial_tab_count = tab_strip_model->count();
1586 ASSERT_EQ(num_loading_tabs, NumLoadingTabs());
1587 EXPECT_EQ(num_timed_out_tabs, NumBrokenTabs() - NumLoadingTabs());
1589 // Verify that the login page is on top.
1590 int login_tab_index = tab_strip_model->active_index();
1591 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1592 GetStateOfTabReloaderAt(browser, login_tab_index));
1593 ASSERT_TRUE(IsLoginTab(tab_strip_model->GetWebContentsAt(login_tab_index)));
1595 // Trigger a navigation.
1596 EXPECT_TRUE(content::ExecuteScript(tab_strip_model->GetActiveWebContents(),
1597 "submitForm()"));
1599 portal_observer.WaitForResults(1);
1601 // Wait for all the timed out tabs to reload.
1602 navigation_observer.WaitForNavigations(1 + num_timed_out_tabs);
1603 EXPECT_EQ(1, portal_observer.num_results_received());
1605 // The tabs that were loading before should still be loading, and now be in
1606 // STATE_NEEDS_RELOAD.
1607 EXPECT_EQ(0, NumBrokenTabs());
1608 EXPECT_EQ(num_loading_tabs, NumLoadingTabs());
1609 EXPECT_EQ(num_loading_tabs, NumNeedReloadTabs());
1611 // Make sure that the broken tabs have reloaded, and there's no more
1612 // captive portal tab.
1613 EXPECT_EQ(initial_tab_count, tab_strip_model->count());
1614 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1615 GetStateOfTabReloaderAt(browser, login_tab_index));
1616 EXPECT_FALSE(IsLoginTab(tab_strip_model->GetWebContentsAt(login_tab_index)));
1618 // Make sure there were no unexpected navigations of the login tab.
1619 EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
1620 tab_strip_model->GetWebContentsAt(login_tab_index)));
1623 void CaptivePortalBrowserTest::LoginCertError(Browser* browser) {
1624 factory_.SetBehindCaptivePortal(false);
1626 MultiNavigationObserver navigation_observer;
1627 CaptivePortalObserver portal_observer(browser->profile());
1629 TabStripModel* tab_strip_model = browser->tab_strip_model();
1631 // Verify that the login page is on top.
1632 int login_tab_index = tab_strip_model->active_index();
1633 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1634 GetStateOfTabReloaderAt(browser, login_tab_index));
1635 ASSERT_TRUE(IsLoginTab(tab_strip_model->GetWebContentsAt(login_tab_index)));
1637 // Trigger a navigation.
1638 EXPECT_TRUE(content::ExecuteScript(tab_strip_model->GetActiveWebContents(),
1639 "submitForm()"));
1641 // The captive portal tab navigation will trigger a captive portal check,
1642 // and reloading the original tab will bring up the interstitial page again,
1643 // triggering a second captive portal check.
1644 portal_observer.WaitForResults(2);
1646 // Wait for both tabs to finish loading.
1647 navigation_observer.WaitForNavigations(2);
1648 EXPECT_EQ(2, portal_observer.num_results_received());
1649 EXPECT_FALSE(CheckPending(browser));
1650 EXPECT_EQ(captive_portal::RESULT_INTERNET_CONNECTED,
1651 portal_observer.captive_portal_result());
1653 // Check state of tabs. While the first tab is still displaying an
1654 // interstitial page, since no portal was found, it should be in STATE_NONE,
1655 // as should the login tab.
1656 ASSERT_EQ(2, tab_strip_model->count());
1657 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1658 GetStateOfTabReloaderAt(browser, 0));
1659 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1660 GetStateOfTabReloaderAt(browser, login_tab_index));
1661 EXPECT_FALSE(IsLoginTab(tab_strip_model->GetWebContentsAt(login_tab_index)));
1663 // Make sure only one navigation was for the login tab.
1664 EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
1665 tab_strip_model->GetWebContentsAt(login_tab_index)));
1668 void CaptivePortalBrowserTest::FailLoadsAfterLogin(Browser* browser,
1669 int num_loading_tabs) {
1670 ASSERT_EQ(num_loading_tabs, NumLoadingTabs());
1671 ASSERT_EQ(num_loading_tabs, NumNeedReloadTabs());
1672 EXPECT_EQ(0, NumBrokenTabs());
1674 TabStripModel* tab_strip_model = browser->tab_strip_model();
1675 int initial_num_tabs = tab_strip_model->count();
1676 int initial_active_tab = tab_strip_model->active_index();
1678 CaptivePortalObserver portal_observer(browser->profile());
1679 FailLoadsAfterLoginObserver fail_loads_observer;
1680 // Connection(s) finally time out. There should have already been a call
1681 // to wait for the requests to be issued before logging on.
1682 URLRequestTimeoutOnDemandJob::WaitForJobs(num_loading_tabs);
1683 URLRequestTimeoutOnDemandJob::FailJobs(num_loading_tabs);
1685 fail_loads_observer.WaitForNavigations();
1687 // No captive portal checks should have ocurred or be pending, and there
1688 // should be no new tabs.
1689 EXPECT_EQ(0, portal_observer.num_results_received());
1690 EXPECT_FALSE(CheckPending(browser));
1691 EXPECT_EQ(initial_num_tabs, tab_strip_model->count());
1693 EXPECT_EQ(initial_active_tab, tab_strip_model->active_index());
1695 EXPECT_EQ(0, NumNeedReloadTabs());
1696 EXPECT_EQ(0, NumLoadingTabs());
1699 void CaptivePortalBrowserTest::FailLoadsWithoutLogin(Browser* browser,
1700 int num_loading_tabs) {
1701 ASSERT_EQ(num_loading_tabs, NumLoadingTabs());
1702 ASSERT_EQ(0, NumNeedReloadTabs());
1703 EXPECT_EQ(num_loading_tabs, NumBrokenTabs());
1705 TabStripModel* tab_strip_model = browser->tab_strip_model();
1706 int initial_num_tabs = tab_strip_model->count();
1707 int login_tab = tab_strip_model->active_index();
1708 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1709 GetStateOfTabReloader(tab_strip_model->GetActiveWebContents()));
1710 ASSERT_TRUE(IsLoginTab(tab_strip_model->GetActiveWebContents()));
1712 CaptivePortalObserver portal_observer(browser->profile());
1713 MultiNavigationObserver navigation_observer;
1714 // Connection(s) finally time out. There should have already been a call
1715 // to wait for the requests to be issued.
1716 URLRequestTimeoutOnDemandJob::FailJobs(num_loading_tabs);
1718 navigation_observer.WaitForNavigations(num_loading_tabs);
1720 // No captive portal checks should have ocurred or be pending, and there
1721 // should be no new tabs.
1722 EXPECT_EQ(0, portal_observer.num_results_received());
1723 EXPECT_FALSE(CheckPending(browser));
1724 EXPECT_EQ(initial_num_tabs, tab_strip_model->count());
1726 EXPECT_EQ(0, NumNeedReloadTabs());
1727 EXPECT_EQ(0, NumLoadingTabs());
1728 EXPECT_EQ(num_loading_tabs, NumBrokenTabs());
1729 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1730 GetStateOfTabReloader(tab_strip_model->GetActiveWebContents()));
1731 EXPECT_TRUE(IsLoginTab(tab_strip_model->GetActiveWebContents()));
1732 EXPECT_EQ(login_tab, tab_strip_model->active_index());
1734 EXPECT_EQ(0, navigation_observer.NumNavigationsForTab(
1735 tab_strip_model->GetWebContentsAt(login_tab)));
1738 void CaptivePortalBrowserTest::RunNavigateLoadingTabToTimeoutTest(
1739 Browser* browser,
1740 const GURL& starting_url,
1741 const GURL& hanging_url,
1742 const GURL& timeout_url) {
1743 // Temporarily disable the captive portal and navigate to the starting
1744 // URL, which may be a URL that will hang when behind a captive portal.
1745 factory_.SetBehindCaptivePortal(false);
1746 NavigateToPageExpectNoTest(browser, starting_url, 1);
1747 factory_.SetBehindCaptivePortal(true);
1749 // Go to the first hanging url.
1750 SlowLoadBehindCaptivePortal(browser, true, hanging_url, 1, 1);
1752 // Abandon the request.
1753 URLRequestTimeoutOnDemandJob::WaitForJobs(1);
1754 URLRequestTimeoutOnDemandJob::AbandonJobs(1);
1756 TabStripModel* tab_strip_model = browser->tab_strip_model();
1757 CaptivePortalTabReloader* tab_reloader =
1758 GetTabReloader(tab_strip_model->GetWebContentsAt(0));
1759 ASSERT_TRUE(tab_reloader);
1761 // A non-zero delay makes it more likely that CaptivePortalTabHelper will
1762 // be confused by events relating to canceling the old navigation.
1763 SetSlowSSLLoadTime(tab_reloader, base::TimeDelta::FromSeconds(2));
1764 CaptivePortalObserver portal_observer(browser->profile());
1766 // Navigate the error tab to another slow loading page. Can't have
1767 // ui_test_utils do the navigation because it will wait for loading tabs to
1768 // stop loading before navigating.
1770 // This may result in either 0 or 1 DidStopLoading events. If there is one,
1771 // it must happen before the CaptivePortalService sends out its test request,
1772 // so waiting for PortalObserver to see that request prevents it from
1773 // confusing the MultiNavigationObservers used later.
1774 tab_strip_model->ActivateTabAt(0, true);
1775 browser->OpenURL(content::OpenURLParams(timeout_url,
1776 content::Referrer(),
1777 CURRENT_TAB,
1778 ui::PAGE_TRANSITION_TYPED,
1779 false));
1780 portal_observer.WaitForResults(1);
1781 EXPECT_FALSE(CheckPending(browser));
1782 EXPECT_EQ(1, NumLoadingTabs());
1783 EXPECT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
1784 GetStateOfTabReloaderAt(browser, 0));
1785 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1786 GetStateOfTabReloaderAt(browser, 1));
1787 ASSERT_TRUE(IsLoginTab(tab_strip_model->GetWebContentsAt(1)));
1789 // Need to make sure the request has been issued before logging in.
1790 URLRequestTimeoutOnDemandJob::WaitForJobs(1);
1792 // Simulate logging in.
1793 tab_strip_model->ActivateTabAt(1, true);
1794 SetSlowSSLLoadTime(tab_reloader, base::TimeDelta::FromDays(1));
1795 Login(browser, 1, 0);
1797 // Timeout occurs, and page is automatically reloaded.
1798 FailLoadsAfterLogin(browser, 1);
1801 void CaptivePortalBrowserTest::SetSlowSSLLoadTime(
1802 CaptivePortalTabReloader* tab_reloader,
1803 base::TimeDelta slow_ssl_load_time) {
1804 tab_reloader->set_slow_ssl_load_time(slow_ssl_load_time);
1807 CaptivePortalTabReloader* CaptivePortalBrowserTest::GetTabReloader(
1808 WebContents* web_contents) const {
1809 return CaptivePortalTabHelper::FromWebContents(web_contents)->
1810 GetTabReloaderForTest();
1813 // Make sure there's no test for a captive portal on HTTP timeouts. This will
1814 // also trigger the link doctor page, which results in the load of a second
1815 // error page.
1816 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, HttpTimeout) {
1817 GURL url = URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_TIMED_OUT);
1818 NavigateToPageExpectNoTest(browser(), url, 2);
1821 // Make sure there's no check for a captive portal on HTTPS errors other than
1822 // timeouts, when they preempt the slow load timer.
1823 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, HttpsNonTimeoutError) {
1824 GURL url = URLRequestFailedJob::GetMockHttpsUrl(net::ERR_UNEXPECTED);
1825 NavigateToPageExpectNoTest(browser(), url, 1);
1828 // Make sure no captive portal test triggers on HTTPS timeouts of iframes.
1829 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, HttpsIframeTimeout) {
1830 // Use an HTTPS server for the top level page.
1831 net::SpawnedTestServer https_server(
1832 net::SpawnedTestServer::TYPE_HTTPS, net::SpawnedTestServer::kLocalhost,
1833 base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
1834 ASSERT_TRUE(https_server.Start());
1836 GURL url = https_server.GetURL(kTestServerIframeTimeoutPath);
1837 NavigateToPageExpectNoTest(browser(), url, 1);
1840 // Check the captive portal result when the test request reports a network
1841 // error. The check is triggered by a slow loading page, and the page
1842 // errors out only after getting a captive portal result.
1843 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, RequestFails) {
1844 SetUpCaptivePortalService(
1845 browser()->profile(),
1846 URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_CLOSED));
1847 SlowLoadNoCaptivePortal(browser(), captive_portal::RESULT_NO_RESPONSE);
1850 // Same as above, but for the rather unlikely case that the connection times out
1851 // before the timer triggers.
1852 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, RequestFailsFastTimout) {
1853 SetUpCaptivePortalService(
1854 browser()->profile(),
1855 URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_CLOSED));
1856 FastTimeoutNoCaptivePortal(browser(), captive_portal::RESULT_NO_RESPONSE);
1859 // Checks the case that captive portal detection is disabled.
1860 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, Disabled) {
1861 EnableCaptivePortalDetection(browser()->profile(), false);
1862 SlowLoadNoCaptivePortal(browser(), captive_portal::RESULT_INTERNET_CONNECTED);
1865 // Checks that we look for a captive portal on HTTPS timeouts and don't reload
1866 // the error tab when the captive portal probe gets a 204 response, indicating
1867 // there is no captive portal.
1868 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, InternetConnected) {
1869 // Can't just use SetBehindCaptivePortal(false), since then there wouldn't
1870 // be a timeout.
1871 ASSERT_TRUE(test_server()->Start());
1872 SetUpCaptivePortalService(browser()->profile(),
1873 test_server()->GetURL("nocontent"));
1874 SlowLoadNoCaptivePortal(browser(), captive_portal::RESULT_INTERNET_CONNECTED);
1877 // Checks that no login page is opened when the HTTP test URL redirects to an
1878 // SSL certificate error.
1879 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, RedirectSSLCertError) {
1880 // Need an HTTP TestServer to handle a dynamically created server redirect.
1881 ASSERT_TRUE(test_server()->Start());
1883 net::SpawnedTestServer::SSLOptions ssl_options;
1884 ssl_options.server_certificate =
1885 net::SpawnedTestServer::SSLOptions::CERT_MISMATCHED_NAME;
1886 net::SpawnedTestServer https_server(
1887 net::SpawnedTestServer::TYPE_HTTPS, ssl_options,
1888 base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
1889 ASSERT_TRUE(https_server.Start());
1891 GURL ssl_login_url = https_server.GetURL(kTestServerLoginPath);
1893 CaptivePortalService* captive_portal_service =
1894 CaptivePortalServiceFactory::GetForProfile(browser()->profile());
1895 ASSERT_TRUE(captive_portal_service);
1896 SetUpCaptivePortalService(
1897 browser()->profile(),
1898 test_server()->GetURL(CreateServerRedirect(ssl_login_url.spec())));
1900 SlowLoadNoCaptivePortal(browser(), captive_portal::RESULT_NO_RESPONSE);
1903 // A slow SSL load triggers a captive portal check. The user logs on before
1904 // the SSL page times out. We wait for the timeout and subsequent reload.
1905 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, Login) {
1906 // Load starts, detect captive portal and open up a login tab.
1907 SlowLoadBehindCaptivePortal(browser(), true);
1909 // Log in. One loading tab, no timed out ones.
1910 Login(browser(), 1, 0);
1912 // Timeout occurs, and page is automatically reloaded.
1913 FailLoadsAfterLogin(browser(), 1);
1916 // Same as above, except we make sure everything works with an incognito
1917 // profile. Main issues it tests for are that the incognito has its own
1918 // non-NULL captive portal service, and we open the tab in the correct
1919 // window.
1920 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, LoginIncognito) {
1921 // This will watch tabs for both profiles, but only used to make sure no
1922 // navigations occur for the non-incognito profile.
1923 MultiNavigationObserver navigation_observer;
1924 CaptivePortalObserver non_incognito_portal_observer(browser()->profile());
1926 Browser* incognito_browser = CreateIncognitoBrowser();
1927 EnableCaptivePortalDetection(incognito_browser->profile(), true);
1928 SetUpCaptivePortalService(incognito_browser->profile(),
1929 GURL(kMockCaptivePortalTestUrl));
1931 SlowLoadBehindCaptivePortal(incognito_browser, true);
1933 TabStripModel* tab_strip_model = browser()->tab_strip_model();
1934 EXPECT_EQ(1, tab_strip_model->count());
1935 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1936 GetStateOfTabReloaderAt(browser(), 0));
1938 Login(incognito_browser, 1, 0);
1939 FailLoadsAfterLogin(incognito_browser, 1);
1941 EXPECT_EQ(1, tab_strip_model->count());
1942 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1943 GetStateOfTabReloaderAt(browser(), 0));
1945 EXPECT_EQ(0, navigation_observer.NumNavigationsForTab(
1946 tab_strip_model->GetWebContentsAt(0)));
1947 EXPECT_EQ(0, non_incognito_portal_observer.num_results_received());
1950 // The captive portal page is opened before the SSL page times out,
1951 // but the user logs in only after the page times out.
1952 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, LoginSlow) {
1953 SlowLoadBehindCaptivePortal(browser(), true);
1954 FailLoadsWithoutLogin(browser(), 1);
1955 Login(browser(), 0, 1);
1958 // Checks the unlikely case that the tab times out before the timer triggers.
1959 // This most likely won't happen, but should still work:
1960 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, LoginFastTimeout) {
1961 FastTimeoutBehindCaptivePortal(browser(), true);
1962 Login(browser(), 0, 1);
1965 // A cert error triggers a captive portal check and results in opening a login
1966 // tab.
1967 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
1968 ShowCaptivePortalInterstitialOnCertError) {
1969 net::SpawnedTestServer::SSLOptions https_options;
1970 https_options.server_certificate =
1971 net::SpawnedTestServer::SSLOptions::CERT_MISMATCHED_NAME;
1972 net::SpawnedTestServer https_server(
1973 net::SpawnedTestServer::TYPE_HTTPS, https_options,
1974 base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
1975 ASSERT_TRUE(https_server.Start());
1977 TabStripModel* tab_strip_model = browser()->tab_strip_model();
1978 WebContents* broken_tab_contents = tab_strip_model->GetActiveWebContents();
1980 // The path does not matter.
1981 GURL cert_error_url = https_server.GetURL(kTestServerLoginPath);
1982 int cert_error_tab_index = tab_strip_model->active_index();
1983 // The interstitial should trigger a captive portal check when it opens, just
1984 // like navigating to kMockHttpsQuickTimeoutUrl.
1985 FastErrorBehindCaptivePortal(browser(), true, cert_error_url, false);
1986 EXPECT_EQ(CaptivePortalBlockingPage::kTypeForTesting,
1987 GetInterstitialType(broken_tab_contents));
1989 // Switch to the interstitial and click the |Connect| button. Should switch
1990 // active tab to the captive portal landing page.
1991 int login_tab_index = tab_strip_model->active_index();
1992 tab_strip_model->ActivateTabAt(cert_error_tab_index, false);
1993 // Wait for the interstitial to load all the JavaScript code. Otherwise,
1994 // trying to click on a button will fail.
1995 content::RenderFrameHost* rfh =
1996 broken_tab_contents->GetInterstitialPage()->GetMainFrame();
1997 EXPECT_TRUE(WaitForRenderFrameReady(rfh));
1998 const char kClickConnectButtonJS[] =
1999 "document.getElementById('primary-button').click();";
2000 EXPECT_TRUE(
2001 content::ExecuteScript(rfh, kClickConnectButtonJS));
2002 EXPECT_EQ(login_tab_index, tab_strip_model->active_index());
2004 // For completeness, close the login tab and try clicking |Connect| again.
2005 // A new login tab should open.
2006 EXPECT_EQ(1, login_tab_index);
2007 content::WebContentsDestroyedWatcher destroyed_watcher(
2008 tab_strip_model->GetActiveWebContents());
2009 EXPECT_TRUE(
2010 tab_strip_model->CloseWebContentsAt(tab_strip_model->active_index(), 0));
2011 destroyed_watcher.Wait();
2012 MultiNavigationObserver navigation_observer;
2013 EXPECT_TRUE(
2014 content::ExecuteScript(rfh, kClickConnectButtonJS));
2015 navigation_observer.WaitForNavigations(1);
2016 EXPECT_EQ(login_tab_index, tab_strip_model->active_index());
2018 LoginCertError(browser());
2020 // Once logged in, broken tab should reload and display the SSL interstitial.
2021 WaitForInterstitialAttach(broken_tab_contents);
2022 tab_strip_model->ActivateTabAt(cert_error_tab_index, false);
2024 EXPECT_EQ(SSLBlockingPage::kTypeForTesting,
2025 GetInterstitialType(tab_strip_model->GetActiveWebContents()));
2027 // Trigger another captive portal check while the SSL interstitial is showing.
2028 // At this point the user is logged in to the captive portal, so the captive
2029 // portal interstitial shouldn't get recreated.
2030 CaptivePortalObserver portal_observer(browser()->profile());
2031 CaptivePortalService* captive_portal_service =
2032 CaptivePortalServiceFactory::GetForProfile(browser()->profile());
2033 captive_portal_service->DetectCaptivePortal();
2034 portal_observer.WaitForResults(1);
2035 EXPECT_EQ(SSLBlockingPage::kTypeForTesting,
2036 GetInterstitialType(broken_tab_contents));
2038 // A captive portal appears. Trigger a final captive portal check. The
2039 // captive portal interstitial should still not get recreated.
2040 factory_.SetBehindCaptivePortal(true);
2041 CaptivePortalObserver final_portal_observer(browser()->profile());
2042 captive_portal_service->DetectCaptivePortal();
2043 final_portal_observer.WaitForResults(1);
2044 EXPECT_EQ(SSLBlockingPage::kTypeForTesting,
2045 GetInterstitialType(broken_tab_contents));
2048 // Tests this scenario:
2049 // - Portal probe requests are ignored, so that no captive portal result can
2050 // arrive.
2051 // - A cert error triggers an interstitial timer with a very long timeout.
2052 // - No captive portal results arrive, causing the tab to appear as loading
2053 // indefinitely (because probe requests are ignored).
2054 // - Stopping the page load shouldn't result in any interstitials.
2055 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
2056 InterstitialTimerStopNavigationWhileLoading) {
2057 net::SpawnedTestServer::SSLOptions https_options;
2058 https_options.server_certificate =
2059 net::SpawnedTestServer::SSLOptions::CERT_MISMATCHED_NAME;
2060 net::SpawnedTestServer https_server(
2061 net::SpawnedTestServer::TYPE_HTTPS, https_options,
2062 base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
2063 ASSERT_TRUE(https_server.Start());
2064 // The path does not matter.
2065 GURL cert_error_url = https_server.GetURL(kTestServerLoginPath);
2067 TabStripModel* tab_strip_model = browser()->tab_strip_model();
2068 WebContents* broken_tab_contents = tab_strip_model->GetActiveWebContents();
2070 CaptivePortalObserver portal_observer1(browser()->profile());
2071 FastErrorWithInterstitialTimer(browser(), cert_error_url);
2073 // Page appears loading. Stop the navigation. There should be no interstitial.
2074 MultiNavigationObserver test_navigation_observer;
2075 broken_tab_contents->Stop();
2076 test_navigation_observer.WaitForNavigations(1);
2078 EXPECT_FALSE(broken_tab_contents->ShowingInterstitialPage());
2079 EXPECT_FALSE(broken_tab_contents->IsLoading());
2080 EXPECT_EQ(0, portal_observer1.num_results_received());
2081 EXPECT_EQ(0, NumLoadingTabs());
2082 EXPECT_FALSE(CheckPending(browser()));
2083 EXPECT_EQ(1, browser()->tab_strip_model()->count());
2084 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
2085 GetStateOfTabReloaderAt(browser(), 0));
2087 // Re-enable captive portal checks and fire one. The result should be ignored.
2088 RespondToProbeRequests(true);
2089 CaptivePortalObserver portal_observer2(browser()->profile());
2090 CaptivePortalService* captive_portal_service =
2091 CaptivePortalServiceFactory::GetForProfile(browser()->profile());
2092 captive_portal_service->DetectCaptivePortal();
2093 portal_observer2.WaitForResults(1);
2095 EXPECT_FALSE(broken_tab_contents->ShowingInterstitialPage());
2096 EXPECT_FALSE(broken_tab_contents->IsLoading());
2097 EXPECT_EQ(1, portal_observer2.num_results_received());
2098 EXPECT_EQ(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
2099 portal_observer2.captive_portal_result());
2100 EXPECT_EQ(0, NumLoadingTabs());
2101 EXPECT_FALSE(CheckPending(browser()));
2102 EXPECT_EQ(1, browser()->tab_strip_model()->count());
2103 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
2104 GetStateOfTabReloaderAt(browser(), 0));
2107 // Same as above, but instead of stopping, the loading page is reloaded. The end
2108 // result is the same. (i.e. page load stops, no interstitials shown)
2109 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
2110 InterstitialTimerReloadWhileLoading) {
2111 net::SpawnedTestServer::SSLOptions https_options;
2112 https_options.server_certificate =
2113 net::SpawnedTestServer::SSLOptions::CERT_MISMATCHED_NAME;
2114 net::SpawnedTestServer https_server(
2115 net::SpawnedTestServer::TYPE_HTTPS, https_options,
2116 base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
2117 ASSERT_TRUE(https_server.Start());
2118 // The path does not matter.
2119 GURL cert_error_url = https_server.GetURL(kTestServerLoginPath);
2121 TabStripModel* tab_strip_model = browser()->tab_strip_model();
2122 WebContents* broken_tab_contents = tab_strip_model->GetActiveWebContents();
2124 CaptivePortalObserver portal_observer(browser()->profile());
2125 FastErrorWithInterstitialTimer(browser(), cert_error_url);
2127 // Page appears loading. Reloading it cancels the page load. Since the load is
2128 // stopped, no cert error occurs and SSLErrorHandler isn't instantiated.
2129 MultiNavigationObserver test_navigation_observer;
2130 chrome::Reload(browser(), CURRENT_TAB);
2131 test_navigation_observer.WaitForNavigations(2);
2133 EXPECT_FALSE(broken_tab_contents->ShowingInterstitialPage());
2134 EXPECT_FALSE(broken_tab_contents->IsLoading());
2135 EXPECT_EQ(0, portal_observer.num_results_received());
2136 EXPECT_EQ(2, test_navigation_observer.num_navigations());
2137 EXPECT_EQ(0, NumLoadingTabs());
2138 EXPECT_FALSE(CheckPending(browser()));
2139 EXPECT_EQ(1, browser()->tab_strip_model()->count());
2140 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
2141 GetStateOfTabReloaderAt(browser(), 0));
2143 // Re-enable captive portal checks and fire one. The result should be ignored.
2144 RespondToProbeRequests(true);
2145 CaptivePortalObserver portal_observer2(browser()->profile());
2146 CaptivePortalService* captive_portal_service =
2147 CaptivePortalServiceFactory::GetForProfile(browser()->profile());
2148 captive_portal_service->DetectCaptivePortal();
2149 portal_observer2.WaitForResults(1);
2151 EXPECT_FALSE(broken_tab_contents->ShowingInterstitialPage());
2152 EXPECT_FALSE(broken_tab_contents->IsLoading());
2153 EXPECT_EQ(1, portal_observer2.num_results_received());
2154 EXPECT_EQ(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
2155 portal_observer2.captive_portal_result());
2156 EXPECT_EQ(0, NumLoadingTabs());
2157 EXPECT_FALSE(CheckPending(browser()));
2158 EXPECT_EQ(1, browser()->tab_strip_model()->count());
2159 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
2160 GetStateOfTabReloaderAt(browser(), 0));
2163 // Same as |InterstitialTimerReloadWhileLoading_NoSSLError|, but instead of
2164 // reloading, the page is navigated away. The new page should load, and no
2165 // interstitials should be shown.
2166 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
2167 InterstitialTimerNavigateAwayWhileLoading) {
2168 net::SpawnedTestServer::SSLOptions https_options;
2169 https_options.server_certificate =
2170 net::SpawnedTestServer::SSLOptions::CERT_MISMATCHED_NAME;
2171 net::SpawnedTestServer https_server(
2172 net::SpawnedTestServer::TYPE_HTTPS, https_options,
2173 base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
2174 ASSERT_TRUE(https_server.Start());
2175 // The path does not matter.
2176 GURL cert_error_url = https_server.GetURL(kTestServerLoginPath);
2178 TabStripModel* tab_strip_model = browser()->tab_strip_model();
2179 WebContents* broken_tab_contents = tab_strip_model->GetActiveWebContents();
2181 CaptivePortalObserver portal_observer(browser()->profile());
2182 FastErrorWithInterstitialTimer(browser(), cert_error_url);
2184 // Page appears loading. Navigating away shouldn't result in any interstitial.
2185 // Can't use ui_test_utils::NavigateToURLWithDisposition because it waits for
2186 // a load stop notification before starting a new navigation.
2187 MultiNavigationObserver test_navigation_observer;
2188 browser()->OpenURL(content::OpenURLParams(
2189 URLRequestMockHTTPJob::GetMockUrl(
2190 base::FilePath(FILE_PATH_LITERAL("title2.html"))),
2191 content::Referrer(),
2192 CURRENT_TAB,
2193 ui::PAGE_TRANSITION_TYPED, false));
2194 // Expect two navigations: First one for stopping the hanging page, second one
2195 // for completing the load of the above navigation.
2196 test_navigation_observer.WaitForNavigations(2);
2198 EXPECT_FALSE(broken_tab_contents->ShowingInterstitialPage());
2199 EXPECT_FALSE(broken_tab_contents->IsLoading());
2200 EXPECT_EQ(0, portal_observer.num_results_received());
2201 EXPECT_EQ(2, test_navigation_observer.num_navigations());
2202 EXPECT_EQ(0, NumLoadingTabs());
2203 EXPECT_FALSE(CheckPending(browser()));
2204 EXPECT_EQ(1, browser()->tab_strip_model()->count());
2205 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
2206 GetStateOfTabReloaderAt(browser(), 0));
2208 // Re-enable captive portal checks and fire one. The result should be ignored.
2209 RespondToProbeRequests(true);
2210 CaptivePortalObserver portal_observer2(browser()->profile());
2211 CaptivePortalService* captive_portal_service =
2212 CaptivePortalServiceFactory::GetForProfile(browser()->profile());
2213 captive_portal_service->DetectCaptivePortal();
2214 portal_observer2.WaitForResults(1);
2216 EXPECT_FALSE(broken_tab_contents->ShowingInterstitialPage());
2217 EXPECT_FALSE(broken_tab_contents->IsLoading());
2218 EXPECT_EQ(1, portal_observer2.num_results_received());
2219 EXPECT_EQ(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
2220 portal_observer2.captive_portal_result());
2221 EXPECT_EQ(0, NumLoadingTabs());
2222 EXPECT_FALSE(CheckPending(browser()));
2223 EXPECT_EQ(1, browser()->tab_strip_model()->count());
2224 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
2225 GetStateOfTabReloaderAt(browser(), 0));
2228 // Same as above, but the hanging load is interrupted by a navigation to the
2229 // same page, this time committing the navigation. This should end up with an
2230 // SSL interstitial when not behind a captive portal. This ensures that a new
2231 // |SSLErrorHandler| is created on a new navigation, even though the tab's
2232 // WebContents doesn't change.
2233 IN_PROC_BROWSER_TEST_F(
2234 CaptivePortalBrowserTest,
2235 InterstitialTimerNavigateWhileLoading_EndWithSSLInterstitial) {
2236 net::SpawnedTestServer::SSLOptions https_options;
2237 https_options.server_certificate =
2238 net::SpawnedTestServer::SSLOptions::CERT_MISMATCHED_NAME;
2239 net::SpawnedTestServer https_server(
2240 net::SpawnedTestServer::TYPE_HTTPS, https_options,
2241 base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
2242 ASSERT_TRUE(https_server.Start());
2243 // The path does not matter.
2244 GURL cert_error_url = https_server.GetURL(kTestServerLoginPath);
2245 factory_.SetBehindCaptivePortal(false);
2247 TabStripModel* tab_strip_model = browser()->tab_strip_model();
2248 WebContents* broken_tab_contents = tab_strip_model->GetActiveWebContents();
2250 FastErrorWithInterstitialTimer(browser(), cert_error_url);
2251 // Page appears loading. Turn on response to probe request again, and navigate
2252 // to the same page. This should result in a cert error which should
2253 // instantiate an |SSLErrorHandler| and end up showing an SSL interstitial.
2254 RespondToProbeRequests(true);
2255 // Can't have ui_test_utils do the navigation because it will wait for loading
2256 // tabs to stop loading before navigating.
2257 CaptivePortalObserver portal_observer(browser()->profile());
2258 MultiNavigationObserver test_navigation_observer;
2259 browser()->OpenURL(content::OpenURLParams(cert_error_url, content::Referrer(),
2260 CURRENT_TAB,
2261 ui::PAGE_TRANSITION_TYPED, false));
2262 // Expect two navigations: First one for stopping the hanging page, second one
2263 // for completing the load of the above navigation.
2264 test_navigation_observer.WaitForNavigations(2);
2265 // Should end up with an SSL interstitial.
2266 WaitForInterstitialAttach(broken_tab_contents);
2267 ASSERT_TRUE(broken_tab_contents->ShowingInterstitialPage());
2268 EXPECT_EQ(SSLBlockingPage::kTypeForTesting,
2269 broken_tab_contents->GetInterstitialPage()
2270 ->GetDelegateForTesting()
2271 ->GetTypeForTesting());
2272 EXPECT_FALSE(broken_tab_contents->IsLoading());
2273 EXPECT_EQ(1, portal_observer.num_results_received());
2274 EXPECT_EQ(captive_portal::RESULT_INTERNET_CONNECTED,
2275 portal_observer.captive_portal_result());
2276 EXPECT_EQ(0, NumLoadingTabs());
2277 EXPECT_FALSE(CheckPending(browser()));
2278 EXPECT_EQ(1, browser()->tab_strip_model()->count());
2279 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
2280 GetStateOfTabReloaderAt(browser(), 0));
2283 // Same as above, but this time behind a captive portal.
2284 IN_PROC_BROWSER_TEST_F(
2285 CaptivePortalBrowserTest,
2286 InterstitialTimerNavigateWhileLoading_EndWithCaptivePortalInterstitial) {
2287 net::SpawnedTestServer::SSLOptions https_options;
2288 https_options.server_certificate =
2289 net::SpawnedTestServer::SSLOptions::CERT_MISMATCHED_NAME;
2290 net::SpawnedTestServer https_server(
2291 net::SpawnedTestServer::TYPE_HTTPS, https_options,
2292 base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
2293 ASSERT_TRUE(https_server.Start());
2294 // The path does not matter.
2295 GURL cert_error_url = https_server.GetURL(kTestServerLoginPath);
2296 factory_.SetBehindCaptivePortal(true);
2298 TabStripModel* tab_strip_model = browser()->tab_strip_model();
2299 WebContents* broken_tab_contents = tab_strip_model->GetActiveWebContents();
2300 int initial_tab_count = tab_strip_model->count();
2302 FastErrorWithInterstitialTimer(browser(), cert_error_url);
2303 // Page appears loading. Turn on response to probe request again, and navigate
2304 // to the same page. This should result in a cert error which should
2305 // instantiate an |SSLErrorHandler| and end up showing an SSL.
2306 RespondToProbeRequests(true);
2307 // Can't have ui_test_utils do the navigation because it will wait for loading
2308 // tabs to stop loading before navigating.
2309 CaptivePortalObserver portal_observer(browser()->profile());
2310 MultiNavigationObserver test_navigation_observer;
2311 browser()->OpenURL(content::OpenURLParams(cert_error_url, content::Referrer(),
2312 CURRENT_TAB,
2313 ui::PAGE_TRANSITION_TYPED, false));
2314 // Expect three navigations:
2315 // 1- For stopping the hanging page.
2316 // 2- For completing the load of the above navigation.
2317 // 3- For completing the load of the login tab.
2318 test_navigation_observer.WaitForNavigations(3);
2319 // Should end up with a captive portal interstitial and a new login tab.
2320 WaitForInterstitialAttach(broken_tab_contents);
2321 ASSERT_TRUE(broken_tab_contents->ShowingInterstitialPage());
2322 EXPECT_EQ(CaptivePortalBlockingPage::kTypeForTesting,
2323 broken_tab_contents->GetInterstitialPage()
2324 ->GetDelegateForTesting()
2325 ->GetTypeForTesting());
2326 ASSERT_EQ(initial_tab_count + 1, tab_strip_model->count());
2327 EXPECT_EQ(initial_tab_count, tab_strip_model->active_index());
2328 EXPECT_FALSE(broken_tab_contents->IsLoading());
2329 EXPECT_EQ(1, portal_observer.num_results_received());
2330 EXPECT_EQ(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
2331 portal_observer.captive_portal_result());
2332 EXPECT_EQ(0, NumLoadingTabs());
2333 EXPECT_FALSE(CheckPending(browser()));
2334 EXPECT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
2335 GetStateOfTabReloaderAt(browser(), 0));
2336 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
2337 GetStateOfTabReloaderAt(browser(), 1));
2338 EXPECT_TRUE(IsLoginTab(tab_strip_model->GetWebContentsAt(1)));
2341 // A cert error triggers a captive portal check and results in opening a login
2342 // tab. The user then logs in and the page with the error is reloaded.
2343 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, SSLCertErrorLogin) {
2344 // Need an HTTP TestServer to handle a dynamically created server redirect.
2345 ASSERT_TRUE(test_server()->Start());
2347 net::SpawnedTestServer::SSLOptions https_options;
2348 https_options.server_certificate =
2349 net::SpawnedTestServer::SSLOptions::CERT_MISMATCHED_NAME;
2350 net::SpawnedTestServer https_server(
2351 net::SpawnedTestServer::TYPE_HTTPS, https_options,
2352 base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
2353 ASSERT_TRUE(https_server.Start());
2355 // Set SSL interstitial delay to zero so that a captive portal result can not
2356 // arrive during this window, so an SSL interstitial is displayed instead
2357 // of a captive portal error page.
2358 SSLErrorHandler::SetInterstitialDelayTypeForTest(SSLErrorHandler::NONE);
2359 TabStripModel* tab_strip_model = browser()->tab_strip_model();
2360 WebContents* broken_tab_contents = tab_strip_model->GetActiveWebContents();
2362 // Setting the delay to zero above has a race condition: A captive portal
2363 // result triggered by a cert error can arrive before the SSL interstitial
2364 // display timer is fired, even though it's set to zero.
2365 // To avoid this, disable captive portal checks until the SSL interstitial is
2366 // displayed. Once it's displayed, enable portal checks and fire one.
2367 bool delay_portal_response_until_interstital = true;
2369 // The path does not matter.
2370 GURL cert_error_url = https_server.GetURL(kTestServerLoginPath);
2371 // A captive portal check is triggered in FastErrorBehindCaptivePortal.
2372 FastErrorBehindCaptivePortal(
2373 browser(),
2374 true,
2375 cert_error_url,
2376 delay_portal_response_until_interstital);
2378 EXPECT_EQ(SSLBlockingPage::kTypeForTesting,
2379 GetInterstitialType(broken_tab_contents));
2381 LoginCertError(browser());
2384 // Tries navigating both the tab that encounters an SSL timeout and the
2385 // login tab twice, only logging in the second time.
2386 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, LoginExtraNavigations) {
2387 FastTimeoutBehindCaptivePortal(browser(), true);
2389 // Activate the timed out tab and navigate it to a timeout again.
2390 TabStripModel* tab_strip_model = browser()->tab_strip_model();
2391 tab_strip_model->ActivateTabAt(0, true);
2392 FastTimeoutBehindCaptivePortal(browser(), false);
2394 // Activate and navigate the captive portal tab. This should not trigger a
2395 // reload of the tab with the error.
2396 tab_strip_model->ActivateTabAt(1, true);
2397 NavigateLoginTab(browser(), 0, 1);
2399 // Simulate logging in.
2400 Login(browser(), 0, 1);
2403 // After the first SSL timeout, closes the login tab and makes sure it's opened
2404 // it again on a second timeout.
2405 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, CloseLoginTab) {
2406 // First load starts, opens a login tab, and then times out.
2407 SlowLoadBehindCaptivePortal(browser(), true);
2408 FailLoadsWithoutLogin(browser(), 1);
2410 // Close login tab.
2411 chrome::CloseTab(browser());
2413 // Go through the standard slow load login, and make sure it still works.
2414 SlowLoadBehindCaptivePortal(browser(), true);
2415 Login(browser(), 1, 0);
2416 FailLoadsAfterLogin(browser(), 1);
2419 // Checks that two tabs with SSL timeouts in the same window work. Both
2420 // tabs only timeout after logging in.
2421 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, TwoBrokenTabs) {
2422 SlowLoadBehindCaptivePortal(browser(), true);
2424 // Can't set the TabReloader HTTPS timeout on a new tab without doing some
2425 // acrobatics, so open a new tab at a normal page, and then navigate it to a
2426 // timeout.
2427 MultiNavigationObserver navigation_observer;
2428 CaptivePortalObserver portal_observer(browser()->profile());
2429 ui_test_utils::NavigateToURLWithDisposition(
2430 browser(),
2431 URLRequestMockHTTPJob::GetMockUrl(
2432 base::FilePath(FILE_PATH_LITERAL("title2.html"))),
2433 NEW_FOREGROUND_TAB,
2434 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
2436 TabStripModel* tab_strip_model = browser()->tab_strip_model();
2437 ASSERT_EQ(3, tab_strip_model->count());
2438 EXPECT_FALSE(CheckPending(browser()));
2439 EXPECT_EQ(0, portal_observer.num_results_received());
2440 EXPECT_EQ(1, NumLoadingTabs());
2441 EXPECT_EQ(1, navigation_observer.num_navigations());
2442 EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
2443 tab_strip_model->GetWebContentsAt(2)));
2444 ASSERT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
2445 GetStateOfTabReloaderAt(browser(), 0));
2446 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
2447 GetStateOfTabReloaderAt(browser(), 1));
2448 ASSERT_TRUE(IsLoginTab(tab_strip_model->GetWebContentsAt(1)));
2449 ASSERT_EQ(CaptivePortalTabReloader::STATE_NONE,
2450 GetStateOfTabReloaderAt(browser(), 2));
2451 ASSERT_EQ(2, tab_strip_model->active_index());
2453 SlowLoadBehindCaptivePortal(browser(), false);
2455 tab_strip_model->ActivateTabAt(1, true);
2456 Login(browser(), 2, 0);
2457 FailLoadsAfterLogin(browser(), 2);
2460 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, AbortLoad) {
2461 SlowLoadBehindCaptivePortal(browser(), true);
2463 // Abandon the request.
2464 URLRequestTimeoutOnDemandJob::WaitForJobs(1);
2465 URLRequestTimeoutOnDemandJob::AbandonJobs(1);
2467 CaptivePortalObserver portal_observer(browser()->profile());
2468 MultiNavigationObserver navigation_observer;
2470 // Switch back to the hung tab from the login tab, and abort the navigation.
2471 TabStripModel* tab_strip_model = browser()->tab_strip_model();
2472 tab_strip_model->ActivateTabAt(0, true);
2473 chrome::Stop(browser());
2474 navigation_observer.WaitForNavigations(1);
2476 EXPECT_EQ(0, NumBrokenTabs());
2477 EXPECT_EQ(0, portal_observer.num_results_received());
2478 EXPECT_FALSE(CheckPending(browser()));
2479 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
2480 GetStateOfTabReloaderAt(browser(), 0));
2482 tab_strip_model->ActivateTabAt(1, true);
2483 Login(browser(), 0, 0);
2486 // Checks the case where the timed out tab is successfully navigated before
2487 // logging in.
2488 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, NavigateBrokenTab) {
2489 // Go to the error page.
2490 SlowLoadBehindCaptivePortal(browser(), true);
2491 FailLoadsWithoutLogin(browser(), 1);
2493 // Navigate the error tab to a non-error page.
2494 TabStripModel* tab_strip_model = browser()->tab_strip_model();
2495 tab_strip_model->ActivateTabAt(0, true);
2496 ui_test_utils::NavigateToURL(
2497 browser(), URLRequestMockHTTPJob::GetMockUrl(
2498 base::FilePath(FILE_PATH_LITERAL("title2.html"))));
2499 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
2500 GetStateOfTabReloaderAt(browser(), 0));
2502 // Simulate logging in.
2503 tab_strip_model->ActivateTabAt(1, true);
2504 Login(browser(), 0, 0);
2507 // Checks that captive portal detection triggers correctly when a same-site
2508 // navigation is cancelled by a navigation to the same site.
2509 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
2510 NavigateLoadingTabToTimeoutSingleSite) {
2511 RunNavigateLoadingTabToTimeoutTest(
2512 browser(),
2513 GURL(kMockHttpsUrl),
2514 GURL(kMockHttpsUrl),
2515 GURL(kMockHttpsUrl));
2518 // Fails on Windows only, mostly on Win7. http://crbug.com/170033
2519 #if defined(OS_WIN)
2520 #define MAYBE_NavigateLoadingTabToTimeoutTwoSites \
2521 DISABLED_NavigateLoadingTabToTimeoutTwoSites
2522 #else
2523 #define MAYBE_NavigateLoadingTabToTimeoutTwoSites \
2524 NavigateLoadingTabToTimeoutTwoSites
2525 #endif
2527 // Checks that captive portal detection triggers correctly when a same-site
2528 // navigation is cancelled by a navigation to another site.
2529 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
2530 MAYBE_NavigateLoadingTabToTimeoutTwoSites) {
2531 RunNavigateLoadingTabToTimeoutTest(
2532 browser(),
2533 GURL(kMockHttpsUrl),
2534 GURL(kMockHttpsUrl),
2535 GURL(kMockHttpsUrl2));
2538 // Checks that captive portal detection triggers correctly when a cross-site
2539 // navigation is cancelled by a navigation to yet another site.
2540 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
2541 NavigateLoadingTabToTimeoutThreeSites) {
2542 RunNavigateLoadingTabToTimeoutTest(
2543 browser(),
2544 URLRequestMockHTTPJob::GetMockUrl(
2545 base::FilePath(FILE_PATH_LITERAL("title.html"))),
2546 GURL(kMockHttpsUrl),
2547 GURL(kMockHttpsUrl2));
2550 // Checks that navigating a timed out tab back clears its state.
2551 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, GoBack) {
2552 // Navigate to a working page.
2553 ui_test_utils::NavigateToURL(
2554 browser(),
2555 URLRequestMockHTTPJob::GetMockUrl(
2556 base::FilePath(FILE_PATH_LITERAL("title2.html"))));
2558 // Go to the error page.
2559 SlowLoadBehindCaptivePortal(browser(), true);
2560 FailLoadsWithoutLogin(browser(), 1);
2562 CaptivePortalObserver portal_observer(browser()->profile());
2563 MultiNavigationObserver navigation_observer;
2565 // Activate the error page tab again and go back.
2566 TabStripModel* tab_strip_model = browser()->tab_strip_model();
2567 tab_strip_model->ActivateTabAt(0, true);
2568 chrome::GoBack(browser(), CURRENT_TAB);
2569 navigation_observer.WaitForNavigations(1);
2571 EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
2572 tab_strip_model->GetWebContentsAt(0)));
2573 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
2574 GetStateOfTabReloaderAt(browser(), 0));
2575 EXPECT_EQ(0, portal_observer.num_results_received());
2578 // Checks that navigating back to a timeout triggers captive portal detection.
2579 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, GoBackToTimeout) {
2580 // Disable captive portal detection so the first navigation doesn't open a
2581 // login tab.
2582 EnableCaptivePortalDetection(browser()->profile(), false);
2584 SlowLoadNoCaptivePortal(browser(), captive_portal::RESULT_INTERNET_CONNECTED);
2586 // Navigate to a working page.
2587 ui_test_utils::NavigateToURL(
2588 browser(), URLRequestMockHTTPJob::GetMockUrl(
2589 base::FilePath(FILE_PATH_LITERAL("title2.html"))));
2590 ASSERT_EQ(CaptivePortalTabReloader::STATE_NONE,
2591 GetStateOfTabReloaderAt(browser(), 0));
2593 EnableCaptivePortalDetection(browser()->profile(), true);
2595 TabStripModel* tab_strip_model = browser()->tab_strip_model();
2596 CaptivePortalTabReloader* tab_reloader =
2597 GetTabReloader(tab_strip_model->GetActiveWebContents());
2598 ASSERT_TRUE(tab_reloader);
2599 SetSlowSSLLoadTime(tab_reloader, base::TimeDelta());
2601 // Go to the error page.
2602 MultiNavigationObserver navigation_observer;
2603 CaptivePortalObserver portal_observer(browser()->profile());
2604 chrome::GoBack(browser(), CURRENT_TAB);
2606 // Wait for the check triggered by the broken tab and for the login tab to
2607 // stop loading.
2608 portal_observer.WaitForResults(1);
2609 navigation_observer.WaitForNavigations(1);
2610 // Make sure the request has been issued.
2611 URLRequestTimeoutOnDemandJob::WaitForJobs(1);
2613 EXPECT_EQ(1, portal_observer.num_results_received());
2614 ASSERT_FALSE(CheckPending(browser()));
2615 ASSERT_EQ(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
2616 portal_observer.captive_portal_result());
2618 ASSERT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
2619 GetStateOfTabReloaderAt(browser(), 0));
2620 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
2621 GetStateOfTabReloaderAt(browser(), 1));
2622 ASSERT_TRUE(IsLoginTab(browser()->tab_strip_model()->GetWebContentsAt(1)));
2624 ASSERT_EQ(2, tab_strip_model->count());
2625 EXPECT_EQ(1, tab_strip_model->active_index());
2626 EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
2627 tab_strip_model->GetWebContentsAt(1)));
2628 EXPECT_EQ(1, NumLoadingTabs());
2630 SetSlowSSLLoadTime(tab_reloader, base::TimeDelta::FromDays(1));
2631 Login(browser(), 1, 0);
2632 FailLoadsAfterLogin(browser(), 1);
2635 // Checks that reloading a timeout triggers captive portal detection.
2636 // Much like the last test, though the captive portal is disabled before
2637 // the inital navigation, rather than captive portal detection.
2638 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, ReloadTimeout) {
2639 factory_.SetBehindCaptivePortal(false);
2641 // Do the first navigation while not behind a captive portal.
2642 TabStripModel* tab_strip_model = browser()->tab_strip_model();
2643 CaptivePortalObserver portal_observer(browser()->profile());
2644 ui_test_utils::NavigateToURL(browser(), GURL(kMockHttpsUrl));
2645 ASSERT_EQ(0, portal_observer.num_results_received());
2646 ASSERT_EQ(1, tab_strip_model->count());
2648 // A captive portal spontaneously appears.
2649 factory_.SetBehindCaptivePortal(true);
2651 CaptivePortalTabReloader* tab_reloader =
2652 GetTabReloader(tab_strip_model->GetActiveWebContents());
2653 ASSERT_TRUE(tab_reloader);
2654 SetSlowSSLLoadTime(tab_reloader, base::TimeDelta());
2656 MultiNavigationObserver navigation_observer;
2657 tab_strip_model->GetActiveWebContents()->GetController().Reload(true);
2659 // Wait for the check triggered by the broken tab and for the login tab to
2660 // stop loading.
2661 portal_observer.WaitForResults(1);
2662 navigation_observer.WaitForNavigations(1);
2663 // Make sure the request has been issued.
2664 URLRequestTimeoutOnDemandJob::WaitForJobs(1);
2666 ASSERT_EQ(1, portal_observer.num_results_received());
2667 ASSERT_FALSE(CheckPending(browser()));
2668 ASSERT_EQ(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
2669 portal_observer.captive_portal_result());
2671 ASSERT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
2672 GetStateOfTabReloaderAt(browser(), 0));
2673 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
2674 GetStateOfTabReloaderAt(browser(), 1));
2675 ASSERT_TRUE(IsLoginTab(tab_strip_model->GetWebContentsAt(1)));
2677 ASSERT_EQ(2, tab_strip_model->count());
2678 EXPECT_EQ(1, tab_strip_model->active_index());
2679 EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
2680 tab_strip_model->GetWebContentsAt(1)));
2681 EXPECT_EQ(1, NumLoadingTabs());
2683 SetSlowSSLLoadTime(tab_reloader, base::TimeDelta::FromDays(1));
2684 Login(browser(), 1, 0);
2685 FailLoadsAfterLogin(browser(), 1);
2688 // Checks the case where there are two windows, and there's an SSL timeout in
2689 // the background one.
2690 // Disabled: http://crbug.com/134357
2691 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, DISABLED_TwoWindows) {
2692 Browser* browser2 =
2693 new Browser(Browser::CreateParams(browser()->profile(),
2694 browser()->host_desktop_type()));
2695 // Navigate the new browser window so it'll be shown and we can pick the
2696 // active window.
2697 ui_test_utils::NavigateToURL(browser2, GURL(url::kAboutBlankURL));
2699 // Generally, |browser2| will be the active window. However, if the
2700 // original browser window lost focus before creating the new one, such as
2701 // when running multiple tests at once, the original browser window may
2702 // remain the profile's active window.
2703 Browser* active_browser =
2704 chrome::FindTabbedBrowser(browser()->profile(), true,
2705 browser()->host_desktop_type());
2706 Browser* inactive_browser;
2707 if (active_browser == browser2) {
2708 // When only one test is running at a time, the new browser will probably be
2709 // on top, but when multiple tests are running at once, this is not
2710 // guaranteed.
2711 inactive_browser = browser();
2712 } else {
2713 ASSERT_EQ(active_browser, browser());
2714 inactive_browser = browser2;
2717 CaptivePortalObserver portal_observer(browser()->profile());
2718 MultiNavigationObserver navigation_observer;
2720 // Navigate the tab in the inactive browser to an SSL timeout. Have to use
2721 // chrome::NavigateParams and NEW_BACKGROUND_TAB to avoid activating the
2722 // window.
2723 chrome::NavigateParams params(inactive_browser,
2724 GURL(kMockHttpsQuickTimeoutUrl),
2725 ui::PAGE_TRANSITION_TYPED);
2726 params.disposition = NEW_BACKGROUND_TAB;
2727 params.window_action = chrome::NavigateParams::NO_ACTION;
2728 ui_test_utils::NavigateToURL(&params);
2729 navigation_observer.WaitForNavigations(2);
2731 // Make sure the active window hasn't changed, and its new tab is
2732 // active.
2733 ASSERT_EQ(active_browser,
2734 chrome::FindTabbedBrowser(browser()->profile(), true,
2735 browser()->host_desktop_type()));
2736 ASSERT_EQ(1, active_browser->tab_strip_model()->active_index());
2738 // Check that the only two navigated tabs were the new error tab in the
2739 // backround windows, and the login tab in the active window.
2740 EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
2741 inactive_browser->tab_strip_model()->GetWebContentsAt(1)));
2742 EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
2743 active_browser->tab_strip_model()->GetWebContentsAt(1)));
2744 EXPECT_EQ(0, NumLoadingTabs());
2746 // Check captive portal test results.
2747 portal_observer.WaitForResults(1);
2748 ASSERT_EQ(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
2749 portal_observer.captive_portal_result());
2750 EXPECT_EQ(1, portal_observer.num_results_received());
2752 // Check the inactive browser.
2753 EXPECT_EQ(2, inactive_browser->tab_strip_model()->count());
2754 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
2755 GetStateOfTabReloaderAt(inactive_browser, 0));
2756 EXPECT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
2757 GetStateOfTabReloaderAt(inactive_browser, 1));
2759 // Check the active browser.
2760 ASSERT_EQ(2, active_browser->tab_strip_model()->count());
2761 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
2762 GetStateOfTabReloaderAt(active_browser, 0));
2763 EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
2764 GetStateOfTabReloaderAt(active_browser, 1));
2765 EXPECT_TRUE(
2766 IsLoginTab(active_browser->tab_strip_model()->GetWebContentsAt(1)));
2768 // Simulate logging in.
2769 Login(active_browser, 0, 1);
2772 // An HTTP page redirects to an HTTPS page loads slowly before timing out. A
2773 // captive portal is found, and then the user logs in before the original page
2774 // times out.
2775 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, HttpToHttpsRedirectLogin) {
2776 ASSERT_TRUE(test_server()->Start());
2777 SlowLoadBehindCaptivePortal(
2778 browser(),
2779 true,
2780 test_server()->GetURL(CreateServerRedirect(kMockHttpsUrl)),
2783 Login(browser(), 1, 0);
2784 FailLoadsAfterLogin(browser(), 1);
2787 // An HTTPS page redirects to an HTTP page.
2788 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, HttpsToHttpRedirect) {
2789 // Use an HTTPS server for the top level page.
2790 net::SpawnedTestServer https_server(
2791 net::SpawnedTestServer::TYPE_HTTPS, net::SpawnedTestServer::kLocalhost,
2792 base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
2793 ASSERT_TRUE(https_server.Start());
2795 GURL http_timeout_url =
2796 URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_TIMED_OUT);
2798 // 2 navigations due to the Link Doctor.
2799 NavigateToPageExpectNoTest(
2800 browser(),
2801 https_server.GetURL(CreateServerRedirect(http_timeout_url.spec())),
2805 // Tests the 511 response code, along with an HTML redirect to a login page.
2806 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, Status511) {
2807 SetUpCaptivePortalService(browser()->profile(),
2808 GURL(kMockCaptivePortal511Url));
2809 SlowLoadBehindCaptivePortal(browser(), true, GURL(kMockHttpsUrl), 2, 2);
2810 Login(browser(), 1, 0);
2811 FailLoadsAfterLogin(browser(), 1);
2814 // HSTS redirects an HTTP request to HTTPS, and the request then times out.
2815 // A captive portal is then detected, and a login tab opened, before logging
2816 // in.
2817 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, HstsLogin) {
2818 GURL::Replacements replacements;
2819 replacements.SetSchemeStr("http");
2820 GURL http_timeout_url = GURL(kMockHttpsUrl).ReplaceComponents(replacements);
2822 URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_TIMED_OUT);
2823 content::BrowserThread::PostTask(
2824 content::BrowserThread::IO, FROM_HERE,
2825 base::Bind(&AddHstsHost,
2826 make_scoped_refptr(browser()->profile()->GetRequestContext()),
2827 http_timeout_url.host()));
2829 SlowLoadBehindCaptivePortal(browser(), true, http_timeout_url, 1, 1);
2830 Login(browser(), 1, 0);
2831 FailLoadsAfterLogin(browser(), 1);
2834 // A slow SSL load starts. The reloader triggers a captive portal check, finds a
2835 // captive portal. The SSL commits with a cert error, triggering another captive
2836 // portal check.
2837 // The second check finds no captive portal. The reloader triggers a reload at
2838 // the same time SSL error handler tries to show an interstitial. Should result
2839 // in an SSL interstitial.
2840 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
2841 InterstitialTimerCertErrorAfterSlowLoad) {
2842 // Use a url that triggers a slow load, instead of creating an https server.
2843 GURL cert_error_url = GURL(kMockHttpsUrl);
2845 TabStripModel* tab_strip_model = browser()->tab_strip_model();
2846 int broken_tab_index = tab_strip_model->active_index();
2847 WebContents* broken_tab_contents = tab_strip_model->GetActiveWebContents();
2848 SlowLoadBehindCaptivePortal(browser(), true, cert_error_url, 1, 1);
2850 // No longer behind a captive portal. Committing the SSL page should trigger
2851 // an SSL interstitial which triggers a new captive portal check. Since there
2852 // is no captive portal anymore, should end up with an SSL interstitial.
2853 factory_.SetBehindCaptivePortal(false);
2855 CaptivePortalObserver portal_observer(browser()->profile());
2856 MultiNavigationObserver navigation_observer;
2857 URLRequestTimeoutOnDemandJob::FailJobsWithCertError(1);
2858 navigation_observer.WaitForNavigations(1);
2860 EXPECT_EQ(CaptivePortalTabReloader::STATE_NEEDS_RELOAD,
2861 GetStateOfTabReloaderAt(browser(), broken_tab_index));
2863 WaitForInterstitialAttach(broken_tab_contents);
2864 portal_observer.WaitForResults(1);
2866 EXPECT_EQ(SSLBlockingPage::kTypeForTesting,
2867 GetInterstitialType(broken_tab_contents));