Stack sampling profiler: add fire-and-forget interface
[chromium-blink-merge.git] / components / signin / core / browser / gaia_cookie_manager_service.cc
blobdcc74aefbeeb8347f378533f0793128ffcecea8d
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 // It is unknown if the cookie was changed because of processing initiated by
431 // this class or other (such as the user clearing all cookies or a cookie being
432 // evicted).
433 void GaiaCookieManagerService::OnCookieChanged(
434 const net::CanonicalCookie& cookie,
435 bool removed) {
436 DCHECK_EQ("APISID", cookie.Name());
437 DCHECK_EQ(GaiaUrls::GetInstance()->google_url().host(), cookie.Domain());
438 if (requests_.empty()) {
439 requests_.push_back(GaiaCookieRequest::CreateListAccountsRequest());
440 fetcher_retries_ = 0;
441 signin_client_->DelayNetworkCall(
442 base::Bind(&GaiaCookieManagerService::StartFetchingListAccounts,
443 base::Unretained(this)));
444 } else {
445 // Remove all pending ListAccount calls; for efficiency, only call
446 // after all pending requests are processed.
447 // Track requests to keep; all other unstarted requests will be removed.
448 std::vector<GaiaCookieRequest> requests_to_keep;
450 // Check all pending, non-executing requests.
451 for (auto it = requests_.begin() + 1; it != requests_.end(); ++it) {
452 // Keep all requests except for LIST_ACCOUNTS.
453 if (it->request_type() != GaiaCookieRequestType::LIST_ACCOUNTS)
454 requests_to_keep.push_back(*it);
457 // Remove all but the executing request. Re-add all requests being kept.
458 if (requests_.size() > 1) {
459 requests_.erase(requests_.begin() + 1, requests_.end());
460 requests_.insert(
461 requests_.end(), requests_to_keep.begin(), requests_to_keep.end());
463 requests_.push_back(GaiaCookieRequest::CreateListAccountsRequest());
467 void GaiaCookieManagerService::SignalComplete(
468 const std::string& account_id,
469 const GoogleServiceAuthError& error) {
470 // Its possible for the observer to delete |this| object. Don't access
471 // access any members after this calling the observer. This method should
472 // be the last call in any other method.
473 FOR_EACH_OBSERVER(Observer, observer_list_,
474 OnAddAccountToCookieCompleted(account_id, error));
477 void GaiaCookieManagerService::OnUbertokenSuccess(
478 const std::string& uber_token) {
479 DCHECK(requests_.front().request_type() ==
480 GaiaCookieRequestType::ADD_ACCOUNT);
481 VLOG(1) << "GaiaCookieManagerService::OnUbertokenSuccess"
482 << " account=" << requests_.front().account_id();
483 fetcher_retries_ = 0;
484 uber_token_ = uber_token;
486 if (!external_cc_result_fetched_ &&
487 !external_cc_result_fetcher_.IsRunning()) {
488 external_cc_result_fetcher_.Start();
489 return;
492 signin_client_->DelayNetworkCall(
493 base::Bind(&GaiaCookieManagerService::StartFetchingMergeSession,
494 base::Unretained(this)));
497 void GaiaCookieManagerService::OnUbertokenFailure(
498 const GoogleServiceAuthError& error) {
499 // Note that the UberToken fetcher already retries transient errors.
500 VLOG(1) << "Failed to retrieve ubertoken"
501 << " account=" << requests_.front().account_id()
502 << " error=" << error.ToString();
503 const std::string account_id = requests_.front().account_id();
504 HandleNextRequest();
505 SignalComplete(account_id, error);
508 void GaiaCookieManagerService::OnMergeSessionSuccess(const std::string& data) {
509 VLOG(1) << "MergeSession successful account="
510 << requests_.front().account_id();
511 DCHECK(requests_.front().request_type() ==
512 GaiaCookieRequestType::ADD_ACCOUNT);
513 const std::string account_id = requests_.front().account_id();
514 HandleNextRequest();
515 SignalComplete(account_id, GoogleServiceAuthError::AuthErrorNone());
517 fetcher_backoff_.InformOfRequest(true);
518 uber_token_ = std::string();
521 void GaiaCookieManagerService::OnMergeSessionFailure(
522 const GoogleServiceAuthError& error) {
523 DCHECK(requests_.front().request_type() ==
524 GaiaCookieRequestType::ADD_ACCOUNT);
525 VLOG(1) << "Failed MergeSession"
526 << " account=" << requests_.front().account_id()
527 << " error=" << error.ToString();
528 if (++fetcher_retries_ < kMaxFetcherRetries && error.IsTransientError()) {
529 fetcher_backoff_.InformOfRequest(false);
530 UMA_HISTOGRAM_ENUMERATION("OAuth2Login.MergeSessionRetry",
531 error.state(), GoogleServiceAuthError::NUM_STATES);
532 fetcher_timer_.Start(
533 FROM_HERE, fetcher_backoff_.GetTimeUntilRelease(),
534 base::Bind(&SigninClient::DelayNetworkCall,
535 base::Unretained(signin_client_),
536 base::Bind(
537 &GaiaCookieManagerService::StartFetchingMergeSession,
538 base::Unretained(this))));
539 return;
542 uber_token_ = std::string();
543 const std::string account_id = requests_.front().account_id();
545 UMA_HISTOGRAM_ENUMERATION("OAuth2Login.MergeSessionFailure",
546 error.state(), GoogleServiceAuthError::NUM_STATES);
547 HandleNextRequest();
548 SignalComplete(account_id, error);
551 void GaiaCookieManagerService::OnListAccountsSuccess(const std::string& data) {
552 VLOG(1) << "ListAccounts successful";
553 DCHECK(requests_.front().request_type() ==
554 GaiaCookieRequestType::LIST_ACCOUNTS);
555 fetcher_backoff_.InformOfRequest(true);
557 if (!gaia::ParseListAccountsData(data, &listed_accounts_)) {
558 listed_accounts_.clear();
559 OnListAccountsFailure(GoogleServiceAuthError(
560 GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE));
561 return;
564 for (gaia::ListedAccount& account : listed_accounts_) {
565 DCHECK(account.id.empty());
566 account.id = AccountTrackerService::PickAccountIdForAccount(
567 signin_client_->GetPrefs(), account.gaia_id, account.email);
570 list_accounts_fetched_once_ = true;
571 HandleNextRequest();
572 // HandleNextRequest before sending out the notification because some
573 // services, in response to OnGaiaAccountsInCookieUpdated, may try in return
574 // to call ListAccounts, which would immediately return false if the
575 // ListAccounts request is still sitting in queue.
576 FOR_EACH_OBSERVER(Observer, observer_list_,
577 OnGaiaAccountsInCookieUpdated(
578 listed_accounts_,
579 GoogleServiceAuthError(GoogleServiceAuthError::NONE)));
582 void GaiaCookieManagerService::OnListAccountsFailure(
583 const GoogleServiceAuthError& error) {
584 VLOG(1) << "ListAccounts failed";
585 DCHECK(requests_.front().request_type() ==
586 GaiaCookieRequestType::LIST_ACCOUNTS);
587 if (++fetcher_retries_ < kMaxFetcherRetries && error.IsTransientError()) {
588 fetcher_backoff_.InformOfRequest(false);
589 UMA_HISTOGRAM_ENUMERATION("Signin.ListAccountsRetry",
590 error.state(), GoogleServiceAuthError::NUM_STATES);
591 fetcher_timer_.Start(
592 FROM_HERE, fetcher_backoff_.GetTimeUntilRelease(),
593 base::Bind(&SigninClient::DelayNetworkCall,
594 base::Unretained(signin_client_),
595 base::Bind(
596 &GaiaCookieManagerService::StartFetchingListAccounts,
597 base::Unretained(this))));
598 return;
601 UMA_HISTOGRAM_ENUMERATION("Signin.ListAccountsFailure",
602 error.state(), GoogleServiceAuthError::NUM_STATES);
603 FOR_EACH_OBSERVER(Observer, observer_list_,
604 OnGaiaAccountsInCookieUpdated(listed_accounts_, error));
605 HandleNextRequest();
608 void GaiaCookieManagerService::OnLogOutSuccess() {
609 DCHECK(requests_.front().request_type() == GaiaCookieRequestType::LOG_OUT);
610 VLOG(1) << "GaiaCookieManagerService::OnLogOutSuccess";
612 fetcher_backoff_.InformOfRequest(true);
613 HandleNextRequest();
616 void GaiaCookieManagerService::OnLogOutFailure(
617 const GoogleServiceAuthError& error) {
618 DCHECK(requests_.front().request_type() == GaiaCookieRequestType::LOG_OUT);
619 VLOG(1) << "GaiaCookieManagerService::OnLogOutFailure";
621 if (++fetcher_retries_ < kMaxFetcherRetries) {
622 fetcher_backoff_.InformOfRequest(false);
623 fetcher_timer_.Start(
624 FROM_HERE, fetcher_backoff_.GetTimeUntilRelease(),
625 base::Bind(&SigninClient::DelayNetworkCall,
626 base::Unretained(signin_client_),
627 base::Bind(&GaiaCookieManagerService::StartFetchingLogOut,
628 base::Unretained(this))));
629 return;
632 HandleNextRequest();
635 void GaiaCookieManagerService::StartFetchingUbertoken() {
636 VLOG(1) << "GaiaCookieManagerService::StartFetchingUbertoken account_id="
637 << requests_.front().account_id();
638 uber_token_fetcher_.reset(new UbertokenFetcher(
639 token_service_, this, source_, signin_client_->GetURLRequestContext(),
640 base::Bind(&SigninClient::CreateGaiaAuthFetcher,
641 base::Unretained(signin_client_))));
642 if (access_token_.empty()) {
643 uber_token_fetcher_->StartFetchingToken(requests_.front().account_id());
644 } else {
645 uber_token_fetcher_->StartFetchingTokenWithAccessToken(
646 requests_.front().account_id(), access_token_);
650 void GaiaCookieManagerService::StartFetchingMergeSession() {
651 DCHECK(!uber_token_.empty());
652 gaia_auth_fetcher_.reset(signin_client_->CreateGaiaAuthFetcher(
653 this, source_, signin_client_->GetURLRequestContext()));
655 gaia_auth_fetcher_->StartMergeSession(uber_token_,
656 external_cc_result_fetcher_.GetExternalCcResult());
659 void GaiaCookieManagerService::StartFetchingLogOut() {
660 DCHECK(requests_.front().request_type() == GaiaCookieRequestType::LOG_OUT);
661 VLOG(1) << "GaiaCookieManagerService::StartFetchingLogOut";
662 gaia_auth_fetcher_.reset(signin_client_->CreateGaiaAuthFetcher(
663 this, source_, signin_client_->GetURLRequestContext()));
664 gaia_auth_fetcher_->StartLogOut();
667 void GaiaCookieManagerService::StartFetchingListAccounts() {
668 VLOG(1) << "GaiaCookieManagerService::ListAccounts";
669 gaia_auth_fetcher_.reset(signin_client_->CreateGaiaAuthFetcher(
670 this, source_, signin_client_->GetURLRequestContext()));
671 gaia_auth_fetcher_->StartListAccounts();
674 void GaiaCookieManagerService::HandleNextRequest() {
675 VLOG(1) << "GaiaCookieManagerService::HandleNextRequest";
676 if (requests_.front().request_type() ==
677 GaiaCookieRequestType::LIST_ACCOUNTS) {
678 // This and any directly subsequent list accounts would return the same.
679 while (!requests_.empty() && requests_.front().request_type() ==
680 GaiaCookieRequestType::LIST_ACCOUNTS) {
681 requests_.pop_front();
683 } else {
684 // Pop the completed request.
685 requests_.pop_front();
688 gaia_auth_fetcher_.reset();
689 fetcher_retries_ = 0;
690 if (requests_.empty()) {
691 VLOG(1) << "GaiaCookieManagerService::HandleNextRequest: no more";
692 uber_token_fetcher_.reset();
693 access_token_ = std::string();
694 } else {
695 switch (requests_.front().request_type()) {
696 case GaiaCookieRequestType::ADD_ACCOUNT:
697 signin_client_->DelayNetworkCall(
698 base::Bind(&GaiaCookieManagerService::StartFetchingUbertoken,
699 base::Unretained(this)));
700 break;
701 case GaiaCookieRequestType::LOG_OUT:
702 signin_client_->DelayNetworkCall(
703 base::Bind(&GaiaCookieManagerService::StartFetchingLogOut,
704 base::Unretained(this)));
705 break;
706 case GaiaCookieRequestType::LIST_ACCOUNTS:
707 uber_token_fetcher_.reset();
708 signin_client_->DelayNetworkCall(
709 base::Bind(&GaiaCookieManagerService::StartFetchingListAccounts,
710 base::Unretained(this)));
711 break;