blob: 85671c9604415d193aca009dcabe576a3ac78c39 [file] [log] [blame]
// 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.
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/callback.h"
#include "base/cancelable_callback.h"
#include "base/mac/scoped_nsobject.h"
#include "base/macros.h"
#include "base/memory/weak_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"
@class NSHTTPCookie;
@class NSHTTPCookieStorage;
@class NSArray;
namespace net {
class CookieCreationTimeManager;
// Observer for changes on |NSHTTPCookieStorge sharedHTTPCookieStorage|.
class CookieNotificationObserver {
// Called when any cookie is added, deleted or changed in
// |NSHTTPCookieStorge sharedHTTPCookieStorage|.
virtual void OnSystemCookiesChanged() = 0;
// The CookieStoreIOS is an implementation of CookieStore relying on
// NSHTTPCookieStorage, ensuring that the cookies are consistent between the
// network stack and NSHTTPCookieStorage. CookieStoreIOS is not thread safe.
// CookieStoreIOS is created synchronized with the system cookie 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.
// For not synchronized CookieStore, please see CookieStoreIOSPersistent.
class CookieStoreIOS : public net::CookieStore,
public CookieNotificationObserver {
// Creates 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.
explicit CookieStoreIOS(NSHTTPCookieStorage* cookie_storage);
~CookieStoreIOS() override;
enum CookiePolicy { ALLOW, BLOCK };
// Must be called when the state of
// |NSHTTPCookieStorage sharedHTTPCookieStorage| changes.
// Affects only those CookieStoreIOS instances that are backed by
// |NSHTTPCookieStorage sharedHTTPCookieStorage|.
static void NotifySystemCookiesChanged();
// Only one cookie store may enable metrics.
void SetMetricsEnabled();
// 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,
CookieSameSite same_site,
CookiePriority priority,
const SetCookiesCallback& callback) override;
void GetCookiesWithOptionsAsync(const GURL& url,
const net::CookieOptions& options,
const GetCookiesCallback& callback) override;
void GetCookieListWithOptionsAsync(
const GURL& url,
const net::CookieOptions& options,
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;
void DeleteCanonicalCookieAsync(
const CanonicalCookie& cookie,
const DeleteCallback& callback) override;
void DeleteAllCreatedBetweenAsync(const base::Time& delete_begin,
const base::Time& delete_end,
const DeleteCallback& callback) override;
void DeleteAllCreatedBetweenWithPredicateAsync(
const base::Time& delete_begin,
const base::Time& delete_end,
const CookiePredicate& predicate,
const DeleteCallback& callback) override;
void DeleteSessionCookiesAsync(const DeleteCallback& callback) override;
void FlushStore(const base::Closure& callback) override;
std::unique_ptr<CookieChangedSubscription> AddCallbackForCookie(
const GURL& url,
const std::string& name,
const CookieChangedCallback& callback) override;
bool IsEphemeral() override;
CookieStoreIOS(net::CookieMonster::PersistentCookieStore* persistent_store,
NSHTTPCookieStorage* system_store);
// 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);
bool metrics_enabled() { return metrics_enabled_; }
net::CookieMonster* cookie_monster() { return cookie_monster_.get(); }
const base::ThreadChecker& thread_checker() { return thread_checker_; }
// Cookie filter for DeleteCookiesWithFilter().
// Takes a cookie and a creation time and returns true the cookie must be
// deleted.
typedef base::Callback<bool(NSHTTPCookie*, base::Time)> CookieFilterFunction;
// Clears the system cookie store.
void ClearSystemStore();
// Returns true if the system cookie store policy is
// |NSHTTPCookieAcceptPolicyAlways|.
bool SystemCookiesAllowed();
// Copies the cookies to the backing CookieMonster.
virtual void WriteToCookieMonster(NSArray* system_cookies);
// Inherited CookieNotificationObserver methods.
void OnSystemCookiesChanged() override;
void DeleteCookiesWithFilter(const CookieFilterFunction& filter,
const DeleteCallback& callback);
std::unique_ptr<net::CookieMonster> cookie_monster_;
base::scoped_nsobject<NSHTTPCookieStorage> system_store_;
std::unique_ptr<CookieCreationTimeManager> creation_time_manager_;
bool metrics_enabled_;
base::CancelableClosure flush_closure_;
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,
net::CookieStore::ChangeCause cause);
// 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, 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);
// Cached values of system cookies. Only cookies which have an observer added
// with AddCallbackForCookie are kept in this cache.
std::unique_ptr<CookieCache> cookie_cache_;
// Callbacks for cookie changes installed by AddCallbackForCookie.
std::map<std::pair<GURL, std::string>,
base::WeakPtrFactory<CookieStoreIOS> weak_factory_;
} // namespace net