OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 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" |
5 #include "sync/notifier/gcm_network_channel.h" | 9 #include "sync/notifier/gcm_network_channel.h" |
| 10 #include "sync/notifier/gcm_network_channel_delegate.h" |
6 | 11 |
7 namespace syncer { | 12 namespace syncer { |
8 | 13 |
9 GCMNetworkChannel::GCMNetworkChannel() { | 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())); |
10 } | 22 } |
11 | 23 |
12 GCMNetworkChannel::~GCMNetworkChannel() { | 24 GCMNetworkChannel::~GCMNetworkChannel() { |
13 } | 25 } |
14 | 26 |
15 void GCMNetworkChannel::SendEncodedMessage(const std::string& encoded_message) { | 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. |
16 } | 31 } |
17 | 32 |
18 void GCMNetworkChannel::UpdateCredentials(const std::string& email, | 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, |
19 const std::string& token) { | 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"); |
20 } | 126 } |
21 | 127 |
22 } // namespace syncer | 128 } // namespace syncer |
OLD | NEW |