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

Side by Side Diff: google_apis/gcm/engine/unregistration_request.cc

Issue 147763008: [GCM] Unregistration request (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Reordering enum description in histograms.xml Created 6 years, 10 months 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
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "google_apis/gcm/engine/unregistration_request.h"
6
7 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/metrics/histogram.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_piece.h"
12 #include "base/values.h"
13 #include "net/base/escape.h"
14 #include "net/http/http_request_headers.h"
15 #include "net/http/http_status_code.h"
16 #include "net/url_request/url_fetcher.h"
17 #include "net/url_request/url_request_context_getter.h"
18 #include "net/url_request/url_request_status.h"
19 #include "url/gurl.h"
20
21 namespace gcm {
22
23 namespace {
24
25 const char kRegistrationURL[] =
26 "https://android.clients.google.com/c2dm/register3";
27 const char kRequestContentType[] = "application/x-www-form-urlencoded";
28
29 // Request constants.
30 const char kAppIdKey[] = "app";
31 const char kDeleteKey[] = "delete";
32 const char kDeleteValue[] = "true";
33 const char kDeviceIdKey[] = "device";
34 const char kLoginHeader[] = "AidLogin";
35 const char kUnregistrationCallerKey[] = "gcm_unreg_caller";
36 // We are going to set the value to "false" in order to forcefully unregister
37 // the application.
38 const char kUnregistrationCallerValue[] = "false";
39
40 // Response constants.
41 const char kDeletedPrefix[] = "deleted=";
42 const char kErrorPrefix[] = "Error=";
43 const char kInvalidParameters[] = "INVALID_PARAMETERS";
44
45 // Outcomens of the response parsing. Note that these enums are consumed by a
46 // histogram, so ordering should not be modified.
47 enum UnregistrationRequestStatus {
48 SUCCESS, // Unregistration completed successfully.
49 URL_FETCHING_FAILED, // URL fetching failed.
50 NO_RESPONSE_BODY, // No response body.
51 RESPONSE_PARSING_FAILED, // Failed to parse a meaningful output from response
52 // body.
53 INCORRECT_APP_ID, // App ID returned by the fetcher does not match
54 // request.
55 INVALID_PARAMETERS, // Request parameters were invalid.
56 SERVICE_UNAVAILABLE, // Unregistration service unavailable.
57 INTERNAL_SERVER_ERROR, // Internal server error happened during request.
58 HTTP_NOT_OK, // HTTP response code was not OK.
59 UNKNOWN_ERROR, // Unknown error.
60 // NOTE: Always keep this entry at the end. Add new status types only
61 // immediately above this line. Make sure to update the corresponding
62 // histogram enum accordingly.
63 UNREGISTRATION_STATUS_COUNT,
64 };
65
66 void BuildFormEncoding(const std::string& key,
67 const std::string& value,
68 std::string* out) {
69 if (!out->empty())
70 out->append("&");
71 out->append(key + "=" + net::EscapeUrlEncodedData(value, true));
72 }
73
74 UnregistrationRequestStatus ParseFetcherResponse(const net::URLFetcher* source,
75 std::string request_app_id) {
76 std::string response;
jianli 2014/02/14 18:36:18 nit: better to move the definition of local variab
fgorski 2014/02/14 18:48:42 Done.
77 if (!source->GetStatus().is_success()) {
78 DVLOG(1) << "Fetcher failed";
79 return URL_FETCHING_FAILED;
80 }
81
82 net::HttpStatusCode response_status = static_cast<net::HttpStatusCode>(
83 source->GetResponseCode());
84 if (response_status != net::HTTP_OK) {
85 DVLOG(1) << "HTTP Status code is not OK, but: " << response_status;
86 if (response_status == net::HTTP_SERVICE_UNAVAILABLE)
87 return SERVICE_UNAVAILABLE;
88 else if (response_status == net::HTTP_INTERNAL_SERVER_ERROR)
89 return INTERNAL_SERVER_ERROR;
90 return HTTP_NOT_OK;
91 }
92
93 if (!source->GetResponseAsString(&response)) {
94 DVLOG(1) << "Failed to get response body.";
95 return NO_RESPONSE_BODY;
96 }
97
98 DVLOG(1) << "Parsing unregistration response.";
99 if (response.find(kDeletedPrefix) != std::string::npos) {
100 std::string app_id = response.substr(
101 response.find(kDeletedPrefix) + arraysize(kDeletedPrefix) - 1);
102 if (app_id == request_app_id)
103 return SUCCESS;
104 return INCORRECT_APP_ID;
105 }
106
107 if (response.find(kErrorPrefix) != std::string::npos) {
108 std::string error = response.substr(
109 response.find(kErrorPrefix) + arraysize(kErrorPrefix) - 1);
110 if (error == kInvalidParameters)
111 return INVALID_PARAMETERS;
112 return UNKNOWN_ERROR;
113 }
114
115 DVLOG(1) << "Not able to parse a meaningful output from response body."
116 << response;
117 return RESPONSE_PARSING_FAILED;
118 }
119
120 } // namespace
121
122 UnregistrationRequest::RequestInfo::RequestInfo(
123 uint64 android_id,
124 uint64 security_token,
125 const std::string& app_id)
126 : android_id(android_id),
127 security_token(security_token),
128 app_id(app_id) {
129 }
130
131 UnregistrationRequest::RequestInfo::~RequestInfo() {}
132
133 UnregistrationRequest::UnregistrationRequest(
134 const RequestInfo& request_info,
135 const net::BackoffEntry::Policy& backoff_policy,
136 const UnregistrationCallback& callback,
137 scoped_refptr<net::URLRequestContextGetter> request_context_getter)
138 : callback_(callback),
139 request_info_(request_info),
140 backoff_entry_(&backoff_policy),
141 request_context_getter_(request_context_getter),
142 weak_ptr_factory_(this) {
143 }
144
145 UnregistrationRequest::~UnregistrationRequest() {}
146
147 void UnregistrationRequest::Start() {
148 DCHECK(!callback_.is_null());
149 DCHECK(request_info_.android_id != 0UL);
150 DCHECK(request_info_.security_token != 0UL);
151 DCHECK(!url_fetcher_.get());
152
153 url_fetcher_.reset(net::URLFetcher::Create(
154 GURL(kRegistrationURL), net::URLFetcher::DELETE_REQUEST, this));
155 url_fetcher_->SetRequestContext(request_context_getter_);
156
157 std::string android_id = base::Uint64ToString(request_info_.android_id);
158 std::string auth_header =
159 std::string(kLoginHeader) + " " + android_id + ":" +
160 base::Uint64ToString(request_info_.security_token);
161 net::HttpRequestHeaders headers;
162 headers.SetHeader(net::HttpRequestHeaders::kAuthorization, auth_header);
163 headers.SetHeader(kAppIdKey, request_info_.app_id);
164 url_fetcher_->SetExtraRequestHeaders(headers.ToString());
165
166 std::string body;
167 BuildFormEncoding(kAppIdKey, request_info_.app_id, &body);
168 BuildFormEncoding(kDeviceIdKey, android_id, &body);
169 BuildFormEncoding(kDeleteKey, kDeleteValue, &body);
170 BuildFormEncoding(kUnregistrationCallerKey,
171 kUnregistrationCallerValue,
172 &body);
173
174 DVLOG(1) << "Unregistration request: " << body;
175 url_fetcher_->SetUploadData(kRequestContentType, body);
176
177 DVLOG(1) << "Performing unregistration for: " << request_info_.app_id;
178 url_fetcher_->Start();
179 }
180
181 void UnregistrationRequest::RetryWithBackoff(bool update_backoff) {
182 if (update_backoff) {
183 url_fetcher_.reset();
184 backoff_entry_.InformOfRequest(false);
185 }
186
187 if (backoff_entry_.ShouldRejectRequest()) {
188 DVLOG(1) << "Delaying GCM unregistration of app: "
189 << request_info_.app_id << ", for "
190 << backoff_entry_.GetTimeUntilRelease().InMilliseconds()
191 << " milliseconds.";
192 base::MessageLoop::current()->PostDelayedTask(
193 FROM_HERE,
194 base::Bind(&UnregistrationRequest::RetryWithBackoff,
195 weak_ptr_factory_.GetWeakPtr(),
196 false),
197 backoff_entry_.GetTimeUntilRelease());
198 return;
199 }
200
201 Start();
202 }
203
204 void UnregistrationRequest::OnURLFetchComplete(const net::URLFetcher* source) {
205 UnregistrationRequestStatus status =
206 ParseFetcherResponse(source, request_info_.app_id);
207
208 DVLOG(1) << "UnregistrationRequestStauts: " << status;
209 UMA_HISTOGRAM_ENUMERATION("GCM.UnregistrationRequestStatus",
210 status,
211 UNREGISTRATION_STATUS_COUNT);
212
213 if (status == URL_FETCHING_FAILED ||
214 status == SERVICE_UNAVAILABLE ||
215 status == INTERNAL_SERVER_ERROR ||
216 status == INCORRECT_APP_ID ||
217 status == RESPONSE_PARSING_FAILED) {
218 RetryWithBackoff(true);
219 } else {
220 // status == SUCCESS || HTTP_NOT_OK || NO_RESPONSE_BODY ||
221 // INVALID_PARAMETERS || UNKNOWN_ERROR
222 callback_.Run(status == SUCCESS);
223 }
224 }
225
226 } // namespace gcm
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698