summaryrefslogtreecommitdiffstats
path: root/ios/net/cookies/cookie_store_ios.h
blob: 36f92e33f962e3a2eac225dab5f37ff61d55ea32 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
// Copyright 2012 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.

#ifndef IOS_NET_COOKIES_COOKIE_STORE_IOS_H_
#define IOS_NET_COOKIES_COOKIE_STORE_IOS_H_

#include <map>
#include <string>
#include <utility>
#include <vector>

#include "base/callback.h"
#include "base/cancelable_callback.h"
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "ios/net/cookies/cookie_cache.h"
#include "net/cookies/cookie_monster.h"
#include "net/cookies/cookie_store.h"
#include "url/gurl.h"

#if defined(__OBJC__)
@class NSHTTPCookie;
@class NSHTTPCookieStorage;
@class NSArray;
#else
class NSHTTPCookie;
class NSHTTPCookieStorage;
class NSArray;
#endif

namespace net {

class CookieCreationTimeManager;

// Observer for changes on |NSHTTPCookieStorge sharedHTTPCookieStorage|.
class CookieNotificationObserver {
 public:
  // Called when any cookie is added, deleted or changed in
  // |NSHTTPCookieStorge sharedHTTPCookieStorage|.
  virtual void OnSystemCookiesChanged() = 0;
  // Called when the cookie policy changes on
  // |NSHTTPCookieStorge sharedHTTPCookieStorage|.
  virtual void OnSystemCookiePolicyChanged() = 0;
};

// The CookieStoreIOS is an implementation of CookieStore relying on
// NSHTTPCookieStorage, ensuring that the cookies are consistent between the
// network stack and the UIWebViews.
// On iOS, the Chrome CookieMonster is not used in conjunction with UIWebView,
// because UIWebView expects the cookies to be in the shared
// NSHTTPCookieStorage. In particular, javascript may read and write cookies
// there.
// CookieStoreIOS is not thread safe.
//
// At any given time, a CookieStoreIOS can either be synchronized with the
// system cookie store or not. If a CookieStoreIOS is not synchronized with the
// system store, changes are written back to the backing CookieStore. If a
// CookieStoreIOS is synchronized with the system store, changes are written
// directly to the system cookie store, then propagated to the backing store by
// OnSystemCookiesChanged, which is called by the system store once the change
// to the system store is written back.
//
// To unsynchronize, CookieStoreIOS copies the system cookie store into its
// backing CookieStore. To synchronize, CookieStoreIOS clears the system cookie
// store, copies its backing CookieStore into the system cookie store.
class CookieStoreIOS : public net::CookieStore,
                       public CookieNotificationObserver {
 public:
  // Creates a CookieStoreIOS with a default value of
  // |NSHTTPCookieStorage sharedCookieStorage| as the system's cookie store.
  explicit CookieStoreIOS(
      net::CookieMonster::PersistentCookieStore* persistent_store);

  explicit CookieStoreIOS(
      net::CookieMonster::PersistentCookieStore* persistent_store,
      NSHTTPCookieStorage* system_store);

  enum CookiePolicy { ALLOW, BLOCK };

  // Must be called on the thread where CookieStoreIOS instances live.
  // Affects only those CookieStoreIOS instances that are backed by
  // |NSHTTPCookieStorage sharedHTTPCookieStorage|.
  static void SetCookiePolicy(CookiePolicy setting);

  // Create an instance of CookieStoreIOS that is generated from the cookies
  // stored in |cookie_storage|. The CookieStoreIOS uses the |cookie_storage|
  // as its default backend and is initially synchronized with it.
  // Apple does not persist the cookies' creation dates in NSHTTPCookieStorage,
  // so callers should not expect these values to be populated.
  static CookieStoreIOS* CreateCookieStore(NSHTTPCookieStorage* cookie_storage);

  // As there is only one system store, only one CookieStoreIOS at a time may
  // be synchronized with it.
  static void SwitchSynchronizedStore(CookieStoreIOS* old_store,
                                      CookieStoreIOS* new_store);

  // Must be called when the state of
  // |NSHTTPCookieStorage sharedHTTPCookieStorage| changes.
  // Affects only those CookieStoreIOS instances that are backed by
  // |NSHTTPCookieStorage sharedHTTPCookieStorage|.
  static void NotifySystemCookiesChanged();

  // Unsynchronizes the cookie store if it is currently synchronized.
  void UnSynchronize();

  // Only one cookie store may enable metrics.
  void SetMetricsEnabled();

  // Sets the delay between flushes. Only used in tests.
  void set_flush_delay_for_testing(base::TimeDelta delay) {
    flush_delay_ = delay;
  }

  // Inherited CookieStore methods.
  void SetCookieWithOptionsAsync(const GURL& url,
                                 const std::string& cookie_line,
                                 const net::CookieOptions& options,
                                 const SetCookiesCallback& callback) override;
  void SetCookieWithDetailsAsync(const GURL& url,
                                 const std::string& name,
                                 const std::string& value,
                                 const std::string& domain,
                                 const std::string& path,
                                 base::Time creation_time,
                                 base::Time expiration_time,
                                 base::Time last_access_time,
                                 bool secure,
                                 bool http_only,
                                 bool same_site,
                                 bool enforce_strict_secure,
                                 CookiePriority priority,
                                 const SetCookiesCallback& callback) override;
  void GetCookiesWithOptionsAsync(const GURL& url,
                                  const net::CookieOptions& options,
                                  const GetCookiesCallback& callback) override;
  void GetAllCookiesForURLAsync(const GURL& url,
                                const GetCookieListCallback& callback) override;
  void GetAllCookiesAsync(const GetCookieListCallback& callback) override;
  void DeleteCookieAsync(const GURL& url,
                         const std::string& cookie_name,
                         const base::Closure& callback) override;
  net::CookieMonster* GetCookieMonster() override;
  void DeleteAllCreatedBetweenAsync(const base::Time& delete_begin,
                                    const base::Time& delete_end,
                                    const DeleteCallback& callback) override;
  void DeleteAllCreatedBetweenForHostAsync(
      const base::Time delete_begin,
      const base::Time delete_end,
      const GURL& url,
      const DeleteCallback& callback) override;
  void DeleteSessionCookiesAsync(const DeleteCallback& callback) override;
  void FlushStore(const base::Closure& callback) override;

  scoped_ptr<CookieChangedSubscription> AddCallbackForCookie(
      const GURL& url,
      const std::string& name,
      const CookieChangedCallback& callback) override;

 protected:
  ~CookieStoreIOS() override;

 private:
  // For tests.
  friend struct CookieStoreIOSTestTraits;

  enum SynchronizationState {
    NOT_SYNCHRONIZED,  // Uses CookieMonster as backend.
    SYNCHRONIZING,     // Moves from NSHTTPCookieStorage to CookieMonster.
    SYNCHRONIZED       // Uses NSHTTPCookieStorage as backend.
  };

  // Cookie fliter for DeleteCookiesWithFilter().
  // Takes a cookie and a creation time and returns true if the cookie must be
  // deleted.
  typedef base::Callback<bool(NSHTTPCookie*, base::Time)> CookieFilterFunction;

  // Clears the system cookie store.
  void ClearSystemStore();
  // Changes the synchronization of the store.
  // If |synchronized| is true, then the system cookie store is used as a
  // backend, else |cookie_monster_| is used. Cookies are moved from one to
  // the other accordingly.
  void SetSynchronizedWithSystemStore(bool synchronized);
  // Returns true if the system cookie store policy is
  // |NSHTTPCookieAcceptPolicyAlways|.
  bool SystemCookiesAllowed();
  // Converts |cookies| to NSHTTPCookie and add them to the system store.
  void AddCookiesToSystemStore(const net::CookieList& cookies);
  // Copies the cookies to the backing CookieMonster. If the cookie store is not
  // synchronized with the system store, this is a no-op.
  void WriteToCookieMonster(NSArray* system_cookies);
  // Runs all the pending tasks.
  void RunAllPendingTasks();

  // Inherited CookieNotificationObserver methods.
  void OnSystemCookiesChanged() override;
  void OnSystemCookiePolicyChanged() override;

  void DeleteCookiesWithFilter(const CookieFilterFunction& filter,
                               const DeleteCallback& callback);

  scoped_refptr<net::CookieMonster> cookie_monster_;
  NSHTTPCookieStorage* system_store_;
  scoped_ptr<CookieCreationTimeManager> creation_time_manager_;
  bool metrics_enabled_;
  base::TimeDelta flush_delay_;
  base::CancelableClosure flush_closure_;

  SynchronizationState synchronization_state_;
  // Tasks received when SYNCHRONIZING are queued and run when SYNCHRONIZED.
  std::vector<base::Closure> tasks_pending_synchronization_;

  base::ThreadChecker thread_checker_;

  // Cookie notification methods.
  // The cookie cache is updated from both the system store and the
  // CookieStoreIOS' own mutators. Changes when the CookieStoreIOS is
  // synchronized are signalled by the system store; changes when the
  // CookieStoreIOS is not synchronized are signalled by the appropriate
  // mutators on CookieStoreIOS. The cookie cache tracks the system store when
  // the CookieStoreIOS is synchronized and the CookieStore when the
  // CookieStoreIOS is not synchronized.

  // Fetches any cookies named |name| that would be sent with a request for
  // |url| from the system cookie store and pushes them onto the back of the
  // vector pointed to by |cookies|. Returns true if any cookies were pushed
  // onto the vector, and false otherwise.
  bool GetSystemCookies(const GURL& url,
                        const std::string& name,
                        std::vector<net::CanonicalCookie>* cookies);

  // Updates the cookie cache with the current set of system cookies named
  // |name| that would be sent with a request for |url|. Returns whether the
  // cache changed.
  // |out_removed_cookies|, if not null, will be populated with the cookies that
  // were removed.
  // |out_changed_cookies|, if not null, will be populated with the cookies that
  // were added.
  bool UpdateCacheForCookieFromSystem(
      const GURL& gurl,
      const std::string& name,
      std::vector<net::CanonicalCookie>* out_removed_cookies,
      std::vector<net::CanonicalCookie>* out_added_cookies);

  // Runs all callbacks registered for cookies named |name| that would be sent
  // with a request for |url|.
  // All cookies in |cookies| must have the name equal to |name|.
  void RunCallbacksForCookies(const GURL& url,
                              const std::string& name,
                              const std::vector<net::CanonicalCookie>& cookies,
                              bool removed);

  // Called by this CookieStoreIOS' internal CookieMonster instance when
  // GetAllCookiesForURLAsync() completes. Updates the cookie cache and runs
  // callbacks if the cache changed.
  void GotCookieListFor(const std::pair<GURL, std::string> key,
                        const net::CookieList& cookies);

  // Fetches new values for all (url, name) pairs that have hooks registered,
  // asynchronously invoking callbacks if necessary.
  void UpdateCachesFromCookieMonster();

  // Called after cookies are cleared from NSHTTPCookieStorage so that cookies
  // can be cleared from .binarycookies file. |callback| is called after all the
  // cookies are deleted (with the total number of cookies deleted).
  // |num_deleted| contains the number of cookies deleted from
  // NSHTTPCookieStorage.
  void DidClearNSHTTPCookieStorageCookies(const DeleteCallback& callback,
                                          int num_deleted);
  // Called after cookies are cleared from .binarycookies files. |callback| is
  // called after all the cookies are deleted with the total number of cookies
  // deleted.
  // |num_deleted_from_nshttp_cookie_storage| contains the number of cookies
  // deleted from NSHTTPCookieStorage.
  void DidClearBinaryCookiesFileCookies(
      const DeleteCallback& callback,
      int num_deleted_from_nshttp_cookie_storage);

  // Callback-wrapping:
  // When this CookieStoreIOS object is synchronized with the system store,
  // OnSystemCookiesChanged is responsible for updating the cookie cache (and
  // hence running callbacks).
  //
  // When this CookieStoreIOS object is not synchronized (or is synchronizing),
  // the various mutator methods (SetCookieWithOptionsAsync &c) instead store
  // their state in a CookieMonster object to be written back when the system
  // store synchronizes. To deliver notifications in a timely manner, the
  // mutators have to ensure that hooks get run, but only after the changes have
  // been written back to CookieMonster. To do this, the mutators wrap the
  // user-supplied callback in a callback which schedules an asynchronous task
  // to synchronize the cache and run callbacks, then calls through to the
  // user-specified callback.
  //
  // These three UpdateCachesAfter functions are responsible for scheduling an
  // asynchronous cache update (using UpdateCachesFromCookieMonster()) and
  // calling the provided callback.

  void UpdateCachesAfterSet(const SetCookiesCallback& callback, bool success);
  void UpdateCachesAfterDelete(const DeleteCallback& callback, int num_deleted);
  void UpdateCachesAfterClosure(const base::Closure& callback);

  // Takes an NSArray of NSHTTPCookies as returns a net::CookieList.
  // The returned cookies are ordered by longest path, then earliest
  // creation date.
  net::CookieList CanonicalCookieListFromSystemCookies(NSArray* cookies);

  // These three functions are used for wrapping user-supplied callbacks given
  // to CookieStoreIOS mutator methods. Given a callback, they return a new
  // callback that invokes UpdateCachesFromCookieMonster() to schedule an
  // asynchronous synchronization of the cookie cache and then calls the
  // original callback.

  SetCookiesCallback WrapSetCallback(const SetCookiesCallback& callback);
  DeleteCallback WrapDeleteCallback(const DeleteCallback& callback);
  base::Closure WrapClosure(const base::Closure& callback);

  // Cached values of system cookies. Only cookies which have an observer added
  // with AddCallbackForCookie are kept in this cache.
  scoped_ptr<CookieCache> cookie_cache_;

  // Callbacks for cookie changes installed by AddCallbackForCookie.
  typedef std::map<std::pair<GURL, std::string>, CookieChangedCallbackList*>
      CookieChangedHookMap;
  CookieChangedHookMap hook_map_;

  DISALLOW_COPY_AND_ASSIGN(CookieStoreIOS);
};

}  // namespace net

#endif  // IOS_NET_COOKIES_COOKIE_STORE_IOS_H_