| 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_util.h" | 10 #include "base/strings/string_util.h" |
| 10 #if !defined(ANDROID) | 11 #if !defined(ANDROID) |
| 11 // channel_common.proto defines ANDROID constant that conflicts with Android | 12 // channel_common.proto defines ANDROID constant that conflicts with Android |
| 12 // build. At the same time TiclInvalidationService is not used on Android so it | 13 // build. At the same time TiclInvalidationService is not used on Android so it |
| 13 // is safe to exclude these protos from Android build. | 14 // is safe to exclude these protos from Android build. |
| 14 #include "google/cacheinvalidation/android_channel.pb.h" | 15 #include "google/cacheinvalidation/android_channel.pb.h" |
| 15 #include "google/cacheinvalidation/channel_common.pb.h" | 16 #include "google/cacheinvalidation/channel_common.pb.h" |
| 16 #endif | 17 #endif |
| 17 #include "google_apis/gaia/google_service_auth_error.h" | 18 #include "google_apis/gaia/google_service_auth_error.h" |
| 18 #include "net/http/http_status_code.h" | 19 #include "net/http/http_status_code.h" |
| (...skipping 30 matching lines...) Expand all Loading... |
| 49 1000 * 3600 * 4, // 4 hours. | 50 1000 * 3600 * 4, // 4 hours. |
| 50 | 51 |
| 51 // Time to keep an entry from being discarded even when it | 52 // Time to keep an entry from being discarded even when it |
| 52 // has no significant state, -1 to never discard. | 53 // has no significant state, -1 to never discard. |
| 53 -1, | 54 -1, |
| 54 | 55 |
| 55 // Don't use initial delay unless the last request was an error. | 56 // Don't use initial delay unless the last request was an error. |
| 56 false, | 57 false, |
| 57 }; | 58 }; |
| 58 | 59 |
| 59 // Outgoing message status values for UMA_HISTOGRAM. | |
| 60 enum OutgoingMessageStatus { | |
| 61 OUTGOING_MESSAGE_SUCCESS, | |
| 62 MESSAGE_DISCARDED, // New message started before old one was sent. | |
| 63 ACCESS_TOKEN_FAILURE, // Requeting access token failed. | |
| 64 POST_FAILURE, // HTTP Post failed. | |
| 65 | |
| 66 // This enum is used in UMA_HISTOGRAM_ENUMERATION. Insert new values above | |
| 67 // this line. | |
| 68 OUTGOING_MESSAGE_STATUS_COUNT | |
| 69 }; | |
| 70 | |
| 71 // Incoming message status values for UMA_HISTOGRAM. | 60 // Incoming message status values for UMA_HISTOGRAM. |
| 72 enum IncomingMessageStatus { | 61 enum IncomingMessageStatus { |
| 73 INCOMING_MESSAGE_SUCCESS, | 62 INCOMING_MESSAGE_SUCCESS, |
| 74 MESSAGE_EMPTY, // GCM message's content is missing or empty. | 63 MESSAGE_EMPTY, // GCM message's content is missing or empty. |
| 75 INVALID_ENCODING, // Base64Decode failed. | 64 INVALID_ENCODING, // Base64Decode failed. |
| 76 INVALID_PROTO, // Parsing protobuf failed. | 65 INVALID_PROTO, // Parsing protobuf failed. |
| 77 | 66 |
| 78 // This enum is used in UMA_HISTOGRAM_ENUMERATION. Insert new values above | 67 // This enum is used in UMA_HISTOGRAM_ENUMERATION. Insert new values above |
| 79 // this line. | 68 // this line. |
| 80 INCOMING_MESSAGE_STATUS_COUNT | 69 INCOMING_MESSAGE_STATUS_COUNT |
| 81 }; | 70 }; |
| 82 | 71 |
| 72 // Outgoing message status values for UMA_HISTOGRAM. |
| 73 enum OutgoingMessageStatus { |
| 74 OUTGOING_MESSAGE_SUCCESS, |
| 75 MESSAGE_DISCARDED, // New message started before old one was sent. |
| 76 ACCESS_TOKEN_FAILURE, // Requeting access token failed. |
| 77 POST_FAILURE, // HTTP Post failed. |
| 78 |
| 79 // This enum is used in UMA_HISTOGRAM_ENUMERATION. Insert new values above |
| 80 // this line. |
| 81 OUTGOING_MESSAGE_STATUS_COUNT |
| 82 }; |
| 83 |
| 84 const char kIncomingMessageStatusHistogram[] = |
| 85 "GCMInvalidations.IncomingMessageStatus"; |
| 83 const char kOutgoingMessageStatusHistogram[] = | 86 const char kOutgoingMessageStatusHistogram[] = |
| 84 "GCMInvalidations.OutgoingMessageStatus"; | 87 "GCMInvalidations.OutgoingMessageStatus"; |
| 85 const char kIncomingMessageStatusHistogram[] = | 88 |
| 86 "GCMInvalidations.IncomingMessageStatus"; | 89 void RecordIncomingMessageStatus(IncomingMessageStatus status) { |
| 90 UMA_HISTOGRAM_ENUMERATION(kIncomingMessageStatusHistogram, |
| 91 status, |
| 92 INCOMING_MESSAGE_STATUS_COUNT); |
| 93 } |
| 94 |
| 95 void RecordOutgoingMessageStatus(OutgoingMessageStatus status) { |
| 96 UMA_HISTOGRAM_ENUMERATION(kOutgoingMessageStatusHistogram, |
| 97 MESSAGE_DISCARDED, |
| 98 OUTGOING_MESSAGE_STATUS_COUNT); |
| 99 } |
| 87 | 100 |
| 88 } // namespace | 101 } // namespace |
| 89 | 102 |
| 90 GCMNetworkChannelDiagnostic::GCMNetworkChannelDiagnostic( | 103 GCMNetworkChannelDiagnostic::GCMNetworkChannelDiagnostic( |
| 91 GCMNetworkChannel* parent) | 104 GCMNetworkChannel* parent) |
| 92 : parent_(parent), | 105 : parent_(parent), |
| 93 last_message_empty_echo_token_(false), | 106 last_message_empty_echo_token_(false), |
| 94 last_post_response_code_(0), | 107 last_post_response_code_(0), |
| 95 registration_result_(gcm::GCMClient::UNKNOWN_ERROR), | 108 registration_result_(gcm::GCMClient::UNKNOWN_ERROR), |
| 96 sent_messages_count_(0) {} | 109 sent_messages_count_(0) {} |
| 97 | 110 |
| 98 scoped_ptr<base::DictionaryValue> | 111 scoped_ptr<base::DictionaryValue> |
| 99 GCMNetworkChannelDiagnostic::CollectDebugData() const { | 112 GCMNetworkChannelDiagnostic::CollectDebugData() const { |
| 100 scoped_ptr<base::DictionaryValue> status(new base::DictionaryValue); | 113 scoped_ptr<base::DictionaryValue> status(new base::DictionaryValue); |
| 101 status->SetString("GCMNetworkChannel.Channel", "GCM"); | 114 status->SetString("GCMNetworkChannel.Channel", "GCM"); |
| 115 std::string reg_id_hash = base::SHA1HashString(registration_id_); |
| 102 status->SetString("GCMNetworkChannel.HashedRegistrationID", | 116 status->SetString("GCMNetworkChannel.HashedRegistrationID", |
| 103 base::SHA1HashString(registration_id_)); | 117 base::HexEncode(reg_id_hash.c_str(), reg_id_hash.size())); |
| 104 status->SetString("GCMNetworkChannel.RegistrationResult", | 118 status->SetString("GCMNetworkChannel.RegistrationResult", |
| 105 GCMClientResultToString(registration_result_)); | 119 GCMClientResultToString(registration_result_)); |
| 106 status->SetBoolean("GCMNetworkChannel.HadLastMessageEmptyEchoToken", | 120 status->SetBoolean("GCMNetworkChannel.HadLastMessageEmptyEchoToken", |
| 107 last_message_empty_echo_token_); | 121 last_message_empty_echo_token_); |
| 108 status->SetString( | 122 status->SetString( |
| 109 "GCMNetworkChannel.LastMessageReceivedTime", | 123 "GCMNetworkChannel.LastMessageReceivedTime", |
| 110 base::TimeFormatShortDateAndTime(last_message_received_time_)); | 124 base::TimeFormatShortDateAndTime(last_message_received_time_)); |
| 111 status->SetInteger("GCMNetworkChannel.LastPostResponseCode", | 125 status->SetInteger("GCMNetworkChannel.LastPostResponseCode", |
| 112 last_post_response_code_); | 126 last_post_response_code_); |
| 113 status->SetInteger("GCMNetworkChannel.SentMessages", sent_messages_count_); | 127 status->SetInteger("GCMNetworkChannel.SentMessages", sent_messages_count_); |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 203 diagnostic_info_.registration_id_ = registration_id_; | 217 diagnostic_info_.registration_id_ = registration_id_; |
| 204 diagnostic_info_.registration_result_ = result; | 218 diagnostic_info_.registration_result_ = result; |
| 205 } | 219 } |
| 206 | 220 |
| 207 void GCMNetworkChannel::SendMessage(const std::string& message) { | 221 void GCMNetworkChannel::SendMessage(const std::string& message) { |
| 208 DCHECK(CalledOnValidThread()); | 222 DCHECK(CalledOnValidThread()); |
| 209 DCHECK(!message.empty()); | 223 DCHECK(!message.empty()); |
| 210 DVLOG(2) << "SendMessage"; | 224 DVLOG(2) << "SendMessage"; |
| 211 diagnostic_info_.sent_messages_count_++; | 225 diagnostic_info_.sent_messages_count_++; |
| 212 if (!cached_message_.empty()) { | 226 if (!cached_message_.empty()) { |
| 213 UMA_HISTOGRAM_ENUMERATION(kOutgoingMessageStatusHistogram, | 227 RecordOutgoingMessageStatus(MESSAGE_DISCARDED); |
| 214 MESSAGE_DISCARDED, | |
| 215 OUTGOING_MESSAGE_STATUS_COUNT); | |
| 216 } | 228 } |
| 217 cached_message_ = message; | 229 cached_message_ = message; |
| 218 | 230 |
| 219 if (!registration_id_.empty()) { | 231 if (!registration_id_.empty()) { |
| 220 RequestAccessToken(); | 232 RequestAccessToken(); |
| 221 } | 233 } |
| 222 } | 234 } |
| 223 | 235 |
| 224 void GCMNetworkChannel::SetMessageReceiver( | 236 void GCMNetworkChannel::SetMessageReceiver( |
| 225 invalidation::MessageCallback* incoming_receiver) { | 237 invalidation::MessageCallback* incoming_receiver) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 241 if (cached_message_.empty()) { | 253 if (cached_message_.empty()) { |
| 242 // Nothing to do. | 254 // Nothing to do. |
| 243 return; | 255 return; |
| 244 } | 256 } |
| 245 | 257 |
| 246 if (error.state() != GoogleServiceAuthError::NONE) { | 258 if (error.state() != GoogleServiceAuthError::NONE) { |
| 247 // Requesting access token failed. Persistent errors will be reported by | 259 // Requesting access token failed. Persistent errors will be reported by |
| 248 // token service. Just drop this request, cacheinvalidations will retry | 260 // token service. Just drop this request, cacheinvalidations will retry |
| 249 // sending message and at that time we'll retry requesting access token. | 261 // sending message and at that time we'll retry requesting access token. |
| 250 DVLOG(1) << "RequestAccessToken failed: " << error.ToString(); | 262 DVLOG(1) << "RequestAccessToken failed: " << error.ToString(); |
| 251 UMA_HISTOGRAM_ENUMERATION(kOutgoingMessageStatusHistogram, | 263 RecordOutgoingMessageStatus(ACCESS_TOKEN_FAILURE); |
| 252 ACCESS_TOKEN_FAILURE, | |
| 253 OUTGOING_MESSAGE_STATUS_COUNT); | |
| 254 cached_message_.clear(); | 264 cached_message_.clear(); |
| 255 return; | 265 return; |
| 256 } | 266 } |
| 257 DCHECK(!token.empty()); | 267 DCHECK(!token.empty()); |
| 258 // Save access token in case POST fails and we need to invalidate it. | 268 // Save access token in case POST fails and we need to invalidate it. |
| 259 access_token_ = token; | 269 access_token_ = token; |
| 260 | 270 |
| 261 DVLOG(2) << "Got access token, sending message"; | 271 DVLOG(2) << "Got access token, sending message"; |
| 262 fetcher_.reset(net::URLFetcher::Create( | 272 fetcher_.reset(net::URLFetcher::Create( |
| 263 BuildUrl(registration_id_), net::URLFetcher::POST, this)); | 273 BuildUrl(registration_id_), net::URLFetcher::POST, this)); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 276 | 286 |
| 277 void GCMNetworkChannel::OnIncomingMessage(const std::string& message, | 287 void GCMNetworkChannel::OnIncomingMessage(const std::string& message, |
| 278 const std::string& echo_token) { | 288 const std::string& echo_token) { |
| 279 #if !defined(ANDROID) | 289 #if !defined(ANDROID) |
| 280 if (!echo_token.empty()) | 290 if (!echo_token.empty()) |
| 281 echo_token_ = echo_token; | 291 echo_token_ = echo_token; |
| 282 diagnostic_info_.last_message_empty_echo_token_ = echo_token.empty(); | 292 diagnostic_info_.last_message_empty_echo_token_ = echo_token.empty(); |
| 283 diagnostic_info_.last_message_received_time_ = base::Time::Now(); | 293 diagnostic_info_.last_message_received_time_ = base::Time::Now(); |
| 284 | 294 |
| 285 if (message.empty()) { | 295 if (message.empty()) { |
| 286 UMA_HISTOGRAM_ENUMERATION(kIncomingMessageStatusHistogram, | 296 RecordIncomingMessageStatus(MESSAGE_EMPTY); |
| 287 MESSAGE_EMPTY, | |
| 288 INCOMING_MESSAGE_STATUS_COUNT); | |
| 289 return; | 297 return; |
| 290 } | 298 } |
| 291 std::string data; | 299 std::string data; |
| 292 if (!Base64DecodeURLSafe(message, &data)) { | 300 if (!Base64DecodeURLSafe(message, &data)) { |
| 293 UMA_HISTOGRAM_ENUMERATION(kIncomingMessageStatusHistogram, | 301 RecordIncomingMessageStatus(INVALID_ENCODING); |
| 294 INVALID_ENCODING, | |
| 295 INCOMING_MESSAGE_STATUS_COUNT); | |
| 296 return; | 302 return; |
| 297 } | 303 } |
| 298 ipc::invalidation::AddressedAndroidMessage android_message; | 304 ipc::invalidation::AddressedAndroidMessage android_message; |
| 299 if (!android_message.ParseFromString(data) || | 305 if (!android_message.ParseFromString(data) || |
| 300 !android_message.has_message()) { | 306 !android_message.has_message()) { |
| 301 UMA_HISTOGRAM_ENUMERATION(kIncomingMessageStatusHistogram, | 307 RecordIncomingMessageStatus(INVALID_PROTO); |
| 302 INVALID_PROTO, | |
| 303 INCOMING_MESSAGE_STATUS_COUNT); | |
| 304 return; | 308 return; |
| 305 } | 309 } |
| 306 DVLOG(2) << "Deliver incoming message"; | 310 DVLOG(2) << "Deliver incoming message"; |
| 307 UMA_HISTOGRAM_ENUMERATION(kIncomingMessageStatusHistogram, | 311 RecordIncomingMessageStatus(INCOMING_MESSAGE_SUCCESS); |
| 308 INCOMING_MESSAGE_SUCCESS, | |
| 309 INCOMING_MESSAGE_STATUS_COUNT); | |
| 310 DeliverIncomingMessage(android_message.message()); | 312 DeliverIncomingMessage(android_message.message()); |
| 311 #else | 313 #else |
| 312 // This code shouldn't be invoked on Android. | 314 // This code shouldn't be invoked on Android. |
| 313 NOTREACHED(); | 315 NOTREACHED(); |
| 314 #endif | 316 #endif |
| 315 } | 317 } |
| 316 | 318 |
| 317 void GCMNetworkChannel::OnURLFetchComplete(const net::URLFetcher* source) { | 319 void GCMNetworkChannel::OnURLFetchComplete(const net::URLFetcher* source) { |
| 318 DCHECK(CalledOnValidThread()); | 320 DCHECK(CalledOnValidThread()); |
| 319 DCHECK_EQ(fetcher_, source); | 321 DCHECK_EQ(fetcher_, source); |
| 320 // Free fetcher at the end of function. | 322 // Free fetcher at the end of function. |
| 321 scoped_ptr<net::URLFetcher> fetcher = fetcher_.Pass(); | 323 scoped_ptr<net::URLFetcher> fetcher = fetcher_.Pass(); |
| 322 | 324 |
| 323 net::URLRequestStatus status = fetcher->GetStatus(); | 325 net::URLRequestStatus status = fetcher->GetStatus(); |
| 324 diagnostic_info_.last_post_response_code_ = | 326 diagnostic_info_.last_post_response_code_ = |
| 325 status.is_success() ? source->GetResponseCode() : status.error(); | 327 status.is_success() ? source->GetResponseCode() : status.error(); |
| 326 | 328 |
| 327 if (status.is_success() && | 329 if (status.is_success() && |
| 328 fetcher->GetResponseCode() == net::HTTP_UNAUTHORIZED) { | 330 fetcher->GetResponseCode() == net::HTTP_UNAUTHORIZED) { |
| 329 DVLOG(1) << "URLFetcher failure: HTTP_UNAUTHORIZED"; | 331 DVLOG(1) << "URLFetcher failure: HTTP_UNAUTHORIZED"; |
| 330 delegate_->InvalidateToken(access_token_); | 332 delegate_->InvalidateToken(access_token_); |
| 331 } | 333 } |
| 332 | 334 |
| 333 if (!status.is_success() || fetcher->GetResponseCode() != net::HTTP_OK || | 335 if (!status.is_success() || |
| 334 fetcher->GetResponseCode() != net::HTTP_NO_CONTENT) { | 336 (fetcher->GetResponseCode() != net::HTTP_OK && |
| 337 fetcher->GetResponseCode() != net::HTTP_NO_CONTENT)) { |
| 335 DVLOG(1) << "URLFetcher failure"; | 338 DVLOG(1) << "URLFetcher failure"; |
| 336 UMA_HISTOGRAM_ENUMERATION(kOutgoingMessageStatusHistogram, | 339 RecordOutgoingMessageStatus(POST_FAILURE); |
| 337 POST_FAILURE, | |
| 338 OUTGOING_MESSAGE_STATUS_COUNT); | |
| 339 return; | 340 return; |
| 340 } | 341 } |
| 341 | 342 |
| 342 UMA_HISTOGRAM_ENUMERATION(kOutgoingMessageStatusHistogram, | 343 RecordOutgoingMessageStatus(OUTGOING_MESSAGE_SUCCESS); |
| 343 OUTGOING_MESSAGE_SUCCESS, | |
| 344 OUTGOING_MESSAGE_STATUS_COUNT); | |
| 345 DVLOG(2) << "URLFetcher success"; | 344 DVLOG(2) << "URLFetcher success"; |
| 346 } | 345 } |
| 347 | 346 |
| 348 GURL GCMNetworkChannel::BuildUrl(const std::string& registration_id) { | 347 GURL GCMNetworkChannel::BuildUrl(const std::string& registration_id) { |
| 349 DCHECK(!registration_id.empty()); | 348 DCHECK(!registration_id.empty()); |
| 350 | 349 |
| 351 #if !defined(ANDROID) | 350 #if !defined(ANDROID) |
| 352 ipc::invalidation::EndpointId endpoint_id; | 351 ipc::invalidation::EndpointId endpoint_id; |
| 353 endpoint_id.set_c2dm_registration_id(registration_id); | 352 endpoint_id.set_c2dm_registration_id(registration_id); |
| 354 endpoint_id.set_client_key(std::string()); | 353 endpoint_id.set_client_key(std::string()); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 397 size_t padded_size = (input.size() + 3) - (input.size() + 3) % 4; | 396 size_t padded_size = (input.size() + 3) - (input.size() + 3) % 4; |
| 398 std::string padded_input(input); | 397 std::string padded_input(input); |
| 399 padded_input.resize(padded_size, '='); | 398 padded_input.resize(padded_size, '='); |
| 400 // Convert to standard base64 alphabet. | 399 // Convert to standard base64 alphabet. |
| 401 base::ReplaceChars(padded_input, "-", "+", &padded_input); | 400 base::ReplaceChars(padded_input, "-", "+", &padded_input); |
| 402 base::ReplaceChars(padded_input, "_", "/", &padded_input); | 401 base::ReplaceChars(padded_input, "_", "/", &padded_input); |
| 403 return base::Base64Decode(padded_input, output); | 402 return base::Base64Decode(padded_input, output); |
| 404 } | 403 } |
| 405 | 404 |
| 406 } // namespace syncer | 405 } // namespace syncer |
| OLD | NEW |