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

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: Small fixes. 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 const int kMaxRequestAttempts = 3;
Nikita (slow) 2012/11/20 12:58:45 nit: Please add comments for these contants
ygorshenin1 2012/11/21 09:08:06 Done.
25 const int kMinTimeBetweenAttemptsSec = 3;
26 const int kRequestTimeoutSec = 10;
27
23 std::string CaptivePortalStateString( 28 std::string CaptivePortalStateString(
24 NetworkPortalDetector::CaptivePortalState state) { 29 NetworkPortalDetector::CaptivePortalState state) {
25 switch (state) { 30 switch (state) {
26 case NetworkPortalDetector::CAPTIVE_PORTAL_STATE_UNKNOWN: 31 case NetworkPortalDetector::CAPTIVE_PORTAL_STATE_UNKNOWN:
27 return l10n_util::GetStringUTF8( 32 return l10n_util::GetStringUTF8(
28 IDS_CHROMEOS_CAPTIVE_PORTAL_STATE_UNKNOWN); 33 IDS_CHROMEOS_CAPTIVE_PORTAL_STATE_UNKNOWN);
29 case NetworkPortalDetector::CAPTIVE_PORTAL_STATE_OFFLINE: 34 case NetworkPortalDetector::CAPTIVE_PORTAL_STATE_OFFLINE:
30 return l10n_util::GetStringUTF8( 35 return l10n_util::GetStringUTF8(
31 IDS_CHROMEOS_CAPTIVE_PORTAL_STATE_OFFLINE); 36 IDS_CHROMEOS_CAPTIVE_PORTAL_STATE_OFFLINE);
32 case NetworkPortalDetector::CAPTIVE_PORTAL_STATE_ONLINE: 37 case NetworkPortalDetector::CAPTIVE_PORTAL_STATE_ONLINE:
33 return l10n_util::GetStringUTF8(IDS_CHROMEOS_CAPTIVE_PORTAL_STATE_ONLINE); 38 return l10n_util::GetStringUTF8(IDS_CHROMEOS_CAPTIVE_PORTAL_STATE_ONLINE);
34 case NetworkPortalDetector::CAPTIVE_PORTAL_STATE_PORTAL: 39 case NetworkPortalDetector::CAPTIVE_PORTAL_STATE_PORTAL:
35 return l10n_util::GetStringUTF8(IDS_CHROMEOS_CAPTIVE_PORTAL_STATE_PORTAL); 40 return l10n_util::GetStringUTF8(IDS_CHROMEOS_CAPTIVE_PORTAL_STATE_PORTAL);
36 } 41 }
37 return l10n_util::GetStringUTF8( 42 return l10n_util::GetStringUTF8(
38 IDS_CHROMEOS_CAPTIVE_PORTAL_STATE_UNRECOGNIZED); 43 IDS_CHROMEOS_CAPTIVE_PORTAL_STATE_UNRECOGNIZED);
39 } 44 }
40 45
41 NetworkPortalDetector* g_network_portal_detector = NULL; 46 NetworkPortalDetector* g_network_portal_detector = NULL;
42 47
43 } // namespace 48 } // namespace
44 49
45 NetworkPortalDetector::NetworkPortalDetector( 50 NetworkPortalDetector::NetworkPortalDetector(
46 const scoped_refptr<net::URLRequestContextGetter>& request_context) 51 const scoped_refptr<net::URLRequestContextGetter>& request_context)
47 : test_url_(CaptivePortalDetector::kDefaultURL) { 52 : test_url_(CaptivePortalDetector::kDefaultURL),
53 weak_ptr_factory_(this),
54 attempt_count_(0),
55 min_time_between_attempts_(
56 base::TimeDelta::FromSeconds(kMinTimeBetweenAttemptsSec)),
57 request_timeout_(base::TimeDelta::FromSeconds(kRequestTimeoutSec)) {
48 captive_portal_detector_.reset( 58 captive_portal_detector_.reset(
49 new CaptivePortalDetector(request_context)); 59 new CaptivePortalDetector(request_context));
50 } 60 }
51 61
52 NetworkPortalDetector::~NetworkPortalDetector() { 62 NetworkPortalDetector::~NetworkPortalDetector() {
53 } 63 }
54 64
55 void NetworkPortalDetector::Init() { 65 void NetworkPortalDetector::Init() {
56 DCHECK(CalledOnValidThread()); 66 DCHECK(CalledOnValidThread());
57 67
58 state_ = STATE_IDLE; 68 state_ = STATE_IDLE;
59 chromeos::NetworkLibrary* network_library = 69 chromeos::NetworkLibrary* network_library =
60 chromeos::CrosLibrary::Get()->GetNetworkLibrary(); 70 chromeos::CrosLibrary::Get()->GetNetworkLibrary();
61 network_library->AddNetworkManagerObserver(this); 71 network_library->AddNetworkManagerObserver(this);
62 } 72 }
63 73
64 void NetworkPortalDetector::Shutdown() { 74 void NetworkPortalDetector::Shutdown() {
65 DCHECK(CalledOnValidThread()); 75 DCHECK(CalledOnValidThread());
66 76
77 detection_task_.Cancel();
78 detection_timeout_.Cancel();
79
67 captive_portal_detector_->Cancel(); 80 captive_portal_detector_->Cancel();
68 captive_portal_detector_.reset(); 81 captive_portal_detector_.reset();
69 observers_.Clear(); 82 observers_.Clear();
70 chromeos::NetworkLibrary* network_library = 83 chromeos::NetworkLibrary* network_library =
71 chromeos::CrosLibrary::Get()->GetNetworkLibrary(); 84 chromeos::CrosLibrary::Get()->GetNetworkLibrary();
72 network_library->RemoveNetworkManagerObserver(this); 85 network_library->RemoveNetworkManagerObserver(this);
73 } 86 }
74 87
75 void NetworkPortalDetector::AddObserver(Observer* observer) { 88 void NetworkPortalDetector::AddObserver(Observer* observer) {
76 DCHECK(CalledOnValidThread()); 89 DCHECK(CalledOnValidThread());
90
77 if (!observers_.HasObserver(observer)) 91 if (!observers_.HasObserver(observer))
78 observers_.AddObserver(observer); 92 observers_.AddObserver(observer);
79 } 93 }
80 94
81 void NetworkPortalDetector::RemoveObserver(Observer* observer) { 95 void NetworkPortalDetector::RemoveObserver(Observer* observer) {
82 DCHECK(CalledOnValidThread()); 96 DCHECK(CalledOnValidThread());
97
83 observers_.RemoveObserver(observer); 98 observers_.RemoveObserver(observer);
84 } 99 }
85 100
86 NetworkPortalDetector::CaptivePortalState 101 NetworkPortalDetector::CaptivePortalState
87 NetworkPortalDetector::GetCaptivePortalState(const Network* network) { 102 NetworkPortalDetector::GetCaptivePortalState(const Network* network) {
103 DCHECK(CalledOnValidThread());
104
88 if (!network) 105 if (!network)
89 return CAPTIVE_PORTAL_STATE_UNKNOWN; 106 return CAPTIVE_PORTAL_STATE_UNKNOWN;
90 CaptivePortalStateMap::const_iterator it = 107 CaptivePortalStateMap::const_iterator it =
91 captive_portal_state_map_.find(network->unique_id()); 108 captive_portal_state_map_.find(network->unique_id());
92 if (it == captive_portal_state_map_.end()) 109 if (it == captive_portal_state_map_.end())
93 return CAPTIVE_PORTAL_STATE_UNKNOWN; 110 return CAPTIVE_PORTAL_STATE_UNKNOWN;
94 return it->second; 111 return it->second;
95 } 112 }
96 113
97 void NetworkPortalDetector::OnNetworkManagerChanged(NetworkLibrary* cros) { 114 void NetworkPortalDetector::OnNetworkManagerChanged(NetworkLibrary* cros) {
98 DCHECK(CalledOnValidThread()); 115 DCHECK(CalledOnValidThread());
99 116
100 // Suppose that if there are no active network, then unique id is 117 // Suppose that if there are no active network, then unique id is
101 // empty and connection state is unknown. 118 // empty and connection state is unknown.
102 std::string new_active_network_id; 119 std::string new_active_network_id;
103 ConnectionState connection_state = STATE_UNKNOWN; 120 ConnectionState connection_state = STATE_UNKNOWN;
104 const Network* active_network = cros->active_network(); 121 const Network* active_network = cros->active_network();
105 if (active_network) { 122 if (active_network) {
106 new_active_network_id = active_network->unique_id(); 123 new_active_network_id = active_network->unique_id();
107 connection_state = active_network->connection_state(); 124 connection_state = active_network->connection_state();
108 } 125 }
109 126
110 if (active_network_id_ != new_active_network_id) { 127 if (active_network_id_ != new_active_network_id) {
111 active_network_id_ = new_active_network_id; 128 active_network_id_ = new_active_network_id;
112 if (IsCheckingForPortal()) { 129 attempt_count_ = 0;
113 // Network is changed, so detection results will be incorrect. 130 if (IsPortalCheckPending()) {
114 state_ = STATE_CHECKING_FOR_PORTAL_NETWORK_CHANGED; 131 detection_task_.Cancel();
115 } else if (Network::IsConnectedState(connection_state)) { 132 detection_timeout_.Cancel();
116 // Start captive portal detection, if possible. 133 } else if (IsCheckingForPortal()) {
117 DetectCaptivePortal(); 134 captive_portal_detector_->Cancel();
118 } 135 }
119 } else if (!IsCheckingForPortal() && 136 state_ = STATE_IDLE;
120 Network::IsConnectedState(connection_state)) { 137 }
138 if (!IsCheckingForPortal() && !IsPortalCheckPending() &&
139 Network::IsConnectedState(connection_state) &&
140 attempt_count_ < kMaxRequestAttempts) {
121 DCHECK(active_network); 141 DCHECK(active_network);
142
122 // Initiate Captive Portal detection only if network's captive 143 // Initiate Captive Portal detection only if network's captive
123 // portal state is unknown (e.g. for freshly created networks) or offline. 144 // portal state is unknown (e.g. for freshly created networks) or
145 // offline.
124 CaptivePortalState state = GetCaptivePortalState(active_network); 146 CaptivePortalState state = GetCaptivePortalState(active_network);
125 if (state == CAPTIVE_PORTAL_STATE_UNKNOWN || 147 if (state == CAPTIVE_PORTAL_STATE_UNKNOWN ||
126 state == CAPTIVE_PORTAL_STATE_OFFLINE) { 148 state == CAPTIVE_PORTAL_STATE_OFFLINE) {
127 DetectCaptivePortal(); 149 DetectCaptivePortal(base::TimeDelta());
128 } 150 }
129 } 151 }
130 } 152 }
131 153
132 // static 154 // static
133 NetworkPortalDetector* NetworkPortalDetector::CreateInstance() { 155 NetworkPortalDetector* NetworkPortalDetector::CreateInstance() {
134 DCHECK(!g_network_portal_detector); 156 DCHECK(!g_network_portal_detector);
135 g_network_portal_detector = new NetworkPortalDetector( 157 g_network_portal_detector = new NetworkPortalDetector(
136 g_browser_process->system_request_context()); 158 g_browser_process->system_request_context());
137 return g_network_portal_detector; 159 return g_network_portal_detector;
138 } 160 }
139 161
140 // static 162 // static
141 NetworkPortalDetector* NetworkPortalDetector::GetInstance() { 163 NetworkPortalDetector* NetworkPortalDetector::GetInstance() {
142 if (!g_network_portal_detector) 164 if (!g_network_portal_detector)
143 return CreateInstance(); 165 return CreateInstance();
144 return g_network_portal_detector; 166 return g_network_portal_detector;
145 } 167 }
146 168
147 // static 169 // static
148 bool NetworkPortalDetector::IsEnabled() { 170 bool NetworkPortalDetector::IsEnabled() {
149 return !CommandLine::ForCurrentProcess()->HasSwitch( 171 return !CommandLine::ForCurrentProcess()->HasSwitch(
150 switches::kDisableChromeCaptivePortalDetector); 172 switches::kDisableChromeCaptivePortalDetector);
151 } 173 }
152 174
153 void NetworkPortalDetector::DetectCaptivePortal() { 175 void NetworkPortalDetector::DetectCaptivePortal(const base::TimeDelta& delay) {
176 DCHECK(!IsPortalCheckPending());
177 DCHECK(!IsCheckingForPortal());
178 DCHECK(attempt_count_ < kMaxRequestAttempts);
179
Nikita (slow) 2012/11/20 12:58:45 I think it makes sense to clear tasks here just in
ygorshenin1 2012/11/21 09:08:06 Done.
180 state_ = STATE_PORTAL_CHECK_PENDING;
181
182 next_attempt_delay_ = delay;
183 if (attempt_count_ > 0) {
184 base::TimeTicks now = GetCurrentTimeTicks();
185 base::TimeDelta elapsed_time;
186 if (now > attempt_start_time_)
187 elapsed_time = now - attempt_start_time_;
188 if (elapsed_time < min_time_between_attempts_ &&
189 min_time_between_attempts_ - elapsed_time > next_attempt_delay_) {
190 next_attempt_delay_ = min_time_between_attempts_ - elapsed_time;
191 }
192 }
193 detection_task_.Reset(
194 base::Bind(&NetworkPortalDetector::DetectCaptivePortalTask,
195 weak_ptr_factory_.GetWeakPtr()));
196 MessageLoop::current()->PostDelayedTask(FROM_HERE,
197 detection_task_.callback(),
198 next_attempt_delay_);
199 }
200
201 void NetworkPortalDetector::DetectCaptivePortalTask() {
202 DCHECK(IsPortalCheckPending());
203
154 state_ = STATE_CHECKING_FOR_PORTAL; 204 state_ = STATE_CHECKING_FOR_PORTAL;
205
206 ++attempt_count_;
207 attempt_start_time_ = GetCurrentTimeTicks();
208
209 LOG(INFO) << "Portal detection starting attempt " << attempt_count_
Nikita (slow) 2012/11/20 12:58:45 Note that by default LOG(INFO) is not captured in
ygorshenin1 2012/11/21 09:08:06 Done.
210 << " of " << kMaxRequestAttempts;
211
155 captive_portal_detector_->DetectCaptivePortal( 212 captive_portal_detector_->DetectCaptivePortal(
156 test_url_, 213 test_url_,
157 base::Bind(&NetworkPortalDetector::OnPortalDetectionCompleted, 214 base::Bind(&NetworkPortalDetector::OnPortalDetectionCompleted,
158 base::Unretained(this))); 215 weak_ptr_factory_.GetWeakPtr()));
216 detection_timeout_.Reset(
217 base::Bind(&NetworkPortalDetector::PortalDetectionTimeout,
218 weak_ptr_factory_.GetWeakPtr()));
219 MessageLoop::current()->PostDelayedTask(FROM_HERE,
220 detection_timeout_.callback(),
221 request_timeout_);
222 }
223
224 void NetworkPortalDetector::PortalDetectionTimeout() {
225 DCHECK(CalledOnValidThread());
226 DCHECK(IsCheckingForPortal());
227
228 LOG(ERROR) << "Portal detection timeout";
229
230 captive_portal_detector_->Cancel();
231 CaptivePortalDetector::Results results;
232 results.result = captive_portal::RESULT_NO_RESPONSE;
233 OnPortalDetectionCompleted(results);
159 } 234 }
160 235
161 void NetworkPortalDetector::OnPortalDetectionCompleted( 236 void NetworkPortalDetector::OnPortalDetectionCompleted(
162 const CaptivePortalDetector::Results& results) { 237 const CaptivePortalDetector::Results& results) {
163 DCHECK(CalledOnValidThread()); 238 DCHECK(CalledOnValidThread());
239 DCHECK(IsCheckingForPortal());
164 240
165 DCHECK(IsCheckingForPortal()); 241 LOG(ERROR) << "On portal detection completed";
Nikita (slow) 2012/11/20 12:58:45 LOG(INFO) or VLOG - see above.
ygorshenin1 2012/11/21 09:08:06 Done.
242
243 state_ = STATE_IDLE;
244 detection_timeout_.Cancel();
166 245
167 NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); 246 NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary();
168 const Network* active_network = cros->active_network(); 247 const Network* active_network = cros->active_network();
169 if (!active_network) 248 if (!active_network)
170 return; 249 return;
171 250
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) { 251 switch (results.result) {
186 case captive_portal::RESULT_NO_RESPONSE: 252 case captive_portal::RESULT_NO_RESPONSE:
187 SetCaptivePortalState(active_network, CAPTIVE_PORTAL_STATE_OFFLINE); 253 if (attempt_count_ >= kMaxRequestAttempts)
254 SetCaptivePortalState(active_network, CAPTIVE_PORTAL_STATE_OFFLINE);
255 else
256 DetectCaptivePortal(results.retry_after_delta);
188 break; 257 break;
189 case captive_portal::RESULT_INTERNET_CONNECTED: 258 case captive_portal::RESULT_INTERNET_CONNECTED:
190 SetCaptivePortalState(active_network, CAPTIVE_PORTAL_STATE_ONLINE); 259 SetCaptivePortalState(active_network, CAPTIVE_PORTAL_STATE_ONLINE);
191 break; 260 break;
192 case captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL: 261 case captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL:
193 SetCaptivePortalState(active_network, CAPTIVE_PORTAL_STATE_PORTAL); 262 SetCaptivePortalState(active_network, CAPTIVE_PORTAL_STATE_PORTAL);
194 break; 263 break;
195 default: 264 default:
196 break; 265 break;
197 } 266 }
198 } 267 }
199 268
269 bool NetworkPortalDetector::IsPortalCheckPending() const {
270 return state_ == STATE_PORTAL_CHECK_PENDING;
271 }
272
200 bool NetworkPortalDetector::IsCheckingForPortal() const { 273 bool NetworkPortalDetector::IsCheckingForPortal() const {
201 return state_ == STATE_CHECKING_FOR_PORTAL || 274 return state_ == STATE_CHECKING_FOR_PORTAL;
202 state_ == STATE_CHECKING_FOR_PORTAL_NETWORK_CHANGED;
203 } 275 }
204 276
205 void NetworkPortalDetector::SetCaptivePortalState(const Network* network, 277 void NetworkPortalDetector::SetCaptivePortalState(const Network* network,
206 CaptivePortalState state) { 278 CaptivePortalState state) {
207 DCHECK(network); 279 DCHECK(network);
280
208 CaptivePortalStateMap::const_iterator it = 281 CaptivePortalStateMap::const_iterator it =
209 captive_portal_state_map_.find(network->unique_id()); 282 captive_portal_state_map_.find(network->unique_id());
210 if (it == captive_portal_state_map_.end() || 283 if (it == captive_portal_state_map_.end() ||
211 it->second != state) { 284 it->second != state) {
212 VLOG(2) << "Updating Chrome Captive Portal state: " 285 VLOG(2) << "Updating Chrome Captive Portal state: "
213 << "network=" << network->unique_id() << ", " 286 << "network=" << network->unique_id() << ", "
214 << "state=" << CaptivePortalStateString(state); 287 << "state=" << CaptivePortalStateString(state);
215 captive_portal_state_map_[network->unique_id()] = state; 288 captive_portal_state_map_[network->unique_id()] = state;
216 NotifyPortalStateChanged(network, state); 289 NotifyPortalStateChanged(network, state);
217 } 290 }
218 } 291 }
219 292
220 void NetworkPortalDetector::NotifyPortalStateChanged(const Network* network, 293 void NetworkPortalDetector::NotifyPortalStateChanged(const Network* network,
221 CaptivePortalState state) { 294 CaptivePortalState state) {
222 FOR_EACH_OBSERVER(Observer, observers_, OnPortalStateChanged(network, state)); 295 FOR_EACH_OBSERVER(Observer, observers_, OnPortalStateChanged(network, state));
223 } 296 }
224 297
298 base::TimeTicks NetworkPortalDetector::GetCurrentTimeTicks() const {
299 if (time_ticks_for_testing_.is_null())
300 return base::TimeTicks::Now();
301 else
302 return time_ticks_for_testing_;
303 }
304
225 } // namespace chromeos 305 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698