blob: c3c8a2ead10904d79547c77eb166c5e052b71cc4 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "google_apis/gaia/merge_session_helper.h"
#include "google_apis/gaia/gaia_auth_fetcher.h"
#include "google_apis/gaia/gaia_constants.h"
#include "google_apis/gaia/gaia_urls.h"
#include "google_apis/gaia/oauth2_token_service.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_fetcher_delegate.h"
MergeSessionHelper::MergeSessionHelper(
OAuth2TokenService* token_service,
net::URLRequestContextGetter* request_context,
Observer* observer)
: token_service_(token_service),
request_context_(request_context) {
if (observer)
AddObserver(observer);
}
MergeSessionHelper::~MergeSessionHelper() {
DCHECK(accounts_.empty());
}
void MergeSessionHelper::LogIn(const std::string& account_id) {
DCHECK(!account_id.empty());
accounts_.push_back(account_id);
if (accounts_.size() == 1)
StartFetching();
}
void MergeSessionHelper::AddObserver(Observer* observer) {
observer_list_.AddObserver(observer);
}
void MergeSessionHelper::RemoveObserver(Observer* observer) {
observer_list_.RemoveObserver(observer);
}
void MergeSessionHelper::CancelAll() {
gaia_auth_fetcher_.reset();
uber_token_fetcher_.reset();
accounts_.clear();
}
void MergeSessionHelper::LogOut(
const std::string& account_id,
const std::vector<std::string>& accounts) {
DCHECK(!account_id.empty());
LogOutInternal(account_id, accounts);
}
void MergeSessionHelper::LogOutInternal(
const std::string& account_id,
const std::vector<std::string>& accounts) {
bool pending = !accounts_.empty();
if (pending) {
for (std::deque<std::string>::const_iterator it = accounts_.begin() + 1;
it != accounts_.end(); it++) {
if (!it->empty() &&
(std::find(accounts.begin(), accounts.end(), *it) == accounts.end() ||
*it == account_id)) {
// We have a pending log in request for an account followed by
// a signout.
GoogleServiceAuthError error(GoogleServiceAuthError::REQUEST_CANCELED);
SignalComplete(*it, error);
}
}
// Remove every thing in the work list besides the one that is running.
accounts_.resize(1);
}
// Signal a logout to be the next thing to do unless the pending
// action is already a logout.
if (!pending || !accounts_.front().empty())
accounts_.push_back("");
for (std::vector<std::string>::const_iterator it = accounts.begin();
it != accounts.end(); it++) {
if (*it != account_id) {
DCHECK(!it->empty());
accounts_.push_back(*it);
}
}
if (!pending)
StartLogOutUrlFetch();
}
void MergeSessionHelper::LogOutAllAccounts() {
LogOutInternal("", std::vector<std::string>());
}
void MergeSessionHelper::SignalComplete(
const std::string& account_id,
const GoogleServiceAuthError& error) {
// Its possible for the observer to delete |this| object. Don't access
// access any members after this calling the observer. This method should
// be the last call in any other method.
FOR_EACH_OBSERVER(Observer, observer_list_,
MergeSessionCompleted(account_id, error));
}
void MergeSessionHelper::StartLogOutUrlFetch() {
DCHECK(accounts_.front().empty());
GURL logout_url(GaiaUrls::GetInstance()->service_logout_url());
net::URLFetcher* fetcher =
net::URLFetcher::Create(logout_url, net::URLFetcher::GET, this);
fetcher->SetRequestContext(request_context_);
fetcher->Start();
}
void MergeSessionHelper::OnUbertokenSuccess(const std::string& uber_token) {
VLOG(1) << "MergeSessionHelper::OnUbertokenSuccess"
<< " account=" << accounts_.front();
gaia_auth_fetcher_.reset(new GaiaAuthFetcher(this,
GaiaConstants::kChromeSource,
request_context_));
gaia_auth_fetcher_->StartMergeSession(uber_token);
}
void MergeSessionHelper::OnUbertokenFailure(
const GoogleServiceAuthError& error) {
VLOG(1) << "Failed to retrieve ubertoken"
<< " account=" << accounts_.front()
<< " error=" << error.ToString();
const std::string account_id = accounts_.front();
HandleNextAccount();
SignalComplete(account_id, error);
}
void MergeSessionHelper::OnMergeSessionSuccess(const std::string& data) {
DVLOG(1) << "MergeSession successful account=" << accounts_.front();
const std::string account_id = accounts_.front();
HandleNextAccount();
SignalComplete(account_id, GoogleServiceAuthError::AuthErrorNone());
}
void MergeSessionHelper::OnMergeSessionFailure(
const GoogleServiceAuthError& error) {
VLOG(1) << "Failed MergeSession"
<< " account=" << accounts_.front()
<< " error=" << error.ToString();
const std::string account_id = accounts_.front();
HandleNextAccount();
SignalComplete(account_id, error);
}
void MergeSessionHelper::StartFetching() {
uber_token_fetcher_.reset(new UbertokenFetcher(token_service_,
this,
request_context_));
uber_token_fetcher_->StartFetchingToken(accounts_.front());
}
void MergeSessionHelper::OnURLFetchComplete(const net::URLFetcher* source) {
DCHECK(accounts_.front().empty());
HandleNextAccount();
}
void MergeSessionHelper::HandleNextAccount() {
accounts_.pop_front();
gaia_auth_fetcher_.reset();
if (accounts_.empty()) {
uber_token_fetcher_.reset();
} else {
if (accounts_.front().empty()) {
StartLogOutUrlFetch();
} else {
StartFetching();
}
}
}