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