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