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#ifndef GOOGLE_APIS_GAIA_MERGE_SESSION_HELPER_H_
6#define GOOGLE_APIS_GAIA_MERGE_SESSION_HELPER_H_
7
8#include <deque>
9
10#include "base/observer_list.h"
11#include "base/timer/timer.h"
12#include "google_apis/gaia/gaia_auth_consumer.h"
13#include "google_apis/gaia/ubertoken_fetcher.h"
14#include "net/url_request/url_fetcher_delegate.h"
15
16class GaiaAuthFetcher;
17class GoogleServiceAuthError;
18class OAuth2TokenService;
19
20namespace net {
21class URLFetcher;
22class URLRequestContextGetter;
23}
24
25// Merges a Google account known to Chrome into the cookie jar.  When merging
26// multiple accounts, one instance of the helper is better than multiple
27// instances if there is the possibility that they run concurrently, since
28// changes to the cookie must be serialized.
29//
30// By default instances of MergeSessionHelper delete themselves when done.
31class MergeSessionHelper : public GaiaAuthConsumer,
32                           public UbertokenConsumer,
33                           public net::URLFetcherDelegate {
34 public:
35  class Observer {
36   public:
37    // Called whenever a merge session is completed.  The account that was
38    // merged is given by |account_id|.  If |error| is equal to
39    // GoogleServiceAuthError::AuthErrorNone() then the merge succeeeded.
40    virtual void MergeSessionCompleted(const std::string& account_id,
41                                       const GoogleServiceAuthError& error) = 0;
42   protected:
43    virtual ~Observer() {}
44  };
45
46  // Class to retrieve the external connection check results from gaia.
47  // Declared publicly for unit tests.
48  class ExternalCcResultFetcher : public GaiaAuthConsumer,
49                                  public net::URLFetcherDelegate {
50   public:
51    // Maps connection URLs, as returned by StartGetCheckConnectionInfo() to
52    // token and URLFetcher used to fetch the URL.
53    typedef std::map<GURL, std::pair<std::string, net::URLFetcher*> >
54        URLToTokenAndFetcher;
55
56    // Maps tokens to the fetched result for that token.
57    typedef std::map<std::string, std::string> ResultMap;
58
59    ExternalCcResultFetcher(MergeSessionHelper* helper);
60    virtual ~ExternalCcResultFetcher();
61
62    // Gets the current value of the external connection check result string.
63    std::string GetExternalCcResult();
64
65    // Start fetching the external CC result.  If a fetch is already in progress
66    // it is canceled.
67    void Start();
68
69    // Are external URLs still being checked?
70    bool IsRunning();
71
72    // Returns a copy of the internal token to fetcher map.
73    URLToTokenAndFetcher get_fetcher_map_for_testing() {
74      return fetchers_;
75    }
76
77    // Simulate a timeout for tests.
78    void TimeoutForTests();
79
80   private:
81    // Overridden from GaiaAuthConsumer.
82    virtual void OnGetCheckConnectionInfoSuccess(
83        const std::string& data) OVERRIDE;
84
85    // Creates and initializes a URL fetcher for doing a connection check.
86    net::URLFetcher* CreateFetcher(const GURL& url);
87
88    // Overridden from URLFetcherDelgate.
89    virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
90
91    // Any fetches still ongoing after this call are considered timed out.
92    void Timeout();
93
94    void CleanupTransientState();
95
96    MergeSessionHelper* helper_;
97    base::OneShotTimer<ExternalCcResultFetcher> timer_;
98    scoped_ptr<GaiaAuthFetcher> gaia_auth_fetcher_;
99    URLToTokenAndFetcher fetchers_;
100    ResultMap results_;
101
102    DISALLOW_COPY_AND_ASSIGN(ExternalCcResultFetcher);
103  };
104
105  MergeSessionHelper(OAuth2TokenService* token_service,
106                     net::URLRequestContextGetter* request_context,
107                     Observer* observer);
108  virtual ~MergeSessionHelper();
109
110  void LogIn(const std::string& account_id);
111
112  // Add or remove observers of this helper.
113  void AddObserver(Observer* observer);
114  void RemoveObserver(Observer* observer);
115
116  // Cancel all login requests.
117  void CancelAll();
118
119  // Signout of |account_id| given a list of accounts already signed in.
120  // Since this involves signing out of all accounts and resigning back in,
121  // the order which |accounts| are given is important as it will dictate
122  // the sign in order. |account_id| does not have to be in |accounts|.
123  void LogOut(const std::string& account_id,
124              const std::vector<std::string>& accounts);
125
126  // Signout all accounts.
127  void LogOutAllAccounts();
128
129  // Call observers when merge session completes.  This public so that callers
130  // that know that a given account is already in the cookie jar can simply
131  // inform the observers.
132  void SignalComplete(const std::string& account_id,
133                      const GoogleServiceAuthError& error);
134
135  // Returns true of there are pending log ins or outs.
136  bool is_running() const { return accounts_.size() > 0; }
137
138  // Start the process of fetching the external check connection result so that
139  // its ready when we try to perform a merge session.
140  void StartFetchingExternalCcResult();
141
142  // Returns true if the helper is still fetching external check connection
143  // results.
144  bool StillFetchingExternalCcResult();
145
146 private:
147  net::URLRequestContextGetter* request_context() { return request_context_; }
148
149  // Overridden from UbertokenConsumer.
150  virtual void OnUbertokenSuccess(const std::string& token) OVERRIDE;
151  virtual void OnUbertokenFailure(const GoogleServiceAuthError& error) OVERRIDE;
152
153  // Overridden from GaiaAuthConsumer.
154  virtual void OnMergeSessionSuccess(const std::string& data) OVERRIDE;
155  virtual void OnMergeSessionFailure(const GoogleServiceAuthError& error)
156      OVERRIDE;
157
158  void LogOutInternal(const std::string& account_id,
159                      const std::vector<std::string>& accounts);
160
161  // Starts the proess of fetching the uber token and performing a merge session
162  // for the next account.  Virtual so that it can be overriden in tests.
163  virtual void StartFetching();
164
165  // Virtual for testing purpose.
166  virtual void StartLogOutUrlFetch();
167
168  // Start the next merge session, if needed.
169  void HandleNextAccount();
170
171  // Overridden from URLFetcherDelgate.
172  virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
173
174  OAuth2TokenService* token_service_;
175  net::URLRequestContextGetter* request_context_;
176  scoped_ptr<GaiaAuthFetcher> gaia_auth_fetcher_;
177  scoped_ptr<UbertokenFetcher> uber_token_fetcher_;
178  ExternalCcResultFetcher result_fetcher_;
179
180  // A worklist for this class. Accounts names are stored here if
181  // we are pending a signin action for that account. Empty strings
182  // represent a signout request.
183  std::deque<std::string> accounts_;
184
185  // List of observers to notify when merge session completes.
186  // Makes sure list is empty on destruction.
187  ObserverList<Observer, true> observer_list_;
188
189  DISALLOW_COPY_AND_ASSIGN(MergeSessionHelper);
190};
191
192#endif  // GOOGLE_APIS_GAIA_MERGE_SESSION_HELPER_H_
193