gaia_oauth_client.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "google_apis/gaia/gaia_oauth_client.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_reader.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
10eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/strings/string_util.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "google_apis/gaia/gaia_urls.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/escape.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_status_code.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_fetcher.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_fetcher_delegate.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_context_getter.h"
187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kAccessTokenValue[] = "access_token";
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kRefreshTokenValue[] = "refresh_token";
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kExpiresInValue[] = "expires_in";
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace gaia {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Use a non-zero number, so unit tests can differentiate the URLFetcher used by
29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// this class from other fetchers (most other code just hardcodes the ID to 0).
30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst int GaiaOAuthClient::kUrlFetcherId = 17109006;
31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class GaiaOAuthClient::Core
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : public base::RefCountedThreadSafe<GaiaOAuthClient::Core>,
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      public net::URLFetcherDelegate {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Core(net::URLRequestContextGetter* request_context_getter)
37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      : num_retries_(0),
38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        request_context_getter_(request_context_getter),
39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        delegate_(NULL),
40eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        request_type_(NO_PENDING_REQUEST) {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void GetTokensFromAuthCode(const OAuthClientInfo& oauth_client_info,
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             const std::string& auth_code,
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             int max_retries,
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             GaiaOAuthClient::Delegate* delegate);
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void RefreshToken(const OAuthClientInfo& oauth_client_info,
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    const std::string& refresh_token,
49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                    const std::vector<std::string>& scopes,
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    int max_retries,
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    GaiaOAuthClient::Delegate* delegate);
52eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void GetUserEmail(const std::string& oauth_access_token,
53eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                    int max_retries,
54eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                    Delegate* delegate);
55eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void GetTokenInfo(const std::string& oauth_access_token,
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    int max_retries,
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    Delegate* delegate);
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // net::URLFetcherDelegate implementation.
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend class base::RefCountedThreadSafe<Core>;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enum RequestType {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NO_PENDING_REQUEST,
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TOKENS_FROM_AUTH_CODE,
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    REFRESH_TOKEN,
69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    TOKEN_INFO,
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    USER_INFO,
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~Core() {}
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  void MakeGaiaRequest(const GURL& url,
76eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                       const std::string& post_body,
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       int max_retries,
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       GaiaOAuthClient::Delegate* delegate);
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void HandleResponse(const net::URLFetcher* source,
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      bool* should_retry_request);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int num_retries_;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GaiaOAuthClient::Delegate* delegate_;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<net::URLFetcher> request_;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RequestType request_type_;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GaiaOAuthClient::Core::GetTokensFromAuthCode(
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const OAuthClientInfo& oauth_client_info,
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& auth_code,
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int max_retries,
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GaiaOAuthClient::Delegate* delegate) {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(request_type_, NO_PENDING_REQUEST);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_type_ = TOKENS_FROM_AUTH_CODE;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string post_body =
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "code=" + net::EscapeUrlEncodedData(auth_code, true) +
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "&client_id=" + net::EscapeUrlEncodedData(oauth_client_info.client_id,
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                true) +
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "&client_secret=" +
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      net::EscapeUrlEncodedData(oauth_client_info.client_secret, true) +
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "&redirect_uri=" +
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      net::EscapeUrlEncodedData(oauth_client_info.redirect_uri, true) +
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "&grant_type=authorization_code";
105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  MakeGaiaRequest(GURL(GaiaUrls::GetInstance()->oauth2_token_url()),
106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                  post_body, max_retries, delegate);
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GaiaOAuthClient::Core::RefreshToken(
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const OAuthClientInfo& oauth_client_info,
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& refresh_token,
112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const std::vector<std::string>& scopes,
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int max_retries,
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GaiaOAuthClient::Delegate* delegate) {
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(request_type_, NO_PENDING_REQUEST);
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_type_ = REFRESH_TOKEN;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string post_body =
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "refresh_token=" + net::EscapeUrlEncodedData(refresh_token, true) +
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "&client_id=" + net::EscapeUrlEncodedData(oauth_client_info.client_id,
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                true) +
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "&client_secret=" +
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      net::EscapeUrlEncodedData(oauth_client_info.client_secret, true) +
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "&grant_type=refresh_token";
124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!scopes.empty()) {
126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    std::string scopes_string = JoinString(scopes, ' ');
127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    post_body += "&scope=" + net::EscapeUrlEncodedData(scopes_string, true);
128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  MakeGaiaRequest(GURL(GaiaUrls::GetInstance()->oauth2_token_url()),
131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                  post_body, max_retries, delegate);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid GaiaOAuthClient::Core::GetUserEmail(const std::string& oauth_access_token,
135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                         int max_retries,
136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                         Delegate* delegate) {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(request_type_, NO_PENDING_REQUEST);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!request_.get());
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_type_ = USER_INFO;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_ = delegate;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  num_retries_ = 0;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_.reset(net::URLFetcher::Create(
143eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      kUrlFetcherId, GURL(GaiaUrls::GetInstance()->oauth_user_info_url()),
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      net::URLFetcher::GET, this));
145868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  request_->SetRequestContext(request_context_getter_.get());
146868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  request_->AddExtraRequestHeader("Authorization: OAuth " + oauth_access_token);
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  request_->SetMaxRetriesOn5xx(max_retries);
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Fetchers are sometimes cancelled because a network change was detected,
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // especially at startup and after sign-in on ChromeOS. Retrying once should
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // be enough in those cases; let the fetcher retry up to 3 times just in case.
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // http://crbug.com/163710
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  request_->SetAutomaticallyRetryOnNetworkChanges(3);
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_->Start();
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
156eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid GaiaOAuthClient::Core::GetTokenInfo(const std::string& oauth_access_token,
157eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                         int max_retries,
158eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                         Delegate* delegate) {
159eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK_EQ(request_type_, NO_PENDING_REQUEST);
160eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(!request_.get());
161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  request_type_ = TOKEN_INFO;
162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string post_body =
163eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      "access_token=" + net::EscapeUrlEncodedData(oauth_access_token, true);
164eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  MakeGaiaRequest(GURL(GaiaUrls::GetInstance()->oauth2_token_info_url()),
165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                  post_body,
166eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                  max_retries,
167eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                  delegate);
168eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
169eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GaiaOAuthClient::Core::MakeGaiaRequest(
171eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const GURL& url,
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& post_body,
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int max_retries,
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GaiaOAuthClient::Delegate* delegate) {
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!request_.get()) << "Tried to fetch two things at once!";
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_ = delegate;
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  num_retries_ = 0;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_.reset(net::URLFetcher::Create(
179eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      kUrlFetcherId, url, net::URLFetcher::POST, this));
180868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  request_->SetRequestContext(request_context_getter_.get());
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_->SetUploadData("application/x-www-form-urlencoded", post_body);
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  request_->SetMaxRetriesOn5xx(max_retries);
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // See comment on SetAutomaticallyRetryOnNetworkChanges() above.
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  request_->SetAutomaticallyRetryOnNetworkChanges(3);
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_->Start();
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// URLFetcher::Delegate implementation.
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GaiaOAuthClient::Core::OnURLFetchComplete(
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const net::URLFetcher* source) {
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool should_retry = false;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HandleResponse(source, &should_retry);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (should_retry) {
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Explicitly call ReceivedContentWasMalformed() to ensure the current
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // request gets counted as a failure for calculation of the back-off
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // period.  If it was already a failure by status code, this call will
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // be ignored.
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request_->ReceivedContentWasMalformed();
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    num_retries_++;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We must set our request_context_getter_ again because
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // URLFetcher::Core::RetryOrCompleteUrlFetch resets it to NULL...
202868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    request_->SetRequestContext(request_context_getter_.get());
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    request_->Start();
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GaiaOAuthClient::Core::HandleResponse(
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const net::URLFetcher* source,
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool* should_retry_request) {
210eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Move ownership of the request fetcher into a local scoped_ptr which
211eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // will be nuked when we're done handling the request, unless we need
212eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // to retry, in which case ownership will be returned to request_.
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<net::URLFetcher> old_request = request_.Pass();
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(source, old_request.get());
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // RC_BAD_REQUEST means the arguments are invalid. No point retrying. We are
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // done here.
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (source->GetResponseCode() == net::HTTP_BAD_REQUEST) {
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->OnOAuthError();
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
223eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  scoped_ptr<base::DictionaryValue> response_dict;
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (source->GetResponseCode() == net::HTTP_OK) {
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string data;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    source->GetResponseAsString(&data);
227eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    scoped_ptr<base::Value> message_value(base::JSONReader::Read(data));
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (message_value.get() &&
229eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        message_value->IsType(base::Value::TYPE_DICTIONARY)) {
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      response_dict.reset(
231eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          static_cast<base::DictionaryValue*>(message_value.release()));
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!response_dict.get()) {
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we don't have an access token yet and the the error was not
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // RC_BAD_REQUEST, we may need to retry.
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if ((source->GetMaxRetriesOn5xx() != -1) &&
239868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        (num_retries_ >= source->GetMaxRetriesOn5xx())) {
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Retry limit reached. Give up.
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate_->OnNetworkError(source->GetResponseCode());
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      request_ = old_request.Pass();
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *should_retry_request = true;
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RequestType type = request_type_;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_type_ = NO_PENDING_REQUEST;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (type) {
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case USER_INFO: {
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string email;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      response_dict->GetString("email", &email);
256eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      delegate_->OnGetUserEmailResponse(email);
257eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      break;
258eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
259eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
260eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    case TOKEN_INFO: {
261eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      delegate_->OnGetTokenInfoResponse(response_dict.Pass());
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case TOKENS_FROM_AUTH_CODE:
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case REFRESH_TOKEN: {
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string access_token;
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string refresh_token;
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int expires_in_seconds = 0;
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      response_dict->GetString(kAccessTokenValue, &access_token);
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      response_dict->GetString(kRefreshTokenValue, &refresh_token);
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      response_dict->GetInteger(kExpiresInValue, &expires_in_seconds);
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (access_token.empty()) {
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        delegate_->OnOAuthError();
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (type == REFRESH_TOKEN) {
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        delegate_->OnRefreshTokenResponse(access_token, expires_in_seconds);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        delegate_->OnGetTokensResponse(refresh_token,
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       access_token,
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       expires_in_seconds);
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
294eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochGaiaOAuthClient::GaiaOAuthClient(net::URLRequestContextGetter* context_getter) {
295eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  core_ = new Core(context_getter);
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GaiaOAuthClient::~GaiaOAuthClient() {
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GaiaOAuthClient::GetTokensFromAuthCode(
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const OAuthClientInfo& oauth_client_info,
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& auth_code,
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int max_retries,
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Delegate* delegate) {
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return core_->GetTokensFromAuthCode(oauth_client_info,
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      auth_code,
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      max_retries,
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      delegate);
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
312eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid GaiaOAuthClient::RefreshToken(
313eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const OAuthClientInfo& oauth_client_info,
314eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const std::string& refresh_token,
315eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const std::vector<std::string>& scopes,
316eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    int max_retries,
317eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    Delegate* delegate) {
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return core_->RefreshToken(oauth_client_info,
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             refresh_token,
320eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                             scopes,
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             max_retries,
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             delegate);
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid GaiaOAuthClient::GetUserEmail(const std::string& access_token,
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  int max_retries,
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  Delegate* delegate) {
328eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return core_->GetUserEmail(access_token, max_retries, delegate);
329eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
330eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
331eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid GaiaOAuthClient::GetTokenInfo(const std::string& access_token,
332eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                   int max_retries,
333eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                   Delegate* delegate) {
334eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return core_->GetTokenInfo(access_token, max_retries, delegate);
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace gaia
338