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 "google_apis/gcm/engine/unregistration_request.h" | 5 #include "google_apis/gcm/engine/unregistration_request.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/message_loop/message_loop.h" | 8 #include "base/message_loop/message_loop.h" |
9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
10 #include "base/strings/string_number_conversions.h" | 10 #include "base/strings/string_number_conversions.h" |
(...skipping 17 matching lines...) Expand all Loading... |
28 const char kAppIdKey[] = "app"; | 28 const char kAppIdKey[] = "app"; |
29 const char kDeleteKey[] = "delete"; | 29 const char kDeleteKey[] = "delete"; |
30 const char kDeleteValue[] = "true"; | 30 const char kDeleteValue[] = "true"; |
31 const char kDeviceIdKey[] = "device"; | 31 const char kDeviceIdKey[] = "device"; |
32 const char kLoginHeader[] = "AidLogin"; | 32 const char kLoginHeader[] = "AidLogin"; |
33 const char kUnregistrationCallerKey[] = "gcm_unreg_caller"; | 33 const char kUnregistrationCallerKey[] = "gcm_unreg_caller"; |
34 // We are going to set the value to "false" in order to forcefully unregister | 34 // We are going to set the value to "false" in order to forcefully unregister |
35 // the application. | 35 // the application. |
36 const char kUnregistrationCallerValue[] = "false"; | 36 const char kUnregistrationCallerValue[] = "false"; |
37 | 37 |
| 38 // Request keys specific to InstanceID's GetToken request. |
| 39 const char kGMSVersionKey[] = "gmsv"; |
| 40 const char kInstanceIDKey[] = "appid"; |
| 41 const char kSenderKey[] = "sender"; |
| 42 const char kScopeKey[] = "scope"; |
| 43 |
38 // Response constants. | 44 // Response constants. |
39 const char kDeletedPrefix[] = "deleted="; | 45 const char kDeletedPrefix[] = "deleted="; |
40 const char kErrorPrefix[] = "Error="; | 46 const char kErrorPrefix[] = "Error="; |
41 const char kInvalidParameters[] = "INVALID_PARAMETERS"; | 47 const char kInvalidParameters[] = "INVALID_PARAMETERS"; |
42 | 48 |
43 | 49 |
44 void BuildFormEncoding(const std::string& key, | 50 void BuildFormEncoding(const std::string& key, |
45 const std::string& value, | 51 const std::string& value, |
46 std::string* out) { | 52 std::string* out) { |
47 if (!out->empty()) | 53 if (!out->empty()) |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
91 return UnregistrationRequest::UNKNOWN_ERROR; | 97 return UnregistrationRequest::UNKNOWN_ERROR; |
92 } | 98 } |
93 | 99 |
94 DVLOG(1) << "Not able to parse a meaningful output from response body." | 100 DVLOG(1) << "Not able to parse a meaningful output from response body." |
95 << response; | 101 << response; |
96 return UnregistrationRequest::RESPONSE_PARSING_FAILED; | 102 return UnregistrationRequest::RESPONSE_PARSING_FAILED; |
97 } | 103 } |
98 | 104 |
99 } // namespace | 105 } // namespace |
100 | 106 |
101 UnregistrationRequest::RequestInfo::RequestInfo( | 107 UnregistrationRequest::RequestInfo::RequestInfo() {} |
102 uint64 android_id, | |
103 uint64 security_token, | |
104 const std::string& app_id) | |
105 : android_id(android_id), | |
106 security_token(security_token), | |
107 app_id(app_id) { | |
108 } | |
109 | 108 |
110 UnregistrationRequest::RequestInfo::~RequestInfo() {} | 109 UnregistrationRequest::RequestInfo::~RequestInfo() {} |
111 | 110 |
| 111 void UnregistrationRequest::RequestInfo::BuildRequestHeaders( |
| 112 std::string* extra_headers) { |
| 113 net::HttpRequestHeaders headers; |
| 114 headers.SetHeader( |
| 115 net::HttpRequestHeaders::kAuthorization, |
| 116 std::string(kLoginHeader) + " " + |
| 117 base::Uint64ToString(android_id_) + ":" + |
| 118 base::Uint64ToString(security_token_)); |
| 119 headers.SetHeader(kAppIdKey, app_id_); |
| 120 *extra_headers = headers.ToString(); |
| 121 } |
| 122 |
| 123 void UnregistrationRequest::RequestInfo::BuildRequestBody(std::string* body){ |
| 124 DCHECK(android_id_ != 0UL && security_token_ != 0UL); |
| 125 |
| 126 BuildFormEncoding(kAppIdKey, app_id_, body); |
| 127 BuildFormEncoding(kDeviceIdKey, base::Uint64ToString(android_id_), body); |
| 128 BuildFormEncoding(kDeleteKey, kDeleteValue, body); |
| 129 } |
| 130 |
| 131 UnregistrationRequest::GCMRequestInfo::GCMRequestInfo() {} |
| 132 |
| 133 UnregistrationRequest::GCMRequestInfo::~GCMRequestInfo() {} |
| 134 |
| 135 void UnregistrationRequest::GCMRequestInfo::BuildRequestBody(std::string* body){ |
| 136 RequestInfo::BuildRequestBody(body); |
| 137 |
| 138 BuildFormEncoding(kUnregistrationCallerKey, kUnregistrationCallerValue, body); |
| 139 } |
| 140 |
| 141 UnregistrationRequest::InstanceIDRequestInfo::InstanceIDRequestInfo() {} |
| 142 |
| 143 UnregistrationRequest::InstanceIDRequestInfo::~InstanceIDRequestInfo() {} |
| 144 |
| 145 void UnregistrationRequest::InstanceIDRequestInfo::BuildRequestBody( |
| 146 std::string* body){ |
| 147 DCHECK(!instance_id_.empty() && !authorized_entity_.empty() && |
| 148 !scope_.empty()); |
| 149 |
| 150 RequestInfo::BuildRequestBody(body); |
| 151 |
| 152 BuildFormEncoding(kGMSVersionKey, chrome_version_, body); |
| 153 BuildFormEncoding(kInstanceIDKey, instance_id_, body); |
| 154 BuildFormEncoding(kSenderKey, authorized_entity_, body); |
| 155 BuildFormEncoding(kScopeKey, scope_, body); |
| 156 } |
| 157 |
112 UnregistrationRequest::UnregistrationRequest( | 158 UnregistrationRequest::UnregistrationRequest( |
113 const GURL& registration_url, | 159 const GURL& registration_url, |
114 const RequestInfo& request_info, | 160 scoped_ptr<RequestInfo> request_info, |
115 const net::BackoffEntry::Policy& backoff_policy, | 161 const net::BackoffEntry::Policy& backoff_policy, |
116 const UnregistrationCallback& callback, | 162 const UnregistrationCallback& callback, |
117 scoped_refptr<net::URLRequestContextGetter> request_context_getter, | 163 scoped_refptr<net::URLRequestContextGetter> request_context_getter, |
118 GCMStatsRecorder* recorder) | 164 GCMStatsRecorder* recorder) |
119 : callback_(callback), | 165 : callback_(callback), |
120 request_info_(request_info), | 166 request_info_(request_info.Pass()), |
121 registration_url_(registration_url), | 167 registration_url_(registration_url), |
122 backoff_entry_(&backoff_policy), | 168 backoff_entry_(&backoff_policy), |
123 request_context_getter_(request_context_getter), | 169 request_context_getter_(request_context_getter), |
124 recorder_(recorder), | 170 recorder_(recorder), |
125 weak_ptr_factory_(this) { | 171 weak_ptr_factory_(this) { |
126 } | 172 } |
127 | 173 |
128 UnregistrationRequest::~UnregistrationRequest() {} | 174 UnregistrationRequest::~UnregistrationRequest() {} |
129 | 175 |
130 void UnregistrationRequest::Start() { | 176 void UnregistrationRequest::Start() { |
131 DCHECK(!callback_.is_null()); | 177 DCHECK(!callback_.is_null()); |
132 DCHECK(request_info_.android_id != 0UL); | |
133 DCHECK(request_info_.security_token != 0UL); | |
134 DCHECK(!url_fetcher_.get()); | 178 DCHECK(!url_fetcher_.get()); |
135 | 179 |
136 url_fetcher_ = | 180 url_fetcher_ = |
137 net::URLFetcher::Create(registration_url_, net::URLFetcher::POST, this); | 181 net::URLFetcher::Create(registration_url_, net::URLFetcher::POST, this); |
138 url_fetcher_->SetRequestContext(request_context_getter_.get()); | 182 url_fetcher_->SetRequestContext(request_context_getter_.get()); |
139 | 183 |
140 std::string android_id = base::Uint64ToString(request_info_.android_id); | 184 std::string extra_headers; |
141 std::string auth_header = | 185 request_info_->BuildRequestHeaders(&extra_headers); |
142 std::string(kLoginHeader) + " " + android_id + ":" + | 186 url_fetcher_->SetExtraRequestHeaders(extra_headers); |
143 base::Uint64ToString(request_info_.security_token); | |
144 net::HttpRequestHeaders headers; | |
145 headers.SetHeader(net::HttpRequestHeaders::kAuthorization, auth_header); | |
146 headers.SetHeader(kAppIdKey, request_info_.app_id); | |
147 url_fetcher_->SetExtraRequestHeaders(headers.ToString()); | |
148 | 187 |
149 std::string body; | 188 std::string body; |
150 BuildFormEncoding(kAppIdKey, request_info_.app_id, &body); | 189 request_info_->BuildRequestBody(&body); |
151 BuildFormEncoding(kDeviceIdKey, android_id, &body); | |
152 BuildFormEncoding(kDeleteKey, kDeleteValue, &body); | |
153 BuildFormEncoding(kUnregistrationCallerKey, | |
154 kUnregistrationCallerValue, | |
155 &body); | |
156 | 190 |
157 DVLOG(1) << "Unregistration request: " << body; | 191 DVLOG(1) << "Unregistration request: " << body; |
158 url_fetcher_->SetUploadData(kRequestContentType, body); | 192 url_fetcher_->SetUploadData(kRequestContentType, body); |
159 | 193 |
160 DVLOG(1) << "Performing unregistration for: " << request_info_.app_id; | 194 DVLOG(1) << "Performing unregistration for: " << request_info_->app_id(); |
161 recorder_->RecordUnregistrationSent(request_info_.app_id); | 195 recorder_->RecordUnregistrationSent(request_info_->app_id()); |
162 request_start_time_ = base::TimeTicks::Now(); | 196 request_start_time_ = base::TimeTicks::Now(); |
163 url_fetcher_->Start(); | 197 url_fetcher_->Start(); |
164 } | 198 } |
165 | 199 |
166 void UnregistrationRequest::RetryWithBackoff(bool update_backoff) { | 200 void UnregistrationRequest::RetryWithBackoff(bool update_backoff) { |
167 if (update_backoff) { | 201 if (update_backoff) { |
168 url_fetcher_.reset(); | 202 url_fetcher_.reset(); |
169 backoff_entry_.InformOfRequest(false); | 203 backoff_entry_.InformOfRequest(false); |
170 } | 204 } |
171 | 205 |
172 if (backoff_entry_.ShouldRejectRequest()) { | 206 if (backoff_entry_.ShouldRejectRequest()) { |
173 DVLOG(1) << "Delaying GCM unregistration of app: " | 207 DVLOG(1) << "Delaying GCM unregistration of app: " |
174 << request_info_.app_id << ", for " | 208 << request_info_->app_id() << ", for " |
175 << backoff_entry_.GetTimeUntilRelease().InMilliseconds() | 209 << backoff_entry_.GetTimeUntilRelease().InMilliseconds() |
176 << " milliseconds."; | 210 << " milliseconds."; |
177 recorder_->RecordUnregistrationRetryDelayed( | 211 recorder_->RecordUnregistrationRetryDelayed( |
178 request_info_.app_id, | 212 request_info_->app_id(), |
179 backoff_entry_.GetTimeUntilRelease().InMilliseconds()); | 213 backoff_entry_.GetTimeUntilRelease().InMilliseconds()); |
180 base::MessageLoop::current()->PostDelayedTask( | 214 base::MessageLoop::current()->PostDelayedTask( |
181 FROM_HERE, | 215 FROM_HERE, |
182 base::Bind(&UnregistrationRequest::RetryWithBackoff, | 216 base::Bind(&UnregistrationRequest::RetryWithBackoff, |
183 weak_ptr_factory_.GetWeakPtr(), | 217 weak_ptr_factory_.GetWeakPtr(), |
184 false), | 218 false), |
185 backoff_entry_.GetTimeUntilRelease()); | 219 backoff_entry_.GetTimeUntilRelease()); |
186 return; | 220 return; |
187 } | 221 } |
188 | 222 |
189 Start(); | 223 Start(); |
190 } | 224 } |
191 | 225 |
192 void UnregistrationRequest::OnURLFetchComplete(const net::URLFetcher* source) { | 226 void UnregistrationRequest::OnURLFetchComplete(const net::URLFetcher* source) { |
193 UnregistrationRequest::Status status = | 227 UnregistrationRequest::Status status = |
194 ParseFetcherResponse(source, request_info_.app_id); | 228 ParseFetcherResponse(source, request_info_->app_id()); |
195 | 229 |
196 DVLOG(1) << "UnregistrationRequestStauts: " << status; | 230 DVLOG(1) << "UnregistrationRequestStauts: " << status; |
197 UMA_HISTOGRAM_ENUMERATION("GCM.UnregistrationRequestStatus", | 231 UMA_HISTOGRAM_ENUMERATION("GCM.UnregistrationRequestStatus", |
198 status, | 232 status, |
199 UNREGISTRATION_STATUS_COUNT); | 233 UNREGISTRATION_STATUS_COUNT); |
200 recorder_->RecordUnregistrationResponse(request_info_.app_id, status); | 234 recorder_->RecordUnregistrationResponse(request_info_->app_id(), status); |
201 | 235 |
202 if (status == URL_FETCHING_FAILED || | 236 if (status == URL_FETCHING_FAILED || |
203 status == SERVICE_UNAVAILABLE || | 237 status == SERVICE_UNAVAILABLE || |
204 status == INTERNAL_SERVER_ERROR || | 238 status == INTERNAL_SERVER_ERROR || |
205 status == INCORRECT_APP_ID || | 239 status == INCORRECT_APP_ID || |
206 status == RESPONSE_PARSING_FAILED) { | 240 status == RESPONSE_PARSING_FAILED) { |
207 RetryWithBackoff(true); | 241 RetryWithBackoff(true); |
208 return; | 242 return; |
209 } | 243 } |
210 | 244 |
211 // status == SUCCESS || HTTP_NOT_OK || NO_RESPONSE_BODY || | 245 // status == SUCCESS || HTTP_NOT_OK || NO_RESPONSE_BODY || |
212 // INVALID_PARAMETERS || UNKNOWN_ERROR | 246 // INVALID_PARAMETERS || UNKNOWN_ERROR |
213 | 247 |
214 if (status == SUCCESS) { | 248 if (status == SUCCESS) { |
215 UMA_HISTOGRAM_COUNTS("GCM.UnregistrationRetryCount", | 249 UMA_HISTOGRAM_COUNTS("GCM.UnregistrationRetryCount", |
216 backoff_entry_.failure_count()); | 250 backoff_entry_.failure_count()); |
217 UMA_HISTOGRAM_TIMES("GCM.UnregistrationCompleteTime", | 251 UMA_HISTOGRAM_TIMES("GCM.UnregistrationCompleteTime", |
218 base::TimeTicks::Now() - request_start_time_); | 252 base::TimeTicks::Now() - request_start_time_); |
219 } | 253 } |
220 | 254 |
221 callback_.Run(status); | 255 callback_.Run(status); |
222 } | 256 } |
223 | 257 |
224 } // namespace gcm | 258 } // namespace gcm |
OLD | NEW |