summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorygorshenin@chromium.org <ygorshenin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-10-24 18:57:23 +0000
committerygorshenin@chromium.org <ygorshenin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-10-24 18:57:23 +0000
commit7d432e240fba393b53a65623df7e649eeb508653 (patch)
tree3f3461d9070de421b8ea60d57d1546d918bfc892
parent812d4f7e14eedef990b9d0dd039276651a4d90fd (diff)
downloadchromium_src-7d432e240fba393b53a65623df7e649eeb508653.zip
chromium_src-7d432e240fba393b53a65623df7e649eeb508653.tar.gz
chromium_src-7d432e240fba393b53a65623df7e649eeb508653.tar.bz2
Basic Captive Portal detection functionality is extracted into
individual service, so, it can be used without CaptivePortalService. BUG=115487 TEST=browser_tests:CaptivePortalBrowserTest Review URL: https://chromiumcodereview.appspot.com/11198066 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@163877 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/captive_portal/captive_portal_browsertest.cc2
-rw-r--r--chrome/browser/captive_portal/captive_portal_detector.cc149
-rw-r--r--chrome/browser/captive_portal/captive_portal_detector.h112
-rw-r--r--chrome/browser/captive_portal/captive_portal_service.cc139
-rw-r--r--chrome/browser/captive_portal/captive_portal_service.h60
-rw-r--r--chrome/browser/captive_portal/captive_portal_service_unittest.cc83
-rw-r--r--chrome/chrome_browser.gypi2
7 files changed, 343 insertions, 204 deletions
diff --git a/chrome/browser/captive_portal/captive_portal_browsertest.cc b/chrome/browser/captive_portal/captive_portal_browsertest.cc
index 6bcec16..f30b972 100644
--- a/chrome/browser/captive_portal/captive_portal_browsertest.cc
+++ b/chrome/browser/captive_portal/captive_portal_browsertest.cc
@@ -1000,7 +1000,7 @@ bool CaptivePortalBrowserTest::CheckPending(Browser* browser) {
CaptivePortalService* captive_portal_service =
CaptivePortalServiceFactory::GetForProfile(browser->profile());
- return captive_portal_service->FetchingURL() ||
+ return captive_portal_service->DetectionInProgress() ||
captive_portal_service->TimerRunning();
}
diff --git a/chrome/browser/captive_portal/captive_portal_detector.cc b/chrome/browser/captive_portal/captive_portal_detector.cc
new file mode 100644
index 0000000..4c59437
--- /dev/null
+++ b/chrome/browser/captive_portal/captive_portal_detector.cc
@@ -0,0 +1,149 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/captive_portal/captive_portal_detector.h"
+
+#include "base/logging.h"
+#include "base/string_number_conversions.h"
+#include "chrome/browser/profiles/profile.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_response_headers.h"
+#include "net/url_request/url_fetcher.h"
+#include "net/url_request/url_request_status.h"
+
+namespace captive_portal {
+
+const char CaptivePortalDetector::kDefaultURL[] =
+ "http://www.gstatic.com/generate_204";
+
+CaptivePortalDetector::CaptivePortalDetector(
+ const scoped_refptr<net::URLRequestContextGetter>& request_context)
+ : request_context_(request_context) {
+}
+
+CaptivePortalDetector::~CaptivePortalDetector() {
+}
+
+void CaptivePortalDetector::DetectCaptivePortal(
+ const GURL& url,
+ const DetectionCallback& detection_callback) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(!FetchingURL());
+ DCHECK(detection_callback_.is_null());
+
+ detection_callback_ = detection_callback;
+
+ // The first 0 means this can use a TestURLFetcherFactory in unit tests.
+ url_fetcher_.reset(net::URLFetcher::Create(0,
+ url,
+ net::URLFetcher::GET,
+ this));
+ url_fetcher_->SetAutomaticallyRetryOn5xx(false);
+ url_fetcher_->SetRequestContext(request_context_);
+
+ // Can't safely use net::LOAD_DISABLE_CERT_REVOCATION_CHECKING here,
+ // since then the connection may be reused without checking the cert.
+ url_fetcher_->SetLoadFlags(
+ net::LOAD_BYPASS_CACHE |
+ net::LOAD_DO_NOT_PROMPT_FOR_LOGIN |
+ net::LOAD_DO_NOT_SAVE_COOKIES |
+ net::LOAD_DO_NOT_SEND_COOKIES |
+ net::LOAD_DO_NOT_SEND_AUTH_DATA);
+ url_fetcher_->Start();
+}
+
+void CaptivePortalDetector::Cancel() {
+ url_fetcher_.reset();
+ detection_callback_.Reset();
+}
+
+void CaptivePortalDetector::OnURLFetchComplete(const net::URLFetcher* source) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(FetchingURL());
+ DCHECK_EQ(url_fetcher_.get(), source);
+ DCHECK(!detection_callback_.is_null());
+
+ Results results;
+ GetCaptivePortalResultFromResponse(url_fetcher_.get(), &results);
+ DetectionCallback callback = detection_callback_;
+ url_fetcher_.reset();
+ detection_callback_.Reset();
+ callback.Run(results);
+}
+
+// Takes a net::URLFetcher that has finished trying to retrieve the test
+// URL, and returns a CaptivePortalService::Result based on its result.
+void CaptivePortalDetector::GetCaptivePortalResultFromResponse(
+ const net::URLFetcher* url_fetcher,
+ Results* results) const {
+ DCHECK(results);
+ DCHECK(!url_fetcher->GetStatus().is_io_pending());
+
+ results->retry_after_delta = base::TimeDelta();
+ results->result = RESULT_NO_RESPONSE;
+
+ // If there's a network error of some sort when fetching a file via HTTP,
+ // there may be a networking problem, rather than a captive portal.
+ // TODO(mmenke): Consider special handling for redirects that end up at
+ // errors, especially SSL certificate errors.
+ if (url_fetcher->GetStatus().status() != net::URLRequestStatus::SUCCESS)
+ return;
+
+ // In the case of 503 errors, look for the Retry-After header.
+ int response_code = url_fetcher->GetResponseCode();
+ if (response_code == 503) {
+ net::HttpResponseHeaders* headers = url_fetcher->GetResponseHeaders();
+ std::string retry_after_string;
+
+ // If there's no Retry-After header, nothing else to do.
+ if (!headers->EnumerateHeader(NULL, "Retry-After", &retry_after_string))
+ return;
+
+ // Otherwise, try parsing it as an integer (seconds) or as an HTTP date.
+ int seconds;
+ base::Time full_date;
+ if (base::StringToInt(retry_after_string, &seconds)) {
+ results->retry_after_delta = base::TimeDelta::FromSeconds(seconds);
+ } else if (headers->GetTimeValuedHeader("Retry-After", &full_date)) {
+ base::Time now = GetCurrentTime();
+ if (full_date > now)
+ results->retry_after_delta = full_date - now;
+ }
+ return;
+ }
+
+ // A 511 response (Network Authentication Required) means that the user needs
+ // to login to whatever server issued the response.
+ // See: http://tools.ietf.org/html/rfc6585
+ if (response_code == 511) {
+ results->result = RESULT_BEHIND_CAPTIVE_PORTAL;
+ return;
+ }
+
+ // Other non-2xx/3xx HTTP responses may indicate server errors.
+ if (response_code >= 400 || response_code < 200)
+ return;
+
+ // A 204 response code indicates there's no captive portal.
+ if (response_code == 204) {
+ results->result = RESULT_INTERNET_CONNECTED;
+ return;
+ }
+
+ // Otherwise, assume it's a captive portal.
+ results->result = RESULT_BEHIND_CAPTIVE_PORTAL;
+}
+
+base::Time CaptivePortalDetector::GetCurrentTime() const {
+ if (time_for_testing_.is_null())
+ return base::Time::Now();
+ else
+ return time_for_testing_;
+}
+
+bool CaptivePortalDetector::FetchingURL() const {
+ return url_fetcher_.get() != NULL;
+}
+
+} // namespace captive_portal
diff --git a/chrome/browser/captive_portal/captive_portal_detector.h b/chrome/browser/captive_portal/captive_portal_detector.h
new file mode 100644
index 0000000..e1cc1d2
--- /dev/null
+++ b/chrome/browser/captive_portal/captive_portal_detector.h
@@ -0,0 +1,112 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CAPTIVE_PORTAL_CAPTIVE_PORTAL_DETECTOR_H_
+#define CHROME_BROWSER_CAPTIVE_PORTAL_CAPTIVE_PORTAL_DETECTOR_H_
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/threading/non_thread_safe.h"
+#include "base/time.h"
+#include "net/url_request/url_fetcher_delegate.h"
+#include "net/url_request/url_request_context_getter.h"
+
+class GURL;
+
+namespace net {
+class URLFetcher;
+}
+
+namespace captive_portal {
+
+// Possible results of an attempt to detect a captive portal.
+enum Result {
+ // There's a confirmed connection to the Internet.
+ RESULT_INTERNET_CONNECTED,
+ // The URL request received a network or HTTP error, or a non-HTTP response.
+ RESULT_NO_RESPONSE,
+ // The URL request apparently encountered a captive portal. It received a
+ // a valid HTTP response with a 2xx other than 204, 3xx, or 511 status code.
+ RESULT_BEHIND_CAPTIVE_PORTAL,
+ RESULT_COUNT
+};
+
+class CaptivePortalDetector : public net::URLFetcherDelegate,
+ public base::NonThreadSafe {
+ public:
+ struct Results {
+ Result result;
+ base::TimeDelta retry_after_delta;
+ };
+
+ typedef base::Callback<void(const Results& results)> DetectionCallback;
+
+ // The test URL. When connected to the Internet, it should return a
+ // blank page with a 204 status code. When behind a captive portal,
+ // requests for this URL should get an HTTP redirect or a login
+ // page. When neither is true, no server should respond to requests
+ // for this URL.
+ static const char kDefaultURL[];
+
+ explicit CaptivePortalDetector(
+ const scoped_refptr<net::URLRequestContextGetter>& request_context);
+ virtual ~CaptivePortalDetector();
+
+ // Triggers a check for a captive portal. After completion, runs the
+ // |callback|.
+ void DetectCaptivePortal(const GURL& url, const DetectionCallback& callback);
+
+ // Cancels captive portal check.
+ void Cancel();
+
+ private:
+ friend class CaptivePortalServiceTest;
+
+ // net::URLFetcherDelegate:
+ virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
+
+ // Takes a net::URLFetcher that has finished trying to retrieve the
+ // test URL, and fills a Results struct based on its result. If the
+ // response is a 503 with a Retry-After header, |retry_after| field
+ // of |results| is populated accordingly. Otherwise, it's set to
+ // base::TimeDelta().
+ void GetCaptivePortalResultFromResponse(const net::URLFetcher* url_fetcher,
+ Results* results) const;
+
+ // Returns the current time. Used only when determining time until a
+ // Retry-After date.
+ base::Time GetCurrentTime() const;
+
+ // Returns true if a captive portal check is currently running.
+ bool FetchingURL() const;
+
+ // Sets current test time. Used by unit tests.
+ void set_time_for_testing(const base::Time& time) {
+ time_for_testing_ = time;
+ }
+
+ // Advances current test time. Used by unit tests.
+ void advance_time_for_testing(const base::TimeDelta& delta) {
+ time_for_testing_ += delta;
+ }
+
+ // URL request context.
+ scoped_refptr<net::URLRequestContextGetter> request_context_;
+
+ DetectionCallback detection_callback_;
+
+ scoped_ptr<net::URLFetcher> url_fetcher_;
+
+ // Test time used by unit tests.
+ base::Time time_for_testing_;
+
+ DISALLOW_COPY_AND_ASSIGN(CaptivePortalDetector);
+};
+
+} // namespace captive_portal
+
+#endif // CHROME_BROWSER_CAPTIVE_PORTAL_CAPTIVE_PORTAL_DETECTOR_H_
diff --git a/chrome/browser/captive_portal/captive_portal_service.cc b/chrome/browser/captive_portal/captive_portal_service.cc
index 8d8d59d..d6a013c 100644
--- a/chrome/browser/captive_portal/captive_portal_service.cc
+++ b/chrome/browser/captive_portal/captive_portal_service.cc
@@ -5,21 +5,15 @@
#include "chrome/browser/captive_portal/captive_portal_service.h"
#include "base/bind.h"
-#include "base/command_line.h"
+#include "base/bind_helpers.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/metrics/histogram.h"
-#include "base/rand_util.h"
-#include "base/string_number_conversions.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/notification_service.h"
-#include "net/base/load_flags.h"
-#include "net/http/http_response_headers.h"
-#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_request_status.h"
#if defined(OS_MACOSX)
#include "base/mac/mac_util.h"
@@ -33,14 +27,6 @@ namespace captive_portal {
namespace {
-// The test URL. When connected to the Internet, it should return a blank page
-// with a 204 status code. When behind a captive portal, requests for this
-// URL should get an HTTP redirect or a login page. When neither is true,
-// no server should respond to requests for this URL.
-// TODO(mmenke): Look into getting another domain, for better load management.
-// Need a cookieless domain, so can't use clients*.google.com.
-const char* const kDefaultTestURL = "http://www.gstatic.com/generate_204";
-
// Used for histograms.
const char* const kCaptivePortalResultNames[] = {
"InternetConnected",
@@ -166,10 +152,11 @@ CaptivePortalService::RecheckPolicy::RecheckPolicy()
CaptivePortalService::CaptivePortalService(Profile* profile)
: profile_(profile),
state_(STATE_IDLE),
+ captive_portal_detector_(profile->GetRequestContext()),
enabled_(false),
last_detection_result_(RESULT_INTERNET_CONNECTED),
num_checks_with_same_result_(0),
- test_url_(kDefaultTestURL) {
+ test_url_(CaptivePortalDetector::kDefaultURL) {
// The order matters here:
// |resolve_errors_with_web_service_| must be initialized and |backoff_entry_|
// created before the call to UpdateEnabledState.
@@ -206,7 +193,6 @@ void CaptivePortalService::DetectCaptivePortal() {
void CaptivePortalService::DetectCaptivePortalInternal() {
DCHECK(CalledOnValidThread());
DCHECK(state_ == STATE_TIMER_RUNNING || state_ == STATE_IDLE);
- DCHECK(!FetchingURL());
DCHECK(!TimerRunning());
state_ = STATE_CHECKING_FOR_PORTAL;
@@ -220,42 +206,26 @@ void CaptivePortalService::DetectCaptivePortalInternal() {
return;
}
- // The first 0 means this can use a TestURLFetcherFactory in unit tests.
- url_fetcher_.reset(net::URLFetcher::Create(0,
- test_url_,
- net::URLFetcher::GET,
- this));
- url_fetcher_->SetAutomaticallyRetryOn5xx(false);
- url_fetcher_->SetRequestContext(profile_->GetRequestContext());
- // Can't safely use net::LOAD_DISABLE_CERT_REVOCATION_CHECKING here,
- // since then the connection may be reused without checking the cert.
- url_fetcher_->SetLoadFlags(
- net::LOAD_BYPASS_CACHE |
- net::LOAD_DO_NOT_PROMPT_FOR_LOGIN |
- net::LOAD_DO_NOT_SAVE_COOKIES |
- net::LOAD_DO_NOT_SEND_COOKIES |
- net::LOAD_DO_NOT_SEND_AUTH_DATA);
- url_fetcher_->Start();
+ captive_portal_detector_.DetectCaptivePortal(
+ test_url_, base::Bind(
+ &CaptivePortalService::OnPortalDetectionCompleted,
+ base::Unretained(this)));
}
-void CaptivePortalService::OnURLFetchComplete(const net::URLFetcher* source) {
+void CaptivePortalService::OnPortalDetectionCompleted(
+ const CaptivePortalDetector::Results& results) {
DCHECK(CalledOnValidThread());
DCHECK_EQ(STATE_CHECKING_FOR_PORTAL, state_);
- DCHECK(FetchingURL());
DCHECK(!TimerRunning());
- DCHECK_EQ(url_fetcher_.get(), source);
DCHECK(enabled_);
+ Result result = results.result;
+ const base::TimeDelta& retry_after_delta = results.retry_after_delta;
base::TimeTicks now = GetCurrentTimeTicks();
- base::TimeDelta retry_after_delta;
- Result new_result = GetCaptivePortalResultFromResponse(source,
- &retry_after_delta);
- url_fetcher_.reset();
-
// Record histograms.
UMA_HISTOGRAM_ENUMERATION("CaptivePortal.DetectResult",
- new_result,
+ result,
RESULT_COUNT);
// If this isn't the first captive portal result, record stats.
@@ -263,7 +233,7 @@ void CaptivePortalService::OnURLFetchComplete(const net::URLFetcher* source) {
UMA_HISTOGRAM_LONG_TIMES("CaptivePortal.TimeBetweenChecks",
now - last_check_time_);
- if (last_detection_result_ != new_result) {
+ if (last_detection_result_ != result) {
// If the last result was different from the result of the latest test,
// record histograms about the previous period over which the result was
// the same.
@@ -273,13 +243,13 @@ void CaptivePortalService::OnURLFetchComplete(const net::URLFetcher* source) {
}
}
- if (last_check_time_.is_null() || new_result != last_detection_result_) {
+ if (last_check_time_.is_null() || result != last_detection_result_) {
first_check_time_with_same_result_ = now;
num_checks_with_same_result_ = 1;
// Reset the backoff entry both to update the default time and clear
// previous failures.
- ResetBackoffEntry(new_result);
+ ResetBackoffEntry(result);
backoff_entry_->SetCustomReleaseTime(now + retry_after_delta);
// The BackoffEntry is not informed of this request, so there's no delay
@@ -298,7 +268,7 @@ void CaptivePortalService::OnURLFetchComplete(const net::URLFetcher* source) {
last_check_time_ = now;
- OnResult(new_result);
+ OnResult(result);
}
void CaptivePortalService::Observe(
@@ -372,10 +342,10 @@ void CaptivePortalService::UpdateEnabledState() {
ResetBackoffEntry(last_detection_result_);
if (state_ == STATE_CHECKING_FOR_PORTAL || state_ == STATE_TIMER_RUNNING) {
- // If a captive portal check was running or pending, stop the check or the
- // timer.
- url_fetcher_.reset();
+ // If a captive portal check was running or pending, cancel check
+ // and the timer.
check_captive_portal_timer_.Stop();
+ captive_portal_detector_.Cancel();
state_ = STATE_IDLE;
// Since a captive portal request was queued or running, something may be
@@ -384,74 +354,15 @@ void CaptivePortalService::UpdateEnabledState() {
}
}
-// Takes a net::URLFetcher that has finished trying to retrieve the test
-// URL, and returns a CaptivePortalService::Result based on its result.
-Result CaptivePortalService::GetCaptivePortalResultFromResponse(
- const net::URLFetcher* url_fetcher,
- base::TimeDelta* retry_after) const {
- DCHECK(retry_after);
- DCHECK(!url_fetcher->GetStatus().is_io_pending());
-
- *retry_after = base::TimeDelta();
-
- // If there's a network error of some sort when fetching a file via HTTP,
- // there may be a networking problem, rather than a captive portal.
- // TODO(mmenke): Consider special handling for redirects that end up at
- // errors, especially SSL certificate errors.
- if (url_fetcher->GetStatus().status() != net::URLRequestStatus::SUCCESS)
- return RESULT_NO_RESPONSE;
-
- // In the case of 503 errors, look for the Retry-After header.
- int response_code = url_fetcher->GetResponseCode();
- if (response_code == 503) {
- net::HttpResponseHeaders* headers = url_fetcher->GetResponseHeaders();
- std::string retry_after_string;
-
- // If there's no Retry-After header, nothing else to do.
- if (!headers->EnumerateHeader(NULL, "Retry-After", &retry_after_string))
- return RESULT_NO_RESPONSE;
-
- // Otherwise, try parsing it as an integer (seconds) or as an HTTP date.
- int seconds;
- base::Time full_date;
- if (base::StringToInt(retry_after_string, &seconds)) {
- *retry_after = base::TimeDelta::FromSeconds(seconds);
- } else if (headers->GetTimeValuedHeader("Retry-After", &full_date)) {
- base::Time now = GetCurrentTime();
- if (full_date > now)
- *retry_after = full_date - now;
- }
- return RESULT_NO_RESPONSE;
- }
-
- // A 511 response (Network Authentication Required) means that the user needs
- // to login to whatever server issued the response.
- // See: http://tools.ietf.org/html/rfc6585
- if (response_code == 511)
- return RESULT_BEHIND_CAPTIVE_PORTAL;
-
- // Other non-2xx/3xx HTTP responses may indicate server errors.
- if (response_code >= 400 || response_code < 200)
- return RESULT_NO_RESPONSE;
-
- // A 204 response code indicates there's no captive portal.
- if (response_code == 204)
- return RESULT_INTERNET_CONNECTED;
-
- // Otherwise, assume it's a captive portal.
- return RESULT_BEHIND_CAPTIVE_PORTAL;
-}
-
-base::Time CaptivePortalService::GetCurrentTime() const {
- return base::Time::Now();
-}
-
base::TimeTicks CaptivePortalService::GetCurrentTimeTicks() const {
- return base::TimeTicks::Now();
+ if (time_ticks_for_testing_.is_null())
+ return base::TimeTicks::Now();
+ else
+ return time_ticks_for_testing_;
}
-bool CaptivePortalService::FetchingURL() const {
- return url_fetcher_.get() != NULL;
+bool CaptivePortalService::DetectionInProgress() const {
+ return state_ == STATE_CHECKING_FOR_PORTAL;
}
bool CaptivePortalService::TimerRunning() const {
diff --git a/chrome/browser/captive_portal/captive_portal_service.h b/chrome/browser/captive_portal/captive_portal_service.h
index 6ad53b2..82b3d71 100644
--- a/chrome/browser/captive_portal/captive_portal_service.h
+++ b/chrome/browser/captive_portal/captive_portal_service.h
@@ -11,32 +11,16 @@
#include "base/time.h"
#include "base/timer.h"
#include "chrome/browser/api/prefs/pref_member.h"
+#include "chrome/browser/captive_portal/captive_portal_detector.h"
#include "chrome/browser/profiles/profile_keyed_service.h"
#include "content/public/browser/notification_observer.h"
#include "googleurl/src/gurl.h"
#include "net/base/backoff_entry.h"
-#include "net/url_request/url_fetcher_delegate.h"
class Profile;
-namespace net {
-class URLFetcher;
-}
-
namespace captive_portal {
-// Possible results of an attempt to detect a captive portal.
-enum Result {
- // There's a confirmed connection to the Internet.
- RESULT_INTERNET_CONNECTED,
- // The URL request received a network or HTTP error, or a non-HTTP response.
- RESULT_NO_RESPONSE,
- // The URL request apparently encountered a captive portal. It received a
- // a valid HTTP response with a 2xx, 3xx, or 511 status code, other than 204.
- RESULT_BEHIND_CAPTIVE_PORTAL,
- RESULT_COUNT
-};
-
// Service that checks for captive portals when queried, and sends a
// NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT with the Profile as the source and
// a CaptivePortalService::Results as the details.
@@ -45,7 +29,6 @@ enum Result {
// be accessed on the UI thread.
// Design doc: https://docs.google.com/document/d/1k-gP2sswzYNvryu9NcgN7q5XrsMlUdlUdoW9WRaEmfM/edit
class CaptivePortalService : public ProfileKeyedService,
- public net::URLFetcherDelegate,
public content::NotificationObserver,
public base::NonThreadSafe {
public:
@@ -129,8 +112,9 @@ class CaptivePortalService : public ProfileKeyedService,
// is disabled, just acts like there's an Internet connection.
void DetectCaptivePortalInternal();
- // net::URLFetcherDelegate:
- virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
+ // Called by CaptivePortalDetector when detection completes.
+ void OnPortalDetectionCompleted(
+ const CaptivePortalDetector::Results& results);
// content::NotificationObserver:
virtual void Observe(
@@ -157,22 +141,10 @@ class CaptivePortalService : public ProfileKeyedService,
// Android, since it lacks the Browser class.
void UpdateEnabledState();
- // Takes a net::URLFetcher that has finished trying to retrieve the test
- // URL, and returns a captive_portal::Result based on its result.
- // If the response is a 503 with a Retry-After header, |retry_after| is
- // populated accordingly. Otherwise, it's set to base::TimeDelta().
- Result GetCaptivePortalResultFromResponse(const net::URLFetcher* url_fetcher,
- base::TimeDelta* retry_after) const;
+ // Returns the current TimeTicks.
+ base::TimeTicks GetCurrentTimeTicks() const;
- // Returns the current time. Used only when determining time until a
- // Retry-After date. Overridden by unit tests.
- virtual base::Time GetCurrentTime() const;
-
- // Returns the current TimeTicks. Overridden by unit tests.
- virtual base::TimeTicks GetCurrentTimeTicks() const;
-
- // Returns true if a captive portal check is currently running.
- bool FetchingURL() const;
+ bool DetectionInProgress() const;
// Returns true if the timer to try and detect a captive portal is running.
bool TimerRunning() const;
@@ -183,11 +155,24 @@ class CaptivePortalService : public ProfileKeyedService,
void set_test_url(const GURL& test_url) { test_url_ = test_url; }
+ // Sets current test time ticks. Used by unit tests.
+ void set_time_ticks_for_testing(const base::TimeTicks& time_ticks) {
+ time_ticks_for_testing_ = time_ticks;
+ }
+
+ // Advances current test time ticks. Used by unit tests.
+ void advance_time_ticks_for_testing(const base::TimeDelta& delta) {
+ time_ticks_for_testing_ += delta;
+ }
+
// The profile that owns this CaptivePortalService.
Profile* profile_;
State state_;
+ // Detector for checking active network for a portal state.
+ CaptivePortalDetector captive_portal_detector_;
+
// True if the service is enabled. When not enabled, all checks will return
// RESULT_INTERNET_CONNECTED.
bool enabled_;
@@ -213,8 +198,6 @@ class CaptivePortalService : public ProfileKeyedService,
// is considered a "failure", to trigger throttling.
scoped_ptr<net::BackoffEntry> backoff_entry_;
- scoped_ptr<net::URLFetcher> url_fetcher_;
-
// URL that returns a 204 response code when connected to the Internet.
GURL test_url_;
@@ -227,6 +210,9 @@ class CaptivePortalService : public ProfileKeyedService,
static TestingState testing_state_;
+ // Test time ticks used by unit tests.
+ base::TimeTicks time_ticks_for_testing_;
+
DISALLOW_COPY_AND_ASSIGN(CaptivePortalService);
};
diff --git a/chrome/browser/captive_portal/captive_portal_service_unittest.cc b/chrome/browser/captive_portal/captive_portal_service_unittest.cc
index f6714ea..9a88335 100644
--- a/chrome/browser/captive_portal/captive_portal_service_unittest.cc
+++ b/chrome/browser/captive_portal/captive_portal_service_unittest.cc
@@ -39,47 +39,7 @@ scoped_refptr<net::HttpResponseHeaders> CreateResponseHeaders(
return new net::HttpResponseHeaders(raw_headers);
}
-// Allows setting the time, for testing timers.
-class TestCaptivePortalService : public CaptivePortalService {
- public:
- // The initial time does not matter, except it must not be NULL.
- explicit TestCaptivePortalService(Profile* profile)
- : CaptivePortalService(profile),
- time_ticks_(base::TimeTicks::Now()),
- time_(base::Time::Now()) {
- }
-
- virtual ~TestCaptivePortalService() {}
-
- void AdvanceTime(base::TimeDelta delta) {
- time_ticks_ += delta;
- time_ += delta;
- }
-
- // CaptivePortalService:
- virtual base::TimeTicks GetCurrentTimeTicks() const OVERRIDE {
- return time_ticks_;
- }
-
- virtual base::Time GetCurrentTime() const OVERRIDE {
- return time_;
- }
-
- void set_time(base::Time time) {
- time_= time;
- }
-
- private:
- base::TimeTicks time_ticks_;
-
- // Not necessarily consistent with |time_ticks_|. Used solely with
- // Retry-After dates.
- base::Time time_;
-
- DISALLOW_COPY_AND_ASSIGN(TestCaptivePortalService);
-};
-
-// An observer watches the CaptivePortalService. It tracks the last
+// An observer watches the CaptivePortalDetector. It tracks the last
// received result and the total number of received results.
class CaptivePortalObserver : public content::NotificationObserver {
public:
@@ -149,8 +109,7 @@ class CaptivePortalServiceTest : public testing::Test {
CaptivePortalService::set_state_for_testing(testing_state);
profile_.reset(new TestingProfile());
- service_.reset(new TestCaptivePortalService(profile_.get()));
- scoped_ptr<TestCaptivePortalService> service_;
+ service_.reset(CreateTestCaptivePortalService(profile_.get()));
// Use no delays for most tests.
set_initial_backoff_no_portal(base::TimeDelta());
@@ -182,7 +141,7 @@ class CaptivePortalServiceTest : public testing::Test {
// Calls the corresponding CaptivePortalService function.
void OnURLFetchComplete(net::URLFetcher* fetcher) {
- service()->OnURLFetchComplete(fetcher);
+ service()->captive_portal_detector_.OnURLFetchComplete(fetcher);
}
// Triggers a captive portal check, then simulates the URL request
@@ -207,7 +166,7 @@ class CaptivePortalServiceTest : public testing::Test {
ASSERT_EQ(CaptivePortalService::STATE_IDLE, service()->state());
ASSERT_EQ(expected_delay, GetTimeUntilNextRequest());
- service()->AdvanceTime(expected_delay);
+ AdvanceTime(expected_delay);
ASSERT_EQ(base::TimeDelta(), GetTimeUntilNextRequest());
CaptivePortalObserver observer(profile(), service());
@@ -256,7 +215,7 @@ class CaptivePortalServiceTest : public testing::Test {
ASSERT_EQ(CaptivePortalService::STATE_IDLE, service()->state());
ASSERT_EQ(expected_delay, GetTimeUntilNextRequest());
- service()->AdvanceTime(expected_delay);
+ AdvanceTime(expected_delay);
ASSERT_EQ(base::TimeDelta(), GetTimeUntilNextRequest());
CaptivePortalObserver observer(profile(), service());
@@ -287,8 +246,27 @@ class CaptivePortalServiceTest : public testing::Test {
RunTest(expected_result, net_error, status_code, 1600, NULL);
}
+ CaptivePortalService* CreateTestCaptivePortalService(Profile* profile) {
+ scoped_ptr<CaptivePortalService> service(new CaptivePortalService(profile));
+ service->set_time_ticks_for_testing(base::TimeTicks::Now());
+ service->captive_portal_detector_.set_time_for_testing(base::Time::Now());
+ return service.release();
+ }
+
+ // Changes test time for the service and service's captive portal
+ // detector.
+ void AdvanceTime(const base::TimeDelta& delta) {
+ service()->advance_time_ticks_for_testing(delta);
+ service()->captive_portal_detector_.advance_time_for_testing(delta);
+ }
+
+ // Sets test time for service's captive portal detector.
+ void SetTime(const base::Time& time) {
+ service()->captive_portal_detector_.set_time_for_testing(time);
+ }
+
bool FetchingURL() {
- return service()->FetchingURL();
+ return service()->captive_portal_detector_.FetchingURL();
}
bool TimerRunning() {
@@ -331,7 +309,7 @@ class CaptivePortalServiceTest : public testing::Test {
TestingProfile* profile() { return profile_.get(); }
- TestCaptivePortalService* service() { return service_.get(); }
+ CaptivePortalService* service() { return service_.get(); }
private:
// Stores the initial CaptivePortalService::TestingState so it can be restored
@@ -342,7 +320,7 @@ class CaptivePortalServiceTest : public testing::Test {
// Note that the construction order of these matters.
scoped_ptr<TestingProfile> profile_;
- scoped_ptr<TestCaptivePortalService> service_;
+ scoped_ptr<CaptivePortalService> service_;
};
// Test that the CaptivePortalService returns the expected result codes in
@@ -370,8 +348,9 @@ TEST_F(CaptivePortalServiceTest, CaptivePortalResultCodes) {
TEST_F(CaptivePortalServiceTest, CaptivePortalTwoProfiles) {
Initialize(CaptivePortalService::SKIP_OS_CHECK_FOR_TESTING);
TestingProfile profile2;
- TestCaptivePortalService service2(&profile2);
- CaptivePortalObserver observer2(&profile2, &service2);
+ scoped_ptr<CaptivePortalService> service2(
+ CreateTestCaptivePortalService(&profile2));
+ CaptivePortalObserver observer2(&profile2, service2.get());
RunTest(RESULT_INTERNET_CONNECTED, net::OK, 204, 0, NULL);
EXPECT_EQ(0, observer2.num_results_received());
@@ -598,7 +577,7 @@ TEST_F(CaptivePortalServiceTest, CaptivePortalRetryAfterDate) {
base::Time start_time;
ASSERT_TRUE(
base::Time::FromString("Tue, 17 Apr 2012 18:02:00 GMT", &start_time));
- service()->set_time(start_time);
+ SetTime(start_time);
RunTest(RESULT_NO_RESPONSE,
net::OK,
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index f2d9129..a090c42 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -419,6 +419,8 @@
'browser/feedback/feedback_data.h',
'browser/feedback/feedback_util.cc',
'browser/feedback/feedback_util.h',
+ 'browser/captive_portal/captive_portal_detector.cc',
+ 'browser/captive_portal/captive_portal_detector.h',
'browser/captive_portal/captive_portal_login_detector.cc',
'browser/captive_portal/captive_portal_login_detector.h',
'browser/captive_portal/captive_portal_service.cc',