Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(129)

Side by Side Diff: chrome/browser/chromeos/net/network_portal_detector.cc

Issue 11419070: Added detection timeouts and usage of Retry-After HTTP header. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix. Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 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.h" 5 #include "chrome/browser/chromeos/net/network_portal_detector.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/command_line.h" 8 #include "base/command_line.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/message_loop.h"
10 #include "chrome/browser/browser_process.h" 11 #include "chrome/browser/browser_process.h"
11 #include "chrome/browser/chromeos/cros/cros_library.h" 12 #include "chrome/browser/chromeos/cros/cros_library.h"
12 #include "chrome/common/chrome_switches.h" 13 #include "chrome/common/chrome_switches.h"
13 #include "content/public/browser/browser_thread.h" 14 #include "content/public/browser/browser_thread.h"
14 #include "grit/generated_resources.h" 15 #include "grit/generated_resources.h"
15 #include "ui/base/l10n/l10n_util.h" 16 #include "ui/base/l10n/l10n_util.h"
16 17
17 using captive_portal::CaptivePortalDetector; 18 using captive_portal::CaptivePortalDetector;
18 19
19 namespace chromeos { 20 namespace chromeos {
20 21
21 namespace { 22 namespace {
22 23
24 // Maximum number of portal detections for the same active network
25 // after network change.
26 const int kMaxRequestAttempts = 3;
27
28 // Minimum timeout between consecutive portal checks for the same
29 // network.
30 const int kMinTimeBetweenAttemptsSec = 3;
31
32 // Timeout for a portal check.
33 const int kRequestTimeoutSec = 10;
34
23 std::string CaptivePortalStateString( 35 std::string CaptivePortalStateString(
24 NetworkPortalDetector::CaptivePortalState state) { 36 NetworkPortalDetector::CaptivePortalState state) {
25 switch (state) { 37 switch (state) {
26 case NetworkPortalDetector::CAPTIVE_PORTAL_STATE_UNKNOWN: 38 case NetworkPortalDetector::CAPTIVE_PORTAL_STATE_UNKNOWN:
27 return l10n_util::GetStringUTF8( 39 return l10n_util::GetStringUTF8(
28 IDS_CHROMEOS_CAPTIVE_PORTAL_STATE_UNKNOWN); 40 IDS_CHROMEOS_CAPTIVE_PORTAL_STATE_UNKNOWN);
29 case NetworkPortalDetector::CAPTIVE_PORTAL_STATE_OFFLINE: 41 case NetworkPortalDetector::CAPTIVE_PORTAL_STATE_OFFLINE:
30 return l10n_util::GetStringUTF8( 42 return l10n_util::GetStringUTF8(
31 IDS_CHROMEOS_CAPTIVE_PORTAL_STATE_OFFLINE); 43 IDS_CHROMEOS_CAPTIVE_PORTAL_STATE_OFFLINE);
32 case NetworkPortalDetector::CAPTIVE_PORTAL_STATE_ONLINE: 44 case NetworkPortalDetector::CAPTIVE_PORTAL_STATE_ONLINE:
33 return l10n_util::GetStringUTF8(IDS_CHROMEOS_CAPTIVE_PORTAL_STATE_ONLINE); 45 return l10n_util::GetStringUTF8(IDS_CHROMEOS_CAPTIVE_PORTAL_STATE_ONLINE);
34 case NetworkPortalDetector::CAPTIVE_PORTAL_STATE_PORTAL: 46 case NetworkPortalDetector::CAPTIVE_PORTAL_STATE_PORTAL:
35 return l10n_util::GetStringUTF8(IDS_CHROMEOS_CAPTIVE_PORTAL_STATE_PORTAL); 47 return l10n_util::GetStringUTF8(IDS_CHROMEOS_CAPTIVE_PORTAL_STATE_PORTAL);
36 } 48 }
37 return l10n_util::GetStringUTF8( 49 return l10n_util::GetStringUTF8(
38 IDS_CHROMEOS_CAPTIVE_PORTAL_STATE_UNRECOGNIZED); 50 IDS_CHROMEOS_CAPTIVE_PORTAL_STATE_UNRECOGNIZED);
39 } 51 }
40 52
41 NetworkPortalDetector* g_network_portal_detector = NULL; 53 NetworkPortalDetector* g_network_portal_detector = NULL;
42 54
43 } // namespace 55 } // namespace
44 56
45 NetworkPortalDetector::NetworkPortalDetector( 57 NetworkPortalDetector::NetworkPortalDetector(
46 const scoped_refptr<net::URLRequestContextGetter>& request_context) 58 const scoped_refptr<net::URLRequestContextGetter>& request_context)
47 : test_url_(CaptivePortalDetector::kDefaultURL) { 59 : test_url_(CaptivePortalDetector::kDefaultURL),
60 weak_ptr_factory_(this),
61 attempt_count_(0),
62 min_time_between_attempts_(
63 base::TimeDelta::FromSeconds(kMinTimeBetweenAttemptsSec)),
64 request_timeout_(base::TimeDelta::FromSeconds(kRequestTimeoutSec)) {
48 captive_portal_detector_.reset( 65 captive_portal_detector_.reset(
49 new CaptivePortalDetector(request_context)); 66 new CaptivePortalDetector(request_context));
50 } 67 }
51 68
52 NetworkPortalDetector::~NetworkPortalDetector() { 69 NetworkPortalDetector::~NetworkPortalDetector() {
53 } 70 }
54 71
55 void NetworkPortalDetector::Init() { 72 void NetworkPortalDetector::Init() {
56 DCHECK(CalledOnValidThread()); 73 DCHECK(CalledOnValidThread());
57 74
58 state_ = STATE_IDLE; 75 state_ = STATE_IDLE;
59 chromeos::NetworkLibrary* network_library = 76 chromeos::NetworkLibrary* network_library =
60 chromeos::CrosLibrary::Get()->GetNetworkLibrary(); 77 chromeos::CrosLibrary::Get()->GetNetworkLibrary();
61 network_library->AddNetworkManagerObserver(this); 78 network_library->AddNetworkManagerObserver(this);
62 } 79 }
63 80
64 void NetworkPortalDetector::Shutdown() { 81 void NetworkPortalDetector::Shutdown() {
65 DCHECK(CalledOnValidThread()); 82 DCHECK(CalledOnValidThread());
66 83
84 detection_task_.Cancel();
85 detection_timeout_.Cancel();
86
67 captive_portal_detector_->Cancel(); 87 captive_portal_detector_->Cancel();
68 captive_portal_detector_.reset(); 88 captive_portal_detector_.reset();
69 observers_.Clear(); 89 observers_.Clear();
70 chromeos::NetworkLibrary* network_library = 90 chromeos::NetworkLibrary* network_library =
71 chromeos::CrosLibrary::Get()->GetNetworkLibrary(); 91 chromeos::CrosLibrary::Get()->GetNetworkLibrary();
72 network_library->RemoveNetworkManagerObserver(this); 92 network_library->RemoveNetworkManagerObserver(this);
73 } 93 }
74 94
75 void NetworkPortalDetector::AddObserver(Observer* observer) { 95 void NetworkPortalDetector::AddObserver(Observer* observer) {
76 DCHECK(CalledOnValidThread()); 96 DCHECK(CalledOnValidThread());
97
77 if (!observers_.HasObserver(observer)) 98 if (!observers_.HasObserver(observer))
78 observers_.AddObserver(observer); 99 observers_.AddObserver(observer);
79 } 100 }
80 101
81 void NetworkPortalDetector::RemoveObserver(Observer* observer) { 102 void NetworkPortalDetector::RemoveObserver(Observer* observer) {
82 DCHECK(CalledOnValidThread()); 103 DCHECK(CalledOnValidThread());
104
83 observers_.RemoveObserver(observer); 105 observers_.RemoveObserver(observer);
84 } 106 }
85 107
86 NetworkPortalDetector::CaptivePortalState 108 NetworkPortalDetector::CaptivePortalState
87 NetworkPortalDetector::GetCaptivePortalState(const Network* network) { 109 NetworkPortalDetector::GetCaptivePortalState(const Network* network) {
110 DCHECK(CalledOnValidThread());
111
88 if (!network) 112 if (!network)
89 return CAPTIVE_PORTAL_STATE_UNKNOWN; 113 return CAPTIVE_PORTAL_STATE_UNKNOWN;
90 CaptivePortalStateMap::const_iterator it = 114 CaptivePortalStateMap::const_iterator it =
91 captive_portal_state_map_.find(network->unique_id()); 115 captive_portal_state_map_.find(network->unique_id());
92 if (it == captive_portal_state_map_.end()) 116 if (it == captive_portal_state_map_.end())
93 return CAPTIVE_PORTAL_STATE_UNKNOWN; 117 return CAPTIVE_PORTAL_STATE_UNKNOWN;
94 return it->second; 118 return it->second;
95 } 119 }
96 120
97 void NetworkPortalDetector::OnNetworkManagerChanged(NetworkLibrary* cros) { 121 void NetworkPortalDetector::OnNetworkManagerChanged(NetworkLibrary* cros) {
98 DCHECK(CalledOnValidThread()); 122 DCHECK(CalledOnValidThread());
99 123
100 // Suppose that if there are no active network, then unique id is 124 // Suppose that if there are no active network, then unique id is
101 // empty and connection state is unknown. 125 // empty and connection state is unknown.
102 std::string new_active_network_id; 126 std::string new_active_network_id;
103 ConnectionState connection_state = STATE_UNKNOWN; 127 ConnectionState connection_state = STATE_UNKNOWN;
104 const Network* active_network = cros->active_network(); 128 const Network* active_network = cros->active_network();
105 if (active_network) { 129 if (active_network) {
106 new_active_network_id = active_network->unique_id(); 130 new_active_network_id = active_network->unique_id();
107 connection_state = active_network->connection_state(); 131 connection_state = active_network->connection_state();
108 } 132 }
109 133
110 if (active_network_id_ != new_active_network_id) { 134 if (active_network_id_ != new_active_network_id) {
111 active_network_id_ = new_active_network_id; 135 active_network_id_ = new_active_network_id;
112 if (IsCheckingForPortal()) { 136 attempt_count_ = 0;
113 // Network is changed, so detection results will be incorrect. 137 if (IsPortalCheckPending()) {
114 state_ = STATE_CHECKING_FOR_PORTAL_NETWORK_CHANGED; 138 detection_task_.Cancel();
115 } else if (Network::IsConnectedState(connection_state)) { 139 detection_timeout_.Cancel();
116 // Start captive portal detection, if possible. 140 } else if (IsCheckingForPortal()) {
117 DetectCaptivePortal(); 141 captive_portal_detector_->Cancel();
118 } 142 }
119 } else if (!IsCheckingForPortal() && 143 state_ = STATE_IDLE;
120 Network::IsConnectedState(connection_state)) { 144 }
145 if (!IsCheckingForPortal() && !IsPortalCheckPending() &&
146 Network::IsConnectedState(connection_state) &&
147 attempt_count_ < kMaxRequestAttempts) {
121 DCHECK(active_network); 148 DCHECK(active_network);
149
122 // Initiate Captive Portal detection only if network's captive 150 // Initiate Captive Portal detection only if network's captive
123 // portal state is unknown (e.g. for freshly created networks) or offline. 151 // portal state is unknown (e.g. for freshly created networks) or
152 // offline.
124 CaptivePortalState state = GetCaptivePortalState(active_network); 153 CaptivePortalState state = GetCaptivePortalState(active_network);
125 if (state == CAPTIVE_PORTAL_STATE_UNKNOWN || 154 if (state == CAPTIVE_PORTAL_STATE_UNKNOWN ||
126 state == CAPTIVE_PORTAL_STATE_OFFLINE) { 155 state == CAPTIVE_PORTAL_STATE_OFFLINE) {
127 DetectCaptivePortal(); 156 DetectCaptivePortal(base::TimeDelta());
128 } 157 }
129 } 158 }
130 } 159 }
131 160
132 // static 161 // static
133 NetworkPortalDetector* NetworkPortalDetector::CreateInstance() { 162 NetworkPortalDetector* NetworkPortalDetector::CreateInstance() {
134 DCHECK(!g_network_portal_detector); 163 DCHECK(!g_network_portal_detector);
135 g_network_portal_detector = new NetworkPortalDetector( 164 g_network_portal_detector = new NetworkPortalDetector(
136 g_browser_process->system_request_context()); 165 g_browser_process->system_request_context());
137 return g_network_portal_detector; 166 return g_network_portal_detector;
138 } 167 }
139 168
140 // static 169 // static
141 NetworkPortalDetector* NetworkPortalDetector::GetInstance() { 170 NetworkPortalDetector* NetworkPortalDetector::GetInstance() {
142 if (!g_network_portal_detector) 171 if (!g_network_portal_detector)
143 return CreateInstance(); 172 return CreateInstance();
144 return g_network_portal_detector; 173 return g_network_portal_detector;
145 } 174 }
146 175
147 // static 176 // static
148 bool NetworkPortalDetector::IsEnabled() { 177 bool NetworkPortalDetector::IsEnabled() {
149 return !CommandLine::ForCurrentProcess()->HasSwitch( 178 return !CommandLine::ForCurrentProcess()->HasSwitch(
150 switches::kDisableChromeCaptivePortalDetector); 179 switches::kDisableChromeCaptivePortalDetector);
151 } 180 }
152 181
153 void NetworkPortalDetector::DetectCaptivePortal() { 182 void NetworkPortalDetector::DetectCaptivePortal(const base::TimeDelta& delay) {
183 DCHECK(!IsPortalCheckPending());
184 DCHECK(!IsCheckingForPortal());
185 DCHECK(attempt_count_ < kMaxRequestAttempts);
186
187 detection_task_.Cancel();
188 detection_timeout_.Cancel();
189 state_ = STATE_PORTAL_CHECK_PENDING;
190
191 next_attempt_delay_ = delay;
192 if (attempt_count_ > 0) {
193 base::TimeTicks now = GetCurrentTimeTicks();
194 base::TimeDelta elapsed_time;
195 if (now > attempt_start_time_)
196 elapsed_time = now - attempt_start_time_;
197 if (elapsed_time < min_time_between_attempts_ &&
198 min_time_between_attempts_ - elapsed_time > next_attempt_delay_) {
199 next_attempt_delay_ = min_time_between_attempts_ - elapsed_time;
200 }
201 }
202 detection_task_.Reset(
203 base::Bind(&NetworkPortalDetector::DetectCaptivePortalTask,
204 weak_ptr_factory_.GetWeakPtr()));
205 MessageLoop::current()->PostDelayedTask(FROM_HERE,
206 detection_task_.callback(),
207 next_attempt_delay_);
208 }
209
210 void NetworkPortalDetector::DetectCaptivePortalTask() {
211 DCHECK(IsPortalCheckPending());
212
154 state_ = STATE_CHECKING_FOR_PORTAL; 213 state_ = STATE_CHECKING_FOR_PORTAL;
214
215 ++attempt_count_;
216 attempt_start_time_ = GetCurrentTimeTicks();
217
218 VLOG(1) << "Portal detection started: "
219 << "network=" << active_network_id_ << ", "
220 << "attempt=" << attempt_count_ << " of " << kMaxRequestAttempts;
221
155 captive_portal_detector_->DetectCaptivePortal( 222 captive_portal_detector_->DetectCaptivePortal(
156 test_url_, 223 test_url_,
157 base::Bind(&NetworkPortalDetector::OnPortalDetectionCompleted, 224 base::Bind(&NetworkPortalDetector::OnPortalDetectionCompleted,
158 base::Unretained(this))); 225 weak_ptr_factory_.GetWeakPtr()));
226 detection_timeout_.Reset(
227 base::Bind(&NetworkPortalDetector::PortalDetectionTimeout,
228 weak_ptr_factory_.GetWeakPtr()));
229 MessageLoop::current()->PostDelayedTask(FROM_HERE,
230 detection_timeout_.callback(),
231 request_timeout_);
232 }
233
234 void NetworkPortalDetector::PortalDetectionTimeout() {
235 DCHECK(CalledOnValidThread());
236 DCHECK(IsCheckingForPortal());
237
238 VLOG(1) << "Portal detection timeout: network=" << active_network_id_;
239
240 captive_portal_detector_->Cancel();
241 CaptivePortalDetector::Results results;
242 results.result = captive_portal::RESULT_NO_RESPONSE;
243 OnPortalDetectionCompleted(results);
159 } 244 }
160 245
161 void NetworkPortalDetector::OnPortalDetectionCompleted( 246 void NetworkPortalDetector::OnPortalDetectionCompleted(
162 const CaptivePortalDetector::Results& results) { 247 const CaptivePortalDetector::Results& results) {
163 DCHECK(CalledOnValidThread()); 248 DCHECK(CalledOnValidThread());
249 DCHECK(IsCheckingForPortal());
164 250
165 DCHECK(IsCheckingForPortal()); 251 VLOG(1) << "Portal detection completed: "
252 << "network=" << active_network_id_ << ", "
253 << "result=" << CaptivePortalDetector::CaptivePortalResultToString(
254 results.result);
255
256 state_ = STATE_IDLE;
257 detection_timeout_.Cancel();
166 258
167 NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); 259 NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary();
168 const Network* active_network = cros->active_network(); 260 const Network* active_network = cros->active_network();
169 if (!active_network) 261 if (!active_network)
170 return; 262 return;
171 263
172 if (state_ == STATE_CHECKING_FOR_PORTAL_NETWORK_CHANGED) {
173 // Can't use detection results, because network was changed. So
174 // retry portal detection for the active network or, if possible.
175 if (Network::IsConnectedState(active_network->connection_state()) &&
176 GetCaptivePortalState(active_network) ==
177 CAPTIVE_PORTAL_STATE_UNKNOWN) {
178 DetectCaptivePortal();
179 }
180 return;
181 }
182
183 state_ = STATE_IDLE;
184
185 switch (results.result) { 264 switch (results.result) {
186 case captive_portal::RESULT_NO_RESPONSE: 265 case captive_portal::RESULT_NO_RESPONSE:
187 SetCaptivePortalState(active_network, CAPTIVE_PORTAL_STATE_OFFLINE); 266 if (attempt_count_ >= kMaxRequestAttempts)
267 SetCaptivePortalState(active_network, CAPTIVE_PORTAL_STATE_OFFLINE);
268 else
269 DetectCaptivePortal(results.retry_after_delta);
188 break; 270 break;
189 case captive_portal::RESULT_INTERNET_CONNECTED: 271 case captive_portal::RESULT_INTERNET_CONNECTED:
190 SetCaptivePortalState(active_network, CAPTIVE_PORTAL_STATE_ONLINE); 272 SetCaptivePortalState(active_network, CAPTIVE_PORTAL_STATE_ONLINE);
191 break; 273 break;
192 case captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL: 274 case captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL:
193 SetCaptivePortalState(active_network, CAPTIVE_PORTAL_STATE_PORTAL); 275 SetCaptivePortalState(active_network, CAPTIVE_PORTAL_STATE_PORTAL);
194 break; 276 break;
195 default: 277 default:
196 break; 278 break;
197 } 279 }
198 } 280 }
199 281
282 bool NetworkPortalDetector::IsPortalCheckPending() const {
283 return state_ == STATE_PORTAL_CHECK_PENDING;
284 }
285
200 bool NetworkPortalDetector::IsCheckingForPortal() const { 286 bool NetworkPortalDetector::IsCheckingForPortal() const {
201 return state_ == STATE_CHECKING_FOR_PORTAL || 287 return state_ == STATE_CHECKING_FOR_PORTAL;
202 state_ == STATE_CHECKING_FOR_PORTAL_NETWORK_CHANGED;
203 } 288 }
204 289
205 void NetworkPortalDetector::SetCaptivePortalState(const Network* network, 290 void NetworkPortalDetector::SetCaptivePortalState(const Network* network,
206 CaptivePortalState state) { 291 CaptivePortalState state) {
207 DCHECK(network); 292 DCHECK(network);
293
208 CaptivePortalStateMap::const_iterator it = 294 CaptivePortalStateMap::const_iterator it =
209 captive_portal_state_map_.find(network->unique_id()); 295 captive_portal_state_map_.find(network->unique_id());
210 if (it == captive_portal_state_map_.end() || 296 if (it == captive_portal_state_map_.end() ||
211 it->second != state) { 297 it->second != state) {
212 VLOG(2) << "Updating Chrome Captive Portal state: " 298 VLOG(1) << "Updating Chrome Captive Portal state: "
213 << "network=" << network->unique_id() << ", " 299 << "network=" << network->unique_id() << ", "
214 << "state=" << CaptivePortalStateString(state); 300 << "state=" << CaptivePortalStateString(state);
215 captive_portal_state_map_[network->unique_id()] = state; 301 captive_portal_state_map_[network->unique_id()] = state;
216 NotifyPortalStateChanged(network, state); 302 NotifyPortalStateChanged(network, state);
217 } 303 }
218 } 304 }
219 305
220 void NetworkPortalDetector::NotifyPortalStateChanged(const Network* network, 306 void NetworkPortalDetector::NotifyPortalStateChanged(const Network* network,
221 CaptivePortalState state) { 307 CaptivePortalState state) {
222 FOR_EACH_OBSERVER(Observer, observers_, OnPortalStateChanged(network, state)); 308 FOR_EACH_OBSERVER(Observer, observers_, OnPortalStateChanged(network, state));
223 } 309 }
224 310
311 base::TimeTicks NetworkPortalDetector::GetCurrentTimeTicks() const {
312 if (time_ticks_for_testing_.is_null())
313 return base::TimeTicks::Now();
314 else
315 return time_ticks_for_testing_;
316 }
317
225 } // namespace chromeos 318 } // namespace chromeos
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/net/network_portal_detector.h ('k') | chrome/browser/chromeos/net/network_portal_detector_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698