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#ifndef CHROME_BROWSER_CAPTIVE_PORTAL_CAPTIVE_PORTAL_SERVICE_H_ 6#define CHROME_BROWSER_CAPTIVE_PORTAL_CAPTIVE_PORTAL_SERVICE_H_ 7 8#include "base/basictypes.h" 9#include "base/memory/scoped_ptr.h" 10#include "base/prefs/pref_member.h" 11#include "base/threading/non_thread_safe.h" 12#include "base/time/time.h" 13#include "base/timer/timer.h" 14#include "chrome/browser/captive_portal/captive_portal_detector.h" 15#include "components/browser_context_keyed_service/browser_context_keyed_service.h" 16#include "net/base/backoff_entry.h" 17#include "url/gurl.h" 18 19class Profile; 20 21namespace captive_portal { 22 23// Service that checks for captive portals when queried, and sends a 24// NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT with the Profile as the source and 25// a CaptivePortalService::Results as the details. 26// 27// Captive portal checks are rate-limited. The CaptivePortalService may only 28// be accessed on the UI thread. 29// Design doc: https://docs.google.com/document/d/1k-gP2sswzYNvryu9NcgN7q5XrsMlUdlUdoW9WRaEmfM/edit 30class CaptivePortalService : public BrowserContextKeyedService, 31 public base::NonThreadSafe { 32 public: 33 enum TestingState { 34 NOT_TESTING, 35 DISABLED_FOR_TESTING, // The service is always disabled. 36 SKIP_OS_CHECK_FOR_TESTING // The service can be enabled even if the OS has 37 // native captive portal detection. 38 }; 39 40 // The details sent via a NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT. 41 struct Results { 42 // The result of the second most recent captive portal check. 43 Result previous_result; 44 // The result of the most recent captive portal check. 45 Result result; 46 }; 47 48 explicit CaptivePortalService(Profile* profile); 49 virtual ~CaptivePortalService(); 50 51 // Triggers a check for a captive portal. If there's already a check in 52 // progress, does nothing. Throttles the rate at which requests are sent. 53 // Always sends the result notification asynchronously. 54 void DetectCaptivePortal(); 55 56 // Returns the URL used for captive portal testing. When a captive portal is 57 // detected, this URL will take us to the captive portal landing page. 58 const GURL& test_url() const { return test_url_; } 59 60 // Result of the most recent captive portal check. 61 Result last_detection_result() const { return last_detection_result_; } 62 63 // Whether or not the CaptivePortalService is enabled. When disabled, all 64 // checks return INTERNET_CONNECTED. 65 bool enabled() const { return enabled_; } 66 67 // Used to disable captive portal detection so it doesn't interfere with 68 // tests. Should be called before the service is created. 69 static void set_state_for_testing(TestingState testing_state) { 70 testing_state_ = testing_state; 71 } 72 static TestingState get_state_for_testing() { return testing_state_; } 73 74 private: 75 friend class CaptivePortalServiceTest; 76 friend class CaptivePortalBrowserTest; 77 78 // Subclass of BackoffEntry that uses the CaptivePortalService's 79 // GetCurrentTime function, for unit testing. 80 class RecheckBackoffEntry; 81 82 enum State { 83 // No check is running or pending. 84 STATE_IDLE, 85 // The timer to check for a captive portal is running. 86 STATE_TIMER_RUNNING, 87 // There's an outstanding HTTP request to check for a captive portal. 88 STATE_CHECKING_FOR_PORTAL, 89 }; 90 91 // Contains all the information about the minimum time allowed between two 92 // consecutive captive portal checks. 93 struct RecheckPolicy { 94 // Constructor initializes all values to defaults. 95 RecheckPolicy(); 96 97 // The minimum amount of time between two captive portal checks, when the 98 // last check found no captive portal. 99 int initial_backoff_no_portal_ms; 100 101 // The minimum amount of time between two captive portal checks, when the 102 // last check found a captive portal. This is expected to be less than 103 // |initial_backoff_no_portal_ms|. Also used when the service is disabled. 104 int initial_backoff_portal_ms; 105 106 net::BackoffEntry::Policy backoff_policy; 107 }; 108 109 // Initiates a captive portal check, without any throttling. If the service 110 // is disabled, just acts like there's an Internet connection. 111 void DetectCaptivePortalInternal(); 112 113 // Called by CaptivePortalDetector when detection completes. 114 void OnPortalDetectionCompleted( 115 const CaptivePortalDetector::Results& results); 116 117 // BrowserContextKeyedService: 118 virtual void Shutdown() OVERRIDE; 119 120 // Called when a captive portal check completes. Passes the result to all 121 // observers. 122 void OnResult(Result result); 123 124 // Updates BackoffEntry::Policy and creates a new BackoffEntry, which 125 // resets the count used for throttling. 126 void ResetBackoffEntry(Result result); 127 128 // Updates |enabled_| based on command line flags and Profile preferences, 129 // and sets |state_| to STATE_NONE if it's false. 130 // TODO(mmenke): Figure out on which platforms, if any, should not use 131 // automatic captive portal detection. Currently it's enabled 132 // on all platforms, though this code is not compiled on 133 // Android, since it lacks the Browser class. 134 void UpdateEnabledState(); 135 136 // Returns the current TimeTicks. 137 base::TimeTicks GetCurrentTimeTicks() const; 138 139 bool DetectionInProgress() const; 140 141 // Returns true if the timer to try and detect a captive portal is running. 142 bool TimerRunning() const; 143 144 State state() const { return state_; } 145 146 RecheckPolicy& recheck_policy() { return recheck_policy_; } 147 148 void set_test_url(const GURL& test_url) { test_url_ = test_url; } 149 150 // Sets current test time ticks. Used by unit tests. 151 void set_time_ticks_for_testing(const base::TimeTicks& time_ticks) { 152 time_ticks_for_testing_ = time_ticks; 153 } 154 155 // Advances current test time ticks. Used by unit tests. 156 void advance_time_ticks_for_testing(const base::TimeDelta& delta) { 157 time_ticks_for_testing_ += delta; 158 } 159 160 // The profile that owns this CaptivePortalService. 161 Profile* profile_; 162 163 State state_; 164 165 // Detector for checking active network for a portal state. 166 CaptivePortalDetector captive_portal_detector_; 167 168 // True if the service is enabled. When not enabled, all checks will return 169 // RESULT_INTERNET_CONNECTED. 170 bool enabled_; 171 172 // The result of the most recent captive portal check. 173 Result last_detection_result_; 174 175 // Number of sequential checks with the same captive portal result. 176 int num_checks_with_same_result_; 177 178 // Time when |last_detection_result_| was first received. 179 base::TimeTicks first_check_time_with_same_result_; 180 181 // Time the last captive portal check completed. 182 base::TimeTicks last_check_time_; 183 184 // Policy for throttling portal checks. 185 RecheckPolicy recheck_policy_; 186 187 // Implements behavior needed by |recheck_policy_|. Whenever there's a new 188 // captive_portal::Result, BackoffEntry::Policy is updated and 189 // |backoff_entry_| is recreated. Each check that returns the same Result 190 // is considered a "failure", to trigger throttling. 191 scoped_ptr<net::BackoffEntry> backoff_entry_; 192 193 // URL that returns a 204 response code when connected to the Internet. 194 GURL test_url_; 195 196 // The pref member for whether navigation errors should be resolved with a web 197 // service. Actually called "alternate_error_pages", since it's also used for 198 // the Link Doctor. 199 BooleanPrefMember resolve_errors_with_web_service_; 200 201 base::OneShotTimer<CaptivePortalService> check_captive_portal_timer_; 202 203 static TestingState testing_state_; 204 205 // Test time ticks used by unit tests. 206 base::TimeTicks time_ticks_for_testing_; 207 208 DISALLOW_COPY_AND_ASSIGN(CaptivePortalService); 209}; 210 211} // namespace captive_portal 212 213#endif // CHROME_BROWSER_CAPTIVE_PORTAL_CAPTIVE_PORTAL_SERVICE_H_ 214