| OLD | NEW | 
|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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/oauth2_access_token_fetcher.h" | 5 #include "google_apis/gaia/oauth2_access_token_fetcher_impl.h" | 
| 6 | 6 | 
| 7 #include <algorithm> | 7 #include <algorithm> | 
| 8 #include <string> | 8 #include <string> | 
| 9 #include <vector> | 9 #include <vector> | 
| 10 | 10 | 
| 11 #include "base/json/json_reader.h" | 11 #include "base/json/json_reader.h" | 
| 12 #include "base/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" | 
| 13 #include "base/metrics/sparse_histogram.h" | 13 #include "base/metrics/sparse_histogram.h" | 
| 14 #include "base/strings/string_util.h" | 14 #include "base/strings/string_util.h" | 
| 15 #include "base/strings/stringprintf.h" | 15 #include "base/strings/stringprintf.h" | 
| (...skipping 28 matching lines...) Expand all  Loading... | 
| 44     "refresh_token=%s&" | 44     "refresh_token=%s&" | 
| 45     "scope=%s"; | 45     "scope=%s"; | 
| 46 | 46 | 
| 47 static const char kAccessTokenKey[] = "access_token"; | 47 static const char kAccessTokenKey[] = "access_token"; | 
| 48 static const char kExpiresInKey[] = "expires_in"; | 48 static const char kExpiresInKey[] = "expires_in"; | 
| 49 static const char kErrorKey[] = "error"; | 49 static const char kErrorKey[] = "error"; | 
| 50 | 50 | 
| 51 // Enumerated constants for logging server responses on 400 errors, matching | 51 // Enumerated constants for logging server responses on 400 errors, matching | 
| 52 // RFC 6749. | 52 // RFC 6749. | 
| 53 enum OAuth2ErrorCodesForHistogram { | 53 enum OAuth2ErrorCodesForHistogram { | 
| 54    OAUTH2_ACCESS_ERROR_INVALID_REQUEST = 0, | 54   OAUTH2_ACCESS_ERROR_INVALID_REQUEST = 0, | 
| 55    OAUTH2_ACCESS_ERROR_INVALID_CLIENT, | 55   OAUTH2_ACCESS_ERROR_INVALID_CLIENT, | 
| 56    OAUTH2_ACCESS_ERROR_INVALID_GRANT, | 56   OAUTH2_ACCESS_ERROR_INVALID_GRANT, | 
| 57    OAUTH2_ACCESS_ERROR_UNAUTHORIZED_CLIENT, | 57   OAUTH2_ACCESS_ERROR_UNAUTHORIZED_CLIENT, | 
| 58    OAUTH2_ACCESS_ERROR_UNSUPPORTED_GRANT_TYPE, | 58   OAUTH2_ACCESS_ERROR_UNSUPPORTED_GRANT_TYPE, | 
| 59    OAUTH2_ACCESS_ERROR_INVALID_SCOPE, | 59   OAUTH2_ACCESS_ERROR_INVALID_SCOPE, | 
| 60    OAUTH2_ACCESS_ERROR_UNKNOWN, | 60   OAUTH2_ACCESS_ERROR_UNKNOWN, | 
| 61    OAUTH2_ACCESS_ERROR_COUNT | 61   OAUTH2_ACCESS_ERROR_COUNT | 
| 62 }; | 62 }; | 
| 63 | 63 | 
| 64 OAuth2ErrorCodesForHistogram OAuth2ErrorToHistogramValue( | 64 OAuth2ErrorCodesForHistogram OAuth2ErrorToHistogramValue( | 
| 65     const std::string& error) { | 65     const std::string& error) { | 
| 66   if (error == "invalid_request") | 66   if (error == "invalid_request") | 
| 67     return OAUTH2_ACCESS_ERROR_INVALID_REQUEST; | 67     return OAUTH2_ACCESS_ERROR_INVALID_REQUEST; | 
| 68   else if (error == "invalid_client") | 68   else if (error == "invalid_client") | 
| 69     return OAUTH2_ACCESS_ERROR_INVALID_CLIENT; | 69     return OAUTH2_ACCESS_ERROR_INVALID_CLIENT; | 
| 70   else if (error == "invalid_grant") | 70   else if (error == "invalid_grant") | 
| 71     return OAUTH2_ACCESS_ERROR_INVALID_GRANT; | 71     return OAUTH2_ACCESS_ERROR_INVALID_GRANT; | 
| (...skipping 17 matching lines...) Expand all  Loading... | 
| 89     return GoogleServiceAuthError::FromConnectionError(status.error()); | 89     return GoogleServiceAuthError::FromConnectionError(status.error()); | 
| 90   } | 90   } | 
| 91 } | 91 } | 
| 92 | 92 | 
| 93 static URLFetcher* CreateFetcher(URLRequestContextGetter* getter, | 93 static URLFetcher* CreateFetcher(URLRequestContextGetter* getter, | 
| 94                                  const GURL& url, | 94                                  const GURL& url, | 
| 95                                  const std::string& body, | 95                                  const std::string& body, | 
| 96                                  URLFetcherDelegate* delegate) { | 96                                  URLFetcherDelegate* delegate) { | 
| 97   bool empty_body = body.empty(); | 97   bool empty_body = body.empty(); | 
| 98   URLFetcher* result = net::URLFetcher::Create( | 98   URLFetcher* result = net::URLFetcher::Create( | 
| 99       0, url, | 99       0, url, empty_body ? URLFetcher::GET : URLFetcher::POST, delegate); | 
| 100       empty_body ? URLFetcher::GET : URLFetcher::POST, |  | 
| 101       delegate); |  | 
| 102 | 100 | 
| 103   result->SetRequestContext(getter); | 101   result->SetRequestContext(getter); | 
| 104   result->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | | 102   result->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | | 
| 105                        net::LOAD_DO_NOT_SAVE_COOKIES); | 103                        net::LOAD_DO_NOT_SAVE_COOKIES); | 
| 106   // Fetchers are sometimes cancelled because a network change was detected, | 104   // Fetchers are sometimes cancelled because a network change was detected, | 
| 107   // especially at startup and after sign-in on ChromeOS. Retrying once should | 105   // especially at startup and after sign-in on ChromeOS. Retrying once should | 
| 108   // be enough in those cases; let the fetcher retry up to 3 times just in case. | 106   // be enough in those cases; let the fetcher retry up to 3 times just in case. | 
| 109   // http://crbug.com/163710 | 107   // http://crbug.com/163710 | 
| 110   result->SetAutomaticallyRetryOnNetworkChanges(3); | 108   result->SetAutomaticallyRetryOnNetworkChanges(3); | 
| 111 | 109 | 
| 112   if (!empty_body) | 110   if (!empty_body) | 
| 113     result->SetUploadData("application/x-www-form-urlencoded", body); | 111     result->SetUploadData("application/x-www-form-urlencoded", body); | 
| 114 | 112 | 
| 115   return result; | 113   return result; | 
| 116 } | 114 } | 
|  | 115 | 
|  | 116 scoped_ptr<base::DictionaryValue> ParseGetAccessTokenResponse( | 
|  | 117     const net::URLFetcher* source) { | 
|  | 118   CHECK(source); | 
|  | 119 | 
|  | 120   std::string data; | 
|  | 121   source->GetResponseAsString(&data); | 
|  | 122   scoped_ptr<base::Value> value(base::JSONReader::Read(data)); | 
|  | 123   if (!value.get() || value->GetType() != base::Value::TYPE_DICTIONARY) | 
|  | 124     value.reset(); | 
|  | 125 | 
|  | 126   return scoped_ptr<base::DictionaryValue>( | 
|  | 127       static_cast<base::DictionaryValue*>(value.release())); | 
|  | 128 } | 
|  | 129 | 
| 117 }  // namespace | 130 }  // namespace | 
| 118 | 131 | 
| 119 OAuth2AccessTokenFetcher::OAuth2AccessTokenFetcher( | 132 OAuth2AccessTokenFetcherImpl::OAuth2AccessTokenFetcherImpl( | 
| 120     OAuth2AccessTokenConsumer* consumer, | 133     OAuth2AccessTokenConsumer* consumer, URLRequestContextGetter* getter) | 
| 121     URLRequestContextGetter* getter) | 134     : OAuth2AccessTokenFetcher(consumer), getter_(getter), state_(INITIAL) {} | 
| 122     : consumer_(consumer), |  | 
| 123       getter_(getter), |  | 
| 124       state_(INITIAL) { } |  | 
| 125 | 135 | 
| 126 OAuth2AccessTokenFetcher::~OAuth2AccessTokenFetcher() { } | 136 OAuth2AccessTokenFetcherImpl::~OAuth2AccessTokenFetcherImpl() {} | 
| 127 | 137 | 
| 128 void OAuth2AccessTokenFetcher::CancelRequest() { | 138 void OAuth2AccessTokenFetcherImpl::CancelRequest() { fetcher_.reset(); } | 
| 129   fetcher_.reset(); |  | 
| 130 } |  | 
| 131 | 139 | 
| 132 void OAuth2AccessTokenFetcher::Start(const std::string& client_id, | 140 void OAuth2AccessTokenFetcherImpl::Start( | 
| 133                                      const std::string& client_secret, | 141     const std::string& client_id, | 
| 134                                      const std::string& refresh_token, | 142     const std::string& client_secret, | 
| 135                                      const std::vector<std::string>& scopes) { | 143     const std::string& refresh_token, | 
|  | 144     const std::vector<std::string>& scopes) { | 
| 136   client_id_ = client_id; | 145   client_id_ = client_id; | 
| 137   client_secret_ = client_secret; | 146   client_secret_ = client_secret; | 
| 138   refresh_token_ = refresh_token; | 147   refresh_token_ = refresh_token; | 
| 139   scopes_ = scopes; | 148   scopes_ = scopes; | 
| 140   StartGetAccessToken(); | 149   StartGetAccessToken(); | 
| 141 } | 150 } | 
| 142 | 151 | 
| 143 void OAuth2AccessTokenFetcher::StartGetAccessToken() { | 152 void OAuth2AccessTokenFetcherImpl::StartGetAccessToken() { | 
| 144   CHECK_EQ(INITIAL, state_); | 153   CHECK_EQ(INITIAL, state_); | 
| 145   state_ = GET_ACCESS_TOKEN_STARTED; | 154   state_ = GET_ACCESS_TOKEN_STARTED; | 
| 146   fetcher_.reset(CreateFetcher( | 155   fetcher_.reset( | 
| 147       getter_, | 156       CreateFetcher(getter_, | 
| 148       MakeGetAccessTokenUrl(), | 157                     MakeGetAccessTokenUrl(), | 
| 149       MakeGetAccessTokenBody( | 158                     MakeGetAccessTokenBody( | 
| 150           client_id_, client_secret_, refresh_token_, scopes_), | 159                         client_id_, client_secret_, refresh_token_, scopes_), | 
| 151       this)); | 160                     this)); | 
| 152   fetcher_->Start();  // OnURLFetchComplete will be called. | 161   fetcher_->Start();  // OnURLFetchComplete will be called. | 
| 153 } | 162 } | 
| 154 | 163 | 
| 155 void OAuth2AccessTokenFetcher::EndGetAccessToken( | 164 void OAuth2AccessTokenFetcherImpl::EndGetAccessToken( | 
| 156     const net::URLFetcher* source) { | 165     const net::URLFetcher* source) { | 
| 157   CHECK_EQ(GET_ACCESS_TOKEN_STARTED, state_); | 166   CHECK_EQ(GET_ACCESS_TOKEN_STARTED, state_); | 
| 158   state_ = GET_ACCESS_TOKEN_DONE; | 167   state_ = GET_ACCESS_TOKEN_DONE; | 
| 159 | 168 | 
| 160   URLRequestStatus status = source->GetStatus(); | 169   URLRequestStatus status = source->GetStatus(); | 
| 161   int histogram_value = status.is_success() ? source->GetResponseCode() : | 170   int histogram_value = | 
| 162                                               status.error(); | 171       status.is_success() ? source->GetResponseCode() : status.error(); | 
| 163   UMA_HISTOGRAM_SPARSE_SLOWLY("Gaia.ResponseCodesForOAuth2AccessToken", | 172   UMA_HISTOGRAM_SPARSE_SLOWLY("Gaia.ResponseCodesForOAuth2AccessToken", | 
| 164                               histogram_value); | 173                               histogram_value); | 
| 165   if (!status.is_success()) { | 174   if (!status.is_success()) { | 
| 166     OnGetTokenFailure(CreateAuthError(status)); | 175     OnGetTokenFailure(CreateAuthError(status)); | 
| 167     return; | 176     return; | 
| 168   } | 177   } | 
| 169 | 178 | 
| 170   switch (source->GetResponseCode()) { | 179   switch (source->GetResponseCode()) { | 
| 171     case net::HTTP_OK: | 180     case net::HTTP_OK: | 
| 172       break; | 181       break; | 
| 173     case net::HTTP_FORBIDDEN: | 182     case net::HTTP_FORBIDDEN: | 
| 174     case net::HTTP_INTERNAL_SERVER_ERROR: | 183     case net::HTTP_INTERNAL_SERVER_ERROR: | 
| 175       // HTTP_FORBIDDEN (403) is treated as temporary error, because it may be | 184       // HTTP_FORBIDDEN (403) is treated as temporary error, because it may be | 
| 176       // '403 Rate Limit Exeeded.' 500 is always treated as transient. | 185       // '403 Rate Limit Exeeded.' 500 is always treated as transient. | 
| 177       OnGetTokenFailure(GoogleServiceAuthError( | 186       OnGetTokenFailure( | 
| 178           GoogleServiceAuthError::SERVICE_UNAVAILABLE)); | 187           GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE)); | 
| 179       return; | 188       return; | 
| 180     case net::HTTP_BAD_REQUEST: { | 189     case net::HTTP_BAD_REQUEST: { | 
| 181       // HTTP_BAD_REQUEST (400) usually contains error as per | 190       // HTTP_BAD_REQUEST (400) usually contains error as per | 
| 182       // http://tools.ietf.org/html/rfc6749#section-5.2. | 191       // http://tools.ietf.org/html/rfc6749#section-5.2. | 
| 183       std::string gaia_error; | 192       std::string gaia_error; | 
| 184       if (!ParseGetAccessTokenFailureResponse(source, &gaia_error)) { | 193       if (!ParseGetAccessTokenFailureResponse(source, &gaia_error)) { | 
| 185         OnGetTokenFailure(GoogleServiceAuthError( | 194         OnGetTokenFailure( | 
| 186             GoogleServiceAuthError::SERVICE_ERROR)); | 195             GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_ERROR)); | 
| 187         return; | 196         return; | 
| 188       } | 197       } | 
| 189 | 198 | 
| 190       OAuth2ErrorCodesForHistogram access_error(OAuth2ErrorToHistogramValue( | 199       OAuth2ErrorCodesForHistogram access_error( | 
| 191           gaia_error)); | 200           OAuth2ErrorToHistogramValue(gaia_error)); | 
| 192       UMA_HISTOGRAM_ENUMERATION("Gaia.BadRequestTypeForOAuth2AccessToken", | 201       UMA_HISTOGRAM_ENUMERATION("Gaia.BadRequestTypeForOAuth2AccessToken", | 
| 193                                 access_error, OAUTH2_ACCESS_ERROR_COUNT); | 202                                 access_error, | 
|  | 203                                 OAUTH2_ACCESS_ERROR_COUNT); | 
| 194 | 204 | 
| 195       OnGetTokenFailure(access_error == OAUTH2_ACCESS_ERROR_INVALID_GRANT ? | 205       OnGetTokenFailure( | 
| 196           GoogleServiceAuthError( | 206           access_error == OAUTH2_ACCESS_ERROR_INVALID_GRANT | 
| 197               GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS) : | 207               ? GoogleServiceAuthError( | 
| 198           GoogleServiceAuthError( | 208                     GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS) | 
| 199               GoogleServiceAuthError::SERVICE_ERROR)); | 209               : GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_ERROR)); | 
| 200       return; | 210       return; | 
| 201     } | 211     } | 
| 202     default: | 212     default: | 
| 203       // The other errors are treated as permanent error. | 213       // The other errors are treated as permanent error. | 
| 204       OnGetTokenFailure(GoogleServiceAuthError( | 214       OnGetTokenFailure(GoogleServiceAuthError( | 
| 205           GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS)); | 215           GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS)); | 
| 206       return; | 216       return; | 
| 207   } | 217   } | 
| 208 | 218 | 
| 209   // The request was successfully fetched and it returned OK. | 219   // The request was successfully fetched and it returned OK. | 
| 210   // Parse out the access token and the expiration time. | 220   // Parse out the access token and the expiration time. | 
| 211   std::string access_token; | 221   std::string access_token; | 
| 212   int expires_in; | 222   int expires_in; | 
| 213   if (!ParseGetAccessTokenSuccessResponse( | 223   if (!ParseGetAccessTokenSuccessResponse(source, &access_token, &expires_in)) { | 
| 214           source, &access_token, &expires_in)) { |  | 
| 215     DLOG(WARNING) << "Response doesn't match expected format"; | 224     DLOG(WARNING) << "Response doesn't match expected format"; | 
| 216     OnGetTokenFailure( | 225     OnGetTokenFailure( | 
| 217         GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE)); | 226         GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE)); | 
| 218     return; | 227     return; | 
| 219   } | 228   } | 
| 220   // The token will expire in |expires_in| seconds. Take a 10% error margin to | 229   // The token will expire in |expires_in| seconds. Take a 10% error margin to | 
| 221   // prevent reusing a token too close to its expiration date. | 230   // prevent reusing a token too close to its expiration date. | 
| 222   OnGetTokenSuccess( | 231   OnGetTokenSuccess( | 
| 223       access_token, | 232       access_token, | 
| 224       base::Time::Now() + base::TimeDelta::FromSeconds(9 * expires_in / 10)); | 233       base::Time::Now() + base::TimeDelta::FromSeconds(9 * expires_in / 10)); | 
| 225 } | 234 } | 
| 226 | 235 | 
| 227 void OAuth2AccessTokenFetcher::OnGetTokenSuccess( | 236 void OAuth2AccessTokenFetcherImpl::OnGetTokenSuccess( | 
| 228     const std::string& access_token, | 237     const std::string& access_token, | 
| 229     const base::Time& expiration_time) { | 238     const base::Time& expiration_time) { | 
| 230   consumer_->OnGetTokenSuccess(access_token, expiration_time); | 239   FireOnGetTokenSuccess(access_token, expiration_time); | 
| 231 } | 240 } | 
| 232 | 241 | 
| 233 void OAuth2AccessTokenFetcher::OnGetTokenFailure( | 242 void OAuth2AccessTokenFetcherImpl::OnGetTokenFailure( | 
| 234     const GoogleServiceAuthError& error) { | 243     const GoogleServiceAuthError& error) { | 
| 235   state_ = ERROR_STATE; | 244   state_ = ERROR_STATE; | 
| 236   consumer_->OnGetTokenFailure(error); | 245   FireOnGetTokenFailure(error); | 
| 237 } | 246 } | 
| 238 | 247 | 
| 239 void OAuth2AccessTokenFetcher::OnURLFetchComplete( | 248 void OAuth2AccessTokenFetcherImpl::OnURLFetchComplete( | 
| 240     const net::URLFetcher* source) { | 249     const net::URLFetcher* source) { | 
| 241   CHECK(source); | 250   CHECK(source); | 
| 242   CHECK(state_ == GET_ACCESS_TOKEN_STARTED); | 251   CHECK(state_ == GET_ACCESS_TOKEN_STARTED); | 
| 243   EndGetAccessToken(source); | 252   EndGetAccessToken(source); | 
| 244 } | 253 } | 
| 245 | 254 | 
| 246 // static | 255 // static | 
| 247 GURL OAuth2AccessTokenFetcher::MakeGetAccessTokenUrl() { | 256 GURL OAuth2AccessTokenFetcherImpl::MakeGetAccessTokenUrl() { | 
| 248   return GaiaUrls::GetInstance()->oauth2_token_url(); | 257   return GaiaUrls::GetInstance()->oauth2_token_url(); | 
| 249 } | 258 } | 
| 250 | 259 | 
| 251 // static | 260 // static | 
| 252 std::string OAuth2AccessTokenFetcher::MakeGetAccessTokenBody( | 261 std::string OAuth2AccessTokenFetcherImpl::MakeGetAccessTokenBody( | 
| 253     const std::string& client_id, | 262     const std::string& client_id, | 
| 254     const std::string& client_secret, | 263     const std::string& client_secret, | 
| 255     const std::string& refresh_token, | 264     const std::string& refresh_token, | 
| 256     const std::vector<std::string>& scopes) { | 265     const std::vector<std::string>& scopes) { | 
| 257   std::string enc_client_id = net::EscapeUrlEncodedData(client_id, true); | 266   std::string enc_client_id = net::EscapeUrlEncodedData(client_id, true); | 
| 258   std::string enc_client_secret = | 267   std::string enc_client_secret = | 
| 259       net::EscapeUrlEncodedData(client_secret, true); | 268       net::EscapeUrlEncodedData(client_secret, true); | 
| 260   std::string enc_refresh_token = | 269   std::string enc_refresh_token = | 
| 261       net::EscapeUrlEncodedData(refresh_token, true); | 270       net::EscapeUrlEncodedData(refresh_token, true); | 
| 262   if (scopes.empty()) { | 271   if (scopes.empty()) { | 
| 263     return base::StringPrintf( | 272     return base::StringPrintf(kGetAccessTokenBodyFormat, | 
| 264         kGetAccessTokenBodyFormat, | 273                               enc_client_id.c_str(), | 
| 265         enc_client_id.c_str(), | 274                               enc_client_secret.c_str(), | 
| 266         enc_client_secret.c_str(), | 275                               enc_refresh_token.c_str()); | 
| 267         enc_refresh_token.c_str()); |  | 
| 268   } else { | 276   } else { | 
| 269     std::string scopes_string = JoinString(scopes, ' '); | 277     std::string scopes_string = JoinString(scopes, ' '); | 
| 270     return base::StringPrintf( | 278     return base::StringPrintf( | 
| 271         kGetAccessTokenBodyWithScopeFormat, | 279         kGetAccessTokenBodyWithScopeFormat, | 
| 272         enc_client_id.c_str(), | 280         enc_client_id.c_str(), | 
| 273         enc_client_secret.c_str(), | 281         enc_client_secret.c_str(), | 
| 274         enc_refresh_token.c_str(), | 282         enc_refresh_token.c_str(), | 
| 275         net::EscapeUrlEncodedData(scopes_string, true).c_str()); | 283         net::EscapeUrlEncodedData(scopes_string, true).c_str()); | 
| 276   } | 284   } | 
| 277 } | 285 } | 
| 278 | 286 | 
| 279 scoped_ptr<base::DictionaryValue> ParseGetAccessTokenResponse( |  | 
| 280     const net::URLFetcher* source) { |  | 
| 281   CHECK(source); |  | 
| 282 |  | 
| 283   std::string data; |  | 
| 284   source->GetResponseAsString(&data); |  | 
| 285   scoped_ptr<base::Value> value(base::JSONReader::Read(data)); |  | 
| 286   if (!value.get() || value->GetType() != base::Value::TYPE_DICTIONARY) |  | 
| 287     value.reset(); |  | 
| 288 |  | 
| 289   return scoped_ptr<base::DictionaryValue>( |  | 
| 290       static_cast<base::DictionaryValue*>(value.release())); |  | 
| 291 } |  | 
| 292 |  | 
| 293 // static | 287 // static | 
| 294 bool OAuth2AccessTokenFetcher::ParseGetAccessTokenSuccessResponse( | 288 bool OAuth2AccessTokenFetcherImpl::ParseGetAccessTokenSuccessResponse( | 
| 295     const net::URLFetcher* source, | 289     const net::URLFetcher* source, | 
| 296     std::string* access_token, | 290     std::string* access_token, | 
| 297     int* expires_in) { | 291     int* expires_in) { | 
| 298   CHECK(access_token); | 292   CHECK(access_token); | 
| 299   scoped_ptr<base::DictionaryValue> value = ParseGetAccessTokenResponse( | 293   scoped_ptr<base::DictionaryValue> value = ParseGetAccessTokenResponse(source); | 
| 300       source); |  | 
| 301   if (value.get() == NULL) | 294   if (value.get() == NULL) | 
| 302     return false; | 295     return false; | 
| 303 | 296 | 
| 304   return value->GetString(kAccessTokenKey, access_token) && | 297   return value->GetString(kAccessTokenKey, access_token) && | 
| 305       value->GetInteger(kExpiresInKey, expires_in); | 298          value->GetInteger(kExpiresInKey, expires_in); | 
| 306 } | 299 } | 
| 307 | 300 | 
| 308 // static | 301 // static | 
| 309 bool OAuth2AccessTokenFetcher::ParseGetAccessTokenFailureResponse( | 302 bool OAuth2AccessTokenFetcherImpl::ParseGetAccessTokenFailureResponse( | 
| 310     const net::URLFetcher* source, | 303     const net::URLFetcher* source, | 
| 311     std::string* error) { | 304     std::string* error) { | 
| 312   CHECK(error); | 305   CHECK(error); | 
| 313   scoped_ptr<base::DictionaryValue> value = ParseGetAccessTokenResponse( | 306   scoped_ptr<base::DictionaryValue> value = ParseGetAccessTokenResponse(source); | 
| 314       source); |  | 
| 315   if (value.get() == NULL) | 307   if (value.get() == NULL) | 
| 316     return false; | 308     return false; | 
| 317   return value->GetString(kErrorKey, error); | 309   return value->GetString(kErrorKey, error); | 
| 318 } | 310 } | 
| OLD | NEW | 
|---|