captive_portal_browsertest.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <map>
6#include <set>
7
8#include "base/basictypes.h"
9#include "base/bind.h"
10#include "base/command_line.h"
11#include "base/compiler_specific.h"
12#include "base/files/file_path.h"
13#include "base/message_loop/message_loop.h"
14#include "base/path_service.h"
15#include "base/prefs/pref_service.h"
16#include "base/strings/utf_string_conversions.h"
17#include "chrome/browser/captive_portal/captive_portal_service.h"
18#include "chrome/browser/captive_portal/captive_portal_service_factory.h"
19#include "chrome/browser/captive_portal/captive_portal_tab_helper.h"
20#include "chrome/browser/captive_portal/captive_portal_tab_reloader.h"
21#include "chrome/browser/chrome_notification_types.h"
22#include "chrome/browser/net/url_request_mock_util.h"
23#include "chrome/browser/profiles/profile.h"
24#include "chrome/browser/ui/browser.h"
25#include "chrome/browser/ui/browser_commands.h"
26#include "chrome/browser/ui/browser_finder.h"
27#include "chrome/browser/ui/browser_navigator.h"
28#include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
29#include "chrome/browser/ui/tabs/tab_strip_model.h"
30#include "chrome/common/chrome_paths.h"
31#include "chrome/common/chrome_switches.h"
32#include "chrome/common/pref_names.h"
33#include "chrome/test/base/in_process_browser_test.h"
34#include "chrome/test/base/ui_test_utils.h"
35#include "content/public/browser/browser_thread.h"
36#include "content/public/browser/navigation_controller.h"
37#include "content/public/browser/notification_observer.h"
38#include "content/public/browser/notification_registrar.h"
39#include "content/public/browser/notification_service.h"
40#include "content/public/browser/notification_types.h"
41#include "content/public/browser/render_frame_host.h"
42#include "content/public/browser/web_contents.h"
43#include "content/public/common/url_constants.h"
44#include "content/test/net/url_request_failed_job.h"
45#include "content/test/net/url_request_mock_http_job.h"
46#include "net/base/net_errors.h"
47#include "net/http/transport_security_state.h"
48#include "net/url_request/url_request.h"
49#include "net/url_request/url_request_context.h"
50#include "net/url_request/url_request_context_getter.h"
51#include "net/url_request/url_request_filter.h"
52#include "net/url_request/url_request_job.h"
53#include "net/url_request/url_request_status.h"
54#include "testing/gtest/include/gtest/gtest.h"
55
56using captive_portal::CaptivePortalResult;
57using content::BrowserThread;
58using content::URLRequestFailedJob;
59using content::URLRequestMockHTTPJob;
60using content::WebContents;
61
62namespace {
63
64// Path of the fake login page, when using the TestServer.
65const char* const kTestServerLoginPath = "files/captive_portal/login.html";
66
67// Path of a page with an iframe that has a mock SSL timeout, when using the
68// TestServer.
69const char* const kTestServerIframeTimeoutPath =
70    "files/captive_portal/iframe_timeout.html";
71
72// The following URLs each have two different behaviors, depending on whether
73// URLRequestMockCaptivePortalJobFactory is currently simulating the presence
74// of a captive portal or not.  They use different domains so that HSTS can be
75// applied to them independently.
76
77// A mock URL for the CaptivePortalService's |test_url|.  When behind a captive
78// portal, this URL returns a mock login page.  When connected to the Internet,
79// it returns a 204 response.  Uses the name of the login file so that reloading
80// it will not request a different URL.
81const char* const kMockCaptivePortalTestUrl =
82    "http://mock.captive.portal.test/login.html";
83
84// Another mock URL for the CaptivePortalService's |test_url|.  When behind a
85// captive portal, this URL returns a 511 status code and an HTML page that
86// redirect to the above URL.  When connected to the Internet, it returns a 204
87// response.
88const char* const kMockCaptivePortal511Url =
89    "http://mock.captive.portal.511/page511.html";
90
91// When behind a captive portal, this URL hangs without committing until a call
92// to URLRequestTimeoutOnDemandJob::FailJobs.  When that function is called,
93// the request will time out.
94//
95// When connected to the Internet, this URL returns a non-error page.
96const char* const kMockHttpsUrl =
97    "https://mock.captive.portal.long.timeout/title2.html";
98
99// Same as above, but different domain, so can be used to trigger cross-site
100// navigations.
101const char* const kMockHttpsUrl2 =
102    "https://mock.captive.portal.long.timeout2/title2.html";
103
104// Same as kMockHttpsUrl, except the timeout happens instantly.
105const char* const kMockHttpsQuickTimeoutUrl =
106    "https://mock.captive.portal.quick.timeout/title2.html";
107
108// Expected title of a tab once an HTTPS load completes, when not behind a
109// captive portal.
110const char* const kInternetConnectedTitle = "Title Of Awesomeness";
111
112// A URL request job that hangs until FailJobs() is called.  Started jobs
113// are stored in a static class variable containing a linked list so that
114// FailJobs() can locate them.
115class URLRequestTimeoutOnDemandJob : public net::URLRequestJob,
116                                     public base::NonThreadSafe {
117 public:
118  // net::URLRequestJob:
119  virtual void Start() OVERRIDE;
120
121  // All the public static methods below can be called on any thread.
122
123  // Waits for exactly |num_jobs|.
124  static void WaitForJobs(int num_jobs);
125
126  // Fails all active URLRequestTimeoutOnDemandJobs with connection timeouts.
127  // There are expected to be exactly |expected_num_jobs| waiting for
128  // failure.  The only way to gaurantee this is with an earlier call to
129  // WaitForJobs, so makes sure there has been a matching WaitForJobs call.
130  static void FailJobs(int expected_num_jobs);
131
132  // Abandon all active URLRequestTimeoutOnDemandJobs.  |expected_num_jobs|
133  // behaves just as in FailJobs.
134  static void AbandonJobs(int expected_num_jobs);
135
136 private:
137  friend class URLRequestMockCaptivePortalJobFactory;
138
139  // Operation to perform on jobs when removing them from |job_list_|.
140  enum EndJobOperation {
141    FAIL_JOBS,
142    ABANDON_JOBS,
143  };
144
145  URLRequestTimeoutOnDemandJob(net::URLRequest* request,
146                               net::NetworkDelegate* network_delegate);
147  virtual ~URLRequestTimeoutOnDemandJob();
148
149  // Attempts to removes |this| from |jobs_|.  Returns true if it was removed
150  // from the list.
151  bool RemoveFromList();
152
153  static void WaitForJobsOnIOThread(int num_jobs);
154  static void FailOrAbandonJobsOnIOThread(
155      int expected_num_jobs,
156      EndJobOperation end_job_operation);
157
158  // Checks if there are at least |num_jobs_to_wait_for_| jobs in
159  // |job_list_|.  If so, exits the message loop on the UI thread, which
160  // should be spinning in a call to WaitForJobs.  Does nothing when
161  // |num_jobs_to_wait_for_| is 0.
162  static void MaybeStopWaitingForJobsOnIOThread();
163
164  // All class variables are only accessed on the IO thread.
165
166  // Number of jobs currently being waited for, or 0 if not currently
167  // waiting for jobs.
168  static int num_jobs_to_wait_for_;
169
170  // The last number of jobs that were waited for.  When FailJobs or
171  // AbandonJobs is called, this should match |expected_num_jobs|.
172  static int last_num_jobs_to_wait_for_;
173
174  // Number of jobs that have been started, but not yet waited for.  If jobs
175  // are deleted unexpectedly, they're still included in this count, even though
176  // they've been removed from |job_list_|.  Intended to reduce chance of stalls
177  // on regressions.
178  static int num_jobs_started_;
179
180  // Head of linked list of jobs that have been started and are now waiting to
181  // be timed out.
182  static URLRequestTimeoutOnDemandJob* job_list_;
183
184  // The next job that had been started but not yet timed out.
185  URLRequestTimeoutOnDemandJob* next_job_;
186
187  DISALLOW_COPY_AND_ASSIGN(URLRequestTimeoutOnDemandJob);
188};
189
190int URLRequestTimeoutOnDemandJob::num_jobs_to_wait_for_ = 0;
191int URLRequestTimeoutOnDemandJob::last_num_jobs_to_wait_for_ = 0;
192int URLRequestTimeoutOnDemandJob::num_jobs_started_ = 0;
193URLRequestTimeoutOnDemandJob* URLRequestTimeoutOnDemandJob::job_list_ = NULL;
194
195void URLRequestTimeoutOnDemandJob::Start() {
196  EXPECT_TRUE(CalledOnValidThread());
197
198  // Insert at start of the list.
199  next_job_ = job_list_;
200  job_list_ = this;
201  ++num_jobs_started_;
202
203  // Checks if there are at least |num_jobs_to_wait_for_| jobs in
204  // |job_list_|.  If so, exits the message loop on the UI thread, which
205  // should be spinning in a call to WaitForJobs.  Does nothing if
206  // |num_jobs_to_wait_for_| is 0.
207  MaybeStopWaitingForJobsOnIOThread();
208}
209
210// static
211void URLRequestTimeoutOnDemandJob::WaitForJobs(int num_jobs) {
212  content::BrowserThread::PostTask(
213      content::BrowserThread::IO, FROM_HERE,
214      base::Bind(&URLRequestTimeoutOnDemandJob::WaitForJobsOnIOThread,
215                 num_jobs));
216  content::RunMessageLoop();
217}
218
219// static
220void URLRequestTimeoutOnDemandJob::FailJobs(int expected_num_jobs) {
221  content::BrowserThread::PostTask(
222      content::BrowserThread::IO, FROM_HERE,
223      base::Bind(&URLRequestTimeoutOnDemandJob::FailOrAbandonJobsOnIOThread,
224                 expected_num_jobs,
225                 FAIL_JOBS));
226}
227
228// static
229void URLRequestTimeoutOnDemandJob::AbandonJobs(int expected_num_jobs) {
230  content::BrowserThread::PostTask(
231      content::BrowserThread::IO, FROM_HERE,
232      base::Bind(&URLRequestTimeoutOnDemandJob::FailOrAbandonJobsOnIOThread,
233                 expected_num_jobs,
234                 ABANDON_JOBS));
235}
236
237URLRequestTimeoutOnDemandJob::URLRequestTimeoutOnDemandJob(
238    net::URLRequest* request, net::NetworkDelegate* network_delegate)
239    : net::URLRequestJob(request, network_delegate),
240      next_job_(NULL) {
241}
242
243URLRequestTimeoutOnDemandJob::~URLRequestTimeoutOnDemandJob() {
244  // All hanging jobs should have failed or been abandoned before being
245  // destroyed.
246  EXPECT_FALSE(RemoveFromList());
247}
248
249bool URLRequestTimeoutOnDemandJob::RemoveFromList() {
250  URLRequestTimeoutOnDemandJob** job = &job_list_;
251  while (*job) {
252    if (*job == this) {
253      *job = next_job_;
254      next_job_ = NULL;
255      return true;
256    }
257    job = &next_job_;
258  }
259
260  // If the job wasn't in this list, |next_job_| should be NULL.
261  EXPECT_FALSE(next_job_);
262  return false;
263}
264
265// static
266void URLRequestTimeoutOnDemandJob::WaitForJobsOnIOThread(int num_jobs) {
267  ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
268  ASSERT_EQ(0, num_jobs_to_wait_for_);
269  ASSERT_LT(0, num_jobs);
270  // Number of tabs being waited on should be strictly increasing.
271  ASSERT_LE(last_num_jobs_to_wait_for_, num_jobs);
272
273  num_jobs_to_wait_for_ = num_jobs;
274  MaybeStopWaitingForJobsOnIOThread();
275}
276
277// static
278void URLRequestTimeoutOnDemandJob::MaybeStopWaitingForJobsOnIOThread() {
279  ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
280  if (num_jobs_to_wait_for_ == 0)
281    return;
282
283  // There shouldn't be any extra jobs.
284  EXPECT_LE(num_jobs_started_, num_jobs_to_wait_for_);
285
286  // Should never be greater, but if it is, go ahead and exit the message loop
287  // to try and avoid hanging.
288  if (num_jobs_started_ >= num_jobs_to_wait_for_) {
289    last_num_jobs_to_wait_for_ = num_jobs_to_wait_for_;
290    num_jobs_to_wait_for_ = 0;
291    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
292                            base::MessageLoop::QuitClosure());
293  }
294}
295
296// static
297void URLRequestTimeoutOnDemandJob::FailOrAbandonJobsOnIOThread(
298    int expected_num_jobs,
299    EndJobOperation end_job_operation) {
300  ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
301  ASSERT_LT(0, expected_num_jobs);
302  EXPECT_EQ(last_num_jobs_to_wait_for_, expected_num_jobs);
303  last_num_jobs_to_wait_for_ = 0;
304
305  int num_jobs = 0;
306  while (job_list_) {
307    ++num_jobs;
308    URLRequestTimeoutOnDemandJob* job = job_list_;
309    // Since the error notification may result in the job's destruction, remove
310    // it from the job list before the error.
311    EXPECT_TRUE(job->RemoveFromList());
312    if (end_job_operation == FAIL_JOBS) {
313      job->NotifyStartError(net::URLRequestStatus(
314                                net::URLRequestStatus::FAILED,
315                                net::ERR_CONNECTION_TIMED_OUT));
316    }
317  }
318
319  EXPECT_EQ(expected_num_jobs, num_jobs_started_);
320  EXPECT_EQ(expected_num_jobs, num_jobs);
321
322  num_jobs_started_ -= expected_num_jobs;
323}
324
325// URLRequestCaptivePortalJobFactory emulates captive portal behavior.
326// Initially, it emulates being behind a captive portal.  When
327// SetBehindCaptivePortal(false) is called, it emulates behavior when not behind
328// a captive portal.  The class itself is never instantiated.
329//
330// It handles requests for kMockCaptivePortalTestUrl, kMockHttpsUrl, and
331// kMockHttpsQuickTimeoutUrl.
332class URLRequestMockCaptivePortalJobFactory {
333 public:
334  // The public static methods below can be called on any thread.
335
336  // Adds the testing URLs to the net::URLRequestFilter.  Should only be called
337  // once.
338  static void AddUrlHandlers();
339
340  // Sets whether or not there is a captive portal.  Outstanding requests are
341  // not affected.
342  static void SetBehindCaptivePortal(bool behind_captive_portal);
343
344 private:
345  // These do all the work of the corresponding public functions, with the only
346  // difference being that they must be called on the IO thread.
347  static void AddUrlHandlersOnIOThread();
348  static void SetBehindCaptivePortalOnIOThread(bool behind_captive_portal);
349
350  // Returns a URLRequestJob that reflects the current captive portal state
351  // for the URLs: kMockCaptivePortalTestUrl, kMockHttpsUrl, and
352  // kMockHttpsQuickTimeoutUrl.  See documentation of individual URLs for
353  // actual behavior.
354  static net::URLRequestJob* Factory(net::URLRequest* request,
355                                     net::NetworkDelegate* network_delegate,
356                                     const std::string& scheme);
357
358  static bool behind_captive_portal_;
359
360  DISALLOW_IMPLICIT_CONSTRUCTORS(URLRequestMockCaptivePortalJobFactory);
361};
362
363bool URLRequestMockCaptivePortalJobFactory::behind_captive_portal_ = true;
364
365// static
366void URLRequestMockCaptivePortalJobFactory::AddUrlHandlers() {
367  content::BrowserThread::PostTask(
368      content::BrowserThread::IO, FROM_HERE,
369      base::Bind(
370          &URLRequestMockCaptivePortalJobFactory::AddUrlHandlersOnIOThread));
371}
372
373// static
374void URLRequestMockCaptivePortalJobFactory::SetBehindCaptivePortal(
375    bool behind_captive_portal) {
376  content::BrowserThread::PostTask(
377      content::BrowserThread::IO, FROM_HERE,
378      base::Bind(
379          &URLRequestMockCaptivePortalJobFactory::
380              SetBehindCaptivePortalOnIOThread,
381          behind_captive_portal));
382}
383
384// static
385void URLRequestMockCaptivePortalJobFactory::AddUrlHandlersOnIOThread() {
386  EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
387
388  // Handle only exact matches, so any related requests, such as those for
389  // favicons, are not handled by the factory.
390  net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance();
391  filter->AddUrlHandler(GURL(kMockCaptivePortalTestUrl),
392                        URLRequestMockCaptivePortalJobFactory::Factory);
393  filter->AddUrlHandler(GURL(kMockCaptivePortal511Url),
394                        URLRequestMockCaptivePortalJobFactory::Factory);
395  filter->AddUrlHandler(GURL(kMockHttpsUrl),
396                        URLRequestMockCaptivePortalJobFactory::Factory);
397  filter->AddUrlHandler(GURL(kMockHttpsUrl2),
398                        URLRequestMockCaptivePortalJobFactory::Factory);
399  filter->AddUrlHandler(GURL(kMockHttpsQuickTimeoutUrl),
400                        URLRequestMockCaptivePortalJobFactory::Factory);
401}
402
403// static
404void URLRequestMockCaptivePortalJobFactory::SetBehindCaptivePortalOnIOThread(
405    bool behind_captive_portal) {
406  EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
407  behind_captive_portal_ = behind_captive_portal;
408}
409
410// static
411net::URLRequestJob* URLRequestMockCaptivePortalJobFactory::Factory(
412    net::URLRequest* request,
413    net::NetworkDelegate* network_delegate,
414    const std::string& scheme) {
415  EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
416
417  // The PathService is threadsafe.
418  base::FilePath root_http;
419  PathService::Get(chrome::DIR_TEST_DATA, &root_http);
420
421  if (request->url() == GURL(kMockHttpsUrl) ||
422      request->url() == GURL(kMockHttpsUrl2)) {
423    if (behind_captive_portal_)
424      return new URLRequestTimeoutOnDemandJob(request, network_delegate);
425    // Once logged in to the portal, HTTPS requests return the page that was
426    // actually requested.
427    return new URLRequestMockHTTPJob(
428        request,
429        network_delegate,
430        root_http.Append(FILE_PATH_LITERAL("title2.html")));
431  } else if (request->url() == GURL(kMockHttpsQuickTimeoutUrl)) {
432    if (behind_captive_portal_)
433      return new URLRequestFailedJob(
434          request, network_delegate, net::ERR_CONNECTION_TIMED_OUT);
435    // Once logged in to the portal, HTTPS requests return the page that was
436    // actually requested.
437    return new URLRequestMockHTTPJob(
438        request,
439        network_delegate,
440        root_http.Append(FILE_PATH_LITERAL("title2.html")));
441  } else {
442    // The URL should be the captive portal test URL.
443    EXPECT_TRUE(GURL(kMockCaptivePortalTestUrl) == request->url() ||
444                GURL(kMockCaptivePortal511Url) == request->url());
445
446    if (behind_captive_portal_) {
447      // Prior to logging in to the portal, the HTTP test URLs are intercepted
448      // by the captive portal.
449      if (GURL(kMockCaptivePortal511Url) == request->url()) {
450        return new URLRequestMockHTTPJob(
451            request,
452            network_delegate,
453            root_http.Append(FILE_PATH_LITERAL("captive_portal/page511.html")));
454      }
455      return new URLRequestMockHTTPJob(
456          request,
457          network_delegate,
458          root_http.Append(FILE_PATH_LITERAL("captive_portal/login.html")));
459    }
460
461    // After logging in to the portal, the test URLs return a 204 response.
462    return new URLRequestMockHTTPJob(
463        request,
464        network_delegate,
465        root_http.Append(FILE_PATH_LITERAL("captive_portal/page204.html")));
466  }
467}
468
469// Creates a server-side redirect for use with the TestServer.
470std::string CreateServerRedirect(const std::string& dest_url) {
471  const char* const kServerRedirectBase = "server-redirect?";
472  return kServerRedirectBase + dest_url;
473}
474
475// Returns the total number of loading tabs across all Browsers, for all
476// Profiles.
477int NumLoadingTabs() {
478  int num_loading_tabs = 0;
479  for (TabContentsIterator it; !it.done(); it.Next()) {
480    if (it->IsLoading())
481      ++num_loading_tabs;
482  }
483  return num_loading_tabs;
484}
485
486bool IsLoginTab(WebContents* web_contents) {
487  return CaptivePortalTabHelper::FromWebContents(web_contents)->IsLoginTab();
488}
489
490// Tracks how many times each tab has been navigated since the Observer was
491// created.  The standard TestNavigationObserver can only watch specific
492// pre-existing tabs or loads in serial for all tabs.
493class MultiNavigationObserver : public content::NotificationObserver {
494 public:
495  MultiNavigationObserver();
496  virtual ~MultiNavigationObserver();
497
498  // Waits for exactly |num_navigations_to_wait_for| LOAD_STOP
499  // notifications to have occurred since the construction of |this|.  More
500  // navigations than expected occuring will trigger a expect failure.
501  void WaitForNavigations(int num_navigations_to_wait_for);
502
503  // Returns the number of LOAD_STOP events that have occurred for
504  // |web_contents| since this was constructed.
505  int NumNavigationsForTab(WebContents* web_contents) const;
506
507  // The number of LOAD_STOP events since |this| was created.
508  int num_navigations() const { return num_navigations_; }
509
510 private:
511  typedef std::map<const WebContents*, int> TabNavigationMap;
512
513  // content::NotificationObserver:
514  virtual void Observe(int type, const content::NotificationSource& source,
515                       const content::NotificationDetails& details) OVERRIDE;
516
517  int num_navigations_;
518
519  // Map of how many times each tab has navigated since |this| was created.
520  TabNavigationMap tab_navigation_map_;
521
522  // Total number of navigations to wait for.  Value only matters when
523  // |waiting_for_navigation_| is true.
524  int num_navigations_to_wait_for_;
525
526  // True if WaitForNavigations has been called, until
527  // |num_navigations_to_wait_for_| have been observed.
528  bool waiting_for_navigation_;
529
530  content::NotificationRegistrar registrar_;
531
532  DISALLOW_COPY_AND_ASSIGN(MultiNavigationObserver);
533};
534
535MultiNavigationObserver::MultiNavigationObserver()
536    : num_navigations_(0),
537      num_navigations_to_wait_for_(0),
538      waiting_for_navigation_(false) {
539  registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
540                 content::NotificationService::AllSources());
541}
542
543MultiNavigationObserver::~MultiNavigationObserver() {
544}
545
546void MultiNavigationObserver::WaitForNavigations(
547    int num_navigations_to_wait_for) {
548  // Shouldn't already be waiting for navigations.
549  EXPECT_FALSE(waiting_for_navigation_);
550  EXPECT_LT(0, num_navigations_to_wait_for);
551  if (num_navigations_ < num_navigations_to_wait_for) {
552    num_navigations_to_wait_for_ = num_navigations_to_wait_for;
553    waiting_for_navigation_ = true;
554    content::RunMessageLoop();
555    EXPECT_FALSE(waiting_for_navigation_);
556  }
557  EXPECT_EQ(num_navigations_, num_navigations_to_wait_for);
558}
559
560int MultiNavigationObserver::NumNavigationsForTab(
561    WebContents* web_contents) const {
562  TabNavigationMap::const_iterator tab_navigations =
563      tab_navigation_map_.find(web_contents);
564  if (tab_navigations == tab_navigation_map_.end())
565    return 0;
566  return tab_navigations->second;
567}
568
569void MultiNavigationObserver::Observe(
570    int type,
571    const content::NotificationSource& source,
572    const content::NotificationDetails& details) {
573  ASSERT_EQ(type, content::NOTIFICATION_LOAD_STOP);
574  content::NavigationController* controller =
575      content::Source<content::NavigationController>(source).ptr();
576  ++num_navigations_;
577  ++tab_navigation_map_[controller->GetWebContents()];
578  if (waiting_for_navigation_ &&
579      num_navigations_to_wait_for_ == num_navigations_) {
580    waiting_for_navigation_ = false;
581    base::MessageLoopForUI::current()->Quit();
582  }
583}
584
585// This observer creates a list of loading tabs, and then waits for them all
586// to stop loading and have the kInternetConnectedTitle.
587//
588// This is for the specific purpose of observing tabs time out after logging in
589// to a captive portal, which will then cause them to reload.
590// MultiNavigationObserver is insufficient for this because there may or may not
591// be a LOAD_STOP event between the timeout and the reload.
592// See bug http://crbug.com/133227
593class FailLoadsAfterLoginObserver : public content::NotificationObserver {
594 public:
595  FailLoadsAfterLoginObserver();
596  virtual ~FailLoadsAfterLoginObserver();
597
598  void WaitForNavigations();
599
600 private:
601  typedef std::set<const WebContents*> TabSet;
602
603  // content::NotificationObserver:
604  virtual void Observe(int type, const content::NotificationSource& source,
605                       const content::NotificationDetails& details) OVERRIDE;
606
607  // The set of tabs that need to be navigated.  This is the set of loading
608  // tabs when the observer is created.
609  TabSet tabs_needing_navigation_;
610
611  // Number of tabs that have stopped navigating with the expected title.  These
612  // are expected not to be navigated again.
613  TabSet tabs_navigated_to_final_destination_;
614
615  // True if WaitForNavigations has been called, until
616  // |tabs_navigated_to_final_destination_| equals |tabs_needing_navigation_|.
617  bool waiting_for_navigation_;
618
619  content::NotificationRegistrar registrar_;
620
621  DISALLOW_COPY_AND_ASSIGN(FailLoadsAfterLoginObserver);
622};
623
624FailLoadsAfterLoginObserver::FailLoadsAfterLoginObserver()
625    : waiting_for_navigation_(false) {
626  registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
627                 content::NotificationService::AllSources());
628  for (TabContentsIterator it; !it.done(); it.Next()) {
629    if (it->IsLoading())
630      tabs_needing_navigation_.insert(*it);
631  }
632}
633
634FailLoadsAfterLoginObserver::~FailLoadsAfterLoginObserver() {
635}
636
637void FailLoadsAfterLoginObserver::WaitForNavigations() {
638  // Shouldn't already be waiting for navigations.
639  EXPECT_FALSE(waiting_for_navigation_);
640  if (tabs_needing_navigation_.size() !=
641          tabs_navigated_to_final_destination_.size()) {
642    waiting_for_navigation_ = true;
643    content::RunMessageLoop();
644    EXPECT_FALSE(waiting_for_navigation_);
645  }
646  EXPECT_EQ(tabs_needing_navigation_.size(),
647            tabs_navigated_to_final_destination_.size());
648}
649
650void FailLoadsAfterLoginObserver::Observe(
651    int type,
652    const content::NotificationSource& source,
653    const content::NotificationDetails& details) {
654  ASSERT_EQ(type, content::NOTIFICATION_LOAD_STOP);
655  content::NavigationController* controller =
656      content::Source<content::NavigationController>(source).ptr();
657  WebContents* contents = controller->GetWebContents();
658
659  ASSERT_EQ(1u, tabs_needing_navigation_.count(contents));
660  ASSERT_EQ(0u, tabs_navigated_to_final_destination_.count(contents));
661
662  if (contents->GetTitle() != base::ASCIIToUTF16(kInternetConnectedTitle))
663    return;
664  tabs_navigated_to_final_destination_.insert(contents);
665
666  if (waiting_for_navigation_ &&
667      tabs_needing_navigation_.size() ==
668          tabs_navigated_to_final_destination_.size()) {
669    waiting_for_navigation_ = false;
670    base::MessageLoopForUI::current()->Quit();
671  }
672}
673
674// An observer for watching the CaptivePortalService.  It tracks the last
675// received result and the total number of received results.
676class CaptivePortalObserver : public content::NotificationObserver {
677 public:
678  explicit CaptivePortalObserver(Profile* profile);
679
680  // Runs the message loop until until at exactly |update_count| capitive portal
681  // results have been received, since this creation of |this|.  Expects no
682  // additional captive portal results.
683  void WaitForResults(int num_results_to_wait_for);
684
685  int num_results_received() const { return num_results_received_; }
686
687  CaptivePortalResult captive_portal_result() const {
688    return captive_portal_result_;
689  }
690
691 private:
692  // Records results and exits the message loop, if needed.
693  virtual void Observe(int type,
694                       const content::NotificationSource& source,
695                       const content::NotificationDetails& details) OVERRIDE;
696
697  // Number of times OnPortalResult has been called since construction.
698  int num_results_received_;
699
700  // If WaitForResults was called, the total number of updates for which to
701  // wait.  Value doesn't matter when |waiting_for_result_| is false.
702  int num_results_to_wait_for_;
703
704  bool waiting_for_result_;
705
706  Profile* profile_;
707
708  CaptivePortalService* captive_portal_service_;
709
710  // Last result received.
711  CaptivePortalResult captive_portal_result_;
712
713  content::NotificationRegistrar registrar_;
714
715  DISALLOW_COPY_AND_ASSIGN(CaptivePortalObserver);
716};
717
718CaptivePortalObserver::CaptivePortalObserver(Profile* profile)
719    : num_results_received_(0),
720      num_results_to_wait_for_(0),
721      waiting_for_result_(false),
722      profile_(profile),
723      captive_portal_service_(
724          CaptivePortalServiceFactory::GetForProfile(profile)),
725      captive_portal_result_(
726          captive_portal_service_->last_detection_result()) {
727  registrar_.Add(this,
728                 chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT,
729                 content::Source<Profile>(profile_));
730}
731
732void CaptivePortalObserver::WaitForResults(int num_results_to_wait_for) {
733  EXPECT_LT(0, num_results_to_wait_for);
734  EXPECT_FALSE(waiting_for_result_);
735  if (num_results_received_ < num_results_to_wait_for) {
736    num_results_to_wait_for_ = num_results_to_wait_for;
737    waiting_for_result_ = true;
738    content::RunMessageLoop();
739    EXPECT_FALSE(waiting_for_result_);
740  }
741  EXPECT_EQ(num_results_to_wait_for, num_results_received_);
742}
743
744void CaptivePortalObserver::Observe(
745    int type,
746    const content::NotificationSource& source,
747    const content::NotificationDetails& details) {
748  ASSERT_EQ(type, chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT);
749  ASSERT_EQ(profile_, content::Source<Profile>(source).ptr());
750
751  CaptivePortalService::Results* results =
752      content::Details<CaptivePortalService::Results>(details).ptr();
753
754  EXPECT_EQ(captive_portal_result_, results->previous_result);
755  EXPECT_EQ(captive_portal_service_->last_detection_result(),
756            results->result);
757
758  captive_portal_result_ = results->result;
759  ++num_results_received_;
760
761  if (waiting_for_result_ &&
762      num_results_to_wait_for_ == num_results_received_) {
763    waiting_for_result_ = false;
764    base::MessageLoop::current()->Quit();
765  }
766}
767
768// Adds an HSTS rule for |host|, so that all HTTP requests sent to it will
769// be switched to HTTPS requests.
770void AddHstsHost(net::URLRequestContextGetter* context_getter,
771                 const std::string& host) {
772  ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
773  net::TransportSecurityState* transport_security_state =
774      context_getter->GetURLRequestContext()->transport_security_state();
775  if (!transport_security_state) {
776    FAIL();
777    return;
778  }
779
780  base::Time expiry = base::Time::Now() + base::TimeDelta::FromDays(1000);
781  bool include_subdomains = false;
782  transport_security_state->AddHSTS(host, expiry, include_subdomains);
783}
784
785}  // namespace
786
787class CaptivePortalBrowserTest : public InProcessBrowserTest {
788 public:
789  CaptivePortalBrowserTest();
790
791  // InProcessBrowserTest:
792  virtual void SetUpOnMainThread() OVERRIDE;
793  virtual void TearDownOnMainThread() OVERRIDE;
794
795  // Sets the captive portal checking preference.  Does not affect the command
796  // line flag, which is set in SetUpCommandLine.
797  void EnableCaptivePortalDetection(Profile* profile, bool enabled);
798
799  // Sets up the captive portal service for the given profile so that
800  // all checks go to |test_url|.  Also disables all timers.
801  void SetUpCaptivePortalService(Profile* profile, const GURL& test_url);
802
803  // Returns true if |browser|'s profile is currently running a captive portal
804  // check.
805  bool CheckPending(Browser* browser);
806
807  // Returns the CaptivePortalTabReloader::State of |web_contents|.
808  CaptivePortalTabReloader::State GetStateOfTabReloader(
809      WebContents* web_contents) const;
810
811  // Returns the CaptivePortalTabReloader::State of the indicated tab.
812  CaptivePortalTabReloader::State GetStateOfTabReloaderAt(Browser* browser,
813                                                          int index) const;
814
815  // Returns the number of tabs with the given state, across all profiles.
816  int NumTabsWithState(CaptivePortalTabReloader::State state) const;
817
818  // Returns the number of tabs broken by captive portals, across all profiles.
819  int NumBrokenTabs() const;
820
821  // Returns the number of tabs that need to be reloaded due to having logged
822  // in to a captive portal, across all profiles.
823  int NumNeedReloadTabs() const;
824
825  // Navigates |browser|'s active tab to |url| and expects no captive portal
826  // test to be triggered.  |expected_navigations| is the number of times the
827  // active tab will end up being navigated.  It should be 1, except for the
828  // Link Doctor page, which acts like two navigations.
829  void NavigateToPageExpectNoTest(Browser* browser,
830                                  const GURL& url,
831                                  int expected_navigations);
832
833  // Navigates |browser|'s active tab to an SSL tab that takes a while to load,
834  // triggering a captive portal check, which is expected to give the result
835  // |expected_result|.  The page finishes loading, with a timeout, after the
836  // captive portal check.
837  void SlowLoadNoCaptivePortal(Browser* browser,
838                               CaptivePortalResult expected_result);
839
840  // Navigates |browser|'s active tab to an SSL timeout, expecting a captive
841  // portal check to be triggered and return a result which will indicates
842  // there's no detected captive portal.
843  void FastTimeoutNoCaptivePortal(Browser* browser,
844                                  CaptivePortalResult expected_result);
845
846  // Navigates the active tab to a slow loading SSL page, which will then
847  // trigger a captive portal test.  The test is expected to find a captive
848  // portal.  The slow loading page will continue to load after the function
849  // returns, until URLRequestTimeoutOnDemandJob::FailJobs() is called,
850  // at which point it will timeout.
851  //
852  // When |expect_login_tab| is false, no login tab is expected to be opened,
853  // because one already exists, and the function returns once the captive
854  // portal test is complete.
855  //
856  // If |expect_login_tab| is true, a login tab is then expected to be opened.
857  // It waits until both the login tab has finished loading, and two captive
858  // portal tests complete.  The second test is triggered by the load of the
859  // captive portal tab completing.
860  //
861  // This function must not be called when the active tab is currently loading.
862  // Waits for the hanging request to be issued, so other functions can rely
863  // on URLRequestTimeoutOnDemandJob::WaitForJobs having been called.
864  void SlowLoadBehindCaptivePortal(Browser* browser, bool expect_login_tab);
865
866  // Same as above, but takes extra parameters.
867  //
868  // |hanging_url| should either be kMockHttpsUrl or redirect to kMockHttpsUrl.
869  //
870  // |expected_portal_checks| and |expected_login_tab_navigations| allow
871  // client-side redirects to be tested.  |expected_login_tab_navigations| is
872  // ignored when |expect_open_login_tab| is false.
873  void SlowLoadBehindCaptivePortal(Browser* browser,
874                                   bool expect_open_login_tab,
875                                   const GURL& hanging_url,
876                                   int expected_portal_checks,
877                                   int expected_login_tab_navigations);
878
879  // Just like SlowLoadBehindCaptivePortal, except the navigated tab has
880  // a connection timeout rather having its time trigger, and the function
881  // waits until that timeout occurs.
882  void FastTimeoutBehindCaptivePortal(Browser* browser,
883                                      bool expect_open_login_tab);
884
885  // Much as above, but accepts a URL parameter and can be used for errors that
886  // trigger captive portal checks other than timeouts.  |error_url| should
887  // result in an error rather than hanging.
888  void FastErrorBehindCaptivePortal(Browser* browser,
889                                    bool expect_open_login_tab,
890                                    const GURL& error_url);
891
892  // Navigates the login tab without logging in.  The login tab must be the
893  // specified browser's active tab.  Expects no other tab to change state.
894  // |num_loading_tabs| and |num_timed_out_tabs| are used as extra checks
895  // that nothing has gone wrong prior to the function call.
896  void NavigateLoginTab(Browser* browser,
897                        int num_loading_tabs,
898                        int num_timed_out_tabs);
899
900  // Simulates a login by updating the URLRequestMockCaptivePortalJob's
901  // behind captive portal state, and navigating the login tab.  Waits for
902  // all broken but not loading tabs to be reloaded.
903  // |num_loading_tabs| and |num_timed_out_tabs| are used as extra checks
904  // that nothing has gone wrong prior to the function call.
905  void Login(Browser* browser, int num_loading_tabs, int num_timed_out_tabs);
906
907  // Makes the slow SSL loads of all active tabs time out at once, and waits for
908  // them to finish both that load and the automatic reload it should trigger.
909  // There should be no timed out tabs when this is called.
910  void FailLoadsAfterLogin(Browser* browser, int num_loading_tabs);
911
912  // Makes the slow SSL loads of all active tabs time out at once, and waits for
913  // them to finish displaying their error pages.  The login tab should be the
914  // active tab.  There should be no timed out tabs when this is called.
915  void FailLoadsWithoutLogin(Browser* browser, int num_loading_tabs);
916
917  // Navigates |browser|'s active tab to |starting_url| while not behind a
918  // captive portal.  Then navigates to |interrupted_url|, which should create
919  // a URLRequestTimeoutOnDemandJob, which is then abandoned.  The load should
920  // trigger a captive portal check, which finds a captive portal and opens a
921  // tab.
922  //
923  // Then the navigation is interrupted by a navigation to |timeout_url|, which
924  // should trigger a captive portal check, and finally the test simulates
925  // logging in.
926  //
927  // The purpose of this test is to make sure the TabHelper triggers a captive
928  // portal check when a load is interrupted by another load, particularly in
929  // the case of cross-process navigations.
930  void RunNavigateLoadingTabToTimeoutTest(Browser* browser,
931                                          const GURL& starting_url,
932                                          const GURL& interrupted_url,
933                                          const GURL& timeout_url);
934
935  // Sets the timeout used by a CaptivePortalTabReloader on slow SSL loads
936  // before a captive portal check.
937  void SetSlowSSLLoadTime(CaptivePortalTabReloader* tab_reloader,
938                          base::TimeDelta slow_ssl_load_time);
939
940  CaptivePortalTabReloader* GetTabReloader(WebContents* web_contents) const;
941
942 private:
943  DISALLOW_COPY_AND_ASSIGN(CaptivePortalBrowserTest);
944};
945
946CaptivePortalBrowserTest::CaptivePortalBrowserTest() {
947}
948
949void CaptivePortalBrowserTest::SetUpOnMainThread() {
950  // Enable mock requests.
951  content::BrowserThread::PostTask(
952      content::BrowserThread::IO, FROM_HERE,
953      base::Bind(&chrome_browser_net::SetUrlRequestMocksEnabled, true));
954  URLRequestMockCaptivePortalJobFactory::AddUrlHandlers();
955
956  // Double-check that the captive portal service isn't enabled by default for
957  // browser tests.
958  EXPECT_EQ(CaptivePortalService::DISABLED_FOR_TESTING,
959            CaptivePortalService::get_state_for_testing());
960
961  CaptivePortalService::set_state_for_testing(
962      CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING);
963  EnableCaptivePortalDetection(browser()->profile(), true);
964
965  // Set the captive portal service to use URLRequestMockCaptivePortalJob's
966  // mock URL, by default.
967  SetUpCaptivePortalService(browser()->profile(),
968                            GURL(kMockCaptivePortalTestUrl));
969}
970
971void CaptivePortalBrowserTest::TearDownOnMainThread() {
972  // No test should have a captive portal check pending on quit.
973  EXPECT_FALSE(CheckPending(browser()));
974}
975
976void CaptivePortalBrowserTest::EnableCaptivePortalDetection(
977    Profile* profile, bool enabled) {
978  profile->GetPrefs()->SetBoolean(prefs::kAlternateErrorPagesEnabled, enabled);
979}
980
981void CaptivePortalBrowserTest::SetUpCaptivePortalService(Profile* profile,
982                                                         const GURL& test_url) {
983  CaptivePortalService* captive_portal_service =
984      CaptivePortalServiceFactory::GetForProfile(profile);
985  captive_portal_service->set_test_url(test_url);
986
987  // Don't use any non-zero timers.  Timers are checked in unit tests.
988  CaptivePortalService::RecheckPolicy* recheck_policy =
989      &captive_portal_service->recheck_policy();
990  recheck_policy->initial_backoff_no_portal_ms = 0;
991  recheck_policy->initial_backoff_portal_ms = 0;
992  recheck_policy->backoff_policy.maximum_backoff_ms = 0;
993}
994
995bool CaptivePortalBrowserTest::CheckPending(Browser* browser) {
996  CaptivePortalService* captive_portal_service =
997      CaptivePortalServiceFactory::GetForProfile(browser->profile());
998
999  return captive_portal_service->DetectionInProgress() ||
1000      captive_portal_service->TimerRunning();
1001}
1002
1003CaptivePortalTabReloader::State CaptivePortalBrowserTest::GetStateOfTabReloader(
1004    WebContents* web_contents) const {
1005  return GetTabReloader(web_contents)->state();
1006}
1007
1008CaptivePortalTabReloader::State
1009CaptivePortalBrowserTest::GetStateOfTabReloaderAt(Browser* browser,
1010                                                  int index) const {
1011  return GetStateOfTabReloader(
1012      browser->tab_strip_model()->GetWebContentsAt(index));
1013}
1014
1015int CaptivePortalBrowserTest::NumTabsWithState(
1016    CaptivePortalTabReloader::State state) const {
1017  int num_tabs = 0;
1018  for (TabContentsIterator it; !it.done(); it.Next()) {
1019    if (GetStateOfTabReloader(*it) == state)
1020      ++num_tabs;
1021  }
1022  return num_tabs;
1023}
1024
1025int CaptivePortalBrowserTest::NumBrokenTabs() const {
1026  return NumTabsWithState(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL);
1027}
1028
1029int CaptivePortalBrowserTest::NumNeedReloadTabs() const {
1030  return NumTabsWithState(CaptivePortalTabReloader::STATE_NEEDS_RELOAD);
1031}
1032
1033void CaptivePortalBrowserTest::NavigateToPageExpectNoTest(
1034    Browser* browser,
1035    const GURL& url,
1036    int expected_navigations) {
1037  MultiNavigationObserver navigation_observer;
1038  CaptivePortalObserver portal_observer(browser->profile());
1039
1040  ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
1041      browser, url, expected_navigations);
1042
1043  // No captive portal checks should have ocurred or be pending, and there
1044  // should be no new tabs.
1045  EXPECT_EQ(0, portal_observer.num_results_received());
1046  EXPECT_FALSE(CheckPending(browser));
1047  EXPECT_EQ(1, browser->tab_strip_model()->count());
1048  EXPECT_EQ(expected_navigations, navigation_observer.num_navigations());
1049  EXPECT_EQ(0, NumLoadingTabs());
1050  EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1051            GetStateOfTabReloaderAt(browser, 0));
1052}
1053
1054void CaptivePortalBrowserTest::SlowLoadNoCaptivePortal(
1055    Browser* browser,
1056    CaptivePortalResult expected_result) {
1057  CaptivePortalTabReloader* tab_reloader =
1058      GetTabReloader(browser->tab_strip_model()->GetActiveWebContents());
1059  ASSERT_TRUE(tab_reloader);
1060  SetSlowSSLLoadTime(tab_reloader, base::TimeDelta());
1061
1062  MultiNavigationObserver navigation_observer;
1063  CaptivePortalObserver portal_observer(browser->profile());
1064  ui_test_utils::NavigateToURLWithDisposition(browser,
1065                                              GURL(kMockHttpsUrl),
1066                                              CURRENT_TAB,
1067                                              ui_test_utils::BROWSER_TEST_NONE);
1068
1069  portal_observer.WaitForResults(1);
1070
1071  ASSERT_EQ(1, browser->tab_strip_model()->count());
1072  EXPECT_EQ(expected_result, portal_observer.captive_portal_result());
1073  EXPECT_EQ(1, portal_observer.num_results_received());
1074  EXPECT_EQ(0, navigation_observer.num_navigations());
1075  EXPECT_FALSE(CheckPending(browser));
1076
1077  // First tab should still be loading.
1078  EXPECT_EQ(1, NumLoadingTabs());
1079
1080  // Wait for the request to be issued, then time it out.
1081  URLRequestTimeoutOnDemandJob::WaitForJobs(1);
1082  URLRequestTimeoutOnDemandJob::FailJobs(1);
1083  navigation_observer.WaitForNavigations(1);
1084
1085  ASSERT_EQ(1, browser->tab_strip_model()->count());
1086  EXPECT_EQ(1, portal_observer.num_results_received());
1087  EXPECT_FALSE(CheckPending(browser));
1088  EXPECT_EQ(0, NumLoadingTabs());
1089
1090  // Set a slow SSL load time to prevent the timer from triggering.
1091  SetSlowSSLLoadTime(tab_reloader, base::TimeDelta::FromDays(1));
1092}
1093
1094void CaptivePortalBrowserTest::FastTimeoutNoCaptivePortal(
1095    Browser* browser,
1096    CaptivePortalResult expected_result) {
1097  ASSERT_NE(expected_result, captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL);
1098
1099  // Set the load time to be large, so the timer won't trigger.  The value is
1100  // not restored at the end of the function.
1101  CaptivePortalTabReloader* tab_reloader =
1102      GetTabReloader(browser->tab_strip_model()->GetActiveWebContents());
1103  ASSERT_TRUE(tab_reloader);
1104  SetSlowSSLLoadTime(tab_reloader, base::TimeDelta::FromHours(1));
1105
1106  MultiNavigationObserver navigation_observer;
1107  CaptivePortalObserver portal_observer(browser->profile());
1108
1109  // Neither of these should be changed by the navigation.
1110  int active_index = browser->tab_strip_model()->active_index();
1111  int expected_tab_count = browser->tab_strip_model()->count();
1112
1113  ui_test_utils::NavigateToURL(
1114      browser,
1115      URLRequestFailedJob::GetMockHttpsUrl(net::ERR_CONNECTION_TIMED_OUT));
1116
1117  // An attempt to detect a captive portal should have started by now.  If not,
1118  // abort early to prevent hanging.
1119  ASSERT_TRUE(portal_observer.num_results_received() > 0 ||
1120              CheckPending(browser));
1121
1122  portal_observer.WaitForResults(1);
1123  navigation_observer.WaitForNavigations(1);
1124
1125  // Check the result.
1126  EXPECT_EQ(1, portal_observer.num_results_received());
1127  EXPECT_EQ(expected_result, portal_observer.captive_portal_result());
1128
1129  // Check that the right tab was navigated, and there were no extra
1130  // navigations.
1131  EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
1132                   browser->tab_strip_model()->GetWebContentsAt(active_index)));
1133  EXPECT_EQ(0, NumLoadingTabs());
1134
1135  // Check the tab's state, and verify no captive portal check is pending.
1136  EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1137            GetStateOfTabReloaderAt(browser, 0));
1138  EXPECT_FALSE(CheckPending(browser));
1139
1140  // Make sure no login tab was opened.
1141  EXPECT_EQ(expected_tab_count, browser->tab_strip_model()->count());
1142}
1143
1144void CaptivePortalBrowserTest::SlowLoadBehindCaptivePortal(
1145    Browser* browser,
1146    bool expect_open_login_tab) {
1147  SlowLoadBehindCaptivePortal(browser,
1148                              expect_open_login_tab,
1149                              GURL(kMockHttpsUrl),
1150                              1,
1151                              1);
1152}
1153
1154void CaptivePortalBrowserTest::SlowLoadBehindCaptivePortal(
1155    Browser* browser,
1156    bool expect_open_login_tab,
1157    const GURL& hanging_url,
1158    int expected_portal_checks,
1159    int expected_login_tab_navigations) {
1160  ASSERT_GE(expected_portal_checks, 1);
1161  TabStripModel* tab_strip_model = browser->tab_strip_model();
1162  // Calling this on a tab that's waiting for a load to manually be timed out
1163  // will result in a hang.
1164  ASSERT_FALSE(tab_strip_model->GetActiveWebContents()->IsLoading());
1165
1166  // Trigger a captive portal check quickly.
1167  CaptivePortalTabReloader* tab_reloader =
1168      GetTabReloader(tab_strip_model->GetActiveWebContents());
1169  ASSERT_TRUE(tab_reloader);
1170  SetSlowSSLLoadTime(tab_reloader, base::TimeDelta());
1171
1172  // Number of tabs expected to be open after the captive portal checks
1173  // have completed.
1174  int initial_tab_count = tab_strip_model->count();
1175  int initial_active_index = tab_strip_model->active_index();
1176  int initial_loading_tabs = NumLoadingTabs();
1177  int expected_broken_tabs = NumBrokenTabs();
1178  if (CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL !=
1179          GetStateOfTabReloader(tab_strip_model->GetActiveWebContents())) {
1180    ++expected_broken_tabs;
1181  }
1182
1183  MultiNavigationObserver navigation_observer;
1184  CaptivePortalObserver portal_observer(browser->profile());
1185  ui_test_utils::NavigateToURLWithDisposition(browser,
1186                                              hanging_url,
1187                                              CURRENT_TAB,
1188                                              ui_test_utils::BROWSER_TEST_NONE);
1189  portal_observer.WaitForResults(expected_portal_checks);
1190
1191  if (expect_open_login_tab) {
1192    ASSERT_GE(expected_login_tab_navigations, 1);
1193
1194    navigation_observer.WaitForNavigations(expected_login_tab_navigations);
1195
1196    ASSERT_EQ(initial_tab_count + 1, tab_strip_model->count());
1197    EXPECT_EQ(initial_tab_count, tab_strip_model->active_index());
1198
1199    EXPECT_EQ(expected_login_tab_navigations,
1200              navigation_observer.NumNavigationsForTab(
1201                  tab_strip_model->GetWebContentsAt(initial_tab_count)));
1202    EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1203              GetStateOfTabReloaderAt(browser, 1));
1204    EXPECT_TRUE(IsLoginTab(tab_strip_model->GetWebContentsAt(1)));
1205  } else {
1206    EXPECT_EQ(0, navigation_observer.num_navigations());
1207    EXPECT_EQ(initial_active_index, tab_strip_model->active_index());
1208    ASSERT_EQ(initial_tab_count, tab_strip_model->count());
1209    EXPECT_EQ(initial_active_index, tab_strip_model->active_index());
1210  }
1211
1212  // Wait for all the expect resource loads to actually start, so subsequent
1213  // functions can rely on them having started.
1214  URLRequestTimeoutOnDemandJob::WaitForJobs(initial_loading_tabs + 1);
1215
1216  EXPECT_EQ(initial_loading_tabs + 1, NumLoadingTabs());
1217  EXPECT_EQ(expected_broken_tabs, NumBrokenTabs());
1218  EXPECT_EQ(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
1219            portal_observer.captive_portal_result());
1220  EXPECT_EQ(expected_portal_checks, portal_observer.num_results_received());
1221  EXPECT_FALSE(CheckPending(browser));
1222
1223  EXPECT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
1224            GetStateOfTabReloaderAt(browser, initial_active_index));
1225
1226  // Reset the load time to be large, so the timer won't trigger on a reload.
1227  SetSlowSSLLoadTime(tab_reloader, base::TimeDelta::FromHours(1));
1228}
1229
1230void CaptivePortalBrowserTest::FastTimeoutBehindCaptivePortal(
1231    Browser* browser,
1232    bool expect_open_login_tab) {
1233  FastErrorBehindCaptivePortal(browser,
1234                               expect_open_login_tab,
1235                               GURL(kMockHttpsQuickTimeoutUrl));
1236}
1237
1238void CaptivePortalBrowserTest::FastErrorBehindCaptivePortal(
1239    Browser* browser,
1240    bool expect_open_login_tab,
1241    const GURL& error_url) {
1242  TabStripModel* tab_strip_model = browser->tab_strip_model();
1243  // Calling this on a tab that's waiting for a load to manually be timed out
1244  // will result in a hang.
1245  ASSERT_FALSE(tab_strip_model->GetActiveWebContents()->IsLoading());
1246
1247  // Set the load time to be large, so the timer won't trigger.  The value is
1248  // not restored at the end of the function.
1249  CaptivePortalTabReloader* tab_reloader =
1250      GetTabReloader(tab_strip_model->GetActiveWebContents());
1251  ASSERT_TRUE(tab_reloader);
1252  SetSlowSSLLoadTime(tab_reloader, base::TimeDelta::FromHours(1));
1253
1254  // Number of tabs expected to be open after the captive portal checks
1255  // have completed.
1256  int initial_tab_count = tab_strip_model->count();
1257  int initial_active_index = tab_strip_model->active_index();
1258  int initial_loading_tabs = NumLoadingTabs();
1259  int expected_broken_tabs = NumBrokenTabs();
1260  if (CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL !=
1261          GetStateOfTabReloader(tab_strip_model->GetActiveWebContents())) {
1262    ++expected_broken_tabs;
1263  }
1264
1265  MultiNavigationObserver navigation_observer;
1266  CaptivePortalObserver portal_observer(browser->profile());
1267  ui_test_utils::NavigateToURLWithDisposition(browser,
1268                                              error_url,
1269                                              CURRENT_TAB,
1270                                              ui_test_utils::BROWSER_TEST_NONE);
1271  portal_observer.WaitForResults(1);
1272
1273  if (expect_open_login_tab) {
1274    navigation_observer.WaitForNavigations(2);
1275    ASSERT_EQ(initial_tab_count + 1, tab_strip_model->count());
1276    EXPECT_EQ(initial_tab_count, tab_strip_model->active_index());
1277    // Make sure that the originally active tab and the captive portal tab have
1278    // each loaded once.
1279    EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
1280                     tab_strip_model->GetWebContentsAt(initial_active_index)));
1281    EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
1282                     tab_strip_model->GetWebContentsAt(initial_tab_count)));
1283    EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1284              GetStateOfTabReloaderAt(browser, 1));
1285    EXPECT_TRUE(IsLoginTab(tab_strip_model->GetWebContentsAt(1)));
1286  } else {
1287    navigation_observer.WaitForNavigations(1);
1288    EXPECT_EQ(initial_active_index, tab_strip_model->active_index());
1289    EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
1290                     tab_strip_model->GetWebContentsAt(initial_active_index)));
1291    ASSERT_EQ(initial_tab_count, tab_strip_model->count());
1292    EXPECT_EQ(initial_active_index, tab_strip_model->active_index());
1293  }
1294
1295  EXPECT_EQ(initial_loading_tabs, NumLoadingTabs());
1296  EXPECT_EQ(expected_broken_tabs, NumBrokenTabs());
1297  EXPECT_EQ(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
1298            portal_observer.captive_portal_result());
1299  EXPECT_EQ(1, portal_observer.num_results_received());
1300  EXPECT_FALSE(CheckPending(browser));
1301
1302  EXPECT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
1303            GetStateOfTabReloaderAt(browser, initial_active_index));
1304}
1305
1306void CaptivePortalBrowserTest::NavigateLoginTab(Browser* browser,
1307                                                int num_loading_tabs,
1308                                                int num_timed_out_tabs) {
1309  MultiNavigationObserver navigation_observer;
1310  CaptivePortalObserver portal_observer(browser->profile());
1311
1312  TabStripModel* tab_strip_model = browser->tab_strip_model();
1313  int initial_tab_count = tab_strip_model->count();
1314  EXPECT_EQ(num_loading_tabs, NumLoadingTabs());
1315  EXPECT_EQ(num_timed_out_tabs, NumBrokenTabs() - NumLoadingTabs());
1316
1317  int login_tab_index = tab_strip_model->active_index();
1318  EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1319            GetStateOfTabReloader(tab_strip_model->GetActiveWebContents()));
1320  ASSERT_TRUE(IsLoginTab(browser->tab_strip_model()->GetActiveWebContents()));
1321
1322  // Do the navigation.
1323  content::RenderFrameHost* render_frame_host =
1324      tab_strip_model->GetActiveWebContents()->GetMainFrame();
1325  render_frame_host->ExecuteJavaScript(base::ASCIIToUTF16("submitForm()"));
1326
1327  portal_observer.WaitForResults(1);
1328  navigation_observer.WaitForNavigations(1);
1329
1330  // Check the captive portal result.
1331  EXPECT_EQ(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
1332            portal_observer.captive_portal_result());
1333  EXPECT_EQ(1, portal_observer.num_results_received());
1334  EXPECT_FALSE(CheckPending(browser));
1335
1336  // Make sure not much has changed.
1337  EXPECT_EQ(initial_tab_count, tab_strip_model->count());
1338  EXPECT_EQ(num_loading_tabs, NumLoadingTabs());
1339  EXPECT_EQ(num_loading_tabs + num_timed_out_tabs, NumBrokenTabs());
1340  EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1341            GetStateOfTabReloaderAt(browser, login_tab_index));
1342  EXPECT_TRUE(IsLoginTab(tab_strip_model->GetWebContentsAt(login_tab_index)));
1343
1344  // Make sure there were no unexpected navigations.
1345  EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
1346                   tab_strip_model->GetWebContentsAt(login_tab_index)));
1347}
1348
1349void CaptivePortalBrowserTest::Login(Browser* browser,
1350                                     int num_loading_tabs,
1351                                     int num_timed_out_tabs) {
1352  // Simulate logging in.
1353  URLRequestMockCaptivePortalJobFactory::SetBehindCaptivePortal(false);
1354
1355  MultiNavigationObserver navigation_observer;
1356  CaptivePortalObserver portal_observer(browser->profile());
1357
1358  TabStripModel* tab_strip_model = browser->tab_strip_model();
1359  int initial_tab_count = tab_strip_model->count();
1360  ASSERT_EQ(num_loading_tabs, NumLoadingTabs());
1361  EXPECT_EQ(num_timed_out_tabs, NumBrokenTabs() - NumLoadingTabs());
1362
1363  // Verify that the login page is on top.
1364  int login_tab_index = tab_strip_model->active_index();
1365  EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1366            GetStateOfTabReloaderAt(browser, login_tab_index));
1367  ASSERT_TRUE(IsLoginTab(tab_strip_model->GetWebContentsAt(login_tab_index)));
1368
1369  // Trigger a navigation.
1370  content::RenderFrameHost* render_frame_host =
1371      tab_strip_model->GetActiveWebContents()->GetMainFrame();
1372  render_frame_host->ExecuteJavaScript(base::ASCIIToUTF16("submitForm()"));
1373
1374  portal_observer.WaitForResults(1);
1375
1376  // Wait for all the timed out tabs to reload.
1377  navigation_observer.WaitForNavigations(1 + num_timed_out_tabs);
1378  EXPECT_EQ(1, portal_observer.num_results_received());
1379
1380  // The tabs that were loading before should still be loading, and now be in
1381  // STATE_NEEDS_RELOAD.
1382  EXPECT_EQ(0, NumBrokenTabs());
1383  EXPECT_EQ(num_loading_tabs, NumLoadingTabs());
1384  EXPECT_EQ(num_loading_tabs, NumNeedReloadTabs());
1385
1386  // Make sure that the broken tabs have reloaded, and there's no more
1387  // captive portal tab.
1388  EXPECT_EQ(initial_tab_count, tab_strip_model->count());
1389  EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1390            GetStateOfTabReloaderAt(browser, login_tab_index));
1391  EXPECT_FALSE(IsLoginTab(tab_strip_model->GetWebContentsAt(login_tab_index)));
1392
1393  // Make sure there were no unexpected navigations of the login tab.
1394  EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
1395                   tab_strip_model->GetWebContentsAt(login_tab_index)));
1396}
1397
1398void CaptivePortalBrowserTest::FailLoadsAfterLogin(Browser* browser,
1399                                                   int num_loading_tabs) {
1400  ASSERT_EQ(num_loading_tabs, NumLoadingTabs());
1401  ASSERT_EQ(num_loading_tabs, NumNeedReloadTabs());
1402  EXPECT_EQ(0, NumBrokenTabs());
1403
1404  TabStripModel* tab_strip_model = browser->tab_strip_model();
1405  int initial_num_tabs = tab_strip_model->count();
1406  int initial_active_tab = tab_strip_model->active_index();
1407
1408  CaptivePortalObserver portal_observer(browser->profile());
1409  FailLoadsAfterLoginObserver fail_loads_observer;
1410  // Connection(s) finally time out.  There should have already been a call
1411  // to wait for the requests to be issued before logging on.
1412  URLRequestTimeoutOnDemandJob::WaitForJobs(num_loading_tabs);
1413  URLRequestTimeoutOnDemandJob::FailJobs(num_loading_tabs);
1414
1415  fail_loads_observer.WaitForNavigations();
1416
1417  // No captive portal checks should have ocurred or be pending, and there
1418  // should be no new tabs.
1419  EXPECT_EQ(0, portal_observer.num_results_received());
1420  EXPECT_FALSE(CheckPending(browser));
1421  EXPECT_EQ(initial_num_tabs, tab_strip_model->count());
1422
1423  EXPECT_EQ(initial_active_tab, tab_strip_model->active_index());
1424
1425  EXPECT_EQ(0, NumNeedReloadTabs());
1426  EXPECT_EQ(0, NumLoadingTabs());
1427}
1428
1429void CaptivePortalBrowserTest::FailLoadsWithoutLogin(Browser* browser,
1430                                                     int num_loading_tabs) {
1431  ASSERT_EQ(num_loading_tabs, NumLoadingTabs());
1432  ASSERT_EQ(0, NumNeedReloadTabs());
1433  EXPECT_EQ(num_loading_tabs, NumBrokenTabs());
1434
1435  TabStripModel* tab_strip_model = browser->tab_strip_model();
1436  int initial_num_tabs = tab_strip_model->count();
1437  int login_tab = tab_strip_model->active_index();
1438  EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1439            GetStateOfTabReloader(tab_strip_model->GetActiveWebContents()));
1440  ASSERT_TRUE(IsLoginTab(tab_strip_model->GetActiveWebContents()));
1441
1442  CaptivePortalObserver portal_observer(browser->profile());
1443  MultiNavigationObserver navigation_observer;
1444  // Connection(s) finally time out.  There should have already been a call
1445  // to wait for the requests to be issued.
1446  URLRequestTimeoutOnDemandJob::FailJobs(num_loading_tabs);
1447
1448  navigation_observer.WaitForNavigations(num_loading_tabs);
1449
1450  // No captive portal checks should have ocurred or be pending, and there
1451  // should be no new tabs.
1452  EXPECT_EQ(0, portal_observer.num_results_received());
1453  EXPECT_FALSE(CheckPending(browser));
1454  EXPECT_EQ(initial_num_tabs, tab_strip_model->count());
1455
1456  EXPECT_EQ(0, NumNeedReloadTabs());
1457  EXPECT_EQ(0, NumLoadingTabs());
1458  EXPECT_EQ(num_loading_tabs, NumBrokenTabs());
1459  EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1460            GetStateOfTabReloader(tab_strip_model->GetActiveWebContents()));
1461  EXPECT_TRUE(IsLoginTab(tab_strip_model->GetActiveWebContents()));
1462  EXPECT_EQ(login_tab, tab_strip_model->active_index());
1463
1464  EXPECT_EQ(0, navigation_observer.NumNavigationsForTab(
1465                   tab_strip_model->GetWebContentsAt(login_tab)));
1466}
1467
1468void CaptivePortalBrowserTest::RunNavigateLoadingTabToTimeoutTest(
1469    Browser* browser,
1470    const GURL& starting_url,
1471    const GURL& hanging_url,
1472    const GURL& timeout_url) {
1473  // Temporarily disable the captive portal and navigate to the starting
1474  // URL, which may be a URL that will hang when behind a captive portal.
1475  URLRequestMockCaptivePortalJobFactory::SetBehindCaptivePortal(false);
1476  NavigateToPageExpectNoTest(browser, starting_url, 1);
1477  URLRequestMockCaptivePortalJobFactory::SetBehindCaptivePortal(true);
1478
1479  // Go to the first hanging url.
1480  SlowLoadBehindCaptivePortal(browser, true, hanging_url, 1, 1);
1481
1482  // Abandon the request.
1483  URLRequestTimeoutOnDemandJob::WaitForJobs(1);
1484  URLRequestTimeoutOnDemandJob::AbandonJobs(1);
1485
1486  TabStripModel* tab_strip_model = browser->tab_strip_model();
1487  CaptivePortalTabReloader* tab_reloader =
1488      GetTabReloader(tab_strip_model->GetWebContentsAt(0));
1489  ASSERT_TRUE(tab_reloader);
1490
1491  // A non-zero delay makes it more likely that CaptivePortalTabHelper will
1492  // be confused by events relating to canceling the old navigation.
1493  SetSlowSSLLoadTime(tab_reloader, base::TimeDelta::FromSeconds(2));
1494  CaptivePortalObserver portal_observer(browser->profile());
1495
1496  // Navigate the error tab to another slow loading page.  Can't have
1497  // ui_test_utils do the navigation because it will wait for loading tabs to
1498  // stop loading before navigating.
1499  //
1500  // This may result in either 0 or 1 DidStopLoading events.  If there is one,
1501  // it must happen before the CaptivePortalService sends out its test request,
1502  // so waiting for PortalObserver to see that request prevents it from
1503  // confusing the MultiNavigationObservers used later.
1504  tab_strip_model->ActivateTabAt(0, true);
1505  browser->OpenURL(content::OpenURLParams(timeout_url,
1506                                          content::Referrer(),
1507                                          CURRENT_TAB,
1508                                          content::PAGE_TRANSITION_TYPED,
1509                                          false));
1510  portal_observer.WaitForResults(1);
1511  EXPECT_FALSE(CheckPending(browser));
1512  EXPECT_EQ(1, NumLoadingTabs());
1513  EXPECT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
1514            GetStateOfTabReloaderAt(browser, 0));
1515  EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1516            GetStateOfTabReloaderAt(browser, 1));
1517  ASSERT_TRUE(IsLoginTab(tab_strip_model->GetWebContentsAt(1)));
1518
1519  // Need to make sure the request has been issued before logging in.
1520  URLRequestTimeoutOnDemandJob::WaitForJobs(1);
1521
1522  // Simulate logging in.
1523  tab_strip_model->ActivateTabAt(1, true);
1524  SetSlowSSLLoadTime(tab_reloader, base::TimeDelta::FromDays(1));
1525  Login(browser, 1, 0);
1526
1527  // Timeout occurs, and page is automatically reloaded.
1528  FailLoadsAfterLogin(browser, 1);
1529}
1530
1531void CaptivePortalBrowserTest::SetSlowSSLLoadTime(
1532    CaptivePortalTabReloader* tab_reloader,
1533    base::TimeDelta slow_ssl_load_time) {
1534  tab_reloader->set_slow_ssl_load_time(slow_ssl_load_time);
1535}
1536
1537CaptivePortalTabReloader* CaptivePortalBrowserTest::GetTabReloader(
1538    WebContents* web_contents) const {
1539  return CaptivePortalTabHelper::FromWebContents(web_contents)->
1540      GetTabReloaderForTest();
1541}
1542
1543// Make sure there's no test for a captive portal on HTTP timeouts.  This will
1544// also trigger the link doctor page, which results in the load of a second
1545// error page.
1546IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, HttpTimeout) {
1547  GURL url = URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_TIMED_OUT);
1548  NavigateToPageExpectNoTest(browser(), url, 2);
1549}
1550
1551// Make sure there's no check for a captive portal on HTTPS errors other than
1552// timeouts, when they preempt the slow load timer.
1553IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, HttpsNonTimeoutError) {
1554  GURL url = URLRequestFailedJob::GetMockHttpsUrl(net::ERR_UNEXPECTED);
1555  NavigateToPageExpectNoTest(browser(), url, 1);
1556}
1557
1558// Make sure no captive portal test triggers on HTTPS timeouts of iframes.
1559IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, HttpsIframeTimeout) {
1560  // Use an HTTPS server for the top level page.
1561  net::SpawnedTestServer https_server(
1562      net::SpawnedTestServer::TYPE_HTTPS, net::SpawnedTestServer::kLocalhost,
1563      base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
1564  ASSERT_TRUE(https_server.Start());
1565
1566  GURL url = https_server.GetURL(kTestServerIframeTimeoutPath);
1567  NavigateToPageExpectNoTest(browser(), url, 1);
1568}
1569
1570// Check the captive portal result when the test request reports a network
1571// error.  The check is triggered by a slow loading page, and the page
1572// errors out only after getting a captive portal result.
1573IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, RequestFails) {
1574  SetUpCaptivePortalService(
1575      browser()->profile(),
1576      URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_CLOSED));
1577  SlowLoadNoCaptivePortal(browser(), captive_portal::RESULT_NO_RESPONSE);
1578}
1579
1580// Same as above, but for the rather unlikely case that the connection times out
1581// before the timer triggers.
1582IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, RequestFailsFastTimout) {
1583  SetUpCaptivePortalService(
1584      browser()->profile(),
1585      URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_CLOSED));
1586  FastTimeoutNoCaptivePortal(browser(), captive_portal::RESULT_NO_RESPONSE);
1587}
1588
1589// Checks the case that captive portal detection is disabled.
1590IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, Disabled) {
1591  EnableCaptivePortalDetection(browser()->profile(), false);
1592  SlowLoadNoCaptivePortal(browser(), captive_portal::RESULT_INTERNET_CONNECTED);
1593}
1594
1595// Checks that we look for a captive portal on HTTPS timeouts and don't reload
1596// the error tab when the captive portal probe gets a 204 response, indicating
1597// there is no captive portal.
1598IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, InternetConnected) {
1599  // Can't just use SetBehindCaptivePortal(false), since then there wouldn't
1600  // be a timeout.
1601  ASSERT_TRUE(test_server()->Start());
1602  SetUpCaptivePortalService(browser()->profile(),
1603                            test_server()->GetURL("nocontent"));
1604  SlowLoadNoCaptivePortal(browser(), captive_portal::RESULT_INTERNET_CONNECTED);
1605}
1606
1607// Checks that no login page is opened when the HTTP test URL redirects to an
1608// SSL certificate error.
1609IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, RedirectSSLCertError) {
1610  // Need an HTTP TestServer to handle a dynamically created server redirect.
1611  ASSERT_TRUE(test_server()->Start());
1612
1613  net::SpawnedTestServer::SSLOptions ssl_options;
1614  ssl_options.server_certificate =
1615      net::SpawnedTestServer::SSLOptions::CERT_MISMATCHED_NAME;
1616  net::SpawnedTestServer https_server(
1617      net::SpawnedTestServer::TYPE_HTTPS, ssl_options,
1618      base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
1619  ASSERT_TRUE(https_server.Start());
1620
1621  GURL ssl_login_url = https_server.GetURL(kTestServerLoginPath);
1622
1623  CaptivePortalService* captive_portal_service =
1624      CaptivePortalServiceFactory::GetForProfile(browser()->profile());
1625  ASSERT_TRUE(captive_portal_service);
1626  SetUpCaptivePortalService(
1627      browser()->profile(),
1628      test_server()->GetURL(CreateServerRedirect(ssl_login_url.spec())));
1629
1630  SlowLoadNoCaptivePortal(browser(), captive_portal::RESULT_NO_RESPONSE);
1631}
1632
1633// A slow SSL load triggers a captive portal check.  The user logs on before
1634// the SSL page times out.  We wait for the timeout and subsequent reload.
1635IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, Login) {
1636  // Load starts, detect captive portal and open up a login tab.
1637  SlowLoadBehindCaptivePortal(browser(), true);
1638
1639  // Log in.  One loading tab, no timed out ones.
1640  Login(browser(), 1, 0);
1641
1642  // Timeout occurs, and page is automatically reloaded.
1643  FailLoadsAfterLogin(browser(), 1);
1644}
1645
1646// Same as above, except we make sure everything works with an incognito
1647// profile.  Main issues it tests for are that the incognito has its own
1648// non-NULL captive portal service, and we open the tab in the correct
1649// window.
1650IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, LoginIncognito) {
1651  // This will watch tabs for both profiles, but only used to make sure no
1652  // navigations occur for the non-incognito profile.
1653  MultiNavigationObserver navigation_observer;
1654  CaptivePortalObserver non_incognito_portal_observer(browser()->profile());
1655
1656  Browser* incognito_browser = CreateIncognitoBrowser();
1657  EnableCaptivePortalDetection(incognito_browser->profile(), true);
1658  SetUpCaptivePortalService(incognito_browser->profile(),
1659                            GURL(kMockCaptivePortalTestUrl));
1660
1661  SlowLoadBehindCaptivePortal(incognito_browser, true);
1662
1663  TabStripModel* tab_strip_model = browser()->tab_strip_model();
1664  EXPECT_EQ(1, tab_strip_model->count());
1665  EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1666            GetStateOfTabReloaderAt(browser(), 0));
1667
1668  Login(incognito_browser, 1, 0);
1669  FailLoadsAfterLogin(incognito_browser, 1);
1670
1671  EXPECT_EQ(1, tab_strip_model->count());
1672  EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1673            GetStateOfTabReloaderAt(browser(), 0));
1674
1675  EXPECT_EQ(0, navigation_observer.NumNavigationsForTab(
1676                   tab_strip_model->GetWebContentsAt(0)));
1677  EXPECT_EQ(0, non_incognito_portal_observer.num_results_received());
1678}
1679
1680// The captive portal page is opened before the SSL page times out,
1681// but the user logs in only after the page times out.
1682IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, LoginSlow) {
1683  SlowLoadBehindCaptivePortal(browser(), true);
1684  FailLoadsWithoutLogin(browser(), 1);
1685  Login(browser(), 0, 1);
1686}
1687
1688// Checks the unlikely case that the tab times out before the timer triggers.
1689// This most likely won't happen, but should still work:
1690IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, LoginFastTimeout) {
1691  FastTimeoutBehindCaptivePortal(browser(), true);
1692  Login(browser(), 0, 1);
1693}
1694
1695// A cert error triggers a captive portal check and results in opening a login
1696// tab.  The user then logs in and the page with the error is reloaded.
1697IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, SSLCertErrorLogin) {
1698  // Need an HTTP TestServer to handle a dynamically created server redirect.
1699  ASSERT_TRUE(test_server()->Start());
1700
1701  net::SpawnedTestServer::SSLOptions https_options;
1702  https_options.server_certificate =
1703      net::SpawnedTestServer::SSLOptions::CERT_MISMATCHED_NAME;
1704  net::SpawnedTestServer https_server(
1705      net::SpawnedTestServer::TYPE_HTTPS, https_options,
1706      base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
1707  ASSERT_TRUE(https_server.Start());
1708
1709  // The path does not matter.
1710  GURL cert_error_url = https_server.GetURL(kTestServerLoginPath);
1711  // The interstitial should trigger a captive portal check when it opens, just
1712  // like navigating to kMockHttpsQuickTimeoutUrl.
1713  FastErrorBehindCaptivePortal(browser(), true, cert_error_url);
1714
1715  // Simulate logging in.  Can't use Login() because the interstitial tab looks
1716  // like a cross between a hung tab (Load was never committed) and a tab at an
1717  // error page (The load was stopped).
1718  URLRequestMockCaptivePortalJobFactory::SetBehindCaptivePortal(false);
1719  MultiNavigationObserver navigation_observer;
1720  CaptivePortalObserver portal_observer(browser()->profile());
1721
1722  TabStripModel* tab_strip_model = browser()->tab_strip_model();
1723  content::RenderFrameHost* render_frame_host =
1724      tab_strip_model->GetActiveWebContents()->GetMainFrame();
1725  render_frame_host->ExecuteJavaScript(base::ASCIIToUTF16("submitForm()"));
1726
1727  // The captive portal tab navigation will trigger a captive portal check,
1728  // and reloading the original tab will bring up the interstitial page again,
1729  // triggering a second captive portal check.
1730  portal_observer.WaitForResults(2);
1731
1732  // Wait for both tabs to finish loading.
1733  navigation_observer.WaitForNavigations(2);
1734  EXPECT_EQ(2, portal_observer.num_results_received());
1735  EXPECT_FALSE(CheckPending(browser()));
1736  EXPECT_EQ(captive_portal::RESULT_INTERNET_CONNECTED,
1737            portal_observer.captive_portal_result());
1738
1739  // Check state of tabs.  While the first tab is still displaying an
1740  // interstitial page, since no portal was found, it should be in STATE_NONE,
1741  // as should the login tab.
1742  ASSERT_EQ(2, tab_strip_model->count());
1743  EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1744            GetStateOfTabReloaderAt(browser(), 0));
1745  EXPECT_FALSE(IsLoginTab(tab_strip_model->GetWebContentsAt(1)));
1746  EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1747            GetStateOfTabReloaderAt(browser(), 1));
1748
1749  // Make sure only one navigation was for the login tab.
1750  EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
1751                   tab_strip_model->GetWebContentsAt(1)));
1752}
1753
1754// Tries navigating both the tab that encounters an SSL timeout and the
1755// login tab twice, only logging in the second time.
1756IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, LoginExtraNavigations) {
1757  FastTimeoutBehindCaptivePortal(browser(), true);
1758
1759  // Activate the timed out tab and navigate it to a timeout again.
1760  TabStripModel* tab_strip_model = browser()->tab_strip_model();
1761  tab_strip_model->ActivateTabAt(0, true);
1762  FastTimeoutBehindCaptivePortal(browser(), false);
1763
1764  // Activate and navigate the captive portal tab.  This should not trigger a
1765  // reload of the tab with the error.
1766  tab_strip_model->ActivateTabAt(1, true);
1767  NavigateLoginTab(browser(), 0, 1);
1768
1769  // Simulate logging in.
1770  Login(browser(), 0, 1);
1771}
1772
1773// After the first SSL timeout, closes the login tab and makes sure it's opened
1774// it again on a second timeout.
1775IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, CloseLoginTab) {
1776  // First load starts, opens a login tab, and then times out.
1777  SlowLoadBehindCaptivePortal(browser(), true);
1778  FailLoadsWithoutLogin(browser(), 1);
1779
1780  // Close login tab.
1781  chrome::CloseTab(browser());
1782
1783  // Go through the standard slow load login, and make sure it still works.
1784  SlowLoadBehindCaptivePortal(browser(), true);
1785  Login(browser(), 1, 0);
1786  FailLoadsAfterLogin(browser(), 1);
1787}
1788
1789// Checks that two tabs with SSL timeouts in the same window work.  Both
1790// tabs only timeout after logging in.
1791IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, TwoBrokenTabs) {
1792  SlowLoadBehindCaptivePortal(browser(), true);
1793
1794  // Can't set the TabReloader HTTPS timeout on a new tab without doing some
1795  // acrobatics, so open a new tab at a normal page, and then navigate it to a
1796  // timeout.
1797  MultiNavigationObserver navigation_observer;
1798  CaptivePortalObserver portal_observer(browser()->profile());
1799  ui_test_utils::NavigateToURLWithDisposition(
1800      browser(),
1801      URLRequestMockHTTPJob::GetMockUrl(
1802          base::FilePath(FILE_PATH_LITERAL("title2.html"))),
1803      NEW_FOREGROUND_TAB,
1804      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
1805
1806  TabStripModel* tab_strip_model = browser()->tab_strip_model();
1807  ASSERT_EQ(3, tab_strip_model->count());
1808  EXPECT_FALSE(CheckPending(browser()));
1809  EXPECT_EQ(0, portal_observer.num_results_received());
1810  EXPECT_EQ(1, NumLoadingTabs());
1811  EXPECT_EQ(1, navigation_observer.num_navigations());
1812  EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
1813                   tab_strip_model->GetWebContentsAt(2)));
1814  ASSERT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
1815            GetStateOfTabReloaderAt(browser(), 0));
1816  EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1817            GetStateOfTabReloaderAt(browser(), 1));
1818  ASSERT_TRUE(IsLoginTab(tab_strip_model->GetWebContentsAt(1)));
1819  ASSERT_EQ(CaptivePortalTabReloader::STATE_NONE,
1820            GetStateOfTabReloaderAt(browser(), 2));
1821  ASSERT_EQ(2, tab_strip_model->active_index());
1822
1823  SlowLoadBehindCaptivePortal(browser(), false);
1824
1825  tab_strip_model->ActivateTabAt(1, true);
1826  Login(browser(), 2, 0);
1827  FailLoadsAfterLogin(browser(), 2);
1828}
1829
1830IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, AbortLoad) {
1831  SlowLoadBehindCaptivePortal(browser(), true);
1832
1833  // Abandon the request.
1834  URLRequestTimeoutOnDemandJob::WaitForJobs(1);
1835  URLRequestTimeoutOnDemandJob::AbandonJobs(1);
1836
1837  CaptivePortalObserver portal_observer(browser()->profile());
1838  MultiNavigationObserver navigation_observer;
1839
1840  // Switch back to the hung tab from the login tab, and abort the navigation.
1841  TabStripModel* tab_strip_model = browser()->tab_strip_model();
1842  tab_strip_model->ActivateTabAt(0, true);
1843  chrome::Stop(browser());
1844  navigation_observer.WaitForNavigations(1);
1845
1846  EXPECT_EQ(0, NumBrokenTabs());
1847  EXPECT_EQ(0, portal_observer.num_results_received());
1848  EXPECT_FALSE(CheckPending(browser()));
1849  EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1850            GetStateOfTabReloaderAt(browser(), 0));
1851
1852  tab_strip_model->ActivateTabAt(1, true);
1853  Login(browser(), 0, 0);
1854}
1855
1856// Checks the case where the timed out tab is successfully navigated before
1857// logging in.
1858IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, NavigateBrokenTab) {
1859  // Go to the error page.
1860  SlowLoadBehindCaptivePortal(browser(), true);
1861  FailLoadsWithoutLogin(browser(), 1);
1862
1863  // Navigate the error tab to a non-error page.
1864  TabStripModel* tab_strip_model = browser()->tab_strip_model();
1865  tab_strip_model->ActivateTabAt(0, true);
1866  ui_test_utils::NavigateToURL(
1867      browser(), URLRequestMockHTTPJob::GetMockUrl(
1868                     base::FilePath(FILE_PATH_LITERAL("title2.html"))));
1869  EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1870            GetStateOfTabReloaderAt(browser(), 0));
1871
1872  // Simulate logging in.
1873  tab_strip_model->ActivateTabAt(1, true);
1874  Login(browser(), 0, 0);
1875}
1876
1877// Checks that captive portal detection triggers correctly when a same-site
1878// navigation is cancelled by a navigation to the same site.
1879IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
1880                       NavigateLoadingTabToTimeoutSingleSite) {
1881  RunNavigateLoadingTabToTimeoutTest(
1882      browser(),
1883      GURL(kMockHttpsUrl),
1884      GURL(kMockHttpsUrl),
1885      GURL(kMockHttpsUrl));
1886}
1887
1888// Fails on Windows only, mostly on Win7. http://crbug.com/170033
1889#if defined(OS_WIN)
1890#define MAYBE_NavigateLoadingTabToTimeoutTwoSites \
1891        DISABLED_NavigateLoadingTabToTimeoutTwoSites
1892#else
1893#define MAYBE_NavigateLoadingTabToTimeoutTwoSites \
1894        NavigateLoadingTabToTimeoutTwoSites
1895#endif
1896
1897// Checks that captive portal detection triggers correctly when a same-site
1898// navigation is cancelled by a navigation to another site.
1899IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
1900                       MAYBE_NavigateLoadingTabToTimeoutTwoSites) {
1901  RunNavigateLoadingTabToTimeoutTest(
1902      browser(),
1903      GURL(kMockHttpsUrl),
1904      GURL(kMockHttpsUrl),
1905      GURL(kMockHttpsUrl2));
1906}
1907
1908// Checks that captive portal detection triggers correctly when a cross-site
1909// navigation is cancelled by a navigation to yet another site.
1910IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest,
1911                       NavigateLoadingTabToTimeoutThreeSites) {
1912  RunNavigateLoadingTabToTimeoutTest(
1913      browser(),
1914      URLRequestMockHTTPJob::GetMockUrl(
1915          base::FilePath(FILE_PATH_LITERAL("title.html"))),
1916      GURL(kMockHttpsUrl),
1917      GURL(kMockHttpsUrl2));
1918}
1919
1920// Checks that navigating a timed out tab back clears its state.
1921IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, GoBack) {
1922  // Navigate to a working page.
1923  ui_test_utils::NavigateToURL(
1924      browser(),
1925      URLRequestMockHTTPJob::GetMockUrl(
1926          base::FilePath(FILE_PATH_LITERAL("title2.html"))));
1927
1928  // Go to the error page.
1929  SlowLoadBehindCaptivePortal(browser(), true);
1930  FailLoadsWithoutLogin(browser(), 1);
1931
1932  CaptivePortalObserver portal_observer(browser()->profile());
1933  MultiNavigationObserver navigation_observer;
1934
1935  // Activate the error page tab again and go back.
1936  TabStripModel* tab_strip_model = browser()->tab_strip_model();
1937  tab_strip_model->ActivateTabAt(0, true);
1938  chrome::GoBack(browser(), CURRENT_TAB);
1939  navigation_observer.WaitForNavigations(1);
1940
1941  EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
1942                   tab_strip_model->GetWebContentsAt(0)));
1943  EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1944            GetStateOfTabReloaderAt(browser(), 0));
1945  EXPECT_EQ(0, portal_observer.num_results_received());
1946}
1947
1948// Checks that navigating back to a timeout triggers captive portal detection.
1949IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, GoBackToTimeout) {
1950  // Disable captive portal detection so the first navigation doesn't open a
1951  // login tab.
1952  EnableCaptivePortalDetection(browser()->profile(), false);
1953
1954  SlowLoadNoCaptivePortal(browser(), captive_portal::RESULT_INTERNET_CONNECTED);
1955
1956  // Navigate to a working page.
1957  ui_test_utils::NavigateToURL(
1958      browser(), URLRequestMockHTTPJob::GetMockUrl(
1959                     base::FilePath(FILE_PATH_LITERAL("title2.html"))));
1960  ASSERT_EQ(CaptivePortalTabReloader::STATE_NONE,
1961            GetStateOfTabReloaderAt(browser(), 0));
1962
1963  EnableCaptivePortalDetection(browser()->profile(), true);
1964
1965  TabStripModel* tab_strip_model = browser()->tab_strip_model();
1966  CaptivePortalTabReloader* tab_reloader =
1967      GetTabReloader(tab_strip_model->GetActiveWebContents());
1968  ASSERT_TRUE(tab_reloader);
1969  SetSlowSSLLoadTime(tab_reloader, base::TimeDelta());
1970
1971  // Go to the error page.
1972  MultiNavigationObserver navigation_observer;
1973  CaptivePortalObserver portal_observer(browser()->profile());
1974  chrome::GoBack(browser(), CURRENT_TAB);
1975
1976  // Wait for the check triggered by the broken tab and for the login tab to
1977  // stop loading.
1978  portal_observer.WaitForResults(1);
1979  navigation_observer.WaitForNavigations(1);
1980  // Make sure the request has been issued.
1981  URLRequestTimeoutOnDemandJob::WaitForJobs(1);
1982
1983  EXPECT_EQ(1, portal_observer.num_results_received());
1984  ASSERT_FALSE(CheckPending(browser()));
1985  ASSERT_EQ(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
1986            portal_observer.captive_portal_result());
1987
1988  ASSERT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
1989            GetStateOfTabReloaderAt(browser(), 0));
1990  EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
1991            GetStateOfTabReloaderAt(browser(), 1));
1992  ASSERT_TRUE(IsLoginTab(browser()->tab_strip_model()->GetWebContentsAt(1)));
1993
1994  ASSERT_EQ(2, tab_strip_model->count());
1995  EXPECT_EQ(1, tab_strip_model->active_index());
1996  EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
1997                   tab_strip_model->GetWebContentsAt(1)));
1998  EXPECT_EQ(1, NumLoadingTabs());
1999
2000  SetSlowSSLLoadTime(tab_reloader, base::TimeDelta::FromDays(1));
2001  Login(browser(), 1, 0);
2002  FailLoadsAfterLogin(browser(), 1);
2003}
2004
2005// Checks that reloading a timeout triggers captive portal detection.
2006// Much like the last test, though the captive portal is disabled before
2007// the inital navigation, rather than captive portal detection.
2008IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, ReloadTimeout) {
2009  URLRequestMockCaptivePortalJobFactory::SetBehindCaptivePortal(false);
2010
2011  // Do the first navigation while not behind a captive portal.
2012  TabStripModel* tab_strip_model = browser()->tab_strip_model();
2013  CaptivePortalObserver portal_observer(browser()->profile());
2014  ui_test_utils::NavigateToURL(browser(), GURL(kMockHttpsUrl));
2015  ASSERT_EQ(0, portal_observer.num_results_received());
2016  ASSERT_EQ(1, tab_strip_model->count());
2017
2018  // A captive portal spontaneously appears.
2019  URLRequestMockCaptivePortalJobFactory::SetBehindCaptivePortal(true);
2020
2021  CaptivePortalTabReloader* tab_reloader =
2022      GetTabReloader(tab_strip_model->GetActiveWebContents());
2023  ASSERT_TRUE(tab_reloader);
2024  SetSlowSSLLoadTime(tab_reloader, base::TimeDelta());
2025
2026  MultiNavigationObserver navigation_observer;
2027  tab_strip_model->GetActiveWebContents()->GetController().Reload(true);
2028
2029  // Wait for the check triggered by the broken tab and for the login tab to
2030  // stop loading.
2031  portal_observer.WaitForResults(1);
2032  navigation_observer.WaitForNavigations(1);
2033  // Make sure the request has been issued.
2034  URLRequestTimeoutOnDemandJob::WaitForJobs(1);
2035
2036  ASSERT_EQ(1, portal_observer.num_results_received());
2037  ASSERT_FALSE(CheckPending(browser()));
2038  ASSERT_EQ(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
2039            portal_observer.captive_portal_result());
2040
2041  ASSERT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
2042            GetStateOfTabReloaderAt(browser(), 0));
2043  EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
2044            GetStateOfTabReloaderAt(browser(), 1));
2045  ASSERT_TRUE(IsLoginTab(tab_strip_model->GetWebContentsAt(1)));
2046
2047  ASSERT_EQ(2, tab_strip_model->count());
2048  EXPECT_EQ(1, tab_strip_model->active_index());
2049  EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
2050                   tab_strip_model->GetWebContentsAt(1)));
2051  EXPECT_EQ(1, NumLoadingTabs());
2052
2053  SetSlowSSLLoadTime(tab_reloader, base::TimeDelta::FromDays(1));
2054  Login(browser(), 1, 0);
2055  FailLoadsAfterLogin(browser(), 1);
2056}
2057
2058// Checks the case where there are two windows, and there's an SSL timeout in
2059// the background one.
2060// Disabled:  http://crbug.com/134357
2061IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, DISABLED_TwoWindows) {
2062  Browser* browser2 =
2063      new Browser(Browser::CreateParams(browser()->profile(),
2064                                        browser()->host_desktop_type()));
2065  // Navigate the new browser window so it'll be shown and we can pick the
2066  // active window.
2067  ui_test_utils::NavigateToURL(browser2, GURL(url::kAboutBlankURL));
2068
2069  // Generally, |browser2| will be the active window.  However, if the
2070  // original browser window lost focus before creating the new one, such as
2071  // when running multiple tests at once, the original browser window may
2072  // remain the profile's active window.
2073  Browser* active_browser =
2074      chrome::FindTabbedBrowser(browser()->profile(), true,
2075                                browser()->host_desktop_type());
2076  Browser* inactive_browser;
2077  if (active_browser == browser2) {
2078    // When only one test is running at a time, the new browser will probably be
2079    // on top, but when multiple tests are running at once, this is not
2080    // guaranteed.
2081    inactive_browser = browser();
2082  } else {
2083    ASSERT_EQ(active_browser, browser());
2084    inactive_browser = browser2;
2085  }
2086
2087  CaptivePortalObserver portal_observer(browser()->profile());
2088  MultiNavigationObserver navigation_observer;
2089
2090  // Navigate the tab in the inactive browser to an SSL timeout.  Have to use
2091  // chrome::NavigateParams and NEW_BACKGROUND_TAB to avoid activating the
2092  // window.
2093  chrome::NavigateParams params(inactive_browser,
2094                                GURL(kMockHttpsQuickTimeoutUrl),
2095                                content::PAGE_TRANSITION_TYPED);
2096  params.disposition = NEW_BACKGROUND_TAB;
2097  params.window_action = chrome::NavigateParams::NO_ACTION;
2098  ui_test_utils::NavigateToURL(&params);
2099  navigation_observer.WaitForNavigations(2);
2100
2101  // Make sure the active window hasn't changed, and its new tab is
2102  // active.
2103  ASSERT_EQ(active_browser,
2104            chrome::FindTabbedBrowser(browser()->profile(), true,
2105                                      browser()->host_desktop_type()));
2106  ASSERT_EQ(1, active_browser->tab_strip_model()->active_index());
2107
2108  // Check that the only two navigated tabs were the new error tab in the
2109  // backround windows, and the login tab in the active window.
2110  EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
2111                   inactive_browser->tab_strip_model()->GetWebContentsAt(1)));
2112  EXPECT_EQ(1, navigation_observer.NumNavigationsForTab(
2113                   active_browser->tab_strip_model()->GetWebContentsAt(1)));
2114  EXPECT_EQ(0, NumLoadingTabs());
2115
2116  // Check captive portal test results.
2117  portal_observer.WaitForResults(1);
2118  ASSERT_EQ(captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL,
2119            portal_observer.captive_portal_result());
2120  EXPECT_EQ(1, portal_observer.num_results_received());
2121
2122  // Check the inactive browser.
2123  EXPECT_EQ(2, inactive_browser->tab_strip_model()->count());
2124  EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
2125            GetStateOfTabReloaderAt(inactive_browser, 0));
2126  EXPECT_EQ(CaptivePortalTabReloader::STATE_BROKEN_BY_PORTAL,
2127            GetStateOfTabReloaderAt(inactive_browser, 1));
2128
2129  // Check the active browser.
2130  ASSERT_EQ(2, active_browser->tab_strip_model()->count());
2131  EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
2132            GetStateOfTabReloaderAt(active_browser, 0));
2133  EXPECT_EQ(CaptivePortalTabReloader::STATE_NONE,
2134            GetStateOfTabReloaderAt(active_browser, 1));
2135  EXPECT_TRUE(
2136      IsLoginTab(active_browser->tab_strip_model()->GetWebContentsAt(1)));
2137
2138  // Simulate logging in.
2139  Login(active_browser, 0, 1);
2140}
2141
2142// An HTTP page redirects to an HTTPS page loads slowly before timing out.  A
2143// captive portal is found, and then the user logs in before the original page
2144// times out.
2145IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, HttpToHttpsRedirectLogin) {
2146  ASSERT_TRUE(test_server()->Start());
2147  SlowLoadBehindCaptivePortal(
2148      browser(),
2149      true,
2150      test_server()->GetURL(CreateServerRedirect(kMockHttpsUrl)),
2151      1,
2152      1);
2153  Login(browser(), 1, 0);
2154  FailLoadsAfterLogin(browser(), 1);
2155}
2156
2157// An HTTPS page redirects to an HTTP page.
2158IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, HttpsToHttpRedirect) {
2159  // Use an HTTPS server for the top level page.
2160  net::SpawnedTestServer https_server(
2161      net::SpawnedTestServer::TYPE_HTTPS, net::SpawnedTestServer::kLocalhost,
2162      base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
2163  ASSERT_TRUE(https_server.Start());
2164
2165  GURL http_timeout_url =
2166      URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_TIMED_OUT);
2167
2168  // 2 navigations due to the Link Doctor.
2169  NavigateToPageExpectNoTest(
2170      browser(),
2171      https_server.GetURL(CreateServerRedirect(http_timeout_url.spec())),
2172      2);
2173}
2174
2175// Tests the 511 response code, along with an HTML redirect to a login page.
2176IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, Status511) {
2177  SetUpCaptivePortalService(browser()->profile(),
2178                            GURL(kMockCaptivePortal511Url));
2179  SlowLoadBehindCaptivePortal(browser(), true, GURL(kMockHttpsUrl), 2, 2);
2180  Login(browser(), 1, 0);
2181  FailLoadsAfterLogin(browser(), 1);
2182}
2183
2184// HSTS redirects an HTTP request to HTTPS, and the request then times out.
2185// A captive portal is then detected, and a login tab opened, before logging
2186// in.
2187IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, HstsLogin) {
2188  GURL::Replacements replacements;
2189  std::string scheme = "http";
2190  replacements.SetSchemeStr(scheme);
2191  GURL http_timeout_url = GURL(kMockHttpsUrl).ReplaceComponents(replacements);
2192
2193  URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_TIMED_OUT);
2194  content::BrowserThread::PostTask(
2195      content::BrowserThread::IO, FROM_HERE,
2196      base::Bind(&AddHstsHost,
2197                 make_scoped_refptr(browser()->profile()->GetRequestContext()),
2198                 http_timeout_url.host()));
2199
2200  SlowLoadBehindCaptivePortal(browser(), true, http_timeout_url, 1, 1);
2201  Login(browser(), 1, 0);
2202  FailLoadsAfterLogin(browser(), 1);
2203}
2204