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