diff options
Diffstat (limited to 'sync/notifier/gcm_network_channel.cc')
-rw-r--r-- | sync/notifier/gcm_network_channel.cc | 110 |
1 files changed, 108 insertions, 2 deletions
diff --git a/sync/notifier/gcm_network_channel.cc b/sync/notifier/gcm_network_channel.cc index 41f288c..2e75472 100644 --- a/sync/notifier/gcm_network_channel.cc +++ b/sync/notifier/gcm_network_channel.cc @@ -2,21 +2,127 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "google_apis/gaia/google_service_auth_error.h" +#include "net/http/http_status_code.h" +#include "net/url_request/url_fetcher.h" +#include "net/url_request/url_request_status.h" #include "sync/notifier/gcm_network_channel.h" +#include "sync/notifier/gcm_network_channel_delegate.h" namespace syncer { -GCMNetworkChannel::GCMNetworkChannel() { +GCMNetworkChannel::GCMNetworkChannel( + scoped_refptr<net::URLRequestContextGetter> request_context_getter, + scoped_ptr<GCMNetworkChannelDelegate> delegate) + : request_context_getter_(request_context_getter), + delegate_(delegate.Pass()), + weak_factory_(this) { + delegate_->Register(base::Bind(&GCMNetworkChannel::OnRegisterComplete, + weak_factory_.GetWeakPtr())); } GCMNetworkChannel::~GCMNetworkChannel() { } +void GCMNetworkChannel::UpdateCredentials( + const std::string& email, + const std::string& token) { + // Do nothing. We get access token by requesting it for every message. +} + +void GCMNetworkChannel::OnRegisterComplete( + const std::string& registration_id, + gcm::GCMClient::Result result) { + DCHECK(CalledOnValidThread()); + if (result == gcm::GCMClient::SUCCESS) { + DCHECK(!registration_id.empty()); + DVLOG(2) << "Got registration_id"; + registration_id_ = registration_id; + if (!encoded_message_.empty()) + RequestAccessToken(); + } else { + DVLOG(2) << "Register failed"; + // TODO(pavely): crbug.com/335670: Implement exponential backoff retry. + } +} + void GCMNetworkChannel::SendEncodedMessage(const std::string& encoded_message) { + DCHECK(CalledOnValidThread()); + DCHECK(!encoded_message.empty()); + DVLOG(2) << "SendEncodedMessage"; + encoded_message_ = encoded_message; + + if (!registration_id_.empty()) { + RequestAccessToken(); + } +} + +void GCMNetworkChannel::RequestAccessToken() { + DCHECK(CalledOnValidThread()); + delegate_->RequestToken(base::Bind(&GCMNetworkChannel::OnGetTokenComplete, + weak_factory_.GetWeakPtr())); } -void GCMNetworkChannel::UpdateCredentials(const std::string& email, +void GCMNetworkChannel::OnGetTokenComplete( + const GoogleServiceAuthError& error, const std::string& token) { + DCHECK(CalledOnValidThread()); + if (encoded_message_.empty()) { + // Nothing to do. + return; + } + + if (error.state() != GoogleServiceAuthError::NONE) { + // Requesting access token failed. Persistent errors will be reported by + // token service. Just drop this request, cacheinvalidations will retry + // sending message and at that time we'll retry requesting access token. + DVLOG(1) << "RequestAccessToken failed: " << error.ToString(); + return; + } + DCHECK(!token.empty()); + // Save access token in case POST fails and we need to invalidate it. + access_token_ = token; + + DVLOG(2) << "Got access token, sending message"; + + fetcher_.reset(net::URLFetcher::Create(BuildUrl(), net::URLFetcher::POST, + this)); + fetcher_->SetRequestContext(request_context_getter_); + const std::string auth_header("Authorization: Bearer " + access_token_); + fetcher_->AddExtraRequestHeader(auth_header); + fetcher_->SetUploadData("application/x-protobuffer", encoded_message_); + fetcher_->Start(); + // Clear message to prevent accidentally resending it in the future. + encoded_message_.clear(); +} + +void GCMNetworkChannel::OnURLFetchComplete(const net::URLFetcher* source) { + DCHECK(CalledOnValidThread()); + DCHECK_EQ(fetcher_, source); + // Free fetcher at the end of function. + scoped_ptr<net::URLFetcher> fetcher = fetcher_.Pass(); + + net::URLRequestStatus status = fetcher->GetStatus(); + if (!status.is_success()) { + DVLOG(1) << "URLFetcher failure"; + return; + } + + if (fetcher->GetResponseCode() == net::HTTP_UNAUTHORIZED) { + DVLOG(1) << "URLFetcher failure: HTTP_UNAUTHORIZED"; + delegate_->InvalidateToken(access_token_); + return; + } + DVLOG(2) << "URLFetcher success"; +} + +GURL GCMNetworkChannel::BuildUrl() { + DCHECK(!registration_id_.empty()); + // Prepare NetworkEndpointId using registration_id + // Serialize NetworkEndpointId into byte array and base64 encode. + // Format url using encoded NetworkEndpointId. + // TODO(pavely): implement all of the above. + return GURL("http://invalid.url.com"); } } // namespace syncer |