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 |