merge_session_helper.cc revision 010d83a9304c5a91596085d917d248abff47903a
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/merge_session_helper.h"
6
7#include "google_apis/gaia/gaia_auth_fetcher.h"
8#include "google_apis/gaia/gaia_constants.h"
9#include "google_apis/gaia/gaia_urls.h"
10#include "google_apis/gaia/oauth2_token_service.h"
11#include "net/url_request/url_fetcher.h"
12#include "net/url_request/url_fetcher_delegate.h"
13
14MergeSessionHelper::MergeSessionHelper(
15    OAuth2TokenService* token_service,
16    net::URLRequestContextGetter* request_context,
17    Observer* observer)
18    : token_service_(token_service),
19      request_context_(request_context) {
20  if (observer)
21    AddObserver(observer);
22}
23
24MergeSessionHelper::~MergeSessionHelper() {
25  DCHECK(accounts_.empty());
26}
27
28void MergeSessionHelper::LogIn(const std::string& account_id) {
29  DCHECK(!account_id.empty());
30  accounts_.push_back(account_id);
31  if (accounts_.size() == 1)
32    StartFetching();
33}
34
35void MergeSessionHelper::AddObserver(Observer* observer) {
36  observer_list_.AddObserver(observer);
37}
38
39void MergeSessionHelper::RemoveObserver(Observer* observer) {
40  observer_list_.RemoveObserver(observer);
41}
42
43void MergeSessionHelper::CancelAll() {
44  gaia_auth_fetcher_.reset();
45  uber_token_fetcher_.reset();
46  accounts_.clear();
47}
48
49void MergeSessionHelper::LogOut(
50    const std::string& account_id,
51    const std::vector<std::string>& accounts) {
52  DCHECK(!account_id.empty());
53  LogOutInternal(account_id, accounts);
54}
55
56void MergeSessionHelper::LogOutInternal(
57    const std::string& account_id,
58    const std::vector<std::string>& accounts) {
59  bool pending = !accounts_.empty();
60
61  if (pending) {
62    for (std::deque<std::string>::const_iterator it = accounts_.begin() + 1;
63        it != accounts_.end(); it++) {
64      if (!it->empty() &&
65          (std::find(accounts.begin(), accounts.end(), *it) == accounts.end() ||
66           *it == account_id)) {
67        // We have a pending log in request for an account followed by
68        // a signout.
69        GoogleServiceAuthError error(GoogleServiceAuthError::REQUEST_CANCELED);
70        SignalComplete(*it, error);
71      }
72    }
73
74    // Remove every thing in the work list besides the one that is running.
75    accounts_.resize(1);
76  }
77
78  // Signal a logout to be the next thing to do unless the pending
79  // action is already a logout.
80  if (!pending || !accounts_.front().empty())
81    accounts_.push_back("");
82
83  for (std::vector<std::string>::const_iterator it = accounts.begin();
84      it != accounts.end(); it++) {
85    if (*it != account_id) {
86      DCHECK(!it->empty());
87      accounts_.push_back(*it);
88    }
89  }
90
91  if (!pending)
92    StartLogOutUrlFetch();
93}
94
95void MergeSessionHelper::LogOutAllAccounts() {
96  LogOutInternal("", std::vector<std::string>());
97}
98
99void MergeSessionHelper::SignalComplete(
100    const std::string& account_id,
101    const GoogleServiceAuthError& error) {
102  // Its possible for the observer to delete |this| object.  Don't access
103  // access any members after this calling the observer.  This method should
104  // be the last call in any other method.
105  FOR_EACH_OBSERVER(Observer, observer_list_,
106                    MergeSessionCompleted(account_id, error));
107}
108
109void MergeSessionHelper::StartLogOutUrlFetch() {
110  DCHECK(accounts_.front().empty());
111  GURL logout_url(GaiaUrls::GetInstance()->service_logout_url());
112  net::URLFetcher* fetcher =
113      net::URLFetcher::Create(logout_url, net::URLFetcher::GET, this);
114  fetcher->SetRequestContext(request_context_);
115  fetcher->Start();
116}
117
118void MergeSessionHelper::OnUbertokenSuccess(const std::string& uber_token) {
119  VLOG(1) << "MergeSessionHelper::OnUbertokenSuccess"
120          << " account=" << accounts_.front();
121  gaia_auth_fetcher_.reset(new GaiaAuthFetcher(this,
122                                               GaiaConstants::kChromeSource,
123                                               request_context_));
124  gaia_auth_fetcher_->StartMergeSession(uber_token);
125}
126
127void MergeSessionHelper::OnUbertokenFailure(
128    const GoogleServiceAuthError& error) {
129  VLOG(1) << "Failed to retrieve ubertoken"
130          << " account=" << accounts_.front()
131          << " error=" << error.ToString();
132  const std::string account_id = accounts_.front();
133  HandleNextAccount();
134  SignalComplete(account_id, error);
135}
136
137void MergeSessionHelper::OnMergeSessionSuccess(const std::string& data) {
138  DVLOG(1) << "MergeSession successful account=" << accounts_.front();
139  const std::string account_id = accounts_.front();
140  HandleNextAccount();
141  SignalComplete(account_id, GoogleServiceAuthError::AuthErrorNone());
142}
143
144void MergeSessionHelper::OnMergeSessionFailure(
145    const GoogleServiceAuthError& error) {
146  VLOG(1) << "Failed MergeSession"
147          << " account=" << accounts_.front()
148          << " error=" << error.ToString();
149  const std::string account_id = accounts_.front();
150  HandleNextAccount();
151  SignalComplete(account_id, error);
152}
153
154void MergeSessionHelper::StartFetching() {
155  uber_token_fetcher_.reset(new UbertokenFetcher(token_service_,
156                                                 this,
157                                                 request_context_));
158  uber_token_fetcher_->StartFetchingToken(accounts_.front());
159}
160
161void MergeSessionHelper::OnURLFetchComplete(const net::URLFetcher* source) {
162  DCHECK(accounts_.front().empty());
163  HandleNextAccount();
164}
165
166void MergeSessionHelper::HandleNextAccount() {
167  accounts_.pop_front();
168  gaia_auth_fetcher_.reset();
169  if (accounts_.empty()) {
170    uber_token_fetcher_.reset();
171  } else {
172    if (accounts_.front().empty()) {
173      StartLogOutUrlFetch();
174    } else {
175      StartFetching();
176    }
177  }
178}
179