summaryrefslogtreecommitdiffstats
path: root/sync/notifier/gcm_network_channel.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sync/notifier/gcm_network_channel.cc')
-rw-r--r--sync/notifier/gcm_network_channel.cc110
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