OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/chromeos/net/network_portal_detector_impl.h" | 5 #include "chrome/browser/chromeos/net/network_portal_detector_impl.h" |
6 | 6 |
| 7 #include <algorithm> |
| 8 |
7 #include "base/bind.h" | 9 #include "base/bind.h" |
8 #include "base/command_line.h" | 10 #include "base/command_line.h" |
9 #include "base/logging.h" | 11 #include "base/logging.h" |
10 #include "base/message_loop/message_loop.h" | 12 #include "base/message_loop/message_loop.h" |
11 #include "base/metrics/histogram.h" | 13 #include "base/metrics/histogram.h" |
12 #include "chrome/browser/chrome_notification_types.h" | 14 #include "chrome/browser/chrome_notification_types.h" |
13 #include "chromeos/dbus/dbus_thread_manager.h" | 15 #include "chromeos/dbus/dbus_thread_manager.h" |
14 #include "chromeos/dbus/shill_profile_client.h" | 16 #include "chromeos/dbus/shill_profile_client.h" |
15 #include "chromeos/network/network_state.h" | 17 #include "chromeos/network/network_state.h" |
16 #include "chromeos/network/network_state_handler.h" | 18 #include "chromeos/network/network_state_handler.h" |
17 #include "content/public/browser/notification_service.h" | 19 #include "content/public/browser/notification_service.h" |
18 #include "grit/generated_resources.h" | 20 #include "grit/generated_resources.h" |
19 #include "net/http/http_status_code.h" | 21 #include "net/http/http_status_code.h" |
20 #include "third_party/cros_system_api/dbus/service_constants.h" | 22 #include "third_party/cros_system_api/dbus/service_constants.h" |
21 #include "ui/base/l10n/l10n_util.h" | 23 #include "ui/base/l10n/l10n_util.h" |
22 | 24 |
23 using captive_portal::CaptivePortalDetector; | 25 using captive_portal::CaptivePortalDetector; |
24 | 26 |
25 namespace chromeos { | 27 namespace chromeos { |
26 | 28 |
27 namespace { | 29 namespace { |
28 | 30 |
29 // Maximum number of portal detections for the same default network | |
30 // after network change. | |
31 const int kMaxRequestAttempts = 3; | |
32 | |
33 // Minimum timeout between consecutive portal checks for the same | |
34 // network. | |
35 const int kMinTimeBetweenAttemptsSec = 3; | |
36 | |
37 // Delay before portal detection caused by changes in proxy settings. | 31 // Delay before portal detection caused by changes in proxy settings. |
38 const int kProxyChangeDelaySec = 1; | 32 const int kProxyChangeDelaySec = 1; |
39 | 33 |
40 // Delay between consecutive portal checks for a network in lazy mode. | 34 const NetworkState* DefaultNetwork() { |
41 const int kLazyCheckIntervalSec = 5; | 35 return NetworkHandler::Get()->network_state_handler()->DefaultNetwork(); |
| 36 } |
42 | 37 |
43 void RecordDiscrepancyWithShill( | 38 void RecordDiscrepancyWithShill( |
44 const NetworkState* network, | 39 const NetworkState* network, |
45 const NetworkPortalDetector::CaptivePortalStatus status) { | 40 const NetworkPortalDetector::CaptivePortalStatus status) { |
46 if (network->connection_state() == shill::kStateOnline) { | 41 if (network->connection_state() == shill::kStateOnline) { |
47 UMA_HISTOGRAM_ENUMERATION( | 42 UMA_HISTOGRAM_ENUMERATION( |
48 NetworkPortalDetectorImpl::kShillOnlineHistogram, | 43 NetworkPortalDetectorImpl::kShillOnlineHistogram, |
49 status, | 44 status, |
50 NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT); | 45 NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT); |
51 } else if (network->connection_state() == shill::kStatePortal) { | 46 } else if (network->connection_state() == shill::kStatePortal) { |
52 UMA_HISTOGRAM_ENUMERATION( | 47 UMA_HISTOGRAM_ENUMERATION( |
53 NetworkPortalDetectorImpl::kShillPortalHistogram, | 48 NetworkPortalDetectorImpl::kShillPortalHistogram, |
54 status, | 49 status, |
55 NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT); | 50 NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT); |
56 } else if (network->connection_state() == shill::kStateOffline) { | 51 } else if (network->connection_state() == shill::kStateOffline) { |
57 UMA_HISTOGRAM_ENUMERATION( | 52 UMA_HISTOGRAM_ENUMERATION( |
58 NetworkPortalDetectorImpl::kShillOfflineHistogram, | 53 NetworkPortalDetectorImpl::kShillOfflineHistogram, |
59 status, | 54 status, |
60 NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT); | 55 NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT); |
61 } | 56 } |
62 } | 57 } |
63 | 58 |
64 } // namespace | 59 } // namespace |
65 | 60 |
66 //////////////////////////////////////////////////////////////////////////////// | 61 //////////////////////////////////////////////////////////////////////////////// |
67 // NetworkPortalDetectorImpl, public: | 62 // NetworkPortalDetectorImpl, public: |
68 | 63 |
69 const char NetworkPortalDetectorImpl::kDetectionResultHistogram[] = | 64 const char NetworkPortalDetectorImpl::kDetectionResultHistogram[] = |
70 "CaptivePortal.OOBE.DetectionResult"; | 65 "CaptivePortal.OOBE.DetectionResult"; |
71 const char NetworkPortalDetectorImpl::kDetectionDurationHistogram[] = | 66 const char NetworkPortalDetectorImpl::kDetectionDurationHistogram[] = |
72 "CaptivePortal.OOBE.DetectionDuration"; | 67 "CaptivePortal.OOBE.DetectionDuration"; |
73 const char NetworkPortalDetectorImpl::kShillOnlineHistogram[] = | 68 const char NetworkPortalDetectorImpl::kShillOnlineHistogram[] = |
74 "CaptivePortal.OOBE.DiscrepancyWithShill_Online"; | 69 "CaptivePortal.OOBE.DiscrepancyWithShill_Online"; |
75 const char NetworkPortalDetectorImpl::kShillPortalHistogram[] = | 70 const char NetworkPortalDetectorImpl::kShillPortalHistogram[] = |
76 "CaptivePortal.OOBE.DiscrepancyWithShill_RestrictedPool"; | 71 "CaptivePortal.OOBE.DiscrepancyWithShill_RestrictedPool"; |
77 const char NetworkPortalDetectorImpl::kShillOfflineHistogram[] = | 72 const char NetworkPortalDetectorImpl::kShillOfflineHistogram[] = |
78 "CaptivePortal.OOBE.DiscrepancyWithShill_Offline"; | 73 "CaptivePortal.OOBE.DiscrepancyWithShill_Offline"; |
79 | 74 |
80 NetworkPortalDetectorImpl::NetworkPortalDetectorImpl( | 75 NetworkPortalDetectorImpl::NetworkPortalDetectorImpl( |
81 const scoped_refptr<net::URLRequestContextGetter>& request_context) | 76 const scoped_refptr<net::URLRequestContextGetter>& request_context) |
82 : state_(STATE_IDLE), | 77 : state_(STATE_IDLE), |
83 test_url_(CaptivePortalDetector::kDefaultURL), | 78 test_url_(CaptivePortalDetector::kDefaultURL), |
84 enabled_(false), | 79 enabled_(false), |
85 weak_ptr_factory_(this), | 80 weak_factory_(this), |
86 attempt_count_(0), | 81 login_screen_strategy_(this), |
87 lazy_detection_enabled_(false), | 82 error_screen_strategy_(this), |
88 lazy_check_interval_(base::TimeDelta::FromSeconds(kLazyCheckIntervalSec)), | 83 strategy_(&login_screen_strategy_) { |
89 min_time_between_attempts_( | |
90 base::TimeDelta::FromSeconds(kMinTimeBetweenAttemptsSec)), | |
91 request_timeout_for_testing_initialized_(false) { | |
92 captive_portal_detector_.reset(new CaptivePortalDetector(request_context)); | 84 captive_portal_detector_.reset(new CaptivePortalDetector(request_context)); |
93 | 85 |
94 registrar_.Add(this, | 86 registrar_.Add(this, |
95 chrome::NOTIFICATION_LOGIN_PROXY_CHANGED, | 87 chrome::NOTIFICATION_LOGIN_PROXY_CHANGED, |
96 content::NotificationService::AllSources()); | 88 content::NotificationService::AllSources()); |
97 registrar_.Add(this, | 89 registrar_.Add(this, |
98 chrome::NOTIFICATION_AUTH_SUPPLIED, | 90 chrome::NOTIFICATION_AUTH_SUPPLIED, |
99 content::NotificationService::AllSources()); | 91 content::NotificationService::AllSources()); |
100 registrar_.Add(this, | 92 registrar_.Add(this, |
101 chrome::NOTIFICATION_AUTH_CANCELLED, | 93 chrome::NOTIFICATION_AUTH_CANCELLED, |
102 content::NotificationService::AllSources()); | 94 content::NotificationService::AllSources()); |
103 | 95 |
104 NetworkHandler::Get()->network_state_handler()->AddObserver( | 96 NetworkHandler::Get()->network_state_handler()->AddObserver(this, FROM_HERE); |
105 this, FROM_HERE); | |
106 } | 97 } |
107 | 98 |
108 NetworkPortalDetectorImpl::~NetworkPortalDetectorImpl() { | 99 NetworkPortalDetectorImpl::~NetworkPortalDetectorImpl() { |
109 DCHECK(CalledOnValidThread()); | 100 DCHECK(CalledOnValidThread()); |
110 | 101 |
111 detection_task_.Cancel(); | 102 attempt_task_.Cancel(); |
112 detection_timeout_.Cancel(); | 103 attempt_timeout_.Cancel(); |
113 | 104 |
114 captive_portal_detector_->Cancel(); | 105 captive_portal_detector_->Cancel(); |
115 captive_portal_detector_.reset(); | 106 captive_portal_detector_.reset(); |
116 observers_.Clear(); | 107 observers_.Clear(); |
117 if (NetworkHandler::IsInitialized()) { | 108 if (NetworkHandler::IsInitialized()) { |
118 NetworkHandler::Get()->network_state_handler()->RemoveObserver( | 109 NetworkHandler::Get()->network_state_handler()->RemoveObserver(this, |
119 this, FROM_HERE); | 110 FROM_HERE); |
120 } | 111 } |
121 } | 112 } |
122 | 113 |
123 void NetworkPortalDetectorImpl::AddObserver(Observer* observer) { | 114 void NetworkPortalDetectorImpl::AddObserver(Observer* observer) { |
124 DCHECK(CalledOnValidThread()); | 115 DCHECK(CalledOnValidThread()); |
125 if (!observer || observers_.HasObserver(observer)) | 116 if (observer && !observers_.HasObserver(observer)) |
126 return; | 117 observers_.AddObserver(observer); |
127 observers_.AddObserver(observer); | |
128 } | 118 } |
129 | 119 |
130 void NetworkPortalDetectorImpl::AddAndFireObserver(Observer* observer) { | 120 void NetworkPortalDetectorImpl::AddAndFireObserver(Observer* observer) { |
131 DCHECK(CalledOnValidThread()); | 121 DCHECK(CalledOnValidThread()); |
132 if (!observer) | 122 if (!observer) |
133 return; | 123 return; |
134 AddObserver(observer); | 124 AddObserver(observer); |
135 CaptivePortalState portal_state; | 125 CaptivePortalState portal_state; |
136 const NetworkState* network = | 126 const NetworkState* network = DefaultNetwork(); |
137 NetworkHandler::Get()->network_state_handler()->DefaultNetwork(); | |
138 if (network) | 127 if (network) |
139 portal_state = GetCaptivePortalState(network->path()); | 128 portal_state = GetCaptivePortalState(network->path()); |
140 observer->OnPortalDetectionCompleted(network, portal_state); | 129 observer->OnPortalDetectionCompleted(network, portal_state); |
141 } | 130 } |
142 | 131 |
143 void NetworkPortalDetectorImpl::RemoveObserver(Observer* observer) { | 132 void NetworkPortalDetectorImpl::RemoveObserver(Observer* observer) { |
144 DCHECK(CalledOnValidThread()); | 133 DCHECK(CalledOnValidThread()); |
145 if (observer) | 134 if (observer) |
146 observers_.RemoveObserver(observer); | 135 observers_.RemoveObserver(observer); |
147 } | 136 } |
148 | 137 |
149 bool NetworkPortalDetectorImpl::IsEnabled() { | 138 bool NetworkPortalDetectorImpl::IsEnabled() { return enabled_; } |
150 return enabled_; | |
151 } | |
152 | 139 |
153 void NetworkPortalDetectorImpl::Enable(bool start_detection) { | 140 void NetworkPortalDetectorImpl::Enable(bool start_detection) { |
154 DCHECK(CalledOnValidThread()); | 141 DCHECK(CalledOnValidThread()); |
155 if (enabled_) | 142 if (enabled_) |
156 return; | 143 return; |
| 144 |
| 145 DCHECK(is_idle()); |
157 enabled_ = true; | 146 enabled_ = true; |
158 DCHECK(!IsPortalCheckPending()); | 147 |
159 DCHECK(!IsCheckingForPortal()); | 148 const NetworkState* network = DefaultNetwork(); |
160 DCHECK(!lazy_detection_enabled()); | 149 if (!start_detection || !network) |
161 if (!start_detection) | |
162 return; | 150 return; |
163 state_ = STATE_IDLE; | 151 portal_state_map_.erase(network->path()); |
164 attempt_count_ = 0; | 152 StartDetection(); |
165 const NetworkState* default_network = | |
166 NetworkHandler::Get()->network_state_handler()->DefaultNetwork(); | |
167 if (!default_network) | |
168 return; | |
169 portal_state_map_.erase(default_network->path()); | |
170 DCHECK(CanPerformDetection()); | |
171 DetectCaptivePortal(base::TimeDelta()); | |
172 } | 153 } |
173 | 154 |
174 NetworkPortalDetectorImpl::CaptivePortalState | 155 NetworkPortalDetectorImpl::CaptivePortalState |
175 NetworkPortalDetectorImpl::GetCaptivePortalState( | 156 NetworkPortalDetectorImpl::GetCaptivePortalState( |
176 const std::string& service_path) { | 157 const std::string& service_path) { |
177 DCHECK(CalledOnValidThread()); | 158 DCHECK(CalledOnValidThread()); |
178 CaptivePortalStateMap::const_iterator it = | 159 CaptivePortalStateMap::const_iterator it = |
179 portal_state_map_.find(service_path); | 160 portal_state_map_.find(service_path); |
180 if (it == portal_state_map_.end()) | 161 if (it == portal_state_map_.end()) |
181 return CaptivePortalState(); | 162 return CaptivePortalState(); |
182 return it->second; | 163 return it->second; |
183 } | 164 } |
184 | 165 |
185 bool NetworkPortalDetectorImpl::StartDetectionIfIdle() { | 166 bool NetworkPortalDetectorImpl::StartDetectionIfIdle() { |
186 if (IsPortalCheckPending() || IsCheckingForPortal()) | 167 if (!is_idle()) |
187 return false; | 168 return false; |
188 if (!CanPerformDetection()) | 169 StartDetection(); |
189 attempt_count_ = 0; | |
190 DCHECK(CanPerformDetection()); | |
191 DetectCaptivePortal(base::TimeDelta()); | |
192 return true; | 170 return true; |
193 } | 171 } |
194 | 172 |
195 void NetworkPortalDetectorImpl::EnableLazyDetection() { | 173 void NetworkPortalDetectorImpl::EnableErrorScreenStrategy() { |
196 if (lazy_detection_enabled()) | 174 if (strategy_ == &error_screen_strategy_) |
197 return; | 175 return; |
198 lazy_detection_enabled_ = true; | 176 VLOG(1) << "Error screen detection strategy enabled."; |
199 VLOG(1) << "Lazy detection mode enabled."; | 177 strategy_ = &error_screen_strategy_; |
| 178 strategy_->Reset(); |
200 StartDetectionIfIdle(); | 179 StartDetectionIfIdle(); |
201 } | 180 } |
202 | 181 |
203 void NetworkPortalDetectorImpl::DisableLazyDetection() { | 182 void NetworkPortalDetectorImpl::DisableErrorScreenStrategy() { |
204 if (!lazy_detection_enabled()) | 183 if (strategy_ != &error_screen_strategy_) |
205 return; | 184 return; |
206 lazy_detection_enabled_ = false; | 185 VLOG(1) << "Error screen detection strategy disabled."; |
207 if (attempt_count_ == kMaxRequestAttempts && IsPortalCheckPending()) | 186 strategy_ = &login_screen_strategy_; |
208 CancelPortalDetection(); | 187 strategy_->Reset(); |
209 VLOG(1) << "Lazy detection mode disabled."; | 188 CancelDetection(); |
210 } | 189 } |
211 | 190 |
212 void NetworkPortalDetectorImpl::DefaultNetworkChanged( | 191 void NetworkPortalDetectorImpl::DefaultNetworkChanged( |
213 const NetworkState* default_network) { | 192 const NetworkState* default_network) { |
214 DCHECK(CalledOnValidThread()); | 193 DCHECK(CalledOnValidThread()); |
215 | 194 |
216 if (!default_network) { | 195 if (!default_network) { |
217 default_network_name_.clear(); | 196 default_network_name_.clear(); |
218 default_network_id_.clear(); | 197 default_network_id_.clear(); |
219 | 198 |
220 CancelPortalDetection(); | 199 CancelDetection(); |
221 | 200 |
222 CaptivePortalState state; | 201 CaptivePortalState state; |
223 state.status = CAPTIVE_PORTAL_STATUS_OFFLINE; | 202 state.status = CAPTIVE_PORTAL_STATUS_OFFLINE; |
224 SetCaptivePortalState(NULL, state); | 203 OnDetectionCompleted(NULL, state); |
225 return; | 204 return; |
226 } | 205 } |
227 | 206 |
228 default_network_name_ = default_network->name(); | 207 default_network_name_ = default_network->name(); |
229 default_network_id_ = default_network->guid(); | 208 default_network_id_ = default_network->guid(); |
230 | 209 |
231 bool network_changed = (default_service_path_ != default_network->path()); | 210 bool network_changed = (default_service_path_ != default_network->path()); |
232 default_service_path_ = default_network->path(); | 211 default_service_path_ = default_network->path(); |
233 | 212 |
234 bool connection_state_changed = (default_connection_state_ != | 213 bool connection_state_changed = |
235 default_network->connection_state()); | 214 (default_connection_state_ != default_network->connection_state()); |
236 default_connection_state_ = default_network->connection_state(); | 215 default_connection_state_ = default_network->connection_state(); |
237 | 216 |
238 if (network_changed || connection_state_changed) { | 217 if (network_changed || connection_state_changed) |
239 attempt_count_ = 0; | 218 CancelDetection(); |
240 CancelPortalDetection(); | |
241 } | |
242 | 219 |
243 if (CanPerformDetection() && | 220 if (CanPerformAttempt() && |
244 NetworkState::StateIsConnected(default_connection_state_)) { | 221 NetworkState::StateIsConnected(default_connection_state_)) { |
245 // Initiate Captive Portal detection if network's captive | 222 // Initiate Captive Portal detection if network's captive |
246 // portal state is unknown (e.g. for freshly created networks), | 223 // portal state is unknown (e.g. for freshly created networks), |
247 // offline or if network connection state was changed. | 224 // offline or if network connection state was changed. |
248 CaptivePortalState state = GetCaptivePortalState(default_network->path()); | 225 CaptivePortalState state = GetCaptivePortalState(default_network->path()); |
249 if (state.status == CAPTIVE_PORTAL_STATUS_UNKNOWN || | 226 if (state.status == CAPTIVE_PORTAL_STATUS_UNKNOWN || |
250 state.status == CAPTIVE_PORTAL_STATUS_OFFLINE || | 227 state.status == CAPTIVE_PORTAL_STATUS_OFFLINE || |
251 (!network_changed && connection_state_changed)) { | 228 (!network_changed && connection_state_changed)) { |
252 DetectCaptivePortal(base::TimeDelta()); | 229 ScheduleAttempt(base::TimeDelta()); |
253 } | 230 } |
254 } | 231 } |
255 } | 232 } |
256 | 233 |
| 234 base::TimeTicks NetworkPortalDetectorImpl::GetCurrentTimeTicks() { |
| 235 if (time_ticks_for_testing_.is_null()) |
| 236 return base::TimeTicks::Now(); |
| 237 return time_ticks_for_testing_; |
| 238 } |
| 239 |
257 //////////////////////////////////////////////////////////////////////////////// | 240 //////////////////////////////////////////////////////////////////////////////// |
258 // NetworkPortalDetectorImpl, private: | 241 // NetworkPortalDetectorImpl, private: |
259 | 242 |
260 bool NetworkPortalDetectorImpl::CanPerformDetection() const { | 243 void NetworkPortalDetectorImpl::StartDetection() { |
261 if (IsPortalCheckPending() || IsCheckingForPortal()) | 244 strategy_->Reset(); |
262 return false; | 245 DCHECK(CanPerformAttempt()); |
263 return attempt_count_ < kMaxRequestAttempts || lazy_detection_enabled(); | 246 detection_start_time_ = GetCurrentTimeTicks(); |
| 247 ScheduleAttempt(base::TimeDelta()); |
264 } | 248 } |
265 | 249 |
266 void NetworkPortalDetectorImpl::DetectCaptivePortal( | 250 void NetworkPortalDetectorImpl::CancelDetection() { |
267 const base::TimeDelta& delay) { | 251 attempt_task_.Cancel(); |
268 DCHECK(CanPerformDetection()); | 252 attempt_timeout_.Cancel(); |
| 253 captive_portal_detector_->Cancel(); |
| 254 state_ = STATE_IDLE; |
| 255 strategy_->Reset(); |
| 256 } |
| 257 |
| 258 bool NetworkPortalDetectorImpl::CanPerformAttempt() const { |
| 259 return is_idle() && strategy_->CanPerformAttempt(); |
| 260 } |
| 261 |
| 262 void NetworkPortalDetectorImpl::ScheduleAttempt(const base::TimeDelta& delay) { |
| 263 DCHECK(CanPerformAttempt()); |
269 | 264 |
270 if (!IsEnabled()) | 265 if (!IsEnabled()) |
271 return; | 266 return; |
272 | 267 |
273 detection_task_.Cancel(); | 268 attempt_task_.Cancel(); |
274 detection_timeout_.Cancel(); | 269 attempt_timeout_.Cancel(); |
275 state_ = STATE_PORTAL_CHECK_PENDING; | 270 state_ = STATE_PORTAL_CHECK_PENDING; |
276 | 271 |
277 next_attempt_delay_ = delay; | 272 next_attempt_delay_ = |
278 if (attempt_count_ > 0) { | 273 std::max(delay, strategy_->GetDelayBeforeCurrentAttempt()); |
279 base::TimeTicks now = GetCurrentTimeTicks(); | 274 attempt_task_.Reset(base::Bind(&NetworkPortalDetectorImpl::StartAttempt, |
280 base::TimeDelta elapsed_time; | 275 weak_factory_.GetWeakPtr())); |
281 | |
282 base::TimeDelta delay_between_attempts = min_time_between_attempts_; | |
283 if (attempt_count_ == kMaxRequestAttempts) { | |
284 DCHECK(lazy_detection_enabled()); | |
285 delay_between_attempts = lazy_check_interval_; | |
286 } | |
287 if (now > attempt_start_time_) | |
288 elapsed_time = now - attempt_start_time_; | |
289 if (elapsed_time < delay_between_attempts && | |
290 delay_between_attempts - elapsed_time > next_attempt_delay_) { | |
291 next_attempt_delay_ = delay_between_attempts - elapsed_time; | |
292 } | |
293 } else { | |
294 detection_start_time_ = GetCurrentTimeTicks(); | |
295 } | |
296 detection_task_.Reset( | |
297 base::Bind(&NetworkPortalDetectorImpl::DetectCaptivePortalTask, | |
298 weak_ptr_factory_.GetWeakPtr())); | |
299 base::MessageLoop::current()->PostDelayedTask( | 276 base::MessageLoop::current()->PostDelayedTask( |
300 FROM_HERE, detection_task_.callback(), next_attempt_delay_); | 277 FROM_HERE, attempt_task_.callback(), next_attempt_delay_); |
301 } | 278 } |
302 | 279 |
303 void NetworkPortalDetectorImpl::DetectCaptivePortalTask() { | 280 void NetworkPortalDetectorImpl::StartAttempt() { |
304 DCHECK(IsPortalCheckPending()); | 281 DCHECK(is_portal_check_pending()); |
305 | 282 |
306 state_ = STATE_CHECKING_FOR_PORTAL; | 283 state_ = STATE_CHECKING_FOR_PORTAL; |
307 attempt_start_time_ = GetCurrentTimeTicks(); | |
308 | |
309 if (attempt_count_ < kMaxRequestAttempts) { | |
310 ++attempt_count_; | |
311 VLOG(1) << "Portal detection started: " | |
312 << "name=" << default_network_name_ << ", " | |
313 << "id=" << default_network_id_ << ", " | |
314 << "attempt=" << attempt_count_ << " of " << kMaxRequestAttempts; | |
315 } else { | |
316 DCHECK(lazy_detection_enabled()); | |
317 VLOG(1) << "Lazy portal detection attempt started"; | |
318 } | |
319 | 284 |
320 captive_portal_detector_->DetectCaptivePortal( | 285 captive_portal_detector_->DetectCaptivePortal( |
321 test_url_, | 286 test_url_, |
322 base::Bind(&NetworkPortalDetectorImpl::OnPortalDetectionCompleted, | 287 base::Bind(&NetworkPortalDetectorImpl::OnAttemptCompleted, |
323 weak_ptr_factory_.GetWeakPtr())); | 288 weak_factory_.GetWeakPtr())); |
324 detection_timeout_.Reset( | 289 attempt_timeout_.Reset( |
325 base::Bind(&NetworkPortalDetectorImpl::PortalDetectionTimeout, | 290 base::Bind(&NetworkPortalDetectorImpl::OnAttemptTimeout, |
326 weak_ptr_factory_.GetWeakPtr())); | 291 weak_factory_.GetWeakPtr())); |
327 base::TimeDelta request_timeout; | |
328 | 292 |
329 // For easier unit testing check for testing state is performed here | 293 strategy_->OnAttemptStarted(); |
330 // and not in the GetRequestTimeoutSec(). | |
331 if (request_timeout_for_testing_initialized_) | |
332 request_timeout = request_timeout_for_testing_; | |
333 else | |
334 request_timeout = base::TimeDelta::FromSeconds(GetRequestTimeoutSec()); | |
335 base::MessageLoop::current()->PostDelayedTask( | 294 base::MessageLoop::current()->PostDelayedTask( |
336 FROM_HERE, detection_timeout_.callback(), request_timeout); | 295 FROM_HERE, |
| 296 attempt_timeout_.callback(), |
| 297 strategy_->GetCurrentAttemptTimeout()); |
337 } | 298 } |
338 | 299 |
339 void NetworkPortalDetectorImpl::PortalDetectionTimeout() { | 300 void NetworkPortalDetectorImpl::OnAttemptTimeout() { |
340 DCHECK(CalledOnValidThread()); | 301 DCHECK(CalledOnValidThread()); |
341 DCHECK(IsCheckingForPortal()); | 302 DCHECK(is_checking_for_portal()); |
342 | 303 |
343 VLOG(1) << "Portal detection timeout: name=" << default_network_name_ << ", " | 304 VLOG(1) << "Portal detection timeout: name=" << default_network_name_ << ", " |
344 << "id=" << default_network_id_; | 305 << "id=" << default_network_id_; |
345 | 306 |
346 captive_portal_detector_->Cancel(); | 307 captive_portal_detector_->Cancel(); |
347 CaptivePortalDetector::Results results; | 308 CaptivePortalDetector::Results results; |
348 results.result = captive_portal::RESULT_NO_RESPONSE; | 309 results.result = captive_portal::RESULT_NO_RESPONSE; |
349 OnPortalDetectionCompleted(results); | 310 OnAttemptCompleted(results); |
350 } | 311 } |
351 | 312 |
352 void NetworkPortalDetectorImpl::CancelPortalDetection() { | 313 void NetworkPortalDetectorImpl::OnAttemptCompleted( |
353 if (IsPortalCheckPending()) | |
354 detection_task_.Cancel(); | |
355 else if (IsCheckingForPortal()) | |
356 captive_portal_detector_->Cancel(); | |
357 detection_timeout_.Cancel(); | |
358 state_ = STATE_IDLE; | |
359 } | |
360 | |
361 void NetworkPortalDetectorImpl::OnPortalDetectionCompleted( | |
362 const CaptivePortalDetector::Results& results) { | 314 const CaptivePortalDetector::Results& results) { |
363 captive_portal::Result result = results.result; | 315 captive_portal::Result result = results.result; |
364 int response_code = results.response_code; | 316 int response_code = results.response_code; |
365 | 317 |
366 DCHECK(CalledOnValidThread()); | 318 DCHECK(CalledOnValidThread()); |
367 DCHECK(IsCheckingForPortal()); | 319 DCHECK(is_checking_for_portal()); |
368 | 320 |
369 VLOG(1) << "Portal detection completed: " | 321 VLOG(1) << "Detection attempt completed: " |
370 << "name=" << default_network_name_ << ", " | 322 << "name=" << default_network_name_ << ", " |
371 << "id=" << default_network_id_ << ", " | 323 << "id=" << default_network_id_ << ", " |
372 << "result=" | 324 << "result=" |
373 << CaptivePortalDetector::CaptivePortalResultToString(results.result) | 325 << CaptivePortalDetector::CaptivePortalResultToString(results.result) |
374 << ", " | 326 << ", " |
375 << "response_code=" << results.response_code; | 327 << "response_code=" << results.response_code; |
376 | 328 |
377 state_ = STATE_IDLE; | 329 state_ = STATE_IDLE; |
378 detection_timeout_.Cancel(); | 330 attempt_timeout_.Cancel(); |
379 | 331 |
380 const NetworkState* default_network = | 332 const NetworkState* network = DefaultNetwork(); |
381 NetworkHandler::Get()->network_state_handler()->DefaultNetwork(); | |
382 | 333 |
383 // If using a fake profile client, also fake being behind a captive portal | 334 // If using a fake profile client, also fake being behind a captive portal |
384 // if the default network is in portal state. | 335 // if the default network is in portal state. |
385 if (result != captive_portal::RESULT_NO_RESPONSE && | 336 if (result != captive_portal::RESULT_NO_RESPONSE && |
386 DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface() && | 337 DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface() && |
387 default_network && | 338 network && network->connection_state() == shill::kStatePortal) { |
388 default_network->connection_state() == shill::kStatePortal) { | |
389 result = captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL; | 339 result = captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL; |
390 response_code = 200; | 340 response_code = 200; |
391 } | 341 } |
392 | 342 |
393 CaptivePortalState state; | 343 CaptivePortalState state; |
394 state.response_code = response_code; | 344 state.response_code = response_code; |
395 switch (result) { | 345 switch (result) { |
396 case captive_portal::RESULT_NO_RESPONSE: | 346 case captive_portal::RESULT_NO_RESPONSE: |
397 if (state.response_code == net::HTTP_PROXY_AUTHENTICATION_REQUIRED) { | 347 if (state.response_code == net::HTTP_PROXY_AUTHENTICATION_REQUIRED) { |
398 state.status = CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED; | 348 state.status = CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED; |
399 SetCaptivePortalState(default_network, state); | 349 } else if (CanPerformAttempt()) { |
400 } else if (attempt_count_ >= kMaxRequestAttempts) { | 350 ScheduleAttempt(results.retry_after_delta); |
401 if (default_network && | 351 return; |
402 (default_network->connection_state() == shill::kStatePortal)) { | 352 } else if (network && |
403 // Take into account shill's detection results. | 353 (network->connection_state() == shill::kStatePortal)) { |
404 state.status = CAPTIVE_PORTAL_STATUS_PORTAL; | 354 // Take into account shill's detection results. |
405 LOG(WARNING) << "Network name=" << default_network->name() << ", " | 355 state.status = CAPTIVE_PORTAL_STATUS_PORTAL; |
406 << "id=" << default_network->guid() << " " | 356 LOG(WARNING) << "Network name=" << network->name() << ", " |
407 << "is marked as " | 357 << "id=" << network->guid() << " " |
408 << CaptivePortalStatusString(state.status) << " " | 358 << "is marked as " |
409 << "despite the fact that CaptivePortalDetector " | 359 << CaptivePortalStatusString(state.status) << " " |
410 << "received no response"; | 360 << "despite the fact that CaptivePortalDetector " |
411 } else { | 361 << "received no response"; |
412 state.status = CAPTIVE_PORTAL_STATUS_OFFLINE; | |
413 } | |
414 SetCaptivePortalState(default_network, state); | |
415 } else { | 362 } else { |
416 DCHECK(CanPerformDetection()); | 363 state.status = CAPTIVE_PORTAL_STATUS_OFFLINE; |
417 DetectCaptivePortal(results.retry_after_delta); | |
418 } | 364 } |
419 break; | 365 break; |
420 case captive_portal::RESULT_INTERNET_CONNECTED: | 366 case captive_portal::RESULT_INTERNET_CONNECTED: |
421 state.status = CAPTIVE_PORTAL_STATUS_ONLINE; | 367 state.status = CAPTIVE_PORTAL_STATUS_ONLINE; |
422 SetCaptivePortalState(default_network, state); | |
423 break; | 368 break; |
424 case captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL: | 369 case captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL: |
425 state.status = CAPTIVE_PORTAL_STATUS_PORTAL; | 370 state.status = CAPTIVE_PORTAL_STATUS_PORTAL; |
426 SetCaptivePortalState(default_network, state); | |
427 break; | 371 break; |
428 default: | 372 default: |
429 break; | 373 break; |
430 } | 374 } |
431 | 375 |
432 TryLazyDetection(); | 376 OnDetectionCompleted(network, state); |
433 } | 377 if (CanPerformAttempt()) |
434 | 378 ScheduleAttempt(base::TimeDelta()); |
435 void NetworkPortalDetectorImpl::TryLazyDetection() { | |
436 if (lazy_detection_enabled() && CanPerformDetection()) | |
437 DetectCaptivePortal(base::TimeDelta()); | |
438 } | 379 } |
439 | 380 |
440 void NetworkPortalDetectorImpl::Observe( | 381 void NetworkPortalDetectorImpl::Observe( |
441 int type, | 382 int type, |
442 const content::NotificationSource& source, | 383 const content::NotificationSource& source, |
443 const content::NotificationDetails& details) { | 384 const content::NotificationDetails& details) { |
444 if (type == chrome::NOTIFICATION_LOGIN_PROXY_CHANGED || | 385 if (type == chrome::NOTIFICATION_LOGIN_PROXY_CHANGED || |
445 type == chrome::NOTIFICATION_AUTH_SUPPLIED || | 386 type == chrome::NOTIFICATION_AUTH_SUPPLIED || |
446 type == chrome::NOTIFICATION_AUTH_CANCELLED) { | 387 type == chrome::NOTIFICATION_AUTH_CANCELLED) { |
447 VLOG(1) << "Restarting portal detection due to proxy change."; | 388 VLOG(1) << "Restarting portal detection due to proxy change."; |
448 attempt_count_ = 0; | 389 strategy_->Reset(); |
449 if (IsPortalCheckPending()) | 390 if (is_portal_check_pending()) |
450 return; | 391 return; |
451 CancelPortalDetection(); | 392 CancelDetection(); |
452 DCHECK(CanPerformDetection()); | 393 ScheduleAttempt(base::TimeDelta::FromSeconds(kProxyChangeDelaySec)); |
453 DetectCaptivePortal(base::TimeDelta::FromSeconds(kProxyChangeDelaySec)); | |
454 } | 394 } |
455 } | 395 } |
456 | 396 |
457 bool NetworkPortalDetectorImpl::IsPortalCheckPending() const { | 397 void NetworkPortalDetectorImpl::OnDetectionCompleted( |
458 return state_ == STATE_PORTAL_CHECK_PENDING; | |
459 } | |
460 | |
461 bool NetworkPortalDetectorImpl::IsCheckingForPortal() const { | |
462 return state_ == STATE_CHECKING_FOR_PORTAL; | |
463 } | |
464 | |
465 void NetworkPortalDetectorImpl::SetCaptivePortalState( | |
466 const NetworkState* network, | 398 const NetworkState* network, |
467 const CaptivePortalState& state) { | 399 const CaptivePortalState& state) { |
| 400 strategy_->OnDetectionCompleted(); |
| 401 |
468 if (!network) { | 402 if (!network) { |
469 NotifyPortalDetectionCompleted(network, state); | 403 NotifyDetectionCompleted(network, state); |
470 return; | 404 return; |
471 } | 405 } |
472 | 406 |
473 CaptivePortalStateMap::const_iterator it = | 407 CaptivePortalStateMap::const_iterator it = |
474 portal_state_map_.find(network->path()); | 408 portal_state_map_.find(network->path()); |
475 if (it == portal_state_map_.end() || | 409 if (it == portal_state_map_.end() || it->second.status != state.status || |
476 it->second.status != state.status || | |
477 it->second.response_code != state.response_code) { | 410 it->second.response_code != state.response_code) { |
478 VLOG(1) << "Updating Chrome Captive Portal state: " | 411 VLOG(1) << "Updating Chrome Captive Portal state: " |
479 << "name=" << network->name() << ", " | 412 << "name=" << network->name() << ", " |
480 << "id=" << network->guid() << ", " | 413 << "id=" << network->guid() << ", " |
481 << "status=" << CaptivePortalStatusString(state.status) << ", " | 414 << "status=" << CaptivePortalStatusString(state.status) << ", " |
482 << "response_code=" << state.response_code; | 415 << "response_code=" << state.response_code; |
483 | 416 |
484 // Record detection duration iff detection result differs from the | 417 // Record detection duration iff detection result differs from the |
485 // previous one for this network. The reason is to record all stats | 418 // previous one for this network. The reason is to record all stats |
486 // only when network changes it's state. | 419 // only when network changes it's state. |
487 RecordDetectionStats(network, state.status); | 420 RecordDetectionStats(network, state.status); |
488 | 421 |
489 portal_state_map_[network->path()] = state; | 422 portal_state_map_[network->path()] = state; |
490 } | 423 } |
491 NotifyPortalDetectionCompleted(network, state); | 424 NotifyDetectionCompleted(network, state); |
492 } | 425 } |
493 | 426 |
494 void NetworkPortalDetectorImpl::NotifyPortalDetectionCompleted( | 427 void NetworkPortalDetectorImpl::NotifyDetectionCompleted( |
495 const NetworkState* network, | 428 const NetworkState* network, |
496 const CaptivePortalState& state) { | 429 const CaptivePortalState& state) { |
497 FOR_EACH_OBSERVER(Observer, observers_, | 430 FOR_EACH_OBSERVER( |
498 OnPortalDetectionCompleted(network, state)); | 431 Observer, observers_, OnPortalDetectionCompleted(network, state)); |
499 notification_controller_.OnPortalDetectionCompleted(network, state); | 432 notification_controller_.OnPortalDetectionCompleted(network, state); |
500 } | 433 } |
501 | 434 |
502 base::TimeTicks NetworkPortalDetectorImpl::GetCurrentTimeTicks() const { | 435 bool NetworkPortalDetectorImpl::AttemptTimeoutIsCancelledForTesting() const { |
503 if (time_ticks_for_testing_.is_null()) | 436 return attempt_timeout_.IsCancelled(); |
504 return base::TimeTicks::Now(); | |
505 return time_ticks_for_testing_; | |
506 } | |
507 | |
508 bool NetworkPortalDetectorImpl::DetectionTimeoutIsCancelledForTesting() const { | |
509 return detection_timeout_.IsCancelled(); | |
510 } | |
511 | |
512 int NetworkPortalDetectorImpl::GetRequestTimeoutSec() const { | |
513 DCHECK_LE(0, attempt_count_); | |
514 const NetworkState* network = | |
515 NetworkHandler::Get()->network_state_handler()->DefaultNetwork(); | |
516 if (!network) | |
517 return kBaseRequestTimeoutSec; | |
518 if (lazy_detection_enabled_) | |
519 return kLazyRequestTimeoutSec; | |
520 return attempt_count_ * kBaseRequestTimeoutSec; | |
521 } | 437 } |
522 | 438 |
523 void NetworkPortalDetectorImpl::RecordDetectionStats( | 439 void NetworkPortalDetectorImpl::RecordDetectionStats( |
524 const NetworkState* network, | 440 const NetworkState* network, |
525 CaptivePortalStatus status) { | 441 CaptivePortalStatus status) { |
526 // Don't record stats for offline state. | 442 // Don't record stats for offline state. |
527 if (!network) | 443 if (!network) |
528 return; | 444 return; |
529 | 445 |
530 if (!detection_start_time_.is_null()) { | 446 if (!detection_start_time_.is_null()) { |
(...skipping 25 matching lines...) Expand all Loading... |
556 if (network->connection_state() != shill::kStateOnline) | 472 if (network->connection_state() != shill::kStateOnline) |
557 RecordDiscrepancyWithShill(network, status); | 473 RecordDiscrepancyWithShill(network, status); |
558 break; | 474 break; |
559 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT: | 475 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT: |
560 NOTREACHED(); | 476 NOTREACHED(); |
561 break; | 477 break; |
562 } | 478 } |
563 } | 479 } |
564 | 480 |
565 } // namespace chromeos | 481 } // namespace chromeos |
OLD | NEW |