| Index: sync/notifier/gcm_network_channel.cc
|
| diff --git a/sync/notifier/gcm_network_channel.cc b/sync/notifier/gcm_network_channel.cc
|
| index 41f288c42df37dfc48f41c61dfeaf58db1023205..2e7547264a2f9734bde41eb8b28bd1c230f1ef4b 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
|
|
|