Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / sync / notifier / gcm_network_channel.cc
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.
4
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"
11
12 namespace syncer {
13
14 GCMNetworkChannel::GCMNetworkChannel(
15     scoped_refptr<net::URLRequestContextGetter> request_context_getter,
16     scoped_ptr<GCMNetworkChannelDelegate> delegate)
17     : request_context_getter_(request_context_getter),
18       delegate_(delegate.Pass()),
19       weak_factory_(this) {
20   delegate_->Register(base::Bind(&GCMNetworkChannel::OnRegisterComplete,
21                                  weak_factory_.GetWeakPtr()));
22 }
23
24 GCMNetworkChannel::~GCMNetworkChannel() {
25 }
26
27 void GCMNetworkChannel::UpdateCredentials(
28     const std::string& email,
29     const std::string& token) {
30   // Do nothing. We get access token by requesting it for every message.
31 }
32
33 void GCMNetworkChannel::OnRegisterComplete(
34     const std::string& registration_id,
35     gcm::GCMClient::Result result) {
36   DCHECK(CalledOnValidThread());
37   if (result == gcm::GCMClient::SUCCESS) {
38     DCHECK(!registration_id.empty());
39     DVLOG(2) << "Got registration_id";
40     registration_id_ = registration_id;
41     if (!encoded_message_.empty())
42       RequestAccessToken();
43   } else {
44     DVLOG(2) << "Register failed";
45     // TODO(pavely): crbug.com/335670: Implement exponential backoff retry.
46   }
47 }
48
49 void GCMNetworkChannel::SendEncodedMessage(const std::string& encoded_message) {
50   DCHECK(CalledOnValidThread());
51   DCHECK(!encoded_message.empty());
52   DVLOG(2) << "SendEncodedMessage";
53   encoded_message_ = encoded_message;
54
55   if (!registration_id_.empty()) {
56     RequestAccessToken();
57   }
58 }
59
60 void GCMNetworkChannel::RequestAccessToken() {
61   DCHECK(CalledOnValidThread());
62   delegate_->RequestToken(base::Bind(&GCMNetworkChannel::OnGetTokenComplete,
63                                      weak_factory_.GetWeakPtr()));
64 }
65
66 void GCMNetworkChannel::OnGetTokenComplete(
67     const GoogleServiceAuthError& error,
68     const std::string& token) {
69   DCHECK(CalledOnValidThread());
70   if (encoded_message_.empty()) {
71     // Nothing to do.
72     return;
73   }
74
75   if (error.state() != GoogleServiceAuthError::NONE) {
76     // Requesting access token failed. Persistent errors will be reported by
77     // token service. Just drop this request, cacheinvalidations will retry
78     // sending message and at that time we'll retry requesting access token.
79     DVLOG(1) << "RequestAccessToken failed: " << error.ToString();
80     return;
81   }
82   DCHECK(!token.empty());
83   // Save access token in case POST fails and we need to invalidate it.
84   access_token_ = token;
85
86   DVLOG(2) << "Got access token, sending message";
87
88   fetcher_.reset(net::URLFetcher::Create(BuildUrl(), net::URLFetcher::POST,
89                                          this));
90   fetcher_->SetRequestContext(request_context_getter_);
91   const std::string auth_header("Authorization: Bearer " + access_token_);
92   fetcher_->AddExtraRequestHeader(auth_header);
93   fetcher_->SetUploadData("application/x-protobuffer", encoded_message_);
94   fetcher_->Start();
95   // Clear message to prevent accidentally resending it in the future.
96   encoded_message_.clear();
97 }
98
99 void GCMNetworkChannel::OnURLFetchComplete(const net::URLFetcher* source) {
100   DCHECK(CalledOnValidThread());
101   DCHECK_EQ(fetcher_, source);
102   // Free fetcher at the end of function.
103   scoped_ptr<net::URLFetcher> fetcher = fetcher_.Pass();
104
105   net::URLRequestStatus status = fetcher->GetStatus();
106   if (!status.is_success()) {
107     DVLOG(1) << "URLFetcher failure";
108     return;
109   }
110
111   if (fetcher->GetResponseCode() == net::HTTP_UNAUTHORIZED) {
112     DVLOG(1) << "URLFetcher failure: HTTP_UNAUTHORIZED";
113     delegate_->InvalidateToken(access_token_);
114     return;
115   }
116   DVLOG(2) << "URLFetcher success";
117 }
118
119 GURL GCMNetworkChannel::BuildUrl() {
120   DCHECK(!registration_id_.empty());
121   // Prepare NetworkEndpointId using registration_id
122   // Serialize NetworkEndpointId into byte array and base64 encode.
123   // Format url using encoded NetworkEndpointId.
124   // TODO(pavely): implement all of the above.
125   return GURL("http://invalid.url.com");
126 }
127
128 }  // namespace syncer