Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / components / signin / core / browser / gaia_cookie_manager_service.cc
blobb0b86971cc64cf709d525fe5246c644ac034d088
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.
5 #include "components/signin/core/browser/gaia_cookie_manager_service.h"
7 #include <queue>
8 #include <vector>
10 #include "base/json/json_reader.h"
11 #include "base/metrics/histogram_macros.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/time/time.h"
16 #include "base/values.h"
17 #include "components/signin/core/browser/account_tracker_service.h"
18 #include "components/signin/core/browser/signin_metrics.h"
19 #include "google_apis/gaia/gaia_auth_fetcher.h"
20 #include "google_apis/gaia/gaia_constants.h"
21 #include "google_apis/gaia/gaia_urls.h"
22 #include "google_apis/gaia/oauth2_token_service.h"
23 #include "net/base/load_flags.h"
24 #include "net/http/http_status_code.h"
25 #include "net/url_request/url_fetcher.h"
26 #include "net/url_request/url_fetcher_delegate.h"
28 namespace {
30 // In case of an error while fetching using the GaiaAuthFetcher or URLFetcher,
31 // retry with exponential backoff. Try up to 7 times within 15 minutes.
32 const net::BackoffEntry::Policy kBackoffPolicy = {
33 // Number of initial errors (in sequence) to ignore before applying
34 // exponential back-off rules.
37 // Initial delay for exponential backoff in ms.
38 1000,
40 // Factor by which the waiting time will be multiplied.
43 // Fuzzing percentage. ex: 10% will spread requests randomly
44 // between 90%-100% of the calculated time.
45 0.2, // 20%
47 // Maximum amount of time we are willing to delay our request in ms.
48 1000 * 60 * 60 * 4, // 15 minutes.
50 // Time to keep an entry from being discarded even when it
51 // has no significant state, -1 to never discard.
52 -1,
54 // Don't use initial delay unless the last request was an error.
55 false,
58 const int kMaxFetcherRetries = 8;
60 enum GaiaCookieRequestType {
61 ADD_ACCOUNT,
62 LOG_OUT_ALL_ACCOUNTS,
63 LOG_OUT_ONE_ACCOUNT,
64 LIST_ACCOUNTS
67 } // namespace
69 GaiaCookieManagerService::GaiaCookieRequest::GaiaCookieRequest(
70 GaiaCookieRequestType request_type,
71 const std::string& account_id)
72 : request_type_(request_type),
73 account_id_(account_id) {}
75 GaiaCookieManagerService::GaiaCookieRequest::~GaiaCookieRequest() {
78 // static
79 GaiaCookieManagerService::GaiaCookieRequest
80 GaiaCookieManagerService::GaiaCookieRequest::CreateAddAccountRequest(
81 const std::string& account_id) {
82 return GaiaCookieManagerService::GaiaCookieRequest(
83 GaiaCookieManagerService::GaiaCookieRequestType::ADD_ACCOUNT, account_id);
86 // static
87 GaiaCookieManagerService::GaiaCookieRequest
88 GaiaCookieManagerService::GaiaCookieRequest::CreateLogOutRequest() {
89 return GaiaCookieManagerService::GaiaCookieRequest(
90 GaiaCookieManagerService::GaiaCookieRequestType::LOG_OUT, std::string());
93 GaiaCookieManagerService::GaiaCookieRequest
94 GaiaCookieManagerService::GaiaCookieRequest::CreateListAccountsRequest() {
95 return GaiaCookieManagerService::GaiaCookieRequest(
96 GaiaCookieManagerService::GaiaCookieRequestType::LIST_ACCOUNTS,
97 std::string());
100 GaiaCookieManagerService::ExternalCcResultFetcher::ExternalCcResultFetcher(
101 GaiaCookieManagerService* helper)
102 : helper_(helper) {
103 DCHECK(helper_);
106 GaiaCookieManagerService::ExternalCcResultFetcher::~ExternalCcResultFetcher() {
107 CleanupTransientState();
110 std::string
111 GaiaCookieManagerService::ExternalCcResultFetcher::GetExternalCcResult() {
112 std::vector<std::string> results;
113 for (ResultMap::const_iterator it = results_.begin(); it != results_.end();
114 ++it) {
115 results.push_back(it->first + ":" + it->second);
117 return base::JoinString(results, ",");
120 void GaiaCookieManagerService::ExternalCcResultFetcher::Start() {
121 m_external_cc_result_start_time_ = base::Time::Now();
123 CleanupTransientState();
124 results_.clear();
125 helper_->gaia_auth_fetcher_.reset(
126 helper_->signin_client_->CreateGaiaAuthFetcher(
127 this, helper_->source_, helper_->request_context()));
128 helper_->gaia_auth_fetcher_->StartGetCheckConnectionInfo();
130 // Some fetches may timeout. Start a timer to decide when the result fetcher
131 // has waited long enough.
132 // TODO(rogerta): I have no idea how long to wait before timing out.
133 // Gaia folks say this should take no more than 2 second even in mobile.
134 // This will need to be tweaked.
135 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(5), this,
136 &GaiaCookieManagerService::ExternalCcResultFetcher::Timeout);
139 bool GaiaCookieManagerService::ExternalCcResultFetcher::IsRunning() {
140 return helper_->gaia_auth_fetcher_ || fetchers_.size() > 0u;
143 void GaiaCookieManagerService::ExternalCcResultFetcher::TimeoutForTests() {
144 Timeout();
147 void GaiaCookieManagerService::ExternalCcResultFetcher::
148 OnGetCheckConnectionInfoSuccess(const std::string& data) {
149 helper_->fetcher_backoff_.InformOfRequest(true);
150 gaia_auth_fetcher_timer_.Stop();
151 scoped_ptr<base::Value> value = base::JSONReader::Read(data);
152 const base::ListValue* list;
153 if (!value || !value->GetAsList(&list)) {
154 CleanupTransientState();
155 GetCheckConnectionInfoCompleted(false);
156 return;
159 // If there is nothing to check, terminate immediately.
160 if (list->GetSize() == 0) {
161 CleanupTransientState();
162 GetCheckConnectionInfoCompleted(true);
163 return;
166 // Start a fetcher for each connection URL that needs to be checked.
167 for (size_t i = 0; i < list->GetSize(); ++i) {
168 const base::DictionaryValue* dict;
169 if (list->GetDictionary(i, &dict)) {
170 std::string token;
171 std::string url;
172 if (dict->GetString("carryBackToken", &token) &&
173 dict->GetString("url", &url)) {
174 results_[token] = "null";
175 net::URLFetcher* fetcher = CreateFetcher(GURL(url)).release();
176 fetchers_[fetcher->GetOriginalURL()] = std::make_pair(token, fetcher);
177 fetcher->Start();
183 void GaiaCookieManagerService::ExternalCcResultFetcher::
184 OnGetCheckConnectionInfoError(const GoogleServiceAuthError& error) {
185 if (++helper_->fetcher_retries_ < kMaxFetcherRetries &&
186 error.IsTransientError()) {
187 helper_->fetcher_backoff_.InformOfRequest(false);
188 gaia_auth_fetcher_timer_.Start(
189 FROM_HERE, helper_->fetcher_backoff_.GetTimeUntilRelease(),
190 this, &GaiaCookieManagerService::ExternalCcResultFetcher::Start);
191 return;
194 CleanupTransientState();
195 GetCheckConnectionInfoCompleted(false);
198 scoped_ptr<net::URLFetcher>
199 GaiaCookieManagerService::ExternalCcResultFetcher::CreateFetcher(
200 const GURL& url) {
201 scoped_ptr<net::URLFetcher> fetcher =
202 net::URLFetcher::Create(0, url, net::URLFetcher::GET, this);
203 fetcher->SetRequestContext(helper_->request_context());
204 fetcher->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
205 net::LOAD_DO_NOT_SAVE_COOKIES);
207 // Fetchers are sometimes cancelled because a network change was detected,
208 // especially at startup and after sign-in on ChromeOS.
209 fetcher->SetAutomaticallyRetryOnNetworkChanges(1);
210 return fetcher;
213 void GaiaCookieManagerService::ExternalCcResultFetcher::OnURLFetchComplete(
214 const net::URLFetcher* source) {
215 const GURL& url = source->GetOriginalURL();
216 const net::URLRequestStatus& status = source->GetStatus();
217 int response_code = source->GetResponseCode();
218 if (status.is_success() && response_code == net::HTTP_OK &&
219 fetchers_.count(url) > 0) {
220 std::string data;
221 source->GetResponseAsString(&data);
222 // Only up to the first 16 characters of the response are important to GAIA.
223 // Truncate if needed to keep amount data sent back to GAIA down.
224 if (data.size() > 16)
225 data.resize(16);
226 results_[fetchers_[url].first] = data;
228 // Clean up tracking of this fetcher. The rest will be cleaned up after
229 // the timer expires in CleanupTransientState().
230 DCHECK_EQ(source, fetchers_[url].second);
231 fetchers_.erase(url);
232 delete source;
234 // If all expected responses have been received, cancel the timer and
235 // report the result.
236 if (fetchers_.empty()) {
237 CleanupTransientState();
238 GetCheckConnectionInfoCompleted(true);
243 void GaiaCookieManagerService::ExternalCcResultFetcher::Timeout() {
244 CleanupTransientState();
245 GetCheckConnectionInfoCompleted(false);
248 void GaiaCookieManagerService::ExternalCcResultFetcher::
249 CleanupTransientState() {
250 timer_.Stop();
251 helper_->gaia_auth_fetcher_.reset();
253 for (URLToTokenAndFetcher::const_iterator it = fetchers_.begin();
254 it != fetchers_.end(); ++it) {
255 delete it->second.second;
257 fetchers_.clear();
260 void GaiaCookieManagerService::ExternalCcResultFetcher::
261 GetCheckConnectionInfoCompleted(bool succeeded) {
262 base::TimeDelta time_to_check_connections =
263 base::Time::Now() - m_external_cc_result_start_time_;
264 signin_metrics::LogExternalCcResultFetches(succeeded,
265 time_to_check_connections);
267 helper_->external_cc_result_fetched_ = true;
268 // Since the ExternalCCResultFetcher is only Started in place of calling
269 // StartFetchingMergeSession, we can assume we need to call
270 // StartFetchingMergeSession. If this assumption becomes invalid, a Callback
271 // will need to be passed to Start() and Run() here.
272 helper_->StartFetchingMergeSession();
275 GaiaCookieManagerService::GaiaCookieManagerService(
276 OAuth2TokenService* token_service,
277 const std::string& source,
278 SigninClient* signin_client)
279 : token_service_(token_service),
280 signin_client_(signin_client),
281 external_cc_result_fetcher_(this),
282 fetcher_backoff_(&kBackoffPolicy),
283 fetcher_retries_(0),
284 source_(source),
285 external_cc_result_fetched_(false),
286 list_accounts_fetched_once_(false) {
289 GaiaCookieManagerService::~GaiaCookieManagerService() {
290 CancelAll();
291 DCHECK(requests_.empty());
294 void GaiaCookieManagerService::Init() {
295 cookie_changed_subscription_ = signin_client_->AddCookieChangedCallback(
296 GaiaUrls::GetInstance()->google_url(),
297 "APISID",
298 base::Bind(&GaiaCookieManagerService::OnCookieChanged,
299 base::Unretained(this)));
302 void GaiaCookieManagerService::Shutdown() {
303 cookie_changed_subscription_.reset();
307 void GaiaCookieManagerService::AddAccountToCookieInternal(
308 const std::string& account_id) {
309 DCHECK(!account_id.empty());
310 if (!signin_client_->AreSigninCookiesAllowed()) {
311 SignalComplete(account_id,
312 GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED));
313 return;
316 requests_.push_back(GaiaCookieRequest::CreateAddAccountRequest(account_id));
317 if (requests_.size() == 1) {
318 signin_client_->DelayNetworkCall(
319 base::Bind(&GaiaCookieManagerService::StartFetchingUbertoken,
320 base::Unretained(this)));
324 void GaiaCookieManagerService::AddAccountToCookie(
325 const std::string& account_id) {
326 VLOG(1) << "GaiaCookieManagerService::AddAccountToCookie: " << account_id;
327 access_token_ = std::string();
328 AddAccountToCookieInternal(account_id);
331 void GaiaCookieManagerService::AddAccountToCookieWithToken(
332 const std::string& account_id,
333 const std::string& access_token) {
334 VLOG(1) << "GaiaCookieManagerService::AddAccountToCookieWithToken: "
335 << account_id;
336 DCHECK(!access_token.empty());
337 access_token_ = access_token;
338 AddAccountToCookieInternal(account_id);
341 bool GaiaCookieManagerService::ListAccounts(
342 std::vector<gaia::ListedAccount>* accounts) {
343 DCHECK(accounts);
344 accounts->clear();
346 // There is a fetch currently executing (the results being provided in the
347 // parameter don't align with the fetches that have been started), or the list
348 // of accounts haven't been fetched even once.
349 if (!requests_.empty())
350 return false;
352 if (!list_accounts_fetched_once_) {
353 fetcher_retries_ = 0;
354 requests_.push_back(GaiaCookieRequest::CreateListAccountsRequest());
355 signin_client_->DelayNetworkCall(
356 base::Bind(&GaiaCookieManagerService::StartFetchingListAccounts,
357 base::Unretained(this)));
358 return false;
361 accounts->assign(listed_accounts_.begin(), listed_accounts_.end());
362 return true;
365 void GaiaCookieManagerService::LogOutAllAccounts() {
366 VLOG(1) << "GaiaCookieManagerService::LogOutAllAccounts";
368 bool log_out_queued = false;
369 if (!requests_.empty()) {
370 // Track requests to keep; all other unstarted requests will be removed.
371 std::vector<GaiaCookieRequest> requests_to_keep;
373 // Check all pending, non-executing requests.
374 for (auto it = requests_.begin() + 1; it != requests_.end(); ++it) {
375 if (it->request_type() == GaiaCookieRequestType::ADD_ACCOUNT) {
376 // We have a pending log in request for an account followed by
377 // a signout.
378 GoogleServiceAuthError error(GoogleServiceAuthError::REQUEST_CANCELED);
379 SignalComplete(it->account_id(), error);
382 // Keep all requests except for ADD_ACCOUNTS.
383 if (it->request_type() != GaiaCookieRequestType::ADD_ACCOUNT)
384 requests_to_keep.push_back(*it);
386 // Verify a LOG_OUT isn't already queued.
387 if (it->request_type() == GaiaCookieRequestType::LOG_OUT)
388 log_out_queued = true;
391 // Verify a LOG_OUT isn't currently being processed.
392 if (requests_.front().request_type() == GaiaCookieRequestType::LOG_OUT)
393 log_out_queued = true;
395 // Remove all but the executing request. Re-add all requests being kept.
396 if (requests_.size() > 1) {
397 requests_.erase(requests_.begin() + 1, requests_.end());
398 requests_.insert(
399 requests_.end(), requests_to_keep.begin(), requests_to_keep.end());
403 if (!log_out_queued) {
404 requests_.push_back(GaiaCookieRequest::CreateLogOutRequest());
405 if (requests_.size() == 1) {
406 fetcher_retries_ = 0;
407 signin_client_->DelayNetworkCall(
408 base::Bind(&GaiaCookieManagerService::StartFetchingLogOut,
409 base::Unretained(this)));
414 void GaiaCookieManagerService::AddObserver(Observer* observer) {
415 observer_list_.AddObserver(observer);
418 void GaiaCookieManagerService::RemoveObserver(Observer* observer) {
419 observer_list_.RemoveObserver(observer);
422 void GaiaCookieManagerService::CancelAll() {
423 VLOG(1) << "GaiaCookieManagerService::CancelAll";
424 gaia_auth_fetcher_.reset();
425 uber_token_fetcher_.reset();
426 requests_.clear();
427 fetcher_timer_.Stop();
430 void GaiaCookieManagerService::OnCookieChanged(
431 const net::CanonicalCookie& cookie,
432 bool removed) {
433 DCHECK_EQ("APISID", cookie.Name());
434 DCHECK_EQ(GaiaUrls::GetInstance()->google_url().host(), cookie.Domain());
435 // Ignore changes to the cookie while requests are pending. These changes
436 // are caused by the service itself as it adds accounts. A side effects is
437 // that any changes to the gaia cookie outside of this class, while requests
438 // are pending, will be lost. However, trying to process these changes could
439 // cause an endless loop (see crbug.com/516070).
440 if (requests_.empty()) {
441 requests_.push_back(GaiaCookieRequest::CreateListAccountsRequest());
442 fetcher_retries_ = 0;
443 signin_client_->DelayNetworkCall(
444 base::Bind(&GaiaCookieManagerService::StartFetchingListAccounts,
445 base::Unretained(this)));
449 void GaiaCookieManagerService::SignalComplete(
450 const std::string& account_id,
451 const GoogleServiceAuthError& error) {
452 // Its possible for the observer to delete |this| object. Don't access
453 // access any members after this calling the observer. This method should
454 // be the last call in any other method.
455 FOR_EACH_OBSERVER(Observer, observer_list_,
456 OnAddAccountToCookieCompleted(account_id, error));
459 void GaiaCookieManagerService::OnUbertokenSuccess(
460 const std::string& uber_token) {
461 DCHECK(requests_.front().request_type() ==
462 GaiaCookieRequestType::ADD_ACCOUNT);
463 VLOG(1) << "GaiaCookieManagerService::OnUbertokenSuccess"
464 << " account=" << requests_.front().account_id();
465 fetcher_retries_ = 0;
466 uber_token_ = uber_token;
468 if (!external_cc_result_fetched_ &&
469 !external_cc_result_fetcher_.IsRunning()) {
470 external_cc_result_fetcher_.Start();
471 return;
474 signin_client_->DelayNetworkCall(
475 base::Bind(&GaiaCookieManagerService::StartFetchingMergeSession,
476 base::Unretained(this)));
479 void GaiaCookieManagerService::OnUbertokenFailure(
480 const GoogleServiceAuthError& error) {
481 // Note that the UberToken fetcher already retries transient errors.
482 VLOG(1) << "Failed to retrieve ubertoken"
483 << " account=" << requests_.front().account_id()
484 << " error=" << error.ToString();
485 const std::string account_id = requests_.front().account_id();
486 HandleNextRequest();
487 SignalComplete(account_id, error);
490 void GaiaCookieManagerService::OnMergeSessionSuccess(const std::string& data) {
491 VLOG(1) << "MergeSession successful account="
492 << requests_.front().account_id();
493 DCHECK(requests_.front().request_type() ==
494 GaiaCookieRequestType::ADD_ACCOUNT);
495 const std::string account_id = requests_.front().account_id();
496 HandleNextRequest();
497 SignalComplete(account_id, GoogleServiceAuthError::AuthErrorNone());
499 fetcher_backoff_.InformOfRequest(true);
500 uber_token_ = std::string();
503 void GaiaCookieManagerService::OnMergeSessionFailure(
504 const GoogleServiceAuthError& error) {
505 DCHECK(requests_.front().request_type() ==
506 GaiaCookieRequestType::ADD_ACCOUNT);
507 VLOG(1) << "Failed MergeSession"
508 << " account=" << requests_.front().account_id()
509 << " error=" << error.ToString();
510 if (++fetcher_retries_ < kMaxFetcherRetries && error.IsTransientError()) {
511 fetcher_backoff_.InformOfRequest(false);
512 UMA_HISTOGRAM_ENUMERATION("OAuth2Login.MergeSessionRetry",
513 error.state(), GoogleServiceAuthError::NUM_STATES);
514 fetcher_timer_.Start(
515 FROM_HERE, fetcher_backoff_.GetTimeUntilRelease(),
516 base::Bind(&SigninClient::DelayNetworkCall,
517 base::Unretained(signin_client_),
518 base::Bind(
519 &GaiaCookieManagerService::StartFetchingMergeSession,
520 base::Unretained(this))));
521 return;
524 uber_token_ = std::string();
525 const std::string account_id = requests_.front().account_id();
527 UMA_HISTOGRAM_ENUMERATION("OAuth2Login.MergeSessionFailure",
528 error.state(), GoogleServiceAuthError::NUM_STATES);
529 HandleNextRequest();
530 SignalComplete(account_id, error);
533 void GaiaCookieManagerService::OnListAccountsSuccess(const std::string& data) {
534 VLOG(1) << "ListAccounts successful";
535 DCHECK(requests_.front().request_type() ==
536 GaiaCookieRequestType::LIST_ACCOUNTS);
537 fetcher_backoff_.InformOfRequest(true);
539 if (!gaia::ParseListAccountsData(data, &listed_accounts_)) {
540 listed_accounts_.clear();
541 OnListAccountsFailure(GoogleServiceAuthError(
542 GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE));
543 return;
546 for (gaia::ListedAccount& account : listed_accounts_) {
547 DCHECK(account.id.empty());
548 account.id = AccountTrackerService::PickAccountIdForAccount(
549 signin_client_->GetPrefs(), account.gaia_id, account.email);
552 list_accounts_fetched_once_ = true;
553 HandleNextRequest();
554 // HandleNextRequest before sending out the notification because some
555 // services, in response to OnGaiaAccountsInCookieUpdated, may try in return
556 // to call ListAccounts, which would immediately return false if the
557 // ListAccounts request is still sitting in queue.
558 FOR_EACH_OBSERVER(Observer, observer_list_,
559 OnGaiaAccountsInCookieUpdated(
560 listed_accounts_,
561 GoogleServiceAuthError(GoogleServiceAuthError::NONE)));
564 void GaiaCookieManagerService::OnListAccountsFailure(
565 const GoogleServiceAuthError& error) {
566 VLOG(1) << "ListAccounts failed";
567 DCHECK(requests_.front().request_type() ==
568 GaiaCookieRequestType::LIST_ACCOUNTS);
569 if (++fetcher_retries_ < kMaxFetcherRetries && error.IsTransientError()) {
570 fetcher_backoff_.InformOfRequest(false);
571 UMA_HISTOGRAM_ENUMERATION("Signin.ListAccountsRetry",
572 error.state(), GoogleServiceAuthError::NUM_STATES);
573 fetcher_timer_.Start(
574 FROM_HERE, fetcher_backoff_.GetTimeUntilRelease(),
575 base::Bind(&SigninClient::DelayNetworkCall,
576 base::Unretained(signin_client_),
577 base::Bind(
578 &GaiaCookieManagerService::StartFetchingListAccounts,
579 base::Unretained(this))));
580 return;
583 UMA_HISTOGRAM_ENUMERATION("Signin.ListAccountsFailure",
584 error.state(), GoogleServiceAuthError::NUM_STATES);
585 FOR_EACH_OBSERVER(Observer, observer_list_,
586 OnGaiaAccountsInCookieUpdated(listed_accounts_, error));
587 HandleNextRequest();
590 void GaiaCookieManagerService::OnLogOutSuccess() {
591 DCHECK(requests_.front().request_type() == GaiaCookieRequestType::LOG_OUT);
592 VLOG(1) << "GaiaCookieManagerService::OnLogOutSuccess";
594 fetcher_backoff_.InformOfRequest(true);
595 HandleNextRequest();
598 void GaiaCookieManagerService::OnLogOutFailure(
599 const GoogleServiceAuthError& error) {
600 DCHECK(requests_.front().request_type() == GaiaCookieRequestType::LOG_OUT);
601 VLOG(1) << "GaiaCookieManagerService::OnLogOutFailure";
603 if (++fetcher_retries_ < kMaxFetcherRetries) {
604 fetcher_backoff_.InformOfRequest(false);
605 fetcher_timer_.Start(
606 FROM_HERE, fetcher_backoff_.GetTimeUntilRelease(),
607 base::Bind(&SigninClient::DelayNetworkCall,
608 base::Unretained(signin_client_),
609 base::Bind(&GaiaCookieManagerService::StartFetchingLogOut,
610 base::Unretained(this))));
611 return;
614 HandleNextRequest();
617 void GaiaCookieManagerService::StartFetchingUbertoken() {
618 VLOG(1) << "GaiaCookieManagerService::StartFetchingUbertoken account_id="
619 << requests_.front().account_id();
620 uber_token_fetcher_.reset(new UbertokenFetcher(
621 token_service_, this, source_, signin_client_->GetURLRequestContext(),
622 base::Bind(&SigninClient::CreateGaiaAuthFetcher,
623 base::Unretained(signin_client_))));
624 if (access_token_.empty()) {
625 uber_token_fetcher_->StartFetchingToken(requests_.front().account_id());
626 } else {
627 uber_token_fetcher_->StartFetchingTokenWithAccessToken(
628 requests_.front().account_id(), access_token_);
632 void GaiaCookieManagerService::StartFetchingMergeSession() {
633 DCHECK(!uber_token_.empty());
634 gaia_auth_fetcher_.reset(signin_client_->CreateGaiaAuthFetcher(
635 this, source_, signin_client_->GetURLRequestContext()));
637 gaia_auth_fetcher_->StartMergeSession(uber_token_,
638 external_cc_result_fetcher_.GetExternalCcResult());
641 void GaiaCookieManagerService::StartFetchingLogOut() {
642 DCHECK(requests_.front().request_type() == GaiaCookieRequestType::LOG_OUT);
643 VLOG(1) << "GaiaCookieManagerService::StartFetchingLogOut";
644 gaia_auth_fetcher_.reset(signin_client_->CreateGaiaAuthFetcher(
645 this, source_, signin_client_->GetURLRequestContext()));
646 gaia_auth_fetcher_->StartLogOut();
649 void GaiaCookieManagerService::StartFetchingListAccounts() {
650 VLOG(1) << "GaiaCookieManagerService::ListAccounts";
651 gaia_auth_fetcher_.reset(signin_client_->CreateGaiaAuthFetcher(
652 this, source_, signin_client_->GetURLRequestContext()));
653 gaia_auth_fetcher_->StartListAccounts();
656 void GaiaCookieManagerService::HandleNextRequest() {
657 VLOG(1) << "GaiaCookieManagerService::HandleNextRequest";
658 if (requests_.front().request_type() ==
659 GaiaCookieRequestType::LIST_ACCOUNTS) {
660 // This and any directly subsequent list accounts would return the same.
661 while (!requests_.empty() && requests_.front().request_type() ==
662 GaiaCookieRequestType::LIST_ACCOUNTS) {
663 requests_.pop_front();
665 } else {
666 // Pop the completed request.
667 requests_.pop_front();
670 gaia_auth_fetcher_.reset();
671 fetcher_retries_ = 0;
672 if (requests_.empty()) {
673 VLOG(1) << "GaiaCookieManagerService::HandleNextRequest: no more";
674 uber_token_fetcher_.reset();
675 access_token_ = std::string();
676 } else {
677 switch (requests_.front().request_type()) {
678 case GaiaCookieRequestType::ADD_ACCOUNT:
679 signin_client_->DelayNetworkCall(
680 base::Bind(&GaiaCookieManagerService::StartFetchingUbertoken,
681 base::Unretained(this)));
682 break;
683 case GaiaCookieRequestType::LOG_OUT:
684 signin_client_->DelayNetworkCall(
685 base::Bind(&GaiaCookieManagerService::StartFetchingLogOut,
686 base::Unretained(this)));
687 break;
688 case GaiaCookieRequestType::LIST_ACCOUNTS:
689 uber_token_fetcher_.reset();
690 signin_client_->DelayNetworkCall(
691 base::Bind(&GaiaCookieManagerService::StartFetchingListAccounts,
692 base::Unretained(this)));
693 break;