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/registration_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/values.h"
125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "google_apis/gcm/monitoring/gcm_stats_recorder.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/base/escape.h"
14116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "net/base/load_flags.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)#include "url/gurl.h"
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace gcm {
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kRegistrationRequestContentType[] =
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    "application/x-www-form-urlencoded";
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Request constants.
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kAppIdKey[] = "app";
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kDeviceIdKey[] = "device";
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kLoginHeader[] = "AidLogin";
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kSenderKey[] = "sender";
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Request validation constants.
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const size_t kMaxSenders = 100;
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Response constants.
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kErrorPrefix[] = "Error=";
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kTokenPrefix[] = "token=";
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kDeviceRegistrationError[] = "PHONE_REGISTRATION_ERROR";
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kAuthenticationFailed[] = "AUTHENTICATION_FAILED";
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kInvalidSender[] = "INVALID_SENDER";
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kInvalidParameters[] = "INVALID_PARAMETERS";
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void BuildFormEncoding(const std::string& key,
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                       const std::string& value,
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                       std::string* out) {
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!out->empty())
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    out->append("&");
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  out->append(key + "=" + net::EscapeUrlEncodedData(value, true));
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Gets correct status from the error message.
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)RegistrationRequest::Status GetStatusFromError(const std::string& error) {
56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // TODO(fgorski): Improve error parsing in case there is nore then just an
57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Error=ERROR_STRING in response.
58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (error.find(kDeviceRegistrationError) != std::string::npos)
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return RegistrationRequest::DEVICE_REGISTRATION_ERROR;
60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (error.find(kAuthenticationFailed) != std::string::npos)
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return RegistrationRequest::AUTHENTICATION_FAILED;
62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (error.find(kInvalidSender) != std::string::npos)
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return RegistrationRequest::INVALID_SENDER;
64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (error.find(kInvalidParameters) != std::string::npos)
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return RegistrationRequest::INVALID_PARAMETERS;
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return RegistrationRequest::UNKNOWN_ERROR;
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Indicates whether a retry attempt should be made based on the status of the
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// last request.
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ShouldRetryWithStatus(RegistrationRequest::Status status) {
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return status == RegistrationRequest::UNKNOWN_ERROR ||
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         status == RegistrationRequest::AUTHENTICATION_FAILED ||
74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)         status == RegistrationRequest::DEVICE_REGISTRATION_ERROR ||
75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)         status == RegistrationRequest::HTTP_NOT_OK ||
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)         status == RegistrationRequest::URL_FETCHING_FAILED ||
77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)         status == RegistrationRequest::RESPONSE_PARSING_FAILED;
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void RecordRegistrationStatusToUMA(RegistrationRequest::Status status) {
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("GCM.RegistrationRequestStatus", status,
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            RegistrationRequest::STATUS_COUNT);
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)RegistrationRequest::RequestInfo::RequestInfo(
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    uint64 android_id,
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    uint64 security_token,
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& app_id,
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::vector<std::string>& sender_ids)
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : android_id(android_id),
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      security_token(security_token),
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      app_id(app_id),
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      sender_ids(sender_ids) {
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)RegistrationRequest::RequestInfo::~RequestInfo() {}
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)RegistrationRequest::RegistrationRequest(
101010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const GURL& registration_url,
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const RequestInfo& request_info,
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const net::BackoffEntry::Policy& backoff_policy,
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const RegistrationCallback& callback,
105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    int max_retry_count,
1065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    scoped_refptr<net::URLRequestContextGetter> request_context_getter,
1075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    GCMStatsRecorder* recorder)
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : callback_(callback),
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      request_info_(request_info),
110010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      registration_url_(registration_url),
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      backoff_entry_(&backoff_policy),
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      request_context_getter_(request_context_getter),
113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      retries_left_(max_retry_count),
1145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      recorder_(recorder),
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      weak_ptr_factory_(this) {
116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK_GE(max_retry_count, 0);
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)RegistrationRequest::~RegistrationRequest() {}
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void RegistrationRequest::Start() {
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!callback_.is_null());
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(request_info_.android_id != 0UL);
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(request_info_.security_token != 0UL);
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(0 < request_info_.sender_ids.size() &&
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         request_info_.sender_ids.size() <= kMaxSenders);
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!url_fetcher_.get());
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  url_fetcher_.reset(net::URLFetcher::Create(
130010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      registration_url_, net::URLFetcher::POST, this));
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  url_fetcher_->SetRequestContext(request_context_getter_.get());
132116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
133116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                             net::LOAD_DO_NOT_SAVE_COOKIES);
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string android_id = base::Uint64ToString(request_info_.android_id);
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string auth_header =
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      std::string(net::HttpRequestHeaders::kAuthorization) + ": " +
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      kLoginHeader + " " + android_id + ":" +
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Uint64ToString(request_info_.security_token);
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  url_fetcher_->SetExtraRequestHeaders(auth_header);
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string body;
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  BuildFormEncoding(kAppIdKey, request_info_.app_id, &body);
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  BuildFormEncoding(kDeviceIdKey, android_id, &body);
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string senders;
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (std::vector<std::string>::const_iterator iter =
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           request_info_.sender_ids.begin();
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter != request_info_.sender_ids.end();
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       ++iter) {
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK(!iter->empty());
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!senders.empty())
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      senders.append(",");
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    senders.append(*iter);
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  BuildFormEncoding(kSenderKey, senders, &body);
1570de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  UMA_HISTOGRAM_COUNTS("GCM.RegistrationSenderIdCount",
1580de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)                       request_info_.sender_ids.size());
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Performing registration for: " << request_info_.app_id;
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DVLOG(1) << "Registration request: " << body;
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  url_fetcher_->SetUploadData(kRegistrationRequestContentType, body);
1635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  recorder_->RecordRegistrationSent(request_info_.app_id, senders);
1640de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  request_start_time_ = base::TimeTicks::Now();
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  url_fetcher_->Start();
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void RegistrationRequest::RetryWithBackoff(bool update_backoff) {
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (update_backoff) {
170a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DCHECK_GT(retries_left_, 0);
171a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    --retries_left_;
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    url_fetcher_.reset();
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    backoff_entry_.InformOfRequest(false);
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (backoff_entry_.ShouldRejectRequest()) {
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Delaying GCM registration of app: "
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             << request_info_.app_id << ", for "
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             << backoff_entry_.GetTimeUntilRelease().InMilliseconds()
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             << " milliseconds.";
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::MessageLoop::current()->PostDelayedTask(
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        FROM_HERE,
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::Bind(&RegistrationRequest::RetryWithBackoff,
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   weak_ptr_factory_.GetWeakPtr(),
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   false),
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        backoff_entry_.GetTimeUntilRelease());
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Start();
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
193a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)RegistrationRequest::Status RegistrationRequest::ParseResponse(
194a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const net::URLFetcher* source, std::string* token) {
195a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!source->GetStatus().is_success()) {
196a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    LOG(ERROR) << "URL fetching failed.";
197a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return URL_FETCHING_FAILED;
198a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
199a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string response;
201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!source->GetResponseAsString(&response)) {
202a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    LOG(ERROR) << "Failed to parse registration response as a string.";
203a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return RESPONSE_PARSING_FAILED;
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
206a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (source->GetResponseCode() == net::HTTP_OK) {
207a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    size_t token_pos = response.find(kTokenPrefix);
208a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (token_pos != std::string::npos) {
209a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      *token = response.substr(token_pos + arraysize(kTokenPrefix) - 1);
210a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return SUCCESS;
211a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
214a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // If we are able to parse a meaningful known error, let's do so. Some errors
215a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // will have HTTP_BAD_REQUEST, some will have HTTP_OK response code.
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  size_t error_pos = response.find(kErrorPrefix);
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (error_pos != std::string::npos) {
218a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    std::string error = response.substr(
219a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        error_pos + arraysize(kErrorPrefix) - 1);
220a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return GetStatusFromError(error);
221a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
222a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
223a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // If we cannot tell what the error is, but at least we know response code was
224a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // not OK.
225a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (source->GetResponseCode() != net::HTTP_OK) {
226a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DLOG(ERROR) << "URL fetching HTTP response code is not OK. It is "
227a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                << source->GetResponseCode();
228a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return HTTP_NOT_OK;
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
230a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return UNKNOWN_ERROR;
232a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
233a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
234a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void RegistrationRequest::OnURLFetchComplete(const net::URLFetcher* source) {
235a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::string token;
236a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  Status status = ParseResponse(source, &token);
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RecordRegistrationStatusToUMA(status);
2385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  recorder_->RecordRegistrationResponse(
2395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      request_info_.app_id,
2405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      request_info_.sender_ids,
2415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      status);
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (ShouldRetryWithStatus(status)) {
244a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (retries_left_ > 0) {
2455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      recorder_->RecordRegistrationRetryRequested(
2465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          request_info_.app_id,
2475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          request_info_.sender_ids,
2485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          retries_left_);
249a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      RetryWithBackoff(true);
250a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return;
251a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
252a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
253a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    status = REACHED_MAX_RETRIES;
2545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    recorder_->RecordRegistrationResponse(
2555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        request_info_.app_id,
2565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        request_info_.sender_ids,
2575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        status);
258a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    RecordRegistrationStatusToUMA(status);
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2610de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  if (status == SUCCESS) {
2620de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    UMA_HISTOGRAM_COUNTS("GCM.RegistrationRetryCount",
2630de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)                         backoff_entry_.failure_count());
2640de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)    UMA_HISTOGRAM_TIMES("GCM.RegistrationCompleteTime",
2650de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)                        base::TimeTicks::Now() - request_start_time_);
2660de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  }
267a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  callback_.Run(status, token);
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace gcm
271