rAc - revert invalid suggestions to edit mode
[chromium-blink-merge.git] / sync / notifier / gcm_network_channel.cc
blobc6fbd0239dc60cd1fb2574793dbeb19a3c3224e8
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.
5 #include "google_apis/gaia/google_service_auth_error.h"
6 #include "net/http/http_status_code.h"
7 #include "net/url_request/url_fetcher.h"
8 #include "net/url_request/url_request_status.h"
9 #include "sync/notifier/gcm_network_channel.h"
10 #include "sync/notifier/gcm_network_channel_delegate.h"
12 namespace syncer {
14 namespace {
16 // Register backoff policy.
17 const net::BackoffEntry::Policy kRegisterBackoffPolicy = {
18 // Number of initial errors (in sequence) to ignore before applying
19 // exponential back-off rules.
22 // Initial delay for exponential back-off in ms.
23 2000, // 2 seconds.
25 // Factor by which the waiting time will be multiplied.
28 // Fuzzing percentage. ex: 10% will spread requests randomly
29 // between 90%-100% of the calculated time.
30 0.2, // 20%.
32 // Maximum amount of time we are willing to delay our request in ms.
33 1000 * 3600 * 4, // 4 hours.
35 // Time to keep an entry from being discarded even when it
36 // has no significant state, -1 to never discard.
37 -1,
39 // Don't use initial delay unless the last request was an error.
40 false,
43 } // namespace
45 GCMNetworkChannel::GCMNetworkChannel(
46 scoped_refptr<net::URLRequestContextGetter> request_context_getter,
47 scoped_ptr<GCMNetworkChannelDelegate> delegate)
48 : request_context_getter_(request_context_getter),
49 delegate_(delegate.Pass()),
50 register_backoff_entry_(new net::BackoffEntry(&kRegisterBackoffPolicy)),
51 weak_factory_(this) {
52 Register();
55 GCMNetworkChannel::~GCMNetworkChannel() {
58 void GCMNetworkChannel::UpdateCredentials(
59 const std::string& email,
60 const std::string& token) {
61 // Do nothing. We get access token by requesting it for every message.
64 void GCMNetworkChannel::ResetRegisterBackoffEntryForTest(
65 const net::BackoffEntry::Policy* policy) {
66 register_backoff_entry_.reset(new net::BackoffEntry(policy));
69 void GCMNetworkChannel::Register() {
70 delegate_->Register(base::Bind(&GCMNetworkChannel::OnRegisterComplete,
71 weak_factory_.GetWeakPtr()));
74 void GCMNetworkChannel::OnRegisterComplete(
75 const std::string& registration_id,
76 gcm::GCMClient::Result result) {
77 DCHECK(CalledOnValidThread());
78 if (result == gcm::GCMClient::SUCCESS) {
79 DCHECK(!registration_id.empty());
80 DVLOG(2) << "Got registration_id";
81 register_backoff_entry_->Reset();
82 registration_id_ = registration_id;
83 if (!encoded_message_.empty())
84 RequestAccessToken();
85 } else {
86 DVLOG(2) << "Register failed: " << result;
87 // Retry in case of transient error.
88 switch (result) {
89 case gcm::GCMClient::NETWORK_ERROR:
90 case gcm::GCMClient::SERVER_ERROR:
91 case gcm::GCMClient::TTL_EXCEEDED:
92 case gcm::GCMClient::UNKNOWN_ERROR: {
93 register_backoff_entry_->InformOfRequest(false);
94 base::MessageLoop::current()->PostDelayedTask(
95 FROM_HERE,
96 base::Bind(&GCMNetworkChannel::Register,
97 weak_factory_.GetWeakPtr()),
98 register_backoff_entry_->GetTimeUntilRelease());
99 break;
101 default:
102 break;
107 void GCMNetworkChannel::SendEncodedMessage(const std::string& encoded_message) {
108 DCHECK(CalledOnValidThread());
109 DCHECK(!encoded_message.empty());
110 DVLOG(2) << "SendEncodedMessage";
111 encoded_message_ = encoded_message;
113 if (!registration_id_.empty()) {
114 RequestAccessToken();
118 void GCMNetworkChannel::RequestAccessToken() {
119 DCHECK(CalledOnValidThread());
120 delegate_->RequestToken(base::Bind(&GCMNetworkChannel::OnGetTokenComplete,
121 weak_factory_.GetWeakPtr()));
124 void GCMNetworkChannel::OnGetTokenComplete(
125 const GoogleServiceAuthError& error,
126 const std::string& token) {
127 DCHECK(CalledOnValidThread());
128 if (encoded_message_.empty()) {
129 // Nothing to do.
130 return;
133 if (error.state() != GoogleServiceAuthError::NONE) {
134 // Requesting access token failed. Persistent errors will be reported by
135 // token service. Just drop this request, cacheinvalidations will retry
136 // sending message and at that time we'll retry requesting access token.
137 DVLOG(1) << "RequestAccessToken failed: " << error.ToString();
138 return;
140 DCHECK(!token.empty());
141 // Save access token in case POST fails and we need to invalidate it.
142 access_token_ = token;
144 DVLOG(2) << "Got access token, sending message";
146 fetcher_.reset(net::URLFetcher::Create(BuildUrl(), net::URLFetcher::POST,
147 this));
148 fetcher_->SetRequestContext(request_context_getter_);
149 const std::string auth_header("Authorization: Bearer " + access_token_);
150 fetcher_->AddExtraRequestHeader(auth_header);
151 fetcher_->SetUploadData("application/x-protobuffer", encoded_message_);
152 fetcher_->Start();
153 // Clear message to prevent accidentally resending it in the future.
154 encoded_message_.clear();
157 void GCMNetworkChannel::OnURLFetchComplete(const net::URLFetcher* source) {
158 DCHECK(CalledOnValidThread());
159 DCHECK_EQ(fetcher_, source);
160 // Free fetcher at the end of function.
161 scoped_ptr<net::URLFetcher> fetcher = fetcher_.Pass();
163 net::URLRequestStatus status = fetcher->GetStatus();
164 if (!status.is_success()) {
165 DVLOG(1) << "URLFetcher failure";
166 return;
169 if (fetcher->GetResponseCode() == net::HTTP_UNAUTHORIZED) {
170 DVLOG(1) << "URLFetcher failure: HTTP_UNAUTHORIZED";
171 delegate_->InvalidateToken(access_token_);
172 return;
174 DVLOG(2) << "URLFetcher success";
177 GURL GCMNetworkChannel::BuildUrl() {
178 DCHECK(!registration_id_.empty());
179 // Prepare NetworkEndpointId using registration_id
180 // Serialize NetworkEndpointId into byte array and base64 encode.
181 // Format url using encoded NetworkEndpointId.
182 // TODO(pavely): implement all of the above.
183 return GURL("http://invalid.url.com");
186 } // namespace syncer