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