15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "google_apis/gcm/engine/unregistration_request.h"
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/bind.h"
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/message_loop/message_loop.h"
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/metrics/histogram.h"
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/string_piece.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/values.h"
135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "google_apis/gcm/monitoring/gcm_stats_recorder.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/base/escape.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/http/http_request_headers.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/http/http_status_code.h"
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/url_request/url_fetcher.h"
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/url_request/url_request_context_getter.h"
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/url_request/url_request_status.h"
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace gcm {
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kRequestContentType[] = "application/x-www-form-urlencoded";
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Request constants.
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kAppIdKey[] = "app";
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kDeleteKey[] = "delete";
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kDeleteValue[] = "true";
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kDeviceIdKey[] = "device";
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kLoginHeader[] = "AidLogin";
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kUnregistrationCallerKey[] = "gcm_unreg_caller";
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// We are going to set the value to "false" in order to forcefully unregister
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// the application.
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kUnregistrationCallerValue[] = "false";
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Response constants.
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kDeletedPrefix[] = "deleted=";
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kErrorPrefix[] = "Error=";
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kInvalidParameters[] = "INVALID_PARAMETERS";
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void BuildFormEncoding(const std::string& key,
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                       const std::string& value,
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                       std::string* out) {
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!out->empty())
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    out->append("&");
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  out->append(key + "=" + net::EscapeUrlEncodedData(value, true));
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)UnregistrationRequest::Status ParseFetcherResponse(
5323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    const net::URLFetcher* source,
5423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    std::string request_app_id) {
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!source->GetStatus().is_success()) {
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Fetcher failed";
5723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return UnregistrationRequest::URL_FETCHING_FAILED;
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  net::HttpStatusCode response_status = static_cast<net::HttpStatusCode>(
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      source->GetResponseCode());
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (response_status != net::HTTP_OK) {
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "HTTP Status code is not OK, but: " << response_status;
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (response_status == net::HTTP_SERVICE_UNAVAILABLE)
6523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      return UnregistrationRequest::SERVICE_UNAVAILABLE;
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    else if (response_status == net::HTTP_INTERNAL_SERVER_ERROR)
6723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      return UnregistrationRequest::INTERNAL_SERVER_ERROR;
6823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return UnregistrationRequest::HTTP_NOT_OK;
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string response;
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!source->GetResponseAsString(&response)) {
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Failed to get response body.";
7423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return UnregistrationRequest::NO_RESPONSE_BODY;
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Parsing unregistration response.";
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (response.find(kDeletedPrefix) != std::string::npos) {
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string app_id = response.substr(
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        response.find(kDeletedPrefix) + arraysize(kDeletedPrefix) - 1);
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (app_id == request_app_id)
8223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      return UnregistrationRequest::SUCCESS;
8323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return UnregistrationRequest::INCORRECT_APP_ID;
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (response.find(kErrorPrefix) != std::string::npos) {
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string error = response.substr(
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        response.find(kErrorPrefix) + arraysize(kErrorPrefix) - 1);
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (error == kInvalidParameters)
9023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      return UnregistrationRequest::INVALID_PARAMETERS;
9123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return UnregistrationRequest::UNKNOWN_ERROR;
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Not able to parse a meaningful output from response body."
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           << response;
9623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return UnregistrationRequest::RESPONSE_PARSING_FAILED;
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)UnregistrationRequest::RequestInfo::RequestInfo(
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    uint64 android_id,
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    uint64 security_token,
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& app_id)
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : android_id(android_id),
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      security_token(security_token),
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      app_id(app_id) {
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)UnregistrationRequest::RequestInfo::~RequestInfo() {}
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)UnregistrationRequest::UnregistrationRequest(
113010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const GURL& registration_url,
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const RequestInfo& request_info,
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const net::BackoffEntry::Policy& backoff_policy,
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const UnregistrationCallback& callback,
1175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    scoped_refptr<net::URLRequestContextGetter> request_context_getter,
1185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    GCMStatsRecorder* recorder)
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : callback_(callback),
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      request_info_(request_info),
121010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      registration_url_(registration_url),
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      backoff_entry_(&backoff_policy),
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      request_context_getter_(request_context_getter),
1245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      recorder_(recorder),
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      weak_ptr_factory_(this) {
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)UnregistrationRequest::~UnregistrationRequest() {}
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void UnregistrationRequest::Start() {
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!callback_.is_null());
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(request_info_.android_id != 0UL);
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(request_info_.security_token != 0UL);
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!url_fetcher_.get());
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  url_fetcher_.reset(net::URLFetcher::Create(
137010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      registration_url_, net::URLFetcher::POST, this));
1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  url_fetcher_->SetRequestContext(request_context_getter_.get());
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string android_id = base::Uint64ToString(request_info_.android_id);
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string auth_header =
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      std::string(kLoginHeader) + " " + android_id + ":" +
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Uint64ToString(request_info_.security_token);
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  net::HttpRequestHeaders headers;
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  headers.SetHeader(net::HttpRequestHeaders::kAuthorization, auth_header);
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  headers.SetHeader(kAppIdKey, request_info_.app_id);
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  url_fetcher_->SetExtraRequestHeaders(headers.ToString());
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string body;
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  BuildFormEncoding(kAppIdKey, request_info_.app_id, &body);
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  BuildFormEncoding(kDeviceIdKey, android_id, &body);
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  BuildFormEncoding(kDeleteKey, kDeleteValue, &body);
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  BuildFormEncoding(kUnregistrationCallerKey,
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    kUnregistrationCallerValue,
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    &body);
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Unregistration request: " << body;
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  url_fetcher_->SetUploadData(kRequestContentType, body);
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Performing unregistration for: " << request_info_.app_id;
1615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  recorder_->RecordUnregistrationSent(request_info_.app_id);
1620de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  request_start_time_ = base::TimeTicks::Now();
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  url_fetcher_->Start();
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void UnregistrationRequest::RetryWithBackoff(bool update_backoff) {
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (update_backoff) {
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    url_fetcher_.reset();
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    backoff_entry_.InformOfRequest(false);
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (backoff_entry_.ShouldRejectRequest()) {
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Delaying GCM unregistration of app: "
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             << request_info_.app_id << ", for "
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             << backoff_entry_.GetTimeUntilRelease().InMilliseconds()
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             << " milliseconds.";
1775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    recorder_->RecordUnregistrationRetryDelayed(
1785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        request_info_.app_id,
1795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        backoff_entry_.GetTimeUntilRelease().InMilliseconds());
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::MessageLoop::current()->PostDelayedTask(
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        FROM_HERE,
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::Bind(&UnregistrationRequest::RetryWithBackoff,
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   weak_ptr_factory_.GetWeakPtr(),
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   false),
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        backoff_entry_.GetTimeUntilRelease());
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Start();
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void UnregistrationRequest::OnURLFetchComplete(const net::URLFetcher* source) {
19323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  UnregistrationRequest::Status status =
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ParseFetcherResponse(source, request_info_.app_id);
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "UnregistrationRequestStauts: " << status;
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("GCM.UnregistrationRequestStatus",
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            status,
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            UNREGISTRATION_STATUS_COUNT);
2005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  recorder_->RecordUnregistrationResponse(request_info_.app_id, status);
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (status == URL_FETCHING_FAILED ||
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      status == SERVICE_UNAVAILABLE ||
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      status == INTERNAL_SERVER_ERROR ||
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      status == INCORRECT_APP_ID ||
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      status == RESPONSE_PARSING_FAILED) {
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    RetryWithBackoff(true);
2080de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    return;
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2100de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
2110de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  // status == SUCCESS || HTTP_NOT_OK || NO_RESPONSE_BODY ||
2120de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  // INVALID_PARAMETERS || UNKNOWN_ERROR
2130de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
2140de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  if (status == SUCCESS) {
2150de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    UMA_HISTOGRAM_COUNTS("GCM.UnregistrationRetryCount",
2160de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)                         backoff_entry_.failure_count());
2170de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    UMA_HISTOGRAM_TIMES("GCM.UnregistrationCompleteTime",
2180de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)                        base::TimeTicks::Now() - request_start_time_);
2190de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  }
2200de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)
2210de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  callback_.Run(status);
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace gcm
225