| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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 "chrome/common/net/gaia/gaia_oauth_client.h" | |
| 6 | |
| 7 #include "base/json/json_reader.h" | |
| 8 #include "base/logging.h" | |
| 9 #include "base/memory/scoped_ptr.h" | |
| 10 #include "base/values.h" | |
| 11 #include "googleurl/src/gurl.h" | |
| 12 #include "net/base/escape.h" | |
| 13 #include "net/http/http_status_code.h" | |
| 14 #include "net/url_request/url_fetcher.h" | |
| 15 #include "net/url_request/url_fetcher_delegate.h" | |
| 16 #include "net/url_request/url_request_context_getter.h" | |
| 17 | |
| 18 namespace { | |
| 19 const char kAccessTokenValue[] = "access_token"; | |
| 20 const char kRefreshTokenValue[] = "refresh_token"; | |
| 21 const char kExpiresInValue[] = "expires_in"; | |
| 22 } | |
| 23 | |
| 24 namespace gaia { | |
| 25 | |
| 26 class GaiaOAuthClient::Core | |
| 27 : public base::RefCountedThreadSafe<GaiaOAuthClient::Core>, | |
| 28 public net::URLFetcherDelegate { | |
| 29 public: | |
| 30 Core(const std::string& gaia_url, | |
| 31 net::URLRequestContextGetter* request_context_getter) | |
| 32 : gaia_url_(gaia_url), | |
| 33 num_retries_(0), | |
| 34 request_context_getter_(request_context_getter), | |
| 35 delegate_(NULL) {} | |
| 36 | |
| 37 void GetTokensFromAuthCode(const OAuthClientInfo& oauth_client_info, | |
| 38 const std::string& auth_code, | |
| 39 int max_retries, | |
| 40 GaiaOAuthClient::Delegate* delegate); | |
| 41 void RefreshToken(const OAuthClientInfo& oauth_client_info, | |
| 42 const std::string& refresh_token, | |
| 43 int max_retries, | |
| 44 GaiaOAuthClient::Delegate* delegate); | |
| 45 | |
| 46 // net::URLFetcherDelegate implementation. | |
| 47 virtual void OnURLFetchComplete(const net::URLFetcher* source); | |
| 48 | |
| 49 private: | |
| 50 friend class base::RefCountedThreadSafe<Core>; | |
| 51 virtual ~Core() {} | |
| 52 | |
| 53 void MakeGaiaRequest(const std::string& post_body, | |
| 54 int max_retries, | |
| 55 GaiaOAuthClient::Delegate* delegate); | |
| 56 void HandleResponse(const net::URLFetcher* source, | |
| 57 bool* should_retry_request); | |
| 58 | |
| 59 GURL gaia_url_; | |
| 60 int num_retries_; | |
| 61 scoped_refptr<net::URLRequestContextGetter> request_context_getter_; | |
| 62 GaiaOAuthClient::Delegate* delegate_; | |
| 63 scoped_ptr<net::URLFetcher> request_; | |
| 64 }; | |
| 65 | |
| 66 void GaiaOAuthClient::Core::GetTokensFromAuthCode( | |
| 67 const OAuthClientInfo& oauth_client_info, | |
| 68 const std::string& auth_code, | |
| 69 int max_retries, | |
| 70 GaiaOAuthClient::Delegate* delegate) { | |
| 71 std::string post_body = | |
| 72 "code=" + net::EscapeUrlEncodedData(auth_code, true) + | |
| 73 "&client_id=" + net::EscapeUrlEncodedData(oauth_client_info.client_id, | |
| 74 true) + | |
| 75 "&client_secret=" + | |
| 76 net::EscapeUrlEncodedData(oauth_client_info.client_secret, true) + | |
| 77 "&redirect_uri=oob&grant_type=authorization_code"; | |
| 78 MakeGaiaRequest(post_body, max_retries, delegate); | |
| 79 } | |
| 80 | |
| 81 void GaiaOAuthClient::Core::RefreshToken( | |
| 82 const OAuthClientInfo& oauth_client_info, | |
| 83 const std::string& refresh_token, | |
| 84 int max_retries, | |
| 85 GaiaOAuthClient::Delegate* delegate) { | |
| 86 std::string post_body = | |
| 87 "refresh_token=" + net::EscapeUrlEncodedData(refresh_token, true) + | |
| 88 "&client_id=" + net::EscapeUrlEncodedData(oauth_client_info.client_id, | |
| 89 true) + | |
| 90 "&client_secret=" + | |
| 91 net::EscapeUrlEncodedData(oauth_client_info.client_secret, true) + | |
| 92 "&grant_type=refresh_token"; | |
| 93 MakeGaiaRequest(post_body, max_retries, delegate); | |
| 94 } | |
| 95 | |
| 96 void GaiaOAuthClient::Core::MakeGaiaRequest( | |
| 97 const std::string& post_body, | |
| 98 int max_retries, | |
| 99 GaiaOAuthClient::Delegate* delegate) { | |
| 100 DCHECK(!request_.get()) << "Tried to fetch two things at once!"; | |
| 101 delegate_ = delegate; | |
| 102 num_retries_ = 0; | |
| 103 request_.reset(net::URLFetcher::Create( | |
| 104 0, gaia_url_, net::URLFetcher::POST, this)); | |
| 105 request_->SetRequestContext(request_context_getter_); | |
| 106 request_->SetUploadData("application/x-www-form-urlencoded", post_body); | |
| 107 request_->SetMaxRetries(max_retries); | |
| 108 request_->Start(); | |
| 109 } | |
| 110 | |
| 111 // URLFetcher::Delegate implementation. | |
| 112 void GaiaOAuthClient::Core::OnURLFetchComplete( | |
| 113 const net::URLFetcher* source) { | |
| 114 bool should_retry = false; | |
| 115 HandleResponse(source, &should_retry); | |
| 116 if (should_retry) { | |
| 117 // Explicitly call ReceivedContentWasMalformed() to ensure the current | |
| 118 // request gets counted as a failure for calculation of the back-off | |
| 119 // period. If it was already a failure by status code, this call will | |
| 120 // be ignored. | |
| 121 request_->ReceivedContentWasMalformed(); | |
| 122 num_retries_++; | |
| 123 // We must set our request_context_getter_ again because | |
| 124 // URLFetcher::Core::RetryOrCompleteUrlFetch resets it to NULL... | |
| 125 request_->SetRequestContext(request_context_getter_); | |
| 126 request_->Start(); | |
| 127 } else { | |
| 128 request_.reset(); | |
| 129 } | |
| 130 } | |
| 131 | |
| 132 void GaiaOAuthClient::Core::HandleResponse( | |
| 133 const net::URLFetcher* source, | |
| 134 bool* should_retry_request) { | |
| 135 *should_retry_request = false; | |
| 136 // RC_BAD_REQUEST means the arguments are invalid. No point retrying. We are | |
| 137 // done here. | |
| 138 if (source->GetResponseCode() == net::HTTP_BAD_REQUEST) { | |
| 139 delegate_->OnOAuthError(); | |
| 140 return; | |
| 141 } | |
| 142 std::string access_token; | |
| 143 std::string refresh_token; | |
| 144 int expires_in_seconds = 0; | |
| 145 if (source->GetResponseCode() == net::HTTP_OK) { | |
| 146 std::string data; | |
| 147 source->GetResponseAsString(&data); | |
| 148 scoped_ptr<Value> message_value(base::JSONReader::Read(data)); | |
| 149 if (message_value.get() && | |
| 150 message_value->IsType(Value::TYPE_DICTIONARY)) { | |
| 151 scoped_ptr<DictionaryValue> response_dict( | |
| 152 static_cast<DictionaryValue*>(message_value.release())); | |
| 153 response_dict->GetString(kAccessTokenValue, &access_token); | |
| 154 response_dict->GetString(kRefreshTokenValue, &refresh_token); | |
| 155 response_dict->GetInteger(kExpiresInValue, &expires_in_seconds); | |
| 156 } | |
| 157 } | |
| 158 if (access_token.empty()) { | |
| 159 // If we don't have an access token yet and the the error was not | |
| 160 // RC_BAD_REQUEST, we may need to retry. | |
| 161 if ((-1 != source->GetMaxRetries()) && | |
| 162 (num_retries_ > source->GetMaxRetries())) { | |
| 163 // Retry limit reached. Give up. | |
| 164 delegate_->OnNetworkError(source->GetResponseCode()); | |
| 165 } else { | |
| 166 *should_retry_request = true; | |
| 167 } | |
| 168 } else if (refresh_token.empty()) { | |
| 169 // If we only have an access token, then this was a refresh request. | |
| 170 delegate_->OnRefreshTokenResponse(access_token, expires_in_seconds); | |
| 171 } else { | |
| 172 delegate_->OnGetTokensResponse(refresh_token, | |
| 173 access_token, | |
| 174 expires_in_seconds); | |
| 175 } | |
| 176 } | |
| 177 | |
| 178 GaiaOAuthClient::GaiaOAuthClient(const std::string& gaia_url, | |
| 179 net::URLRequestContextGetter* context_getter) { | |
| 180 core_ = new Core(gaia_url, context_getter); | |
| 181 } | |
| 182 | |
| 183 GaiaOAuthClient::~GaiaOAuthClient() { | |
| 184 } | |
| 185 | |
| 186 | |
| 187 void GaiaOAuthClient::GetTokensFromAuthCode( | |
| 188 const OAuthClientInfo& oauth_client_info, | |
| 189 const std::string& auth_code, | |
| 190 int max_retries, | |
| 191 Delegate* delegate) { | |
| 192 return core_->GetTokensFromAuthCode(oauth_client_info, | |
| 193 auth_code, | |
| 194 max_retries, | |
| 195 delegate); | |
| 196 } | |
| 197 | |
| 198 void GaiaOAuthClient::RefreshToken(const OAuthClientInfo& oauth_client_info, | |
| 199 const std::string& refresh_token, | |
| 200 int max_retries, | |
| 201 Delegate* delegate) { | |
| 202 return core_->RefreshToken(oauth_client_info, | |
| 203 refresh_token, | |
| 204 max_retries, | |
| 205 delegate); | |
| 206 } | |
| 207 | |
| 208 } // namespace gaia | |
| OLD | NEW |