OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "base/base64.h" | 5 #include "base/base64.h" |
6 #include "base/i18n/time_formatting.h" | 6 #include "base/i18n/time_formatting.h" |
7 #include "base/metrics/histogram.h" | 7 #include "base/metrics/histogram.h" |
8 #include "base/sha1.h" | 8 #include "base/sha1.h" |
9 #include "base/strings/string_number_conversions.h" | 9 #include "base/strings/string_number_conversions.h" |
10 #include "base/strings/string_util.h" | 10 #include "base/strings/string_util.h" |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
100 } | 100 } |
101 | 101 |
102 } // namespace | 102 } // namespace |
103 | 103 |
104 GCMNetworkChannel::GCMNetworkChannel( | 104 GCMNetworkChannel::GCMNetworkChannel( |
105 scoped_refptr<net::URLRequestContextGetter> request_context_getter, | 105 scoped_refptr<net::URLRequestContextGetter> request_context_getter, |
106 scoped_ptr<GCMNetworkChannelDelegate> delegate) | 106 scoped_ptr<GCMNetworkChannelDelegate> delegate) |
107 : request_context_getter_(request_context_getter), | 107 : request_context_getter_(request_context_getter), |
108 delegate_(delegate.Pass()), | 108 delegate_(delegate.Pass()), |
109 register_backoff_entry_(new net::BackoffEntry(&kRegisterBackoffPolicy)), | 109 register_backoff_entry_(new net::BackoffEntry(&kRegisterBackoffPolicy)), |
| 110 gcm_channel_online_(false), |
| 111 http_channel_online_(false), |
110 diagnostic_info_(this), | 112 diagnostic_info_(this), |
111 weak_factory_(this) { | 113 weak_factory_(this) { |
112 net::NetworkChangeNotifier::AddNetworkChangeObserver(this); | 114 net::NetworkChangeNotifier::AddNetworkChangeObserver(this); |
113 delegate_->Initialize(base::Bind(&GCMNetworkChannel::OnConnectionStateChanged, | 115 delegate_->Initialize(base::Bind(&GCMNetworkChannel::OnConnectionStateChanged, |
114 weak_factory_.GetWeakPtr())); | 116 weak_factory_.GetWeakPtr())); |
115 Register(); | 117 Register(); |
116 } | 118 } |
117 | 119 |
118 GCMNetworkChannel::~GCMNetworkChannel() { | 120 GCMNetworkChannel::~GCMNetworkChannel() { |
119 net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this); | 121 net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this); |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
188 // Nothing to do. | 190 // Nothing to do. |
189 return; | 191 return; |
190 } | 192 } |
191 | 193 |
192 if (error.state() != GoogleServiceAuthError::NONE) { | 194 if (error.state() != GoogleServiceAuthError::NONE) { |
193 // Requesting access token failed. Persistent errors will be reported by | 195 // Requesting access token failed. Persistent errors will be reported by |
194 // token service. Just drop this request, cacheinvalidations will retry | 196 // token service. Just drop this request, cacheinvalidations will retry |
195 // sending message and at that time we'll retry requesting access token. | 197 // sending message and at that time we'll retry requesting access token. |
196 DVLOG(1) << "RequestAccessToken failed: " << error.ToString(); | 198 DVLOG(1) << "RequestAccessToken failed: " << error.ToString(); |
197 RecordOutgoingMessageStatus(ACCESS_TOKEN_FAILURE); | 199 RecordOutgoingMessageStatus(ACCESS_TOKEN_FAILURE); |
198 // Message won't get sent because of connection failure. Let's retry once | 200 // Message won't get sent. Notify that http channel doesn't work. |
199 // connection is restored. | 201 UpdateHttpChannelState(false); |
200 if (error.state() == GoogleServiceAuthError::CONNECTION_FAILED) | |
201 NotifyStateChange(TRANSIENT_INVALIDATION_ERROR); | |
202 cached_message_.clear(); | 202 cached_message_.clear(); |
203 return; | 203 return; |
204 } | 204 } |
205 DCHECK(!token.empty()); | 205 DCHECK(!token.empty()); |
206 // Save access token in case POST fails and we need to invalidate it. | 206 // Save access token in case POST fails and we need to invalidate it. |
207 access_token_ = token; | 207 access_token_ = token; |
208 | 208 |
209 DVLOG(2) << "Got access token, sending message"; | 209 DVLOG(2) << "Got access token, sending message"; |
210 fetcher_.reset(net::URLFetcher::Create( | 210 fetcher_.reset(net::URLFetcher::Create( |
211 BuildUrl(registration_id_), net::URLFetcher::POST, this)); | 211 BuildUrl(registration_id_), net::URLFetcher::POST, this)); |
(...skipping 24 matching lines...) Expand all Loading... |
236 fetcher->GetResponseCode() == net::HTTP_UNAUTHORIZED) { | 236 fetcher->GetResponseCode() == net::HTTP_UNAUTHORIZED) { |
237 DVLOG(1) << "URLFetcher failure: HTTP_UNAUTHORIZED"; | 237 DVLOG(1) << "URLFetcher failure: HTTP_UNAUTHORIZED"; |
238 delegate_->InvalidateToken(access_token_); | 238 delegate_->InvalidateToken(access_token_); |
239 } | 239 } |
240 | 240 |
241 if (!status.is_success() || | 241 if (!status.is_success() || |
242 (fetcher->GetResponseCode() != net::HTTP_OK && | 242 (fetcher->GetResponseCode() != net::HTTP_OK && |
243 fetcher->GetResponseCode() != net::HTTP_NO_CONTENT)) { | 243 fetcher->GetResponseCode() != net::HTTP_NO_CONTENT)) { |
244 DVLOG(1) << "URLFetcher failure"; | 244 DVLOG(1) << "URLFetcher failure"; |
245 RecordOutgoingMessageStatus(POST_FAILURE); | 245 RecordOutgoingMessageStatus(POST_FAILURE); |
246 NotifyStateChange(TRANSIENT_INVALIDATION_ERROR); | 246 // POST failed. Notify that http channel doesn't work. |
| 247 UpdateHttpChannelState(false); |
247 return; | 248 return; |
248 } | 249 } |
249 | 250 |
250 RecordOutgoingMessageStatus(OUTGOING_MESSAGE_SUCCESS); | 251 RecordOutgoingMessageStatus(OUTGOING_MESSAGE_SUCCESS); |
251 NotifyStateChange(INVALIDATIONS_ENABLED); | 252 // Successfully sent message. Http channel works. |
| 253 UpdateHttpChannelState(true); |
252 DVLOG(2) << "URLFetcher success"; | 254 DVLOG(2) << "URLFetcher success"; |
253 } | 255 } |
254 | 256 |
255 void GCMNetworkChannel::OnIncomingMessage(const std::string& message, | 257 void GCMNetworkChannel::OnIncomingMessage(const std::string& message, |
256 const std::string& echo_token) { | 258 const std::string& echo_token) { |
257 #if !defined(OS_ANDROID) | 259 #if !defined(OS_ANDROID) |
258 if (!echo_token.empty()) | 260 if (!echo_token.empty()) |
259 echo_token_ = echo_token; | 261 echo_token_ = echo_token; |
260 diagnostic_info_.last_message_empty_echo_token_ = echo_token.empty(); | 262 diagnostic_info_.last_message_empty_echo_token_ = echo_token.empty(); |
261 diagnostic_info_.last_message_received_time_ = base::Time::Now(); | 263 diagnostic_info_.last_message_received_time_ = base::Time::Now(); |
262 | 264 |
263 if (message.empty()) { | 265 if (message.empty()) { |
264 RecordIncomingMessageStatus(MESSAGE_EMPTY); | 266 RecordIncomingMessageStatus(MESSAGE_EMPTY); |
265 return; | 267 return; |
266 } | 268 } |
267 std::string data; | 269 std::string data; |
268 if (!Base64DecodeURLSafe(message, &data)) { | 270 if (!Base64DecodeURLSafe(message, &data)) { |
269 RecordIncomingMessageStatus(INVALID_ENCODING); | 271 RecordIncomingMessageStatus(INVALID_ENCODING); |
270 return; | 272 return; |
271 } | 273 } |
272 ipc::invalidation::AddressedAndroidMessage android_message; | 274 ipc::invalidation::AddressedAndroidMessage android_message; |
273 if (!android_message.ParseFromString(data) || | 275 if (!android_message.ParseFromString(data) || |
274 !android_message.has_message()) { | 276 !android_message.has_message()) { |
275 RecordIncomingMessageStatus(INVALID_PROTO); | 277 RecordIncomingMessageStatus(INVALID_PROTO); |
276 return; | 278 return; |
277 } | 279 } |
278 DVLOG(2) << "Deliver incoming message"; | 280 DVLOG(2) << "Deliver incoming message"; |
279 RecordIncomingMessageStatus(INCOMING_MESSAGE_SUCCESS); | 281 RecordIncomingMessageStatus(INCOMING_MESSAGE_SUCCESS); |
| 282 UpdateGcmChannelState(true); |
280 DeliverIncomingMessage(android_message.message()); | 283 DeliverIncomingMessage(android_message.message()); |
281 #else | 284 #else |
282 // This code shouldn't be invoked on Android. | 285 // This code shouldn't be invoked on Android. |
283 NOTREACHED(); | 286 NOTREACHED(); |
284 #endif | 287 #endif |
285 } | 288 } |
286 | 289 |
287 void GCMNetworkChannel::OnConnectionStateChanged( | 290 void GCMNetworkChannel::OnConnectionStateChanged(bool online) { |
288 GCMNetworkChannelDelegate::ConnectionState connection_state) { | 291 UpdateGcmChannelState(online); |
289 switch (connection_state) { | |
290 case GCMNetworkChannelDelegate::CONNECTION_STATE_OFFLINE: { | |
291 NotifyStateChange(TRANSIENT_INVALIDATION_ERROR); | |
292 break; | |
293 } | |
294 case GCMNetworkChannelDelegate::CONNECTION_STATE_ONLINE: { | |
295 NotifyStateChange(INVALIDATIONS_ENABLED); | |
296 break; | |
297 } | |
298 default: { | |
299 NOTREACHED(); | |
300 break; | |
301 } | |
302 } | |
303 } | 292 } |
304 | 293 |
305 void GCMNetworkChannel::OnNetworkChanged( | 294 void GCMNetworkChannel::OnNetworkChanged( |
306 net::NetworkChangeNotifier::ConnectionType connection_type) { | 295 net::NetworkChangeNotifier::ConnectionType connection_type) { |
307 // Network connection is restored. Let's notify cacheinvalidations so it has | 296 // Network connection is restored. Let's notify cacheinvalidations so it has |
308 // chance to retry. | 297 // chance to retry. |
309 if (connection_type != net::NetworkChangeNotifier::CONNECTION_NONE) | 298 NotifyNetworkStatusChange( |
310 NotifyStateChange(INVALIDATIONS_ENABLED); | 299 connection_type != net::NetworkChangeNotifier::CONNECTION_NONE); |
| 300 } |
| 301 |
| 302 void GCMNetworkChannel::UpdateGcmChannelState(bool online) { |
| 303 if (gcm_channel_online_ == online) |
| 304 return; |
| 305 gcm_channel_online_ = online; |
| 306 InvalidatorState channel_state = TRANSIENT_INVALIDATION_ERROR; |
| 307 if (gcm_channel_online_ && http_channel_online_) |
| 308 channel_state = INVALIDATIONS_ENABLED; |
| 309 NotifyChannelStateChange(channel_state); |
| 310 } |
| 311 |
| 312 void GCMNetworkChannel::UpdateHttpChannelState(bool online) { |
| 313 if (http_channel_online_ == online) |
| 314 return; |
| 315 http_channel_online_ = online; |
| 316 InvalidatorState channel_state = TRANSIENT_INVALIDATION_ERROR; |
| 317 if (gcm_channel_online_ && http_channel_online_) |
| 318 channel_state = INVALIDATIONS_ENABLED; |
| 319 NotifyChannelStateChange(channel_state); |
311 } | 320 } |
312 | 321 |
313 GURL GCMNetworkChannel::BuildUrl(const std::string& registration_id) { | 322 GURL GCMNetworkChannel::BuildUrl(const std::string& registration_id) { |
314 DCHECK(!registration_id.empty()); | 323 DCHECK(!registration_id.empty()); |
315 | 324 |
316 #if !defined(OS_ANDROID) | 325 #if !defined(OS_ANDROID) |
317 ipc::invalidation::EndpointId endpoint_id; | 326 ipc::invalidation::EndpointId endpoint_id; |
318 endpoint_id.set_c2dm_registration_id(registration_id); | 327 endpoint_id.set_c2dm_registration_id(registration_id); |
319 endpoint_id.set_client_key(std::string()); | 328 endpoint_id.set_client_key(std::string()); |
320 endpoint_id.set_package_name(kCacheInvalidationPackageName); | 329 endpoint_id.set_package_name(kCacheInvalidationPackageName); |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
440 ENUM_CASE(gcm::GCMClient::NOT_SIGNED_IN); | 449 ENUM_CASE(gcm::GCMClient::NOT_SIGNED_IN); |
441 ENUM_CASE(gcm::GCMClient::INVALID_PARAMETER); | 450 ENUM_CASE(gcm::GCMClient::INVALID_PARAMETER); |
442 ENUM_CASE(gcm::GCMClient::ASYNC_OPERATION_PENDING); | 451 ENUM_CASE(gcm::GCMClient::ASYNC_OPERATION_PENDING); |
443 ENUM_CASE(gcm::GCMClient::GCM_DISABLED); | 452 ENUM_CASE(gcm::GCMClient::GCM_DISABLED); |
444 } | 453 } |
445 NOTREACHED(); | 454 NOTREACHED(); |
446 return ""; | 455 return ""; |
447 } | 456 } |
448 | 457 |
449 } // namespace syncer | 458 } // namespace syncer |
OLD | NEW |