summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/base/cookie_monster.h963
-rw-r--r--net/base/cookie_monster_store_test.h200
-rw-r--r--net/base/cookie_options.h34
-rw-r--r--net/base/cookie_store.h107
-rw-r--r--net/base/cookie_store_test_callbacks.h131
-rw-r--r--net/base/cookie_store_test_helpers.h101
-rw-r--r--net/base/cookie_store_unittest.h1049
-rw-r--r--net/base/cookie_util.h36
-rw-r--r--net/cookies/OWNERS1
-rw-r--r--net/cookies/cookie_monster.cc (renamed from net/base/cookie_monster.cc)4
-rw-r--r--net/cookies/cookie_monster.h971
-rw-r--r--net/cookies/cookie_monster_perftest.cc (renamed from net/base/cookie_monster_perftest.cc)6
-rw-r--r--net/cookies/cookie_monster_store_test.cc (renamed from net/base/cookie_monster_store_test.cc)4
-rw-r--r--net/cookies/cookie_monster_store_test.h206
-rw-r--r--net/cookies/cookie_monster_unittest.cc (renamed from net/base/cookie_monster_unittest.cc)8
-rw-r--r--net/cookies/cookie_options.h40
-rw-r--r--net/cookies/cookie_store.cc (renamed from net/base/cookie_store.cc)6
-rw-r--r--net/cookies/cookie_store.h113
-rw-r--r--net/cookies/cookie_store_test_callbacks.cc (renamed from net/base/cookie_store_test_callbacks.cc)2
-rw-r--r--net/cookies/cookie_store_test_callbacks.h137
-rw-r--r--net/cookies/cookie_store_test_helpers.cc (renamed from net/base/cookie_store_test_helpers.cc)2
-rw-r--r--net/cookies/cookie_store_test_helpers.h105
-rw-r--r--net/cookies/cookie_store_unittest.h1055
-rw-r--r--net/cookies/cookie_util.cc (renamed from net/base/cookie_util.cc)4
-rw-r--r--net/cookies/cookie_util.h40
-rw-r--r--net/cookies/cookie_util_unittest.cc (renamed from net/base/cookie_util_unittest.cc)2
-rw-r--r--net/net.gyp34
27 files changed, 2737 insertions, 2624 deletions
diff --git a/net/base/cookie_monster.h b/net/base/cookie_monster.h
index 0e8febb..f7ebbcc 100644
--- a/net/base/cookie_monster.h
+++ b/net/base/cookie_monster.h
@@ -2,970 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Brought to you by the letter D and the number 2.
+// Provides a temporary redirection while clients are updated to use the new
+// path.
#ifndef NET_BASE_COOKIE_MONSTER_H_
#define NET_BASE_COOKIE_MONSTER_H_
#pragma once
-#include <deque>
-#include <map>
-#include <queue>
-#include <set>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/callback_forward.h"
-#include "base/gtest_prod_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/synchronization/lock.h"
-#include "base/time.h"
-#include "net/base/cookie_store.h"
-#include "net/base/net_export.h"
-
-class GURL;
-
-namespace base {
-class Histogram;
-class TimeTicks;
-} // namespace base
-
-namespace net {
-
-class CookieList;
-
-// The cookie monster is the system for storing and retrieving cookies. It has
-// an in-memory list of all cookies, and synchronizes non-session cookies to an
-// optional permanent storage that implements the PersistentCookieStore
-// interface.
-//
-// This class IS thread-safe. Normally, it is only used on the I/O thread, but
-// is also accessed directly through Automation for UI testing.
-//
-// All cookie tasks are handled asynchronously. Tasks may be deferred if
-// all affected cookies are not yet loaded from the backing store. Otherwise,
-// the callback may be invoked immediately (prior to return of the asynchronous
-// function).
-//
-// A cookie task is either pending loading of the entire cookie store, or
-// loading of cookies for a specfic domain key(eTLD+1). In the former case, the
-// cookie task will be queued in queue_ while PersistentCookieStore chain loads
-// the cookie store on DB thread. In the latter case, the cookie task will be
-// queued in tasks_queued_ while PermanentCookieStore loads cookies for the
-// specified domain key(eTLD+1) on DB thread.
-//
-// Callbacks are guaranteed to be invoked on the calling thread.
-//
-// TODO(deanm) Implement CookieMonster, the cookie database.
-// - Verify that our domain enforcement and non-dotted handling is correct
-class NET_EXPORT CookieMonster : public CookieStore {
- public:
- class CanonicalCookie;
- class Delegate;
- class ParsedCookie;
- class PersistentCookieStore;
-
- // Terminology:
- // * The 'top level domain' (TLD) of an internet domain name is
- // the terminal "." free substring (e.g. "com" for google.com
- // or world.std.com).
- // * The 'effective top level domain' (eTLD) is the longest
- // "." initiated terminal substring of an internet domain name
- // that is controlled by a general domain registrar.
- // (e.g. "co.uk" for news.bbc.co.uk).
- // * The 'effective top level domain plus one' (eTLD+1) is the
- // shortest "." delimited terminal substring of an internet
- // domain name that is not controlled by a general domain
- // registrar (e.g. "bbc.co.uk" for news.bbc.co.uk, or
- // "google.com" for news.google.com). The general assumption
- // is that all hosts and domains under an eTLD+1 share some
- // administrative control.
-
- // CookieMap is the central data structure of the CookieMonster. It
- // is a map whose values are pointers to CanonicalCookie data
- // structures (the data structures are owned by the CookieMonster
- // and must be destroyed when removed from the map). The key is based on the
- // effective domain of the cookies. If the domain of the cookie has an
- // eTLD+1, that is the key for the map. If the domain of the cookie does not
- // have an eTLD+1, the key of the map is the host the cookie applies to (it is
- // not legal to have domain cookies without an eTLD+1). This rule
- // excludes cookies for, e.g, ".com", ".co.uk", or ".internalnetwork".
- // This behavior is the same as the behavior in Firefox v 3.6.10.
-
- // NOTE(deanm):
- // I benchmarked hash_multimap vs multimap. We're going to be query-heavy
- // so it would seem like hashing would help. However they were very
- // close, with multimap being a tiny bit faster. I think this is because
- // our map is at max around 1000 entries, and the additional complexity
- // for the hashing might not overcome the O(log(1000)) for querying
- // a multimap. Also, multimap is standard, another reason to use it.
- // TODO(rdsmith): This benchmark should be re-done now that we're allowing
- // subtantially more entries in the map.
- typedef std::multimap<std::string, CanonicalCookie*> CookieMap;
- typedef std::pair<CookieMap::iterator, CookieMap::iterator> CookieMapItPair;
-
- // The store passed in should not have had Init() called on it yet. This
- // class will take care of initializing it. The backing store is NOT owned by
- // this class, but it must remain valid for the duration of the cookie
- // monster's existence. If |store| is NULL, then no backing store will be
- // updated. If |delegate| is non-NULL, it will be notified on
- // creation/deletion of cookies.
- CookieMonster(PersistentCookieStore* store, Delegate* delegate);
-
- // Only used during unit testing.
- CookieMonster(PersistentCookieStore* store,
- Delegate* delegate,
- int last_access_threshold_milliseconds);
-
- // Parses the string with the cookie time (very forgivingly).
- static base::Time ParseCookieTime(const std::string& time_string);
-
- // Helper function that adds all cookies from |list| into this instance.
- bool InitializeFrom(const CookieList& list);
-
- typedef base::Callback<void(const CookieList& cookies)> GetCookieListCallback;
- typedef base::Callback<void(bool success)> DeleteCookieCallback;
-
- // Sets a cookie given explicit user-provided cookie attributes. The cookie
- // name, value, domain, etc. are each provided as separate strings. This
- // function expects each attribute to be well-formed. It will check for
- // disallowed characters (e.g. the ';' character is disallowed within the
- // cookie value attribute) and will return false without setting the cookie
- // if such characters are found.
- void SetCookieWithDetailsAsync(const GURL& url,
- const std::string& name,
- const std::string& value,
- const std::string& domain,
- const std::string& path,
- const base::Time& expiration_time,
- bool secure, bool http_only,
- const SetCookiesCallback& callback);
-
-
- // Returns all the cookies, for use in management UI, etc. This does not mark
- // the cookies as having been accessed.
- // The returned cookies are ordered by longest path, then by earliest
- // creation date.
- void GetAllCookiesAsync(const GetCookieListCallback& callback);
-
- // Returns all the cookies, for use in management UI, etc. Filters results
- // using given url scheme, host / domain and path and options. This does not
- // mark the cookies as having been accessed.
- // The returned cookies are ordered by longest path, then earliest
- // creation date.
- void GetAllCookiesForURLWithOptionsAsync(
- const GURL& url,
- const CookieOptions& options,
- const GetCookieListCallback& callback);
-
- // Invokes GetAllCookiesForURLWithOptions with options set to include HTTP
- // only cookies.
- void GetAllCookiesForURLAsync(const GURL& url,
- const GetCookieListCallback& callback);
-
- // Deletes all of the cookies.
- void DeleteAllAsync(const DeleteCallback& callback);
-
- // Deletes all cookies that match the host of the given URL
- // regardless of path. This includes all http_only and secure cookies,
- // but does not include any domain cookies that may apply to this host.
- // Returns the number of cookies deleted.
- void DeleteAllForHostAsync(const GURL& url,
- const DeleteCallback& callback);
-
- // Deletes one specific cookie.
- void DeleteCanonicalCookieAsync(const CanonicalCookie& cookie,
- const DeleteCookieCallback& callback);
-
- // Override the default list of schemes that are allowed to be set in
- // this cookie store. Calling his overrides the value of
- // "enable_file_scheme_".
- // If this this method is called, it must be called before first use of
- // the instance (i.e. as part of the instance initialization process).
- void SetCookieableSchemes(const char* schemes[], size_t num_schemes);
-
- // Instructs the cookie monster to not delete expired cookies. This is used
- // in cases where the cookie monster is used as a data structure to keep
- // arbitrary cookies.
- void SetKeepExpiredCookies();
-
- // Delegates the call to set the |clear_local_store_on_exit_| flag of the
- // PersistentStore if it exists.
- void SetClearPersistentStoreOnExit(bool clear_local_store);
-
- // There are some unknowns about how to correctly handle file:// cookies,
- // and our implementation for this is not robust enough. This allows you
- // to enable support, but it should only be used for testing. Bug 1157243.
- // Must be called before creating a CookieMonster instance.
- static void EnableFileScheme();
-
- // Flush the backing store (if any) to disk and post the given callback when
- // done.
- // WARNING: THE CALLBACK WILL RUN ON A RANDOM THREAD. IT MUST BE THREAD SAFE.
- // It may be posted to the current thread, or it may run on the thread that
- // actually does the flushing. Your Task should generally post a notification
- // to the thread you actually want to be notified on.
- void FlushStore(const base::Closure& callback);
-
- // CookieStore implementation.
-
- // Sets the cookies specified by |cookie_list| returned from |url|
- // with options |options| in effect.
- virtual void SetCookieWithOptionsAsync(
- const GURL& url,
- const std::string& cookie_line,
- const CookieOptions& options,
- const SetCookiesCallback& callback) OVERRIDE;
-
- // Gets all cookies that apply to |url| given |options|.
- // The returned cookies are ordered by longest path, then earliest
- // creation date.
- virtual void GetCookiesWithOptionsAsync(
- const GURL& url,
- const CookieOptions& options,
- const GetCookiesCallback& callback) OVERRIDE;
-
- virtual void GetCookiesWithInfoAsync(
- const GURL& url,
- const CookieOptions& options,
- const GetCookieInfoCallback& callback) OVERRIDE;
-
- // Deletes all cookies with that might apply to |url| that has |cookie_name|.
- virtual void DeleteCookieAsync(
- const GURL& url, const std::string& cookie_name,
- const base::Closure& callback) OVERRIDE;
-
- // Deletes all of the cookies that have a creation_date greater than or equal
- // to |delete_begin| and less than |delete_end|
- // Returns the number of cookies that have been deleted.
- virtual void DeleteAllCreatedBetweenAsync(
- const base::Time& delete_begin,
- const base::Time& delete_end,
- const DeleteCallback& callback) OVERRIDE;
-
- virtual CookieMonster* GetCookieMonster() OVERRIDE;
-
- // Enables writing session cookies into the cookie database. If this this
- // method is called, it must be called before first use of the instance
- // (i.e. as part of the instance initialization process).
- void SetPersistSessionCookies(bool persist_session_cookies);
-
- // Protects session cookies from deletion on shutdown.
- void SaveSessionCookies();
-
- // Debugging method to perform various validation checks on the map.
- // Currently just checking that there are no null CanonicalCookie pointers
- // in the map.
- // Argument |arg| is to allow retaining of arbitrary data if the CHECKs
- // in the function trip. TODO(rdsmith):Remove hack.
- void ValidateMap(int arg);
-
- // The default list of schemes the cookie monster can handle.
- static const char* kDefaultCookieableSchemes[];
- static const int kDefaultCookieableSchemesCount;
-
- private:
- // For queueing the cookie monster calls.
- class CookieMonsterTask;
- class DeleteAllCreatedBetweenTask;
- class DeleteAllForHostTask;
- class DeleteAllTask;
- class DeleteCookieTask;
- class DeleteCanonicalCookieTask;
- class GetAllCookiesForURLWithOptionsTask;
- class GetAllCookiesTask;
- class GetCookiesWithOptionsTask;
- class GetCookiesWithInfoTask;
- class SetCookieWithDetailsTask;
- class SetCookieWithOptionsTask;
-
- // Testing support.
- // For SetCookieWithCreationTime.
- FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest,
- TestCookieDeleteAllCreatedBetweenTimestamps);
-
- // For gargage collection constants.
- FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest, TestHostGarbageCollection);
- FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest, TestTotalGarbageCollection);
- FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest, GarbageCollectionTriggers);
- FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest, TestGCTimes);
-
- // For validation of key values.
- FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest, TestDomainTree);
- FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest, TestImport);
- FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest, GetKey);
- FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest, TestGetKey);
-
- // For FindCookiesForKey.
- FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest, ShortLivedSessionCookies);
-
- // Internal reasons for deletion, used to populate informative histograms
- // and to provide a public cause for onCookieChange notifications.
- //
- // If you add or remove causes from this list, please be sure to also update
- // the Delegate::ChangeCause mapping inside ChangeCauseMapping. Moreover,
- // these are used as array indexes, so avoid reordering to keep the
- // histogram buckets consistent. New items (if necessary) should be added
- // at the end of the list, just before DELETE_COOKIE_LAST_ENTRY.
- enum DeletionCause {
- DELETE_COOKIE_EXPLICIT = 0,
- DELETE_COOKIE_OVERWRITE,
- DELETE_COOKIE_EXPIRED,
- DELETE_COOKIE_EVICTED,
- DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE,
- DELETE_COOKIE_DONT_RECORD, // e.g. For final cleanup after flush to store.
- DELETE_COOKIE_EVICTED_DOMAIN,
- DELETE_COOKIE_EVICTED_GLOBAL,
-
- // Cookies evicted during domain level garbage collection that
- // were accessed longer ago than kSafeFromGlobalPurgeDays
- DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE,
-
- // Cookies evicted during domain level garbage collection that
- // were accessed more recently than kSafeFromGlobalPurgeDays
- // (and thus would have been preserved by global garbage collection).
- DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE,
-
- // A common idiom is to remove a cookie by overwriting it with an
- // already-expired expiration date. This captures that case.
- DELETE_COOKIE_EXPIRED_OVERWRITE,
-
- DELETE_COOKIE_LAST_ENTRY
- };
-
- // Cookie garbage collection thresholds. Based off of the Mozilla defaults.
- // When the number of cookies gets to k{Domain,}MaxCookies
- // purge down to k{Domain,}MaxCookies - k{Domain,}PurgeCookies.
- // It might seem scary to have a high purge value, but really it's not.
- // You just make sure that you increase the max to cover the increase
- // in purge, and we would have been purging the same amount of cookies.
- // We're just going through the garbage collection process less often.
- // Note that the DOMAIN values are per eTLD+1; see comment for the
- // CookieMap typedef. So, e.g., the maximum number of cookies allowed for
- // google.com and all of its subdomains will be 150-180.
- //
- // Any cookies accessed more recently than kSafeFromGlobalPurgeDays will not
- // be evicted by global garbage collection, even if we have more than
- // kMaxCookies. This does not affect domain garbage collection.
- //
- // Present in .h file to make accessible to tests through FRIEND_TEST.
- // Actual definitions are in cookie_monster.cc.
- static const size_t kDomainMaxCookies;
- static const size_t kDomainPurgeCookies;
- static const size_t kMaxCookies;
- static const size_t kPurgeCookies;
-
- // The number of days since last access that cookies will not be subject
- // to global garbage collection.
- static const int kSafeFromGlobalPurgeDays;
-
- // Record statistics every kRecordStatisticsIntervalSeconds of uptime.
- static const int kRecordStatisticsIntervalSeconds = 10 * 60;
-
- virtual ~CookieMonster();
-
- // The following are synchronous calls to which the asynchronous methods
- // delegate either immediately (if the store is loaded) or through a deferred
- // task (if the store is not yet loaded).
- bool SetCookieWithDetails(const GURL& url,
- const std::string& name,
- const std::string& value,
- const std::string& domain,
- const std::string& path,
- const base::Time& expiration_time,
- bool secure, bool http_only);
-
- CookieList GetAllCookies();
-
- CookieList GetAllCookiesForURLWithOptions(const GURL& url,
- const CookieOptions& options);
-
- CookieList GetAllCookiesForURL(const GURL& url);
-
- int DeleteAll(bool sync_to_store);
-
- int DeleteAllCreatedBetween(const base::Time& delete_begin,
- const base::Time& delete_end);
-
- int DeleteAllForHost(const GURL& url);
-
- bool DeleteCanonicalCookie(const CanonicalCookie& cookie);
-
- bool SetCookieWithOptions(const GURL& url,
- const std::string& cookie_line,
- const CookieOptions& options);
-
- std::string GetCookiesWithOptions(const GURL& url,
- const CookieOptions& options);
-
- void GetCookiesWithInfo(const GURL& url,
- const CookieOptions& options,
- std::string* cookie_line,
- std::vector<CookieInfo>* cookie_infos);
-
- void DeleteCookie(const GURL& url, const std::string& cookie_name);
-
- bool SetCookieWithCreationTime(const GURL& url,
- const std::string& cookie_line,
- const base::Time& creation_time);
-
- // Called by all non-static functions to ensure that the cookies store has
- // been initialized. This is not done during creating so it doesn't block
- // the window showing.
- // Note: this method should always be called with lock_ held.
- void InitIfNecessary() {
- if (!initialized_) {
- if (store_) {
- InitStore();
- } else {
- loaded_ = true;
- }
- initialized_ = true;
- }
- }
-
- // Initializes the backing store and reads existing cookies from it.
- // Should only be called by InitIfNecessary().
- void InitStore();
-
- // Stores cookies loaded from the backing store and invokes any deferred
- // calls. |beginning_time| should be the moment PersistentCookieStore::Load
- // was invoked and is used for reporting histogram_time_blocked_on_load_.
- // See PersistentCookieStore::Load for details on the contents of cookies.
- void OnLoaded(base::TimeTicks beginning_time,
- const std::vector<CanonicalCookie*>& cookies);
-
- // Stores cookies loaded from the backing store and invokes the deferred
- // task(s) pending loading of cookies associated with the domain key
- // (eTLD+1). Called when all cookies for the domain key(eTLD+1) have been
- // loaded from DB. See PersistentCookieStore::Load for details on the contents
- // of cookies.
- void OnKeyLoaded(
- const std::string& key,
- const std::vector<CanonicalCookie*>& cookies);
-
- // Stores the loaded cookies.
- void StoreLoadedCookies(const std::vector<CanonicalCookie*>& cookies);
-
- // Invokes deferred calls.
- void InvokeQueue();
-
- // Checks that |cookies_| matches our invariants, and tries to repair any
- // inconsistencies. (In other words, it does not have duplicate cookies).
- void EnsureCookiesMapIsValid();
-
- // Checks for any duplicate cookies for CookieMap key |key| which lie between
- // |begin| and |end|. If any are found, all but the most recent are deleted.
- // Returns the number of duplicate cookies that were deleted.
- int TrimDuplicateCookiesForKey(const std::string& key,
- CookieMap::iterator begin,
- CookieMap::iterator end);
-
- void SetDefaultCookieableSchemes();
-
- void FindCookiesForHostAndDomain(const GURL& url,
- const CookieOptions& options,
- bool update_access_time,
- std::vector<CanonicalCookie*>* cookies);
-
- void FindCookiesForKey(const std::string& key,
- const GURL& url,
- const CookieOptions& options,
- const base::Time& current,
- bool update_access_time,
- std::vector<CanonicalCookie*>* cookies);
-
- // Delete any cookies that are equivalent to |ecc| (same path, domain, etc).
- // If |skip_httponly| is true, httponly cookies will not be deleted. The
- // return value with be true if |skip_httponly| skipped an httponly cookie.
- // |key| is the key to find the cookie in cookies_; see the comment before
- // the CookieMap typedef for details.
- // NOTE: There should never be more than a single matching equivalent cookie.
- bool DeleteAnyEquivalentCookie(const std::string& key,
- const CanonicalCookie& ecc,
- bool skip_httponly,
- bool already_expired);
-
- // Takes ownership of *cc.
- void InternalInsertCookie(const std::string& key,
- CanonicalCookie* cc,
- bool sync_to_store);
-
- // Helper function that sets cookies with more control.
- // Not exposed as we don't want callers to have the ability
- // to specify (potentially duplicate) creation times.
- bool SetCookieWithCreationTimeAndOptions(const GURL& url,
- const std::string& cookie_line,
- const base::Time& creation_time,
- const CookieOptions& options);
-
- // Helper function that sets a canonical cookie, deleting equivalents and
- // performing garbage collection.
- bool SetCanonicalCookie(scoped_ptr<CanonicalCookie>* cc,
- const base::Time& creation_time,
- const CookieOptions& options);
-
- void InternalUpdateCookieAccessTime(CanonicalCookie* cc,
- const base::Time& current_time);
-
- // |deletion_cause| argument is used for collecting statistics and choosing
- // the correct Delegate::ChangeCause for OnCookieChanged notifications.
- void InternalDeleteCookie(CookieMap::iterator it, bool sync_to_store,
- DeletionCause deletion_cause);
-
- // If the number of cookies for CookieMap key |key|, or globally, are
- // over the preset maximums above, garbage collect, first for the host and
- // then globally. See comments above garbage collection threshold
- // constants for details.
- //
- // Returns the number of cookies deleted (useful for debugging).
- int GarbageCollect(const base::Time& current, const std::string& key);
-
- // Helper for GarbageCollect(); can be called directly as well. Deletes
- // all expired cookies in |itpair|. If |cookie_its| is non-NULL, it is
- // populated with all the non-expired cookies from |itpair|.
- //
- // Returns the number of cookies deleted.
- int GarbageCollectExpired(const base::Time& current,
- const CookieMapItPair& itpair,
- std::vector<CookieMap::iterator>* cookie_its);
-
- // Helper for GarbageCollect(). Deletes all cookies in the list
- // that were accessed before |keep_accessed_after|, using DeletionCause
- // |cause|. If |keep_accessed_after| is null, deletes all cookies in the
- // list. Returns the number of cookies deleted.
- int GarbageCollectDeleteList(const base::Time& current,
- const base::Time& keep_accessed_after,
- DeletionCause cause,
- std::vector<CookieMap::iterator>& cookie_its);
-
- // Find the key (for lookup in cookies_) based on the given domain.
- // See comment on keys before the CookieMap typedef.
- std::string GetKey(const std::string& domain) const;
-
- bool HasCookieableScheme(const GURL& url);
-
- // Statistics support
-
- // This function should be called repeatedly, and will record
- // statistics if a sufficient time period has passed.
- void RecordPeriodicStats(const base::Time& current_time);
-
- // Initialize the above variables; should only be called from
- // the constructor.
- void InitializeHistograms();
-
- // The resolution of our time isn't enough, so we do something
- // ugly and increment when we've seen the same time twice.
- base::Time CurrentTime();
-
- // Runs the task if, or defers the task until, the full cookie database is
- // loaded.
- void DoCookieTask(const scoped_refptr<CookieMonsterTask>& task_item);
-
- // Runs the task if, or defers the task until, the cookies for the given URL
- // are loaded.
- void DoCookieTaskForURL(const scoped_refptr<CookieMonsterTask>& task_item,
- const GURL& url);
-
- // Histogram variables; see CookieMonster::InitializeHistograms() in
- // cookie_monster.cc for details.
- base::Histogram* histogram_expiration_duration_minutes_;
- base::Histogram* histogram_between_access_interval_minutes_;
- base::Histogram* histogram_evicted_last_access_minutes_;
- base::Histogram* histogram_count_;
- base::Histogram* histogram_domain_count_;
- base::Histogram* histogram_etldp1_count_;
- base::Histogram* histogram_domain_per_etldp1_count_;
- base::Histogram* histogram_number_duplicate_db_cookies_;
- base::Histogram* histogram_cookie_deletion_cause_;
- base::Histogram* histogram_time_get_;
- base::Histogram* histogram_time_mac_;
- base::Histogram* histogram_time_blocked_on_load_;
-
- CookieMap cookies_;
-
- // Indicates whether the cookie store has been initialized. This happens
- // lazily in InitStoreIfNecessary().
- bool initialized_;
-
- // Indicates whether loading from the backend store is completed and
- // calls may be immediately processed.
- bool loaded_;
-
- // List of domain keys that have been loaded from the DB.
- std::set<std::string> keys_loaded_;
-
- // Map of domain keys to their associated task queues. These tasks are blocked
- // until all cookies for the associated domain key eTLD+1 are loaded from the
- // backend store.
- std::map<std::string, std::deque<scoped_refptr<CookieMonsterTask> > >
- tasks_queued_;
-
- // Queues tasks that are blocked until all cookies are loaded from the backend
- // store.
- std::queue<scoped_refptr<CookieMonsterTask> > queue_;
-
- scoped_refptr<PersistentCookieStore> store_;
-
- base::Time last_time_seen_;
-
- // Minimum delay after updating a cookie's LastAccessDate before we will
- // update it again.
- const base::TimeDelta last_access_threshold_;
-
- // Approximate date of access time of least recently accessed cookie
- // in |cookies_|. Note that this is not guaranteed to be accurate, only a)
- // to be before or equal to the actual time, and b) to be accurate
- // immediately after a garbage collection that scans through all the cookies.
- // This value is used to determine whether global garbage collection might
- // find cookies to purge.
- // Note: The default Time() constructor will create a value that compares
- // earlier than any other time value, which is wanted. Thus this
- // value is not initialized.
- base::Time earliest_access_time_;
-
- // During loading, holds the set of all loaded cookie creation times. Used to
- // avoid ever letting cookies with duplicate creation times into the store;
- // that way we don't have to worry about what sections of code are safe
- // to call while it's in that state.
- std::set<int64> creation_times_;
-
- std::vector<std::string> cookieable_schemes_;
-
- scoped_refptr<Delegate> delegate_;
-
- // Lock for thread-safety
- base::Lock lock_;
-
- base::Time last_statistic_record_time_;
-
- bool keep_expired_cookies_;
- bool persist_session_cookies_;
-
- static bool enable_file_scheme_;
-
- DISALLOW_COPY_AND_ASSIGN(CookieMonster);
-};
-
-class NET_EXPORT CookieMonster::CanonicalCookie {
- public:
-
- // These constructors do no validation or canonicalization of their inputs;
- // the resulting CanonicalCookies should not be relied on to be canonical
- // unless the caller has done appropriate validation and canonicalization
- // themselves.
- CanonicalCookie();
- CanonicalCookie(const GURL& url,
- const std::string& name,
- const std::string& value,
- const std::string& domain,
- const std::string& path,
- const std::string& mac_key,
- const std::string& mac_algorithm,
- const base::Time& creation,
- const base::Time& expiration,
- const base::Time& last_access,
- bool secure,
- bool httponly,
- bool has_expires,
- bool is_persistent);
-
- // This constructor does canonicalization but not validation.
- // The result of this constructor should not be relied on in contexts
- // in which pre-validation of the ParsedCookie has not been done.
- CanonicalCookie(const GURL& url, const ParsedCookie& pc);
-
- ~CanonicalCookie();
-
- // Supports the default copy constructor.
-
- // Creates a canonical cookie from parsed cookie.
- // Canonicalizes and validates inputs. May return NULL if an attribute
- // value is invalid.
- static CanonicalCookie* Create(const GURL& url,
- const ParsedCookie& pc);
-
- // Creates a canonical cookie from unparsed attribute values.
- // Canonicalizes and validates inputs. May return NULL if an attribute
- // value is invalid.
- static CanonicalCookie* Create(const GURL& url,
- const std::string& name,
- const std::string& value,
- const std::string& domain,
- const std::string& path,
- const std::string& mac_key,
- const std::string& mac_algorithm,
- const base::Time& creation,
- const base::Time& expiration,
- bool secure,
- bool http_only,
- bool is_persistent);
-
- const std::string& Source() const { return source_; }
- const std::string& Name() const { return name_; }
- const std::string& Value() const { return value_; }
- const std::string& Domain() const { return domain_; }
- const std::string& Path() const { return path_; }
- const std::string& MACKey() const { return mac_key_; }
- const std::string& MACAlgorithm() const { return mac_algorithm_; }
- const base::Time& CreationDate() const { return creation_date_; }
- const base::Time& LastAccessDate() const { return last_access_date_; }
- bool DoesExpire() const { return has_expires_; }
- bool IsPersistent() const { return is_persistent_; }
- const base::Time& ExpiryDate() const { return expiry_date_; }
- bool IsSecure() const { return secure_; }
- bool IsHttpOnly() const { return httponly_; }
- bool IsDomainCookie() const {
- return !domain_.empty() && domain_[0] == '.'; }
- bool IsHostCookie() const { return !IsDomainCookie(); }
-
- bool IsExpired(const base::Time& current) {
- return has_expires_ && current >= expiry_date_;
- }
-
- // Are the cookies considered equivalent in the eyes of RFC 2965.
- // The RFC says that name must match (case-sensitive), domain must
- // match (case insensitive), and path must match (case sensitive).
- // For the case insensitive domain compare, we rely on the domain
- // having been canonicalized (in
- // GetCookieDomainWithString->CanonicalizeHost).
- bool IsEquivalent(const CanonicalCookie& ecc) const {
- // It seems like it would make sense to take secure and httponly into
- // account, but the RFC doesn't specify this.
- // NOTE: Keep this logic in-sync with TrimDuplicateCookiesForHost().
- return (name_ == ecc.Name() && domain_ == ecc.Domain()
- && path_ == ecc.Path());
- }
-
- void SetLastAccessDate(const base::Time& date) {
- last_access_date_ = date;
- }
-
- bool IsOnPath(const std::string& url_path) const;
- bool IsDomainMatch(const std::string& scheme, const std::string& host) const;
-
- std::string DebugString() const;
-
- // Returns the cookie source when cookies are set for |url|. This function
- // is public for unit test purposes only.
- static std::string GetCookieSourceFromURL(const GURL& url);
-
- private:
- // Gives the session cookie an expiration time if needed
- void SetSessionCookieExpiryTime();
-
- // The source member of a canonical cookie is the origin of the URL that tried
- // to set this cookie, minus the port number if any. This field is not
- // persistent though; its only used in the in-tab cookies dialog to show the
- // user the source URL. This is used for both allowed and blocked cookies.
- // When a CanonicalCookie is constructed from the backing store (common case)
- // this field will be null. CanonicalCookie consumers should not rely on
- // this field unless they guarantee that the creator of those
- // CanonicalCookies properly initialized the field.
- // TODO(abarth): We might need to make this field persistent for MAC cookies.
- std::string source_;
- std::string name_;
- std::string value_;
- std::string domain_;
- std::string path_;
- std::string mac_key_; // TODO(abarth): Persist to disk.
- std::string mac_algorithm_; // TODO(abarth): Persist to disk.
- base::Time creation_date_;
- base::Time expiry_date_;
- base::Time last_access_date_;
- bool secure_;
- bool httponly_;
- bool has_expires_;
- bool is_persistent_;
-};
-
-class CookieMonster::Delegate
- : public base::RefCountedThreadSafe<CookieMonster::Delegate> {
- public:
- // The publicly relevant reasons a cookie might be changed.
- enum ChangeCause {
- // The cookie was changed directly by a consumer's action.
- CHANGE_COOKIE_EXPLICIT,
- // The cookie was automatically removed due to an insert operation that
- // overwrote it.
- CHANGE_COOKIE_OVERWRITE,
- // The cookie was automatically removed as it expired.
- CHANGE_COOKIE_EXPIRED,
- // The cookie was automatically evicted during garbage collection.
- CHANGE_COOKIE_EVICTED,
- // The cookie was overwritten with an already-expired expiration date.
- CHANGE_COOKIE_EXPIRED_OVERWRITE
- };
-
- // Will be called when a cookie is added or removed. The function is passed
- // the respective |cookie| which was added to or removed from the cookies.
- // If |removed| is true, the cookie was deleted, and |cause| will be set
- // to the reason for it's removal. If |removed| is false, the cookie was
- // added, and |cause| will be set to CHANGE_COOKIE_EXPLICIT.
- //
- // As a special case, note that updating a cookie's properties is implemented
- // as a two step process: the cookie to be updated is first removed entirely,
- // generating a notification with cause CHANGE_COOKIE_OVERWRITE. Afterwards,
- // a new cookie is written with the updated values, generating a notification
- // with cause CHANGE_COOKIE_EXPLICIT.
- virtual void OnCookieChanged(const CookieMonster::CanonicalCookie& cookie,
- bool removed,
- ChangeCause cause) = 0;
- protected:
- friend class base::RefCountedThreadSafe<CookieMonster::Delegate>;
- virtual ~Delegate() {}
-};
-
-class NET_EXPORT CookieMonster::ParsedCookie {
- public:
- typedef std::pair<std::string, std::string> TokenValuePair;
- typedef std::vector<TokenValuePair> PairList;
-
- // The maximum length of a cookie string we will try to parse
- static const size_t kMaxCookieSize = 4096;
- // The maximum number of Token/Value pairs. Shouldn't have more than 8.
- static const int kMaxPairs = 16;
-
- // Construct from a cookie string like "BLAH=1; path=/; domain=.google.com"
- ParsedCookie(const std::string& cookie_line);
- ~ParsedCookie();
-
- // You should not call any other methods on the class if !IsValid
- bool IsValid() const { return is_valid_; }
-
- const std::string& Name() const { return pairs_[0].first; }
- const std::string& Token() const { return Name(); }
- const std::string& Value() const { return pairs_[0].second; }
-
- bool HasPath() const { return path_index_ != 0; }
- const std::string& Path() const { return pairs_[path_index_].second; }
- bool HasDomain() const { return domain_index_ != 0; }
- const std::string& Domain() const { return pairs_[domain_index_].second; }
- bool HasMACKey() const { return mac_key_index_ != 0; }
- const std::string& MACKey() const { return pairs_[mac_key_index_].second; }
- bool HasMACAlgorithm() const { return mac_algorithm_index_ != 0; }
- const std::string& MACAlgorithm() const {
- return pairs_[mac_algorithm_index_].second;
- }
- bool HasExpires() const { return expires_index_ != 0; }
- const std::string& Expires() const { return pairs_[expires_index_].second; }
- bool HasMaxAge() const { return maxage_index_ != 0; }
- const std::string& MaxAge() const { return pairs_[maxage_index_].second; }
- bool IsSecure() const { return secure_index_ != 0; }
- bool IsHttpOnly() const { return httponly_index_ != 0; }
-
- // Returns the number of attributes, for example, returning 2 for:
- // "BLAH=hah; path=/; domain=.google.com"
- size_t NumberOfAttributes() const { return pairs_.size() - 1; }
-
- // For debugging only!
- std::string DebugString() const;
-
- // Returns an iterator pointing to the first terminator character found in
- // the given string.
- static std::string::const_iterator FindFirstTerminator(const std::string& s);
-
- // Given iterators pointing to the beginning and end of a string segment,
- // returns as output arguments token_start and token_end to the start and end
- // positions of a cookie attribute token name parsed from the segment, and
- // updates the segment iterator to point to the next segment to be parsed.
- // If no token is found, the function returns false.
- static bool ParseToken(std::string::const_iterator* it,
- const std::string::const_iterator& end,
- std::string::const_iterator* token_start,
- std::string::const_iterator* token_end);
-
- // Given iterators pointing to the beginning and end of a string segment,
- // returns as output arguments value_start and value_end to the start and end
- // positions of a cookie attribute value parsed from the segment, and updates
- // the segment iterator to point to the next segment to be parsed.
- static void ParseValue(std::string::const_iterator* it,
- const std::string::const_iterator& end,
- std::string::const_iterator* value_start,
- std::string::const_iterator* value_end);
-
- // Same as the above functions, except the input is assumed to contain the
- // desired token/value and nothing else.
- static std::string ParseTokenString(const std::string& token);
- static std::string ParseValueString(const std::string& value);
-
- private:
- static const char kTerminator[];
- static const int kTerminatorLen;
- static const char kWhitespace[];
- static const char kValueSeparator[];
- static const char kTokenSeparator[];
-
- void ParseTokenValuePairs(const std::string& cookie_line);
- void SetupAttributes();
-
- PairList pairs_;
- bool is_valid_;
- // These will default to 0, but that should never be valid since the
- // 0th index is the user supplied token/value, not an attribute.
- // We're really never going to have more than like 8 attributes, so we
- // could fit these into 3 bits each if we're worried about size...
- size_t path_index_;
- size_t domain_index_;
- size_t mac_key_index_;
- size_t mac_algorithm_index_;
- size_t expires_index_;
- size_t maxage_index_;
- size_t secure_index_;
- size_t httponly_index_;
-
- DISALLOW_COPY_AND_ASSIGN(ParsedCookie);
-};
-
-typedef base::RefCountedThreadSafe<CookieMonster::PersistentCookieStore>
- RefcountedPersistentCookieStore;
-
-class CookieMonster::PersistentCookieStore
- : public RefcountedPersistentCookieStore {
- public:
- virtual ~PersistentCookieStore() {}
-
- typedef base::Callback<void(const std::vector<
- CookieMonster::CanonicalCookie*>&)> LoadedCallback;
-
- // Initializes the store and retrieves the existing cookies. This will be
- // called only once at startup. The callback will return all the cookies
- // that are not yet returned to CookieMonster by previous priority loads.
- virtual void Load(const LoadedCallback& loaded_callback) = 0;
-
- // Does a priority load of all cookies for the domain key (eTLD+1). The
- // callback will return all the cookies that are not yet returned by previous
- // loads, which includes cookies for the requested domain key if they are not
- // already returned, plus all cookies that are chain-loaded and not yet
- // returned to CookieMonster.
- virtual void LoadCookiesForKey(const std::string& key,
- const LoadedCallback& loaded_callback) = 0;
-
- virtual void AddCookie(const CanonicalCookie& cc) = 0;
- virtual void UpdateCookieAccessTime(const CanonicalCookie& cc) = 0;
- virtual void DeleteCookie(const CanonicalCookie& cc) = 0;
-
- // Sets the value of the user preference whether the persistent storage
- // must be deleted upon destruction.
- virtual void SetClearLocalStateOnExit(bool clear_local_state) = 0;
-
- // Flushes the store and posts |callback| when complete.
- virtual void Flush(const base::Closure& callback) = 0;
-
- protected:
- PersistentCookieStore() {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(PersistentCookieStore);
-};
-
-class CookieList : public std::vector<CookieMonster::CanonicalCookie> {
-};
-
-} // namespace net
+#include "net/cookies/cookie_monster.h"
#endif // NET_BASE_COOKIE_MONSTER_H_
diff --git a/net/base/cookie_monster_store_test.h b/net/base/cookie_monster_store_test.h
index e341f7d..d65b3fb 100644
--- a/net/base/cookie_monster_store_test.h
+++ b/net/base/cookie_monster_store_test.h
@@ -1,206 +1,14 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 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.
-// This file contains test infrastructure for multiple files
-// (current cookie_monster_unittest.cc and cookie_monster_perftest.cc)
-// that need to test out CookieMonster interactions with the backing store.
-// It should only be included by test code.
+// Provides a temporary redirection while clients are updated to use the new
+// path.
#ifndef NET_BASE_COOKIE_MONSTER_STORE_TEST_H_
#define NET_BASE_COOKIE_MONSTER_STORE_TEST_H_
#pragma once
-#include <map>
-#include <string>
-#include <utility>
-#include <vector>
-#include "net/base/cookie_monster.h"
-
-namespace base {
-class Time;
-}
-
-namespace net {
-
-// Wrapper class for posting a loaded callback. Since the Callback class is not
-// reference counted, we cannot post a callback to the message loop directly,
-// instead we post a LoadedCallbackTask.
-class LoadedCallbackTask
- : public base::RefCountedThreadSafe<LoadedCallbackTask> {
- public:
- typedef CookieMonster::PersistentCookieStore::LoadedCallback LoadedCallback;
-
- LoadedCallbackTask(LoadedCallback loaded_callback,
- std::vector<CookieMonster::CanonicalCookie*> cookies);
- ~LoadedCallbackTask();
-
- void Run() {
- loaded_callback_.Run(cookies_);
- }
-
- private:
- LoadedCallback loaded_callback_;
- std::vector<CookieMonster::CanonicalCookie*> cookies_;
-
- DISALLOW_COPY_AND_ASSIGN(LoadedCallbackTask);
-}; // Wrapper class LoadedCallbackTask
-
-// Describes a call to one of the 3 functions of PersistentCookieStore.
-struct CookieStoreCommand {
- enum Type {
- ADD,
- UPDATE_ACCESS_TIME,
- REMOVE,
- };
-
- CookieStoreCommand(Type type,
- const CookieMonster::CanonicalCookie& cookie)
- : type(type),
- cookie(cookie) {}
-
- Type type;
- CookieMonster::CanonicalCookie cookie;
-};
-
-// Implementation of PersistentCookieStore that captures the
-// received commands and saves them to a list.
-// The result of calls to Load() can be configured using SetLoadExpectation().
-class MockPersistentCookieStore
- : public CookieMonster::PersistentCookieStore {
- public:
- typedef std::vector<CookieStoreCommand> CommandList;
-
- MockPersistentCookieStore();
- virtual ~MockPersistentCookieStore();
-
- void SetLoadExpectation(
- bool return_value,
- const std::vector<CookieMonster::CanonicalCookie*>& result);
-
- const CommandList& commands() const {
- return commands_;
- }
-
- virtual void Load(const LoadedCallback& loaded_callback) OVERRIDE;
-
- virtual void LoadCookiesForKey(const std::string& key,
- const LoadedCallback& loaded_callback) OVERRIDE;
-
- virtual void AddCookie(const CookieMonster::CanonicalCookie& cookie) OVERRIDE;
-
- virtual void UpdateCookieAccessTime(
- const CookieMonster::CanonicalCookie& cookie) OVERRIDE;
-
- virtual void DeleteCookie(
- const CookieMonster::CanonicalCookie& cookie) OVERRIDE;
-
- virtual void Flush(const base::Closure& callback) OVERRIDE;
-
- // No files are created so nothing to clear either
- virtual void SetClearLocalStateOnExit(bool clear_local_state) OVERRIDE;
-
- private:
- CommandList commands_;
-
- // Deferred result to use when Load() is called.
- bool load_return_value_;
- std::vector<CookieMonster::CanonicalCookie*> load_result_;
- // Indicates if the store has been fully loaded to avoid returning duplicate
- // cookies.
- bool loaded_;
-
- DISALLOW_COPY_AND_ASSIGN(MockPersistentCookieStore);
-};
-
-// Mock for CookieMonster::Delegate
-class MockCookieMonsterDelegate : public CookieMonster::Delegate {
- public:
- typedef std::pair<CookieMonster::CanonicalCookie, bool>
- CookieNotification;
-
- MockCookieMonsterDelegate();
-
- const std::vector<CookieNotification>& changes() const { return changes_; }
-
- void reset() { changes_.clear(); }
-
- virtual void OnCookieChanged(
- const CookieMonster::CanonicalCookie& cookie,
- bool removed,
- CookieMonster::Delegate::ChangeCause cause) OVERRIDE;
-
- private:
- virtual ~MockCookieMonsterDelegate();
-
- std::vector<CookieNotification> changes_;
-
- DISALLOW_COPY_AND_ASSIGN(MockCookieMonsterDelegate);
-};
-
-// Helper to build a single CanonicalCookie.
-CookieMonster::CanonicalCookie BuildCanonicalCookie(
- const std::string& key,
- const std::string& cookie_line,
- const base::Time& creation_time);
-
-// Helper to build a list of CanonicalCookie*s.
-void AddCookieToList(
- const std::string& key,
- const std::string& cookie_line,
- const base::Time& creation_time,
- std::vector<CookieMonster::CanonicalCookie*>* out_list);
-
-// Just act like a backing database. Keep cookie information from
-// Add/Update/Delete and regurgitate it when Load is called.
-class MockSimplePersistentCookieStore
- : public CookieMonster::PersistentCookieStore {
- public:
- MockSimplePersistentCookieStore();
- virtual ~MockSimplePersistentCookieStore();
-
- virtual void Load(const LoadedCallback& loaded_callback) OVERRIDE;
-
- virtual void LoadCookiesForKey(const std::string& key,
- const LoadedCallback& loaded_callback) OVERRIDE;
-
- virtual void AddCookie(
- const CookieMonster::CanonicalCookie& cookie) OVERRIDE;
-
- virtual void UpdateCookieAccessTime(
- const CookieMonster::CanonicalCookie& cookie) OVERRIDE;
-
- virtual void DeleteCookie(
- const CookieMonster::CanonicalCookie& cookie) OVERRIDE;
-
- virtual void Flush(const base::Closure& callback) OVERRIDE;
-
- virtual void SetClearLocalStateOnExit(bool clear_local_state) OVERRIDE;
-
- private:
- typedef std::map<int64, CookieMonster::CanonicalCookie>
- CanonicalCookieMap;
-
- CanonicalCookieMap cookies_;
-
- // Indicates if the store has been fully loaded to avoid return duplicate
- // cookies in subsequent load requests
- bool loaded_;
-};
-
-// Helper function for creating a CookieMonster backed by a
-// MockSimplePersistentCookieStore for garbage collection testing.
-//
-// Fill the store through import with |num_cookies| cookies, |num_old_cookies|
-// with access time Now()-days_old, the rest with access time Now().
-// Do two SetCookies(). Return whether each of the two SetCookies() took
-// longer than |gc_perf_micros| to complete, and how many cookie were
-// left in the store afterwards.
-CookieMonster* CreateMonsterFromStoreForGC(
- int num_cookies,
- int num_old_cookies,
- int days_old);
-
-} // namespace net
+#include "net/cookies/cookie_monster_store_test.h"
#endif // NET_BASE_COOKIE_MONSTER_STORE_TEST_H_
diff --git a/net/base/cookie_options.h b/net/base/cookie_options.h
index 203adaf..74c9664 100644
--- a/net/base/cookie_options.h
+++ b/net/base/cookie_options.h
@@ -1,40 +1,14 @@
-// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 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.
-// Brought to you by number 42.
+// Provides a temporary redirection while clients are updated to use the new
+// path.
#ifndef NET_BASE_COOKIE_OPTIONS_H_
#define NET_BASE_COOKIE_OPTIONS_H_
#pragma once
-namespace net {
-
-class CookieOptions {
- public:
- // Default is to exclude httponly, which means:
- // - reading operations will not return httponly cookies.
- // - writing operations will not write httponly cookies.
- CookieOptions()
- : exclude_httponly_(true),
- force_session_(false) {
- }
-
- void set_exclude_httponly() { exclude_httponly_ = true; }
- void set_include_httponly() { exclude_httponly_ = false; }
- bool exclude_httponly() const { return exclude_httponly_; }
-
- // Forces a cookie to be saved as a session cookie. If the expiration time of
- // the cookie is in the past, i.e. the cookie would end up being deleted, this
- // option is ignored. See CookieMonsterTest.ForceSessionOnly.
- void set_force_session() { force_session_ = true; }
- bool force_session() const { return force_session_; }
-
- private:
- bool exclude_httponly_;
- bool force_session_;
-};
-} // namespace net
+#include "net/cookies/cookie_options.h"
#endif // NET_BASE_COOKIE_OPTIONS_H_
-
diff --git a/net/base/cookie_store.h b/net/base/cookie_store.h
index 0336a9b..810836d 100644
--- a/net/base/cookie_store.h
+++ b/net/base/cookie_store.h
@@ -1,113 +1,14 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 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.
-// Brought to you by number 42.
+// Provides a temporary redirection while clients are updated to use the new
+// path.
#ifndef NET_BASE_COOKIE_STORE_H_
#define NET_BASE_COOKIE_STORE_H_
#pragma once
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/callback.h"
-#include "base/memory/ref_counted.h"
-#include "base/time.h"
-#include "net/base/cookie_options.h"
-#include "net/base/net_export.h"
-
-class GURL;
-
-namespace net {
-
-class CookieMonster;
-
-// An interface for storing and retrieving cookies. Implementations need to
-// be thread safe as its methods can be accessed from IO as well as UI threads.
-class NET_EXPORT CookieStore : public base::RefCountedThreadSafe<CookieStore> {
- public:
- // This struct contains additional consumer-specific information that might
- // be stored with cookies; currently just MAC information, see:
- // http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac
- struct NET_EXPORT CookieInfo {
- CookieInfo();
- ~CookieInfo();
-
- // The name of the cookie.
- std::string name;
- // TODO(abarth): Add value if any clients need it.
-
- // The time at which the cookie was created.
- base::Time creation_date;
-
- // The value of the MAC-Key and MAC-Algorithm attributes, if present.
- std::string mac_key;
- std::string mac_algorithm;
- };
-
- // Callback definitions.
- typedef base::Callback <void(
- const std::string& cookie_line,
- const std::vector<CookieInfo>& cookie_infos)> GetCookieInfoCallback;
- typedef base::Callback<void(const std::string& cookie)>
- GetCookiesCallback;
- typedef base::Callback<void(bool success)> SetCookiesCallback;
- typedef base::Callback<void(int num_deleted)> DeleteCallback;
-
-
- // Sets a single cookie. Expects a cookie line, like "a=1; domain=b.com".
- //
- // Fails either if the cookie is invalid or if this is a non-HTTPONLY cookie
- // and it would overwrite an existing HTTPONLY cookie.
- // Returns true if the cookie is successfully set.
- virtual void SetCookieWithOptionsAsync(
- const GURL& url,
- const std::string& cookie_line,
- const CookieOptions& options,
- const SetCookiesCallback& callback) = 0;
-
- // TODO(???): what if the total size of all the cookies >4k, can we have a
- // header that big or do we need multiple Cookie: headers?
- // Note: Some sites, such as Facebook, occasionally use Cookie headers >4k.
- //
- // Simple interface, gets a cookie string "a=b; c=d" for the given URL.
- // Use options to access httponly cookies.
- virtual void GetCookiesWithOptionsAsync(
- const GURL& url, const CookieOptions& options,
- const GetCookiesCallback& callback) = 0;
-
- // This function is similar to GetCookiesWithOptions same functionality as
- // GetCookiesWithOptions except that it additionally provides detailed
- // information about the cookie contained in the cookie line. See |struct
- // CookieInfo| above for details.
- virtual void GetCookiesWithInfoAsync(
- const GURL& url,
- const CookieOptions& options,
- const GetCookieInfoCallback& callback) = 0;
-
- // Deletes the passed in cookie for the specified URL.
- virtual void DeleteCookieAsync(const GURL& url,
- const std::string& cookie_name,
- const base::Closure& callback) = 0;
-
- // Deletes all of the cookies that have a creation_date greater than or equal
- // to |delete_begin| and less than |delete_end|
- // Returns the number of cookies that have been deleted.
- virtual void DeleteAllCreatedBetweenAsync(const base::Time& delete_begin,
- const base::Time& delete_end,
- const DeleteCallback& callback) = 0;
-
- // Returns the underlying CookieMonster.
- virtual CookieMonster* GetCookieMonster() = 0;
-
- protected:
- friend class base::RefCountedThreadSafe<CookieStore>;
- CookieStore();
- virtual ~CookieStore();
-};
-
-} // namespace net
+#include "net/cookies/cookie_store.h"
#endif // NET_BASE_COOKIE_STORE_H_
diff --git a/net/base/cookie_store_test_callbacks.h b/net/base/cookie_store_test_callbacks.h
index 0957839..328a0b5 100644
--- a/net/base/cookie_store_test_callbacks.h
+++ b/net/base/cookie_store_test_callbacks.h
@@ -2,136 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// Provides a temporary redirection while clients are updated to use the new
+// path.
+
#ifndef NET_BASE_COOKIE_STORE_TEST_CALLBACKS_H_
#define NET_BASE_COOKIE_STORE_TEST_CALLBACKS_H_
#pragma once
-#include <string>
-#include <vector>
-
-#include "net/base/cookie_store.h"
-
-class MessageLoop;
-
-namespace base {
-class Thread;
-}
-
-namespace net {
-
-// Defines common behaviour for the callbacks from GetCookies, SetCookies, etc.
-// Asserts that the current thread is the expected invocation thread, sends a
-// quit to the thread in which it was constructed.
-class CookieCallback {
- public:
- // Indicates whether the callback has been called.
- bool did_run() { return did_run_; }
-
- protected:
- // Constructs a callback that expects to be called in the given thread and
- // will, upon execution, send a QUIT to the constructing thread.
- explicit CookieCallback(base::Thread* run_in_thread);
-
- // Constructs a callback that expects to be called in current thread and will
- // send a QUIT to the constructing thread.
- CookieCallback();
-
- // Tests whether the current thread was the caller's thread.
- // Sends a QUIT to the constructing thread.
- void CallbackEpilogue();
-
- private:
- bool did_run_;
- base::Thread* run_in_thread_;
- MessageLoop* run_in_loop_;
- MessageLoop* parent_loop_;
- MessageLoop* loop_to_quit_;
-};
-
-// Callback implementations for the asynchronous CookieStore methods.
-
-class SetCookieCallback : public CookieCallback {
- public:
- SetCookieCallback();
- explicit SetCookieCallback(base::Thread* run_in_thread);
-
- void Run(bool result) {
- result_ = result;
- CallbackEpilogue();
- }
-
- bool result() { return result_; }
-
- private:
- bool result_;
-};
-
-class GetCookieStringCallback : public CookieCallback {
- public:
- GetCookieStringCallback();
- explicit GetCookieStringCallback(base::Thread* run_in_thread);
-
- void Run(const std::string& cookie) {
- cookie_ = cookie;
- CallbackEpilogue();
- }
-
- const std::string& cookie() { return cookie_; }
-
- private:
- std::string cookie_;
-};
-
-class GetCookiesWithInfoCallback : public CookieCallback {
- public:
- GetCookiesWithInfoCallback();
- explicit GetCookiesWithInfoCallback(base::Thread* run_in_thread);
- ~GetCookiesWithInfoCallback();
-
- void Run(
- const std::string& cookie_line,
- const std::vector<CookieStore::CookieInfo>& cookie_info) {
- cookie_line_ = cookie_line;
- cookie_info_ = cookie_info;
- CallbackEpilogue();
- }
-
- const std::string& cookie_line() { return cookie_line_; }
- const std::vector<CookieStore::CookieInfo>& cookie_info() {
- return cookie_info_;
- }
-
- private:
- std::string cookie_line_;
- std::vector<CookieStore::CookieInfo> cookie_info_;
-};
-
-class DeleteCallback : public CookieCallback {
- public:
- DeleteCallback();
- explicit DeleteCallback(base::Thread* run_in_thread);
-
- void Run(int num_deleted) {
- num_deleted_ = num_deleted;
- CallbackEpilogue();
- }
-
- int num_deleted() { return num_deleted_; }
-
- private:
- int num_deleted_;
-};
-
-class DeleteCookieCallback : public CookieCallback {
- public:
- DeleteCookieCallback();
- explicit DeleteCookieCallback(base::Thread* run_in_thread);
-
- void Run() {
- CallbackEpilogue();
- }
-};
-
-} // namespace net
+#include "net/cookies/cookie_store_test_callbacks.h"
#endif // NET_BASE_COOKIE_STORE_TEST_CALLBACKS_H_
diff --git a/net/base/cookie_store_test_helpers.h b/net/base/cookie_store_test_helpers.h
index 3474655..04d17b0 100644
--- a/net/base/cookie_store_test_helpers.h
+++ b/net/base/cookie_store_test_helpers.h
@@ -1,105 +1,14 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 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.
+// Provides a temporary redirection while clients are updated to use the new
+// path.
+
#ifndef NET_BASE_COOKIE_STORE_TEST_HELPERS_H_
#define NET_BASE_COOKIE_STORE_TEST_HELPERS_H_
#pragma once
-#include "net/base/cookie_monster.h"
-
-#include <string>
-#include <vector>
-
-#include "base/callback_forward.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-
-class DelayedCookieMonster : public CookieStore {
- public:
- DelayedCookieMonster();
-
- // Call the asynchronous CookieMonster function, expect it to immediately
- // invoke the internal callback.
- // Post a delayed task to invoke the original callback with the results.
-
- virtual void SetCookieWithOptionsAsync(
- const GURL& url,
- const std::string& cookie_line,
- const CookieOptions& options,
- const CookieMonster::SetCookiesCallback& callback) OVERRIDE;
-
- virtual void GetCookiesWithOptionsAsync(
- const GURL& url, const CookieOptions& options,
- const CookieMonster::GetCookiesCallback& callback) OVERRIDE;
-
- virtual void GetCookiesWithInfoAsync(
- const GURL& url,
- const CookieOptions& options,
- const CookieMonster::GetCookieInfoCallback& callback) OVERRIDE;
-
- virtual bool SetCookieWithOptions(const GURL& url,
- const std::string& cookie_line,
- const CookieOptions& options);
-
- virtual std::string GetCookiesWithOptions(const GURL& url,
- const CookieOptions& options);
-
- virtual void GetCookiesWithInfo(const GURL& url,
- const CookieOptions& options,
- std::string* cookie_line,
- std::vector<CookieInfo>* cookie_infos);
-
- virtual void DeleteCookie(const GURL& url,
- const std::string& cookie_name);
-
- virtual void DeleteCookieAsync(const GURL& url,
- const std::string& cookie_name,
- const base::Closure& callback) OVERRIDE;
-
- virtual void DeleteAllCreatedBetweenAsync(
- const base::Time& delete_begin,
- const base::Time& delete_end,
- const DeleteCallback& callback) OVERRIDE;
-
- virtual CookieMonster* GetCookieMonster() OVERRIDE;
-
- private:
-
- // Be called immediately from CookieMonster.
-
- void GetCookiesInternalCallback(
- const std::string& cookie_line,
- const std::vector<CookieStore::CookieInfo>& cookie_info);
-
- void SetCookiesInternalCallback(bool result);
-
- void GetCookiesWithOptionsInternalCallback(const std::string& cookie);
-
- // Invoke the original callbacks.
-
- void InvokeGetCookiesCallback(
- const CookieMonster::GetCookieInfoCallback& callback);
-
- void InvokeSetCookiesCallback(
- const CookieMonster::SetCookiesCallback& callback);
-
- void InvokeGetCookieStringCallback(
- const CookieMonster::GetCookiesCallback& callback);
-
- friend class base::RefCountedThreadSafe<DelayedCookieMonster>;
- virtual ~DelayedCookieMonster();
-
- scoped_refptr<CookieMonster> cookie_monster_;
-
- bool did_run_;
- bool result_;
- std::string cookie_;
- std::string cookie_line_;
- std::vector<CookieStore::CookieInfo> cookie_info_;
-};
-
-} // namespace net
+#include "net/cookies/cookie_store_test_helpers.h"
#endif // NET_BASE_COOKIE_STORE_TEST_HELPERS_H_
diff --git a/net/base/cookie_store_unittest.h b/net/base/cookie_store_unittest.h
index 862edbb..42fff04 100644
--- a/net/base/cookie_store_unittest.h
+++ b/net/base/cookie_store_unittest.h
@@ -2,1054 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// Provides a temporary redirection while clients are updated to use the new
+// path.
+
#ifndef NET_BASE_COOKIE_STORE_UNITTEST_H_
#define NET_BASE_COOKIE_STORE_UNITTEST_H_
#pragma once
-#include "base/bind.h"
-#include "base/message_loop.h"
-#include "base/string_tokenizer.h"
-#include "base/threading/thread.h"
-#include "googleurl/src/gurl.h"
-#include "net/base/cookie_monster.h"
-#include "net/base/cookie_store.h"
-#include "net/base/cookie_store_test_callbacks.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-// This file declares unittest templates that can be used to test common
-// behavior of any CookieStore implementation.
-// See cookie_monster_unittest.cc for an example of an implementation.
-
-namespace net {
-
-using base::Thread;
-
-const int kTimeout = 1000;
-
-const char kUrlFtp[] = "ftp://ftp.google.izzle/";
-const char kUrlGoogle[] = "http://www.google.izzle";
-const char kUrlGoogleFoo[] = "http://www.google.izzle/foo";
-const char kUrlGoogleBar[] = "http://www.google.izzle/bar";
-const char kUrlGoogleSecure[] = "https://www.google.izzle";
-const char kValidCookieLine[] = "A=B; path=/";
-const char kValidDomainCookieLine[] = "A=B; path=/; domain=google.izzle";
-
-// The CookieStoreTestTraits must have the following members:
-// struct CookieStoreTestTraits {
-// // Factory function.
-// static scoped_refptr<CookieStore> Create();
-//
-// // The cookie store is a CookieMonster. Only used to test
-// // GetCookieMonster().
-// static const bool is_cookie_monster;
-//
-// // The cookie store supports cookies with the exclude_httponly() option.
-// static const bool supports_http_only;
-//
-// // The cookie store supports the GetCookiesWithInfoAsync() method.
-// static const bool supports_cookies_with_info;
-//
-// // The cookie store is able to make the difference between the ".com"
-// // and the "com" domains.
-// static const bool supports_non_dotted_domains;
-//
-// // The cookie store handles the domains with trailing dots (such as "com.")
-// // correctly.
-// static const bool supports_trailing_dots;
-//
-// // The cookie store rejects cookies for invalid schemes such as ftp.
-// static const bool filters_schemes;
-//
-// // The cookie store has a bug happening when a path is a substring of
-// // another.
-// static const bool has_path_prefix_bug;
-//
-// // Time to wait between two cookie insertions to ensure that cookies have
-// // different creation times.
-// static const int creation_time_granularity_in_ms;
-// };
-
-template <class CookieStoreTestTraits>
-class CookieStoreTest : public testing::Test {
- protected:
- CookieStoreTest()
- : url_google_(kUrlGoogle),
- url_google_secure_(kUrlGoogleSecure),
- url_google_foo_(kUrlGoogleFoo),
- url_google_bar_(kUrlGoogleBar) {
- // This test may be used outside of the net test suite, and thus may not
- // have a message loop.
- if (!MessageLoop::current())
- message_loop_.reset(new MessageLoop);
- weak_factory_.reset(
- new base::WeakPtrFactory<MessageLoop>(MessageLoop::current()));
- }
-
- // Helper methods for the asynchronous Cookie Store API that call the
- // asynchronous method and then pump the loop until the callback is invoked,
- // finally returning the value.
-
- std::string GetCookies(CookieStore* cs, const GURL& url) {
- DCHECK(cs);
- CookieOptions options;
- if (!CookieStoreTestTraits::supports_http_only)
- options.set_include_httponly();
- GetCookieStringCallback callback;
- cs->GetCookiesWithOptionsAsync(
- url, options,
- base::Bind(&GetCookieStringCallback::Run, base::Unretained(&callback)));
- RunFor(kTimeout);
- EXPECT_TRUE(callback.did_run());
- return callback.cookie();
- }
-
- std::string GetCookiesWithOptions(CookieStore* cs,
- const GURL& url,
- const CookieOptions& options) {
- DCHECK(cs);
- GetCookieStringCallback callback;
- cs->GetCookiesWithOptionsAsync(
- url, options, base::Bind(&GetCookieStringCallback::Run,
- base::Unretained(&callback)));
- RunFor(kTimeout);
- EXPECT_TRUE(callback.did_run());
- return callback.cookie();
- }
-
- void GetCookiesWithInfo(CookieStore* cs,
- const GURL& url,
- const CookieOptions& options,
- std::string* cookie_line,
- std::vector<CookieStore::CookieInfo>* cookie_info) {
- DCHECK(cs);
- DCHECK(cookie_line);
- DCHECK(cookie_info);
- GetCookiesWithInfoCallback callback;
- cs->GetCookiesWithInfoAsync(
- url, options, base::Bind(&GetCookiesWithInfoCallback::Run,
- base::Unretained(&callback)));
- RunFor(kTimeout);
- EXPECT_TRUE(callback.did_run());
- *cookie_line = callback.cookie_line();
- *cookie_info = callback.cookie_info();
- }
-
- bool SetCookieWithOptions(CookieStore* cs,
- const GURL& url,
- const std::string& cookie_line,
- const CookieOptions& options) {
- DCHECK(cs);
- SetCookieCallback callback;
- cs->SetCookieWithOptionsAsync(
- url, cookie_line, options,
- base::Bind(&SetCookieCallback::Run, base::Unretained(&callback)));
- RunFor(kTimeout);
- EXPECT_TRUE(callback.did_run());
- return callback.result();
- }
-
- bool SetCookie(CookieStore* cs,
- const GURL& url,
- const std::string& cookie_line) {
- CookieOptions options;
- if (!CookieStoreTestTraits::supports_http_only)
- options.set_include_httponly();
- return SetCookieWithOptions(cs, url, cookie_line, options);
- }
-
- void DeleteCookie(CookieStore* cs,
- const GURL& url,
- const std::string& cookie_name) {
- DCHECK(cs);
- DeleteCookieCallback callback;
- cs->DeleteCookieAsync(
- url, cookie_name,
- base::Bind(&DeleteCookieCallback::Run, base::Unretained(&callback)));
- RunFor(kTimeout);
- EXPECT_TRUE(callback.did_run());
- }
-
- int DeleteCreatedBetween(CookieStore* cs,
- const base::Time& delete_begin,
- const base::Time& delete_end) {
- DCHECK(cs);
- DeleteCallback callback;
- cs->DeleteAllCreatedBetweenAsync(
- delete_begin, delete_end,
- base::Bind(&DeleteCallback::Run, base::Unretained(&callback)));
- RunFor(kTimeout);
- EXPECT_TRUE(callback.did_run());
- return callback.num_deleted();
- }
-
- void RunFor(int ms) {
- // Runs the test thread message loop for up to |ms| milliseconds.
- MessageLoop::current()->PostDelayedTask(
- FROM_HERE, base::Bind(&MessageLoop::Quit, weak_factory_->GetWeakPtr()),
- base::TimeDelta::FromMilliseconds(ms));
- MessageLoop::current()->Run();
- weak_factory_->InvalidateWeakPtrs();
- }
-
- scoped_refptr<CookieStore> GetCookieStore() {
- return CookieStoreTestTraits::Create();
- }
-
- // Compares two cookie lines.
- void MatchCookieLines(const std::string& line1, const std::string& line2) {
- EXPECT_EQ(TokenizeCookieLine(line1), TokenizeCookieLine(line2));
- }
-
- // Check the cookie line by polling until equality or a timeout is reached.
- void MatchCookieLineWithTimeout(CookieStore* cs,
- const GURL& url,
- const std::string& line) {
- std::string cookies = GetCookies(cs, url);
- bool matched = (TokenizeCookieLine(line) == TokenizeCookieLine(cookies));
- base::Time polling_end_date = base::Time::Now() +
- base::TimeDelta::FromMilliseconds(
- CookieStoreTestTraits::creation_time_granularity_in_ms);
-
- while (!matched && base::Time::Now() <= polling_end_date) {
- base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
- cookies = GetCookies(cs, url);
- matched = (TokenizeCookieLine(line) == TokenizeCookieLine(cookies));
- }
-
- EXPECT_TRUE(matched) << "\"" << cookies
- << "\" does not match \"" << line << "\"";
- }
-
- GURL url_google_;
- GURL url_google_secure_;
- GURL url_google_foo_;
- GURL url_google_bar_;
-
- scoped_ptr<base::WeakPtrFactory<MessageLoop> > weak_factory_;
- scoped_ptr<MessageLoop> message_loop_;
-
- private:
- // Returns a set of strings of type "name=value". Fails in case of duplicate.
- std::set<std::string> TokenizeCookieLine(const std::string& line) {
- std::set<std::string> tokens;
- StringTokenizer tokenizer(line, " ;");
- while (tokenizer.GetNext())
- EXPECT_TRUE(tokens.insert(tokenizer.token()).second);
- return tokens;
- }
-};
-
-TYPED_TEST_CASE_P(CookieStoreTest);
-
-TYPED_TEST_P(CookieStoreTest, TypeTest) {
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
- EXPECT_EQ(cs->GetCookieMonster(),
- (TypeParam::is_cookie_monster) ?
- static_cast<CookieMonster*>(cs.get()) : NULL);
-}
-
-TYPED_TEST_P(CookieStoreTest, DomainTest) {
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
- EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "A=B"));
- this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_));
- EXPECT_TRUE(this->SetCookie(cs, this->url_google_,
- "C=D; domain=.google.izzle"));
- this->MatchCookieLines("A=B; C=D", this->GetCookies(cs, this->url_google_));
-
- // Verify that A=B was set as a host cookie rather than a domain
- // cookie -- should not be accessible from a sub sub-domain.
- this->MatchCookieLines("C=D",
- this->GetCookies(cs, GURL("http://foo.www.google.izzle")));
-
- // Test and make sure we find domain cookies on the same domain.
- EXPECT_TRUE(this->SetCookie(cs, this->url_google_,
- "E=F; domain=.www.google.izzle"));
- this->MatchCookieLines("A=B; C=D; E=F",
- this->GetCookies(cs, this->url_google_));
-
- // Test setting a domain= that doesn't start w/ a dot, should
- // treat it as a domain cookie, as if there was a pre-pended dot.
- EXPECT_TRUE(this->SetCookie(cs, this->url_google_,
- "G=H; domain=www.google.izzle"));
- this->MatchCookieLines("A=B; C=D; E=F; G=H",
- this->GetCookies(cs, this->url_google_));
-
- // Test domain enforcement, should fail on a sub-domain or something too deep.
- EXPECT_FALSE(this->SetCookie(cs, this->url_google_, "I=J; domain=.izzle"));
- this->MatchCookieLines("", this->GetCookies(cs, GURL("http://a.izzle")));
- EXPECT_FALSE(this->SetCookie(cs, this->url_google_,
- "K=L; domain=.bla.www.google.izzle"));
- this->MatchCookieLines("C=D; E=F; G=H",
- this->GetCookies(cs, GURL("http://bla.www.google.izzle")));
- this->MatchCookieLines("A=B; C=D; E=F; G=H",
- this->GetCookies(cs, this->url_google_));
-}
-
-// FireFox recognizes domains containing trailing periods as valid.
-// IE and Safari do not. Assert the expected policy here.
-TYPED_TEST_P(CookieStoreTest, DomainWithTrailingDotTest) {
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
- EXPECT_FALSE(this->SetCookie(cs, this->url_google_,
- "a=1; domain=.www.google.com."));
- EXPECT_FALSE(this->SetCookie(cs, this->url_google_,
- "b=2; domain=.www.google.com.."));
- this->MatchCookieLines("", this->GetCookies(cs, this->url_google_));
-}
-
-// Test that cookies can bet set on higher level domains.
-// http://b/issue?id=896491
-TYPED_TEST_P(CookieStoreTest, ValidSubdomainTest) {
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
- GURL url_abcd("http://a.b.c.d.com");
- GURL url_bcd("http://b.c.d.com");
- GURL url_cd("http://c.d.com");
- GURL url_d("http://d.com");
-
- EXPECT_TRUE(this->SetCookie(cs, url_abcd, "a=1; domain=.a.b.c.d.com"));
- EXPECT_TRUE(this->SetCookie(cs, url_abcd, "b=2; domain=.b.c.d.com"));
- EXPECT_TRUE(this->SetCookie(cs, url_abcd, "c=3; domain=.c.d.com"));
- EXPECT_TRUE(this->SetCookie(cs, url_abcd, "d=4; domain=.d.com"));
-
- this->MatchCookieLines("a=1; b=2; c=3; d=4", this->GetCookies(cs, url_abcd));
- this->MatchCookieLines("b=2; c=3; d=4", this->GetCookies(cs, url_bcd));
- this->MatchCookieLines("c=3; d=4", this->GetCookies(cs, url_cd));
- this->MatchCookieLines("d=4", this->GetCookies(cs, url_d));
-
- // Check that the same cookie can exist on different sub-domains.
- EXPECT_TRUE(this->SetCookie(cs, url_bcd, "X=bcd; domain=.b.c.d.com"));
- EXPECT_TRUE(this->SetCookie(cs, url_bcd, "X=cd; domain=.c.d.com"));
- this->MatchCookieLines("b=2; c=3; d=4; X=bcd; X=cd",
- this->GetCookies(cs, url_bcd));
- this->MatchCookieLines("c=3; d=4; X=cd", this->GetCookies(cs, url_cd));
-}
-
-// Test that setting a cookie which specifies an invalid domain has
-// no side-effect. An invalid domain in this context is one which does
-// not match the originating domain.
-// http://b/issue?id=896472
-TYPED_TEST_P(CookieStoreTest, InvalidDomainTest) {
- {
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
- GURL url_foobar("http://foo.bar.com");
-
- // More specific sub-domain than allowed.
- EXPECT_FALSE(this->SetCookie(cs, url_foobar,
- "a=1; domain=.yo.foo.bar.com"));
-
- EXPECT_FALSE(this->SetCookie(cs, url_foobar, "b=2; domain=.foo.com"));
- EXPECT_FALSE(this->SetCookie(cs, url_foobar, "c=3; domain=.bar.foo.com"));
-
- // Different TLD, but the rest is a substring.
- EXPECT_FALSE(this->SetCookie(cs, url_foobar,
- "d=4; domain=.foo.bar.com.net"));
-
- // A substring that isn't really a parent domain.
- EXPECT_FALSE(this->SetCookie(cs, url_foobar, "e=5; domain=ar.com"));
-
- // Completely invalid domains:
- EXPECT_FALSE(this->SetCookie(cs, url_foobar, "f=6; domain=."));
- EXPECT_FALSE(this->SetCookie(cs, url_foobar, "g=7; domain=/"));
- EXPECT_FALSE(this->SetCookie(cs, url_foobar,
- "h=8; domain=http://foo.bar.com"));
- EXPECT_FALSE(this->SetCookie(cs, url_foobar, "i=9; domain=..foo.bar.com"));
- EXPECT_FALSE(this->SetCookie(cs, url_foobar, "j=10; domain=..bar.com"));
-
- // Make sure there isn't something quirky in the domain canonicalization
- // that supports full URL semantics.
- EXPECT_FALSE(this->SetCookie(cs, url_foobar,
- "k=11; domain=.foo.bar.com?blah"));
- EXPECT_FALSE(this->SetCookie(cs, url_foobar,
- "l=12; domain=.foo.bar.com/blah"));
- EXPECT_FALSE(this->SetCookie(cs, url_foobar,
- "m=13; domain=.foo.bar.com:80"));
- EXPECT_FALSE(this->SetCookie(cs, url_foobar,
- "n=14; domain=.foo.bar.com:"));
- EXPECT_FALSE(this->SetCookie(cs, url_foobar,
- "o=15; domain=.foo.bar.com#sup"));
-
- this->MatchCookieLines("", this->GetCookies(cs, url_foobar));
- }
-
- {
- // Make sure the cookie code hasn't gotten its subdomain string handling
- // reversed, missed a suffix check, etc. It's important here that the two
- // hosts below have the same domain + registry.
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
- GURL url_foocom("http://foo.com.com");
- EXPECT_FALSE(this->SetCookie(cs, url_foocom,
- "a=1; domain=.foo.com.com.com"));
- this->MatchCookieLines("", this->GetCookies(cs, url_foocom));
- }
-}
-
-// Test the behavior of omitting dot prefix from domain, should
-// function the same as FireFox.
-// http://b/issue?id=889898
-TYPED_TEST_P(CookieStoreTest, DomainWithoutLeadingDotTest) {
- { // The omission of dot results in setting a domain cookie.
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
- GURL url_hosted("http://manage.hosted.filefront.com");
- GURL url_filefront("http://www.filefront.com");
- EXPECT_TRUE(this->SetCookie(cs, url_hosted,
- "sawAd=1; domain=filefront.com"));
- this->MatchCookieLines("sawAd=1", this->GetCookies(cs, url_hosted));
- this->MatchCookieLines("sawAd=1", this->GetCookies(cs, url_filefront));
- }
-
- { // Even when the domains match exactly, don't consider it host cookie.
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
- GURL url("http://www.google.com");
- EXPECT_TRUE(this->SetCookie(cs, url, "a=1; domain=www.google.com"));
- this->MatchCookieLines("a=1", this->GetCookies(cs, url));
- this->MatchCookieLines("a=1",
- this->GetCookies(cs, GURL("http://sub.www.google.com")));
- this->MatchCookieLines("",
- this->GetCookies(cs, GURL("http://something-else.com")));
- }
-}
-
-// Test that the domain specified in cookie string is treated case-insensitive
-// http://b/issue?id=896475.
-TYPED_TEST_P(CookieStoreTest, CaseInsensitiveDomainTest) {
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
- GURL url("http://www.google.com");
- EXPECT_TRUE(this->SetCookie(cs, url, "a=1; domain=.GOOGLE.COM"));
- EXPECT_TRUE(this->SetCookie(cs, url, "b=2; domain=.wWw.gOOgLE.coM"));
- this->MatchCookieLines("a=1; b=2", this->GetCookies(cs, url));
-}
-
-TYPED_TEST_P(CookieStoreTest, TestIpAddress) {
- GURL url_ip("http://1.2.3.4/weee");
- {
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
- EXPECT_TRUE(this->SetCookie(cs, url_ip, kValidCookieLine));
- this->MatchCookieLines("A=B", this->GetCookies(cs, url_ip));
- }
-
- { // IP addresses should not be able to set domain cookies.
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
- EXPECT_FALSE(this->SetCookie(cs, url_ip, "b=2; domain=.1.2.3.4"));
- EXPECT_FALSE(this->SetCookie(cs, url_ip, "c=3; domain=.3.4"));
- this->MatchCookieLines("", this->GetCookies(cs, url_ip));
- // It should be allowed to set a cookie if domain= matches the IP address
- // exactly. This matches IE/Firefox, even though it seems a bit wrong.
- EXPECT_FALSE(this->SetCookie(cs, url_ip, "b=2; domain=1.2.3.3"));
- this->MatchCookieLines("", this->GetCookies(cs, url_ip));
- EXPECT_TRUE(this->SetCookie(cs, url_ip, "b=2; domain=1.2.3.4"));
- this->MatchCookieLines("b=2", this->GetCookies(cs, url_ip));
- }
-}
-
-// Test host cookies, and setting of cookies on TLD.
-TYPED_TEST_P(CookieStoreTest, TestNonDottedAndTLD) {
- {
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
- GURL url("http://com/");
- // Allow setting on "com", (but only as a host cookie).
- EXPECT_TRUE(this->SetCookie(cs, url, "a=1"));
- EXPECT_FALSE(this->SetCookie(cs, url, "b=2; domain=.com"));
- EXPECT_FALSE(this->SetCookie(cs, url, "c=3; domain=com"));
- this->MatchCookieLines("a=1", this->GetCookies(cs, url));
- // Make sure it doesn't show up for a normal .com, it should be a host
- // not a domain cookie.
- this->MatchCookieLines("",
- this->GetCookies(cs, GURL("http://hopefully-no-cookies.com/")));
- if (TypeParam::supports_non_dotted_domains) {
- this->MatchCookieLines("", this->GetCookies(cs, GURL("http://.com/")));
- }
- }
-
- {
- // http://com. should be treated the same as http://com.
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
- GURL url("http://com./index.html");
- if (TypeParam::supports_trailing_dots) {
- EXPECT_TRUE(this->SetCookie(cs, url, "a=1"));
- this->MatchCookieLines("a=1", this->GetCookies(cs, url));
- this->MatchCookieLines("",
- this->GetCookies(cs, GURL("http://hopefully-no-cookies.com./")));
- } else {
- EXPECT_FALSE(this->SetCookie(cs, url, "a=1"));
- }
- }
-
- { // Should not be able to set host cookie from a subdomain.
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
- GURL url("http://a.b");
- EXPECT_FALSE(this->SetCookie(cs, url, "a=1; domain=.b"));
- EXPECT_FALSE(this->SetCookie(cs, url, "b=2; domain=b"));
- this->MatchCookieLines("", this->GetCookies(cs, url));
- }
-
- { // Same test as above, but explicitly on a known TLD (com).
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
- GURL url("http://google.com");
- EXPECT_FALSE(this->SetCookie(cs, url, "a=1; domain=.com"));
- EXPECT_FALSE(this->SetCookie(cs, url, "b=2; domain=com"));
- this->MatchCookieLines("", this->GetCookies(cs, url));
- }
-
- { // Make sure can't set cookie on TLD which is dotted.
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
- GURL url("http://google.co.uk");
- EXPECT_FALSE(this->SetCookie(cs, url, "a=1; domain=.co.uk"));
- EXPECT_FALSE(this->SetCookie(cs, url, "b=2; domain=.uk"));
- this->MatchCookieLines("", this->GetCookies(cs, url));
- this->MatchCookieLines("",
- this->GetCookies(cs, GURL("http://something-else.co.uk")));
- this->MatchCookieLines("",
- this->GetCookies(cs, GURL("http://something-else.uk")));
- }
-
- { // Intranet URLs should only be able to set host cookies.
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
- GURL url("http://b");
- EXPECT_TRUE(this->SetCookie(cs, url, "a=1"));
- EXPECT_FALSE(this->SetCookie(cs, url, "b=2; domain=.b"));
- EXPECT_FALSE(this->SetCookie(cs, url, "c=3; domain=b"));
- this->MatchCookieLines("a=1", this->GetCookies(cs, url));
- }
-}
-
-// Test reading/writing cookies when the domain ends with a period,
-// as in "www.google.com."
-TYPED_TEST_P(CookieStoreTest, TestHostEndsWithDot) {
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
- GURL url("http://www.google.com");
- GURL url_with_dot("http://www.google.com.");
- EXPECT_TRUE(this->SetCookie(cs, url, "a=1"));
- this->MatchCookieLines("a=1", this->GetCookies(cs, url));
-
- if (TypeParam::supports_trailing_dots) {
- // Do not share cookie space with the dot version of domain.
- // Note: this is not what FireFox does, but it _is_ what IE+Safari do.
- EXPECT_FALSE(this->SetCookie(cs, url, "b=2; domain=.www.google.com."));
- this->MatchCookieLines("a=1", this->GetCookies(cs, url));
-
- EXPECT_TRUE(this->SetCookie(cs, url_with_dot, "b=2; domain=.google.com."));
- this->MatchCookieLines("b=2", this->GetCookies(cs, url_with_dot));
- } else {
- EXPECT_TRUE(this->SetCookie(cs, url, "b=2; domain=.www.google.com."));
- EXPECT_FALSE(this->SetCookie(cs, url_with_dot, "b=2; domain=.google.com."));
- }
-
- // Make sure there weren't any side effects.
- this->MatchCookieLines("",
- this->GetCookies(cs, GURL("http://hopefully-no-cookies.com/")));
- this->MatchCookieLines("", this->GetCookies(cs, GURL("http://.com/")));
-}
-
-TYPED_TEST_P(CookieStoreTest, InvalidScheme) {
- if (!TypeParam::filters_schemes)
- return;
-
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
- EXPECT_FALSE(this->SetCookie(cs, GURL(kUrlFtp), kValidCookieLine));
-}
-
-TYPED_TEST_P(CookieStoreTest, InvalidScheme_Read) {
- if (!TypeParam::filters_schemes)
- return;
-
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
- EXPECT_TRUE(this->SetCookie(cs, GURL(kUrlGoogle), kValidDomainCookieLine));
- this->MatchCookieLines("", this->GetCookies(cs, GURL(kUrlFtp)));
-}
-
-TYPED_TEST_P(CookieStoreTest, PathTest) {
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
- std::string url("http://www.google.izzle");
- EXPECT_TRUE(this->SetCookie(cs, GURL(url), "A=B; path=/wee"));
- this->MatchCookieLines("A=B", this->GetCookies(cs, GURL(url + "/wee")));
- this->MatchCookieLines("A=B", this->GetCookies(cs, GURL(url + "/wee/")));
- this->MatchCookieLines("A=B", this->GetCookies(cs, GURL(url + "/wee/war")));
- this->MatchCookieLines("A=B",
- this->GetCookies(cs, GURL(url + "/wee/war/more/more")));
- if (!TypeParam::has_path_prefix_bug)
- this->MatchCookieLines("", this->GetCookies(cs, GURL(url + "/weehee")));
- this->MatchCookieLines("", this->GetCookies(cs, GURL(url + "/")));
-
- // If we add a 0 length path, it should default to /
- EXPECT_TRUE(this->SetCookie(cs, GURL(url), "A=C; path="));
- this->MatchCookieLines("A=B; A=C", this->GetCookies(cs, GURL(url + "/wee")));
- this->MatchCookieLines("A=C", this->GetCookies(cs, GURL(url + "/")));
-}
-
-TYPED_TEST_P(CookieStoreTest, HttpOnlyTest) {
- if (!TypeParam::supports_http_only)
- return;
-
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
- CookieOptions options;
- options.set_include_httponly();
-
- // Create a httponly cookie.
- EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "A=B; httponly",
- options));
-
- // Check httponly read protection.
- this->MatchCookieLines("", this->GetCookies(cs, this->url_google_));
- this->MatchCookieLines("A=B",
- this->GetCookiesWithOptions(cs, this->url_google_, options));
-
- // Check httponly overwrite protection.
- EXPECT_FALSE(this->SetCookie(cs, this->url_google_, "A=C"));
- this->MatchCookieLines("", this->GetCookies(cs, this->url_google_));
- this->MatchCookieLines("A=B",
- this->GetCookiesWithOptions(cs, this->url_google_, options));
- EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "A=C",
- options));
- this->MatchCookieLines("A=C", this->GetCookies(cs, this->url_google_));
-
- // Check httponly create protection.
- EXPECT_FALSE(this->SetCookie(cs, this->url_google_, "B=A; httponly"));
- this->MatchCookieLines("A=C",
- this->GetCookiesWithOptions(cs, this->url_google_, options));
- EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "B=A; httponly",
- options));
- this->MatchCookieLines("A=C; B=A",
- this->GetCookiesWithOptions(cs, this->url_google_, options));
- this->MatchCookieLines("A=C", this->GetCookies(cs, this->url_google_));
-}
-
-TYPED_TEST_P(CookieStoreTest, TestGetCookiesWithInfo) {
- if (!TypeParam::supports_cookies_with_info)
- return;
-
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
- CookieOptions options;
-
- EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "A=B",
- options));
- EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_,
- "C=D; Mac-Key=390jfn0awf3; Mac-Algorithm=hmac-sha-1", options));
-
- this->MatchCookieLines("A=B; C=D",
- this->GetCookiesWithOptions(cs, this->url_google_, options));
-
- std::string cookie_line;
- std::vector<CookieStore::CookieInfo> cookie_infos;
-
- this->GetCookiesWithInfo(cs, this->url_google_, options, &cookie_line,
- &cookie_infos);
-
- EXPECT_EQ("A=B; C=D", cookie_line);
-
- EXPECT_EQ(2U, cookie_infos.size());
-
- EXPECT_EQ("A", cookie_infos[0].name);
- EXPECT_EQ("", cookie_infos[0].mac_key);
- EXPECT_EQ("", cookie_infos[0].mac_algorithm);
-
- EXPECT_EQ("C", cookie_infos[1].name);
- EXPECT_EQ("390jfn0awf3", cookie_infos[1].mac_key);
- EXPECT_EQ("hmac-sha-1", cookie_infos[1].mac_algorithm);
-}
-
-TYPED_TEST_P(CookieStoreTest, TestCookieDeletion) {
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
-
- // Create a session cookie.
- EXPECT_TRUE(this->SetCookie(cs, this->url_google_, kValidCookieLine));
- this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_));
- // Delete it via Max-Age.
- EXPECT_TRUE(this->SetCookie(cs, this->url_google_,
- std::string(kValidCookieLine) + "; max-age=0"));
- this->MatchCookieLineWithTimeout(cs, this->url_google_, "");
-
- // Create a session cookie.
- EXPECT_TRUE(this->SetCookie(cs, this->url_google_, kValidCookieLine));
- this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_));
- // Delete it via Expires.
- EXPECT_TRUE(this->SetCookie(cs, this->url_google_,
- std::string(kValidCookieLine) +
- "; expires=Mon, 18-Apr-1977 22:50:13 GMT"));
- this->MatchCookieLines("", this->GetCookies(cs, this->url_google_));
-
- // Create a persistent cookie.
- EXPECT_TRUE(this->SetCookie(cs, this->url_google_,
- std::string(kValidCookieLine) +
- "; expires=Mon, 18-Apr-22 22:50:13 GMT"));
-
- this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_));
- // Delete it via Max-Age.
- EXPECT_TRUE(this->SetCookie(cs, this->url_google_,
- std::string(kValidCookieLine) + "; max-age=0"));
- this->MatchCookieLineWithTimeout(cs, this->url_google_, "");
-
- // Create a persistent cookie.
- EXPECT_TRUE(this->SetCookie(cs, this->url_google_,
- std::string(kValidCookieLine) +
- "; expires=Mon, 18-Apr-22 22:50:13 GMT"));
- this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_));
- // Delete it via Expires.
- EXPECT_TRUE(this->SetCookie(cs, this->url_google_,
- std::string(kValidCookieLine) +
- "; expires=Mon, 18-Apr-1977 22:50:13 GMT"));
- this->MatchCookieLines("", this->GetCookies(cs, this->url_google_));
-
- // Create a persistent cookie.
- EXPECT_TRUE(this->SetCookie(cs, this->url_google_,
- std::string(kValidCookieLine) +
- "; expires=Mon, 18-Apr-22 22:50:13 GMT"));
- this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_));
- // Delete it via Expires, with a unix epoch of 0.
- EXPECT_TRUE(this->SetCookie(cs, this->url_google_,
- std::string(kValidCookieLine) +
- "; expires=Thu, 1-Jan-1970 00:00:00 GMT"));
- this->MatchCookieLines("", this->GetCookies(cs, this->url_google_));
-}
-
-TYPED_TEST_P(CookieStoreTest, TestDeleteAllCreatedBetween) {
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
- const base::Time last_month = base::Time::Now() -
- base::TimeDelta::FromDays(30);
- const base::Time last_minute = base::Time::Now() -
- base::TimeDelta::FromMinutes(1);
- const base::Time next_minute = base::Time::Now() +
- base::TimeDelta::FromMinutes(1);
- const base::Time next_month = base::Time::Now() +
- base::TimeDelta::FromDays(30);
-
- // Add a cookie.
- EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "A=B"));
- // Check that the cookie is in the store.
- this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_));
-
- // Remove cookies in empty intervals.
- EXPECT_EQ(0, this->DeleteCreatedBetween(cs, last_month, last_minute));
- EXPECT_EQ(0, this->DeleteCreatedBetween(cs, next_minute, next_month));
- // Check that the cookie is still there.
- this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_));
-
- // Remove the cookie with an interval defined by two dates.
- EXPECT_EQ(1, this->DeleteCreatedBetween(cs, last_minute, next_minute));
- // Check that the cookie disappeared.
- this->MatchCookieLines("", this->GetCookies(cs, this->url_google_));
-
- // Add another cookie.
- EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "C=D"));
- // Check that the cookie is in the store.
- this->MatchCookieLines("C=D", this->GetCookies(cs, this->url_google_));
-
- // Remove the cookie with a null ending time.
- EXPECT_EQ(1, this->DeleteCreatedBetween(cs, last_minute, base::Time()));
- // Check that the cookie disappeared.
- this->MatchCookieLines("", this->GetCookies(cs, this->url_google_));
-}
-
-TYPED_TEST_P(CookieStoreTest, TestSecure) {
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
-
- EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "A=B"));
- this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_));
- this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_secure_));
-
- EXPECT_TRUE(this->SetCookie(cs, this->url_google_secure_, "A=B; secure"));
- // The secure should overwrite the non-secure.
- this->MatchCookieLines("", this->GetCookies(cs, this->url_google_));
- this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_secure_));
-
- EXPECT_TRUE(this->SetCookie(cs, this->url_google_secure_, "D=E; secure"));
- this->MatchCookieLines("", this->GetCookies(cs, this->url_google_));
- this->MatchCookieLines("A=B; D=E",
- this->GetCookies(cs, this->url_google_secure_));
-
- EXPECT_TRUE(this->SetCookie(cs, this->url_google_secure_, "A=B"));
- // The non-secure should overwrite the secure.
- this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_));
- this->MatchCookieLines("D=E; A=B",
- this->GetCookies(cs, this->url_google_secure_));
-}
-
-static const int kLastAccessThresholdMilliseconds = 200;
-
-// Formerly NetUtilTest.CookieTest back when we used wininet's cookie handling.
-TYPED_TEST_P(CookieStoreTest, NetUtilCookieTest) {
- const GURL test_url("http://mojo.jojo.google.izzle/");
-
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
-
- EXPECT_TRUE(this->SetCookie(cs, test_url, "foo=bar"));
- std::string value = this->GetCookies(cs, test_url);
- this->MatchCookieLines("foo=bar", value);
-
- // test that we can retrieve all cookies:
- EXPECT_TRUE(this->SetCookie(cs, test_url, "x=1"));
- EXPECT_TRUE(this->SetCookie(cs, test_url, "y=2"));
-
- std::string result = this->GetCookies(cs, test_url);
- EXPECT_FALSE(result.empty());
- EXPECT_NE(result.find("x=1"), std::string::npos) << result;
- EXPECT_NE(result.find("y=2"), std::string::npos) << result;
-}
-
-TYPED_TEST_P(CookieStoreTest, OverwritePersistentCookie) {
- GURL url_google("http://www.google.com/");
- GURL url_chromium("http://chromium.org");
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
-
- // Insert a cookie "a" for path "/path1"
- EXPECT_TRUE(
- this->SetCookie(cs, url_google, "a=val1; path=/path1; "
- "expires=Mon, 18-Apr-22 22:50:13 GMT"));
-
- // Insert a cookie "b" for path "/path1"
- EXPECT_TRUE(
- this->SetCookie(cs, url_google, "b=val1; path=/path1; "
- "expires=Mon, 18-Apr-22 22:50:14 GMT"));
-
- // Insert a cookie "b" for path "/path1", that is httponly. This should
- // overwrite the non-http-only version.
- CookieOptions allow_httponly;
- allow_httponly.set_include_httponly();
- EXPECT_TRUE(
- this->SetCookieWithOptions(cs, url_google,
- "b=val2; path=/path1; httponly; "
- "expires=Mon, 18-Apr-22 22:50:14 GMT",
- allow_httponly));
-
- // Insert a cookie "a" for path "/path1". This should overwrite.
- EXPECT_TRUE(this->SetCookie(cs, url_google,
- "a=val33; path=/path1; "
- "expires=Mon, 18-Apr-22 22:50:14 GMT"));
-
- // Insert a cookie "a" for path "/path2". This should NOT overwrite
- // cookie "a", since the path is different.
- EXPECT_TRUE(this->SetCookie(cs, url_google,
- "a=val9; path=/path2; "
- "expires=Mon, 18-Apr-22 22:50:14 GMT"));
-
- // Insert a cookie "a" for path "/path1", but this time for "chromium.org".
- // Although the name and path match, the hostnames do not, so shouldn't
- // overwrite.
- EXPECT_TRUE(this->SetCookie(cs, url_chromium,
- "a=val99; path=/path1; "
- "expires=Mon, 18-Apr-22 22:50:14 GMT"));
-
- if (TypeParam::supports_http_only) {
- this->MatchCookieLines("a=val33",
- this->GetCookies(cs, GURL("http://www.google.com/path1")));
- } else {
- this->MatchCookieLines("a=val33; b=val2",
- this->GetCookies(cs, GURL("http://www.google.com/path1")));
- }
- this->MatchCookieLines("a=val9",
- this->GetCookies(cs, GURL("http://www.google.com/path2")));
- this->MatchCookieLines("a=val99",
- this->GetCookies(cs, GURL("http://chromium.org/path1")));
-}
-
-TYPED_TEST_P(CookieStoreTest, CookieOrdering) {
- // Put a random set of cookies into a store and make sure they're returned in
- // the right order.
- // Cookies should be sorted by path length and creation time, as per RFC6265.
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
- EXPECT_TRUE(this->SetCookie(cs, GURL("http://d.c.b.a.google.com/aa/x.html"),
- "c=1"));
- EXPECT_TRUE(this->SetCookie(cs, GURL("http://b.a.google.com/aa/bb/cc/x.html"),
- "d=1; domain=b.a.google.com"));
- base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(
- TypeParam::creation_time_granularity_in_ms));
- EXPECT_TRUE(this->SetCookie(cs, GURL("http://b.a.google.com/aa/bb/cc/x.html"),
- "a=4; domain=b.a.google.com"));
- base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(
- TypeParam::creation_time_granularity_in_ms));
- EXPECT_TRUE(this->SetCookie(cs,
- GURL("http://c.b.a.google.com/aa/bb/cc/x.html"),
- "e=1; domain=c.b.a.google.com"));
- EXPECT_TRUE(this->SetCookie(cs,
- GURL("http://d.c.b.a.google.com/aa/bb/x.html"),
- "b=1"));
- EXPECT_TRUE(this->SetCookie(cs, GURL("http://news.bbc.co.uk/midpath/x.html"),
- "g=10"));
- EXPECT_EQ("d=1; a=4; e=1; b=1; c=1",
- this->GetCookies(cs, GURL("http://d.c.b.a.google.com/aa/bb/cc/dd")));
-}
-
-REGISTER_TYPED_TEST_CASE_P(CookieStoreTest,
- TypeTest, DomainTest, DomainWithTrailingDotTest, ValidSubdomainTest,
- InvalidDomainTest, DomainWithoutLeadingDotTest, CaseInsensitiveDomainTest,
- TestIpAddress, TestNonDottedAndTLD, TestHostEndsWithDot, InvalidScheme,
- InvalidScheme_Read, PathTest, HttpOnlyTest, TestGetCookiesWithInfo,
- TestCookieDeletion, TestDeleteAllCreatedBetween, TestSecure,
- NetUtilCookieTest, OverwritePersistentCookie, CookieOrdering);
-
-template<class CookieStoreTestTraits>
-class MultiThreadedCookieStoreTest :
- public CookieStoreTest<CookieStoreTestTraits> {
- public:
- MultiThreadedCookieStoreTest() : other_thread_("CMTthread") {}
-
- // Helper methods for calling the asynchronous CookieStore methods
- // from a different thread.
-
- void GetCookiesTask(CookieStore* cs,
- const GURL& url,
- GetCookieStringCallback* callback) {
- CookieOptions options;
- if (!CookieStoreTestTraits::supports_http_only)
- options.set_include_httponly();
- cs->GetCookiesWithOptionsAsync(
- url, options,
- base::Bind(&GetCookieStringCallback::Run, base::Unretained(callback)));
- }
-
- void GetCookiesWithOptionsTask(CookieStore* cs,
- const GURL& url,
- const CookieOptions& options,
- GetCookieStringCallback* callback) {
- cs->GetCookiesWithOptionsAsync(
- url, options,
- base::Bind(&GetCookieStringCallback::Run, base::Unretained(callback)));
- }
-
- void GetCookiesWithInfoTask(CookieStore* cs,
- const GURL& url,
- const CookieOptions& options,
- GetCookiesWithInfoCallback* callback) {
- cs->GetCookiesWithInfoAsync(
- url, options,
- base::Bind(&GetCookiesWithInfoCallback::Run,
- base::Unretained(callback)));
- }
-
- void SetCookieWithOptionsTask(CookieStore* cs,
- const GURL& url,
- const std::string& cookie_line,
- const CookieOptions& options,
- SetCookieCallback* callback) {
- cs->SetCookieWithOptionsAsync(
- url, cookie_line, options,
- base::Bind(&SetCookieCallback::Run, base::Unretained(callback)));
- }
-
- void DeleteCookieTask(CookieStore* cs,
- const GURL& url,
- const std::string& cookie_name,
- DeleteCookieCallback* callback) {
- cs->DeleteCookieAsync(
- url, cookie_name,
- base::Bind(&DeleteCookieCallback::Run, base::Unretained(callback)));
- }
-
- protected:
- void RunOnOtherThread(const base::Closure& task) {
- other_thread_.Start();
- other_thread_.message_loop()->PostTask(FROM_HERE, task);
- CookieStoreTest<CookieStoreTestTraits>::RunFor(kTimeout);
- other_thread_.Stop();
- }
-
- Thread other_thread_;
-};
-
-TYPED_TEST_CASE_P(MultiThreadedCookieStoreTest);
-
-// TODO(ycxiao): Eventually, we will need to create a separate thread, create
-// the cookie store on that thread (or at least its store, i.e., the DB
-// thread).
-TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckGetCookies) {
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
- EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "A=B"));
- this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_));
- GetCookieStringCallback callback(&this->other_thread_);
- base::Closure task = base::Bind(
- &net::MultiThreadedCookieStoreTest<TypeParam>::GetCookiesTask,
- base::Unretained(this),
- cs, this->url_google_, &callback);
- this->RunOnOtherThread(task);
- EXPECT_TRUE(callback.did_run());
- EXPECT_EQ("A=B", callback.cookie());
-}
-
-TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckGetCookiesWithOptions) {
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
- CookieOptions options;
- if (!TypeParam::supports_http_only)
- options.set_include_httponly();
- EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "A=B"));
- this->MatchCookieLines("A=B",
- this->GetCookiesWithOptions(cs, this->url_google_, options));
- GetCookieStringCallback callback(&this->other_thread_);
- base::Closure task = base::Bind(
- &net::MultiThreadedCookieStoreTest<TypeParam>::GetCookiesWithOptionsTask,
- base::Unretained(this),
- cs, this->url_google_, options, &callback);
- this->RunOnOtherThread(task);
- EXPECT_TRUE(callback.did_run());
- EXPECT_EQ("A=B", callback.cookie());
-}
-
-TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckGetCookiesWithInfo) {
- if (!TypeParam::supports_cookies_with_info)
- return;
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
- CookieOptions options;
- std::string cookie_line;
- std::vector<CookieStore::CookieInfo> cookie_infos;
- EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "A=B"));
- this->GetCookiesWithInfo(cs, this->url_google_, options, &cookie_line,
- &cookie_infos);
- this->MatchCookieLines("A=B", cookie_line);
- EXPECT_EQ(1U, cookie_infos.size());
- EXPECT_EQ("A", cookie_infos[0].name);
- EXPECT_EQ("", cookie_infos[0].mac_key);
- EXPECT_EQ("", cookie_infos[0].mac_algorithm);
- GetCookiesWithInfoCallback callback(&this->other_thread_);
- base::Closure task = base::Bind(
- &net::MultiThreadedCookieStoreTest<TypeParam>::GetCookiesWithInfoTask,
- base::Unretained(this), cs, this->url_google_, options, &callback);
- this->RunOnOtherThread(task);
- EXPECT_TRUE(callback.did_run());
- this->MatchCookieLines("A=B", callback.cookie_line());
- EXPECT_EQ(1U, callback.cookie_info().size());
- EXPECT_EQ("A", callback.cookie_info()[0].name);
- EXPECT_EQ("", callback.cookie_info()[0].mac_key);
- EXPECT_EQ("", callback.cookie_info()[0].mac_algorithm);
-}
-
-TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckSetCookieWithOptions) {
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
- CookieOptions options;
- if (!TypeParam::supports_http_only)
- options.set_include_httponly();
- EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "A=B",
- options));
- SetCookieCallback callback(&this->other_thread_);
- base::Closure task = base::Bind(
- &net::MultiThreadedCookieStoreTest<TypeParam>::SetCookieWithOptionsTask,
- base::Unretained(this),
- cs, this->url_google_, "A=B", options, &callback);
- this->RunOnOtherThread(task);
- EXPECT_TRUE(callback.did_run());
- EXPECT_TRUE(callback.result());
-}
-
-TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckDeleteCookie) {
- scoped_refptr<CookieStore> cs(this->GetCookieStore());
- CookieOptions options;
- if (!TypeParam::supports_http_only)
- options.set_include_httponly();
- EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "A=B",
- options));
- this->DeleteCookie(cs, this->url_google_, "A");
- EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "A=B",
- options));
- DeleteCookieCallback callback(&this->other_thread_);
- base::Closure task = base::Bind(
- &net::MultiThreadedCookieStoreTest<TypeParam>::DeleteCookieTask,
- base::Unretained(this),
- cs, this->url_google_, "A", &callback);
- this->RunOnOtherThread(task);
- EXPECT_TRUE(callback.did_run());
-}
-
-REGISTER_TYPED_TEST_CASE_P(MultiThreadedCookieStoreTest,
- ThreadCheckGetCookies, ThreadCheckGetCookiesWithOptions,
- ThreadCheckGetCookiesWithInfo, ThreadCheckSetCookieWithOptions,
- ThreadCheckDeleteCookie);
-
-} // namespace net
+#include "net/cookies/cookie_store_unittest.h"
#endif // NET_BASE_COOKIE_STORE_UNITTEST_H_
diff --git a/net/base/cookie_util.h b/net/base/cookie_util.h
index bda52f0..61f72d8 100644
--- a/net/base/cookie_util.h
+++ b/net/base/cookie_util.h
@@ -1,40 +1,14 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 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.
+// Provides a temporary redirection while clients are updated to use the new
+// path.
+
#ifndef NET_BASE_COOKIE_UTIL_H_
#define NET_BASE_COOKIE_UTIL_H_
#pragma once
-#include <string>
-
-#include "net/base/net_export.h"
-
-class GURL;
-
-namespace net {
-namespace cookie_util {
-
-// Returns the effective TLD+1 for a given host. This only makes sense for http
-// and https schemes. For other schemes, the host will be returned unchanged
-// (minus any leading period).
-NET_EXPORT std::string GetEffectiveDomain(const std::string& scheme,
- const std::string& host);
-
-// Determine the actual cookie domain based on the domain string passed
-// (if any) and the URL from which the cookie came.
-// On success returns true, and sets cookie_domain to either a
-// -host cookie domain (ex: "google.com")
-// -domain cookie domain (ex: ".google.com")
-NET_EXPORT bool GetCookieDomainWithString(const GURL& url,
- const std::string& domain_string,
- std::string* result);
-
-// Returns true if a domain string represents a host-only cookie,
-// i.e. it doesn't begin with a leading '.' character.
-NET_EXPORT bool DomainIsHostOnly(const std::string& domain_string);
-
-} // namspace cookie_util
-} // namespace net
+#include "net/cookies/cookie_util.h"
#endif // NET_BASE_COOKIE_UTIL_H_
diff --git a/net/cookies/OWNERS b/net/cookies/OWNERS
new file mode 100644
index 0000000..82e44d8
--- /dev/null
+++ b/net/cookies/OWNERS
@@ -0,0 +1 @@
+erikwright@chromium.org
diff --git a/net/base/cookie_monster.cc b/net/cookies/cookie_monster.cc
index 8904c0b..8a609d8 100644
--- a/net/base/cookie_monster.cc
+++ b/net/cookies/cookie_monster.cc
@@ -42,7 +42,7 @@
*
* ***** END LICENSE BLOCK ***** */
-#include "net/base/cookie_monster.h"
+#include "net/cookies/cookie_monster.h"
#include <algorithm>
#include <set>
@@ -61,7 +61,7 @@
#include "base/stringprintf.h"
#include "googleurl/src/gurl.h"
#include "googleurl/src/url_canon.h"
-#include "net/base/cookie_util.h"
+#include "net/cookies/cookie_util.h"
#include "net/base/registry_controlled_domain.h"
using base::Time;
diff --git a/net/cookies/cookie_monster.h b/net/cookies/cookie_monster.h
new file mode 100644
index 0000000..b23dcfb
--- /dev/null
+++ b/net/cookies/cookie_monster.h
@@ -0,0 +1,971 @@
+// Copyright (c) 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.
+
+// Brought to you by the letter D and the number 2.
+
+#ifndef NET_COOKIES_COOKIE_MONSTER_H_
+#define NET_COOKIES_COOKIE_MONSTER_H_
+#pragma once
+
+#include <deque>
+#include <map>
+#include <queue>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/synchronization/lock.h"
+#include "base/time.h"
+#include "net/cookies/cookie_store.h"
+#include "net/base/net_export.h"
+
+class GURL;
+
+namespace base {
+class Histogram;
+class TimeTicks;
+} // namespace base
+
+namespace net {
+
+class CookieList;
+
+// The cookie monster is the system for storing and retrieving cookies. It has
+// an in-memory list of all cookies, and synchronizes non-session cookies to an
+// optional permanent storage that implements the PersistentCookieStore
+// interface.
+//
+// This class IS thread-safe. Normally, it is only used on the I/O thread, but
+// is also accessed directly through Automation for UI testing.
+//
+// All cookie tasks are handled asynchronously. Tasks may be deferred if
+// all affected cookies are not yet loaded from the backing store. Otherwise,
+// the callback may be invoked immediately (prior to return of the asynchronous
+// function).
+//
+// A cookie task is either pending loading of the entire cookie store, or
+// loading of cookies for a specfic domain key(eTLD+1). In the former case, the
+// cookie task will be queued in queue_ while PersistentCookieStore chain loads
+// the cookie store on DB thread. In the latter case, the cookie task will be
+// queued in tasks_queued_ while PermanentCookieStore loads cookies for the
+// specified domain key(eTLD+1) on DB thread.
+//
+// Callbacks are guaranteed to be invoked on the calling thread.
+//
+// TODO(deanm) Implement CookieMonster, the cookie database.
+// - Verify that our domain enforcement and non-dotted handling is correct
+class NET_EXPORT CookieMonster : public CookieStore {
+ public:
+ class CanonicalCookie;
+ class Delegate;
+ class ParsedCookie;
+ class PersistentCookieStore;
+
+ // Terminology:
+ // * The 'top level domain' (TLD) of an internet domain name is
+ // the terminal "." free substring (e.g. "com" for google.com
+ // or world.std.com).
+ // * The 'effective top level domain' (eTLD) is the longest
+ // "." initiated terminal substring of an internet domain name
+ // that is controlled by a general domain registrar.
+ // (e.g. "co.uk" for news.bbc.co.uk).
+ // * The 'effective top level domain plus one' (eTLD+1) is the
+ // shortest "." delimited terminal substring of an internet
+ // domain name that is not controlled by a general domain
+ // registrar (e.g. "bbc.co.uk" for news.bbc.co.uk, or
+ // "google.com" for news.google.com). The general assumption
+ // is that all hosts and domains under an eTLD+1 share some
+ // administrative control.
+
+ // CookieMap is the central data structure of the CookieMonster. It
+ // is a map whose values are pointers to CanonicalCookie data
+ // structures (the data structures are owned by the CookieMonster
+ // and must be destroyed when removed from the map). The key is based on the
+ // effective domain of the cookies. If the domain of the cookie has an
+ // eTLD+1, that is the key for the map. If the domain of the cookie does not
+ // have an eTLD+1, the key of the map is the host the cookie applies to (it is
+ // not legal to have domain cookies without an eTLD+1). This rule
+ // excludes cookies for, e.g, ".com", ".co.uk", or ".internalnetwork".
+ // This behavior is the same as the behavior in Firefox v 3.6.10.
+
+ // NOTE(deanm):
+ // I benchmarked hash_multimap vs multimap. We're going to be query-heavy
+ // so it would seem like hashing would help. However they were very
+ // close, with multimap being a tiny bit faster. I think this is because
+ // our map is at max around 1000 entries, and the additional complexity
+ // for the hashing might not overcome the O(log(1000)) for querying
+ // a multimap. Also, multimap is standard, another reason to use it.
+ // TODO(rdsmith): This benchmark should be re-done now that we're allowing
+ // subtantially more entries in the map.
+ typedef std::multimap<std::string, CanonicalCookie*> CookieMap;
+ typedef std::pair<CookieMap::iterator, CookieMap::iterator> CookieMapItPair;
+
+ // The store passed in should not have had Init() called on it yet. This
+ // class will take care of initializing it. The backing store is NOT owned by
+ // this class, but it must remain valid for the duration of the cookie
+ // monster's existence. If |store| is NULL, then no backing store will be
+ // updated. If |delegate| is non-NULL, it will be notified on
+ // creation/deletion of cookies.
+ CookieMonster(PersistentCookieStore* store, Delegate* delegate);
+
+ // Only used during unit testing.
+ CookieMonster(PersistentCookieStore* store,
+ Delegate* delegate,
+ int last_access_threshold_milliseconds);
+
+ // Parses the string with the cookie time (very forgivingly).
+ static base::Time ParseCookieTime(const std::string& time_string);
+
+ // Helper function that adds all cookies from |list| into this instance.
+ bool InitializeFrom(const CookieList& list);
+
+ typedef base::Callback<void(const CookieList& cookies)> GetCookieListCallback;
+ typedef base::Callback<void(bool success)> DeleteCookieCallback;
+
+ // Sets a cookie given explicit user-provided cookie attributes. The cookie
+ // name, value, domain, etc. are each provided as separate strings. This
+ // function expects each attribute to be well-formed. It will check for
+ // disallowed characters (e.g. the ';' character is disallowed within the
+ // cookie value attribute) and will return false without setting the cookie
+ // if such characters are found.
+ void SetCookieWithDetailsAsync(const GURL& url,
+ const std::string& name,
+ const std::string& value,
+ const std::string& domain,
+ const std::string& path,
+ const base::Time& expiration_time,
+ bool secure, bool http_only,
+ const SetCookiesCallback& callback);
+
+
+ // Returns all the cookies, for use in management UI, etc. This does not mark
+ // the cookies as having been accessed.
+ // The returned cookies are ordered by longest path, then by earliest
+ // creation date.
+ void GetAllCookiesAsync(const GetCookieListCallback& callback);
+
+ // Returns all the cookies, for use in management UI, etc. Filters results
+ // using given url scheme, host / domain and path and options. This does not
+ // mark the cookies as having been accessed.
+ // The returned cookies are ordered by longest path, then earliest
+ // creation date.
+ void GetAllCookiesForURLWithOptionsAsync(
+ const GURL& url,
+ const CookieOptions& options,
+ const GetCookieListCallback& callback);
+
+ // Invokes GetAllCookiesForURLWithOptions with options set to include HTTP
+ // only cookies.
+ void GetAllCookiesForURLAsync(const GURL& url,
+ const GetCookieListCallback& callback);
+
+ // Deletes all of the cookies.
+ void DeleteAllAsync(const DeleteCallback& callback);
+
+ // Deletes all cookies that match the host of the given URL
+ // regardless of path. This includes all http_only and secure cookies,
+ // but does not include any domain cookies that may apply to this host.
+ // Returns the number of cookies deleted.
+ void DeleteAllForHostAsync(const GURL& url,
+ const DeleteCallback& callback);
+
+ // Deletes one specific cookie.
+ void DeleteCanonicalCookieAsync(const CanonicalCookie& cookie,
+ const DeleteCookieCallback& callback);
+
+ // Override the default list of schemes that are allowed to be set in
+ // this cookie store. Calling his overrides the value of
+ // "enable_file_scheme_".
+ // If this this method is called, it must be called before first use of
+ // the instance (i.e. as part of the instance initialization process).
+ void SetCookieableSchemes(const char* schemes[], size_t num_schemes);
+
+ // Instructs the cookie monster to not delete expired cookies. This is used
+ // in cases where the cookie monster is used as a data structure to keep
+ // arbitrary cookies.
+ void SetKeepExpiredCookies();
+
+ // Delegates the call to set the |clear_local_store_on_exit_| flag of the
+ // PersistentStore if it exists.
+ void SetClearPersistentStoreOnExit(bool clear_local_store);
+
+ // There are some unknowns about how to correctly handle file:// cookies,
+ // and our implementation for this is not robust enough. This allows you
+ // to enable support, but it should only be used for testing. Bug 1157243.
+ // Must be called before creating a CookieMonster instance.
+ static void EnableFileScheme();
+
+ // Flush the backing store (if any) to disk and post the given callback when
+ // done.
+ // WARNING: THE CALLBACK WILL RUN ON A RANDOM THREAD. IT MUST BE THREAD SAFE.
+ // It may be posted to the current thread, or it may run on the thread that
+ // actually does the flushing. Your Task should generally post a notification
+ // to the thread you actually want to be notified on.
+ void FlushStore(const base::Closure& callback);
+
+ // CookieStore implementation.
+
+ // Sets the cookies specified by |cookie_list| returned from |url|
+ // with options |options| in effect.
+ virtual void SetCookieWithOptionsAsync(
+ const GURL& url,
+ const std::string& cookie_line,
+ const CookieOptions& options,
+ const SetCookiesCallback& callback) OVERRIDE;
+
+ // Gets all cookies that apply to |url| given |options|.
+ // The returned cookies are ordered by longest path, then earliest
+ // creation date.
+ virtual void GetCookiesWithOptionsAsync(
+ const GURL& url,
+ const CookieOptions& options,
+ const GetCookiesCallback& callback) OVERRIDE;
+
+ virtual void GetCookiesWithInfoAsync(
+ const GURL& url,
+ const CookieOptions& options,
+ const GetCookieInfoCallback& callback) OVERRIDE;
+
+ // Deletes all cookies with that might apply to |url| that has |cookie_name|.
+ virtual void DeleteCookieAsync(
+ const GURL& url, const std::string& cookie_name,
+ const base::Closure& callback) OVERRIDE;
+
+ // Deletes all of the cookies that have a creation_date greater than or equal
+ // to |delete_begin| and less than |delete_end|
+ // Returns the number of cookies that have been deleted.
+ virtual void DeleteAllCreatedBetweenAsync(
+ const base::Time& delete_begin,
+ const base::Time& delete_end,
+ const DeleteCallback& callback) OVERRIDE;
+
+ virtual CookieMonster* GetCookieMonster() OVERRIDE;
+
+ // Enables writing session cookies into the cookie database. If this this
+ // method is called, it must be called before first use of the instance
+ // (i.e. as part of the instance initialization process).
+ void SetPersistSessionCookies(bool persist_session_cookies);
+
+ // Protects session cookies from deletion on shutdown.
+ void SaveSessionCookies();
+
+ // Debugging method to perform various validation checks on the map.
+ // Currently just checking that there are no null CanonicalCookie pointers
+ // in the map.
+ // Argument |arg| is to allow retaining of arbitrary data if the CHECKs
+ // in the function trip. TODO(rdsmith):Remove hack.
+ void ValidateMap(int arg);
+
+ // The default list of schemes the cookie monster can handle.
+ static const char* kDefaultCookieableSchemes[];
+ static const int kDefaultCookieableSchemesCount;
+
+ private:
+ // For queueing the cookie monster calls.
+ class CookieMonsterTask;
+ class DeleteAllCreatedBetweenTask;
+ class DeleteAllForHostTask;
+ class DeleteAllTask;
+ class DeleteCookieTask;
+ class DeleteCanonicalCookieTask;
+ class GetAllCookiesForURLWithOptionsTask;
+ class GetAllCookiesTask;
+ class GetCookiesWithOptionsTask;
+ class GetCookiesWithInfoTask;
+ class SetCookieWithDetailsTask;
+ class SetCookieWithOptionsTask;
+
+ // Testing support.
+ // For SetCookieWithCreationTime.
+ FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest,
+ TestCookieDeleteAllCreatedBetweenTimestamps);
+
+ // For gargage collection constants.
+ FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest, TestHostGarbageCollection);
+ FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest, TestTotalGarbageCollection);
+ FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest, GarbageCollectionTriggers);
+ FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest, TestGCTimes);
+
+ // For validation of key values.
+ FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest, TestDomainTree);
+ FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest, TestImport);
+ FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest, GetKey);
+ FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest, TestGetKey);
+
+ // For FindCookiesForKey.
+ FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest, ShortLivedSessionCookies);
+
+ // Internal reasons for deletion, used to populate informative histograms
+ // and to provide a public cause for onCookieChange notifications.
+ //
+ // If you add or remove causes from this list, please be sure to also update
+ // the Delegate::ChangeCause mapping inside ChangeCauseMapping. Moreover,
+ // these are used as array indexes, so avoid reordering to keep the
+ // histogram buckets consistent. New items (if necessary) should be added
+ // at the end of the list, just before DELETE_COOKIE_LAST_ENTRY.
+ enum DeletionCause {
+ DELETE_COOKIE_EXPLICIT = 0,
+ DELETE_COOKIE_OVERWRITE,
+ DELETE_COOKIE_EXPIRED,
+ DELETE_COOKIE_EVICTED,
+ DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE,
+ DELETE_COOKIE_DONT_RECORD, // e.g. For final cleanup after flush to store.
+ DELETE_COOKIE_EVICTED_DOMAIN,
+ DELETE_COOKIE_EVICTED_GLOBAL,
+
+ // Cookies evicted during domain level garbage collection that
+ // were accessed longer ago than kSafeFromGlobalPurgeDays
+ DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE,
+
+ // Cookies evicted during domain level garbage collection that
+ // were accessed more recently than kSafeFromGlobalPurgeDays
+ // (and thus would have been preserved by global garbage collection).
+ DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE,
+
+ // A common idiom is to remove a cookie by overwriting it with an
+ // already-expired expiration date. This captures that case.
+ DELETE_COOKIE_EXPIRED_OVERWRITE,
+
+ DELETE_COOKIE_LAST_ENTRY
+ };
+
+ // Cookie garbage collection thresholds. Based off of the Mozilla defaults.
+ // When the number of cookies gets to k{Domain,}MaxCookies
+ // purge down to k{Domain,}MaxCookies - k{Domain,}PurgeCookies.
+ // It might seem scary to have a high purge value, but really it's not.
+ // You just make sure that you increase the max to cover the increase
+ // in purge, and we would have been purging the same amount of cookies.
+ // We're just going through the garbage collection process less often.
+ // Note that the DOMAIN values are per eTLD+1; see comment for the
+ // CookieMap typedef. So, e.g., the maximum number of cookies allowed for
+ // google.com and all of its subdomains will be 150-180.
+ //
+ // Any cookies accessed more recently than kSafeFromGlobalPurgeDays will not
+ // be evicted by global garbage collection, even if we have more than
+ // kMaxCookies. This does not affect domain garbage collection.
+ //
+ // Present in .h file to make accessible to tests through FRIEND_TEST.
+ // Actual definitions are in cookie_monster.cc.
+ static const size_t kDomainMaxCookies;
+ static const size_t kDomainPurgeCookies;
+ static const size_t kMaxCookies;
+ static const size_t kPurgeCookies;
+
+ // The number of days since last access that cookies will not be subject
+ // to global garbage collection.
+ static const int kSafeFromGlobalPurgeDays;
+
+ // Record statistics every kRecordStatisticsIntervalSeconds of uptime.
+ static const int kRecordStatisticsIntervalSeconds = 10 * 60;
+
+ virtual ~CookieMonster();
+
+ // The following are synchronous calls to which the asynchronous methods
+ // delegate either immediately (if the store is loaded) or through a deferred
+ // task (if the store is not yet loaded).
+ bool SetCookieWithDetails(const GURL& url,
+ const std::string& name,
+ const std::string& value,
+ const std::string& domain,
+ const std::string& path,
+ const base::Time& expiration_time,
+ bool secure, bool http_only);
+
+ CookieList GetAllCookies();
+
+ CookieList GetAllCookiesForURLWithOptions(const GURL& url,
+ const CookieOptions& options);
+
+ CookieList GetAllCookiesForURL(const GURL& url);
+
+ int DeleteAll(bool sync_to_store);
+
+ int DeleteAllCreatedBetween(const base::Time& delete_begin,
+ const base::Time& delete_end);
+
+ int DeleteAllForHost(const GURL& url);
+
+ bool DeleteCanonicalCookie(const CanonicalCookie& cookie);
+
+ bool SetCookieWithOptions(const GURL& url,
+ const std::string& cookie_line,
+ const CookieOptions& options);
+
+ std::string GetCookiesWithOptions(const GURL& url,
+ const CookieOptions& options);
+
+ void GetCookiesWithInfo(const GURL& url,
+ const CookieOptions& options,
+ std::string* cookie_line,
+ std::vector<CookieInfo>* cookie_infos);
+
+ void DeleteCookie(const GURL& url, const std::string& cookie_name);
+
+ bool SetCookieWithCreationTime(const GURL& url,
+ const std::string& cookie_line,
+ const base::Time& creation_time);
+
+ // Called by all non-static functions to ensure that the cookies store has
+ // been initialized. This is not done during creating so it doesn't block
+ // the window showing.
+ // Note: this method should always be called with lock_ held.
+ void InitIfNecessary() {
+ if (!initialized_) {
+ if (store_) {
+ InitStore();
+ } else {
+ loaded_ = true;
+ }
+ initialized_ = true;
+ }
+ }
+
+ // Initializes the backing store and reads existing cookies from it.
+ // Should only be called by InitIfNecessary().
+ void InitStore();
+
+ // Stores cookies loaded from the backing store and invokes any deferred
+ // calls. |beginning_time| should be the moment PersistentCookieStore::Load
+ // was invoked and is used for reporting histogram_time_blocked_on_load_.
+ // See PersistentCookieStore::Load for details on the contents of cookies.
+ void OnLoaded(base::TimeTicks beginning_time,
+ const std::vector<CanonicalCookie*>& cookies);
+
+ // Stores cookies loaded from the backing store and invokes the deferred
+ // task(s) pending loading of cookies associated with the domain key
+ // (eTLD+1). Called when all cookies for the domain key(eTLD+1) have been
+ // loaded from DB. See PersistentCookieStore::Load for details on the contents
+ // of cookies.
+ void OnKeyLoaded(
+ const std::string& key,
+ const std::vector<CanonicalCookie*>& cookies);
+
+ // Stores the loaded cookies.
+ void StoreLoadedCookies(const std::vector<CanonicalCookie*>& cookies);
+
+ // Invokes deferred calls.
+ void InvokeQueue();
+
+ // Checks that |cookies_| matches our invariants, and tries to repair any
+ // inconsistencies. (In other words, it does not have duplicate cookies).
+ void EnsureCookiesMapIsValid();
+
+ // Checks for any duplicate cookies for CookieMap key |key| which lie between
+ // |begin| and |end|. If any are found, all but the most recent are deleted.
+ // Returns the number of duplicate cookies that were deleted.
+ int TrimDuplicateCookiesForKey(const std::string& key,
+ CookieMap::iterator begin,
+ CookieMap::iterator end);
+
+ void SetDefaultCookieableSchemes();
+
+ void FindCookiesForHostAndDomain(const GURL& url,
+ const CookieOptions& options,
+ bool update_access_time,
+ std::vector<CanonicalCookie*>* cookies);
+
+ void FindCookiesForKey(const std::string& key,
+ const GURL& url,
+ const CookieOptions& options,
+ const base::Time& current,
+ bool update_access_time,
+ std::vector<CanonicalCookie*>* cookies);
+
+ // Delete any cookies that are equivalent to |ecc| (same path, domain, etc).
+ // If |skip_httponly| is true, httponly cookies will not be deleted. The
+ // return value with be true if |skip_httponly| skipped an httponly cookie.
+ // |key| is the key to find the cookie in cookies_; see the comment before
+ // the CookieMap typedef for details.
+ // NOTE: There should never be more than a single matching equivalent cookie.
+ bool DeleteAnyEquivalentCookie(const std::string& key,
+ const CanonicalCookie& ecc,
+ bool skip_httponly,
+ bool already_expired);
+
+ // Takes ownership of *cc.
+ void InternalInsertCookie(const std::string& key,
+ CanonicalCookie* cc,
+ bool sync_to_store);
+
+ // Helper function that sets cookies with more control.
+ // Not exposed as we don't want callers to have the ability
+ // to specify (potentially duplicate) creation times.
+ bool SetCookieWithCreationTimeAndOptions(const GURL& url,
+ const std::string& cookie_line,
+ const base::Time& creation_time,
+ const CookieOptions& options);
+
+ // Helper function that sets a canonical cookie, deleting equivalents and
+ // performing garbage collection.
+ bool SetCanonicalCookie(scoped_ptr<CanonicalCookie>* cc,
+ const base::Time& creation_time,
+ const CookieOptions& options);
+
+ void InternalUpdateCookieAccessTime(CanonicalCookie* cc,
+ const base::Time& current_time);
+
+ // |deletion_cause| argument is used for collecting statistics and choosing
+ // the correct Delegate::ChangeCause for OnCookieChanged notifications.
+ void InternalDeleteCookie(CookieMap::iterator it, bool sync_to_store,
+ DeletionCause deletion_cause);
+
+ // If the number of cookies for CookieMap key |key|, or globally, are
+ // over the preset maximums above, garbage collect, first for the host and
+ // then globally. See comments above garbage collection threshold
+ // constants for details.
+ //
+ // Returns the number of cookies deleted (useful for debugging).
+ int GarbageCollect(const base::Time& current, const std::string& key);
+
+ // Helper for GarbageCollect(); can be called directly as well. Deletes
+ // all expired cookies in |itpair|. If |cookie_its| is non-NULL, it is
+ // populated with all the non-expired cookies from |itpair|.
+ //
+ // Returns the number of cookies deleted.
+ int GarbageCollectExpired(const base::Time& current,
+ const CookieMapItPair& itpair,
+ std::vector<CookieMap::iterator>* cookie_its);
+
+ // Helper for GarbageCollect(). Deletes all cookies in the list
+ // that were accessed before |keep_accessed_after|, using DeletionCause
+ // |cause|. If |keep_accessed_after| is null, deletes all cookies in the
+ // list. Returns the number of cookies deleted.
+ int GarbageCollectDeleteList(const base::Time& current,
+ const base::Time& keep_accessed_after,
+ DeletionCause cause,
+ std::vector<CookieMap::iterator>& cookie_its);
+
+ // Find the key (for lookup in cookies_) based on the given domain.
+ // See comment on keys before the CookieMap typedef.
+ std::string GetKey(const std::string& domain) const;
+
+ bool HasCookieableScheme(const GURL& url);
+
+ // Statistics support
+
+ // This function should be called repeatedly, and will record
+ // statistics if a sufficient time period has passed.
+ void RecordPeriodicStats(const base::Time& current_time);
+
+ // Initialize the above variables; should only be called from
+ // the constructor.
+ void InitializeHistograms();
+
+ // The resolution of our time isn't enough, so we do something
+ // ugly and increment when we've seen the same time twice.
+ base::Time CurrentTime();
+
+ // Runs the task if, or defers the task until, the full cookie database is
+ // loaded.
+ void DoCookieTask(const scoped_refptr<CookieMonsterTask>& task_item);
+
+ // Runs the task if, or defers the task until, the cookies for the given URL
+ // are loaded.
+ void DoCookieTaskForURL(const scoped_refptr<CookieMonsterTask>& task_item,
+ const GURL& url);
+
+ // Histogram variables; see CookieMonster::InitializeHistograms() in
+ // cookie_monster.cc for details.
+ base::Histogram* histogram_expiration_duration_minutes_;
+ base::Histogram* histogram_between_access_interval_minutes_;
+ base::Histogram* histogram_evicted_last_access_minutes_;
+ base::Histogram* histogram_count_;
+ base::Histogram* histogram_domain_count_;
+ base::Histogram* histogram_etldp1_count_;
+ base::Histogram* histogram_domain_per_etldp1_count_;
+ base::Histogram* histogram_number_duplicate_db_cookies_;
+ base::Histogram* histogram_cookie_deletion_cause_;
+ base::Histogram* histogram_time_get_;
+ base::Histogram* histogram_time_mac_;
+ base::Histogram* histogram_time_blocked_on_load_;
+
+ CookieMap cookies_;
+
+ // Indicates whether the cookie store has been initialized. This happens
+ // lazily in InitStoreIfNecessary().
+ bool initialized_;
+
+ // Indicates whether loading from the backend store is completed and
+ // calls may be immediately processed.
+ bool loaded_;
+
+ // List of domain keys that have been loaded from the DB.
+ std::set<std::string> keys_loaded_;
+
+ // Map of domain keys to their associated task queues. These tasks are blocked
+ // until all cookies for the associated domain key eTLD+1 are loaded from the
+ // backend store.
+ std::map<std::string, std::deque<scoped_refptr<CookieMonsterTask> > >
+ tasks_queued_;
+
+ // Queues tasks that are blocked until all cookies are loaded from the backend
+ // store.
+ std::queue<scoped_refptr<CookieMonsterTask> > queue_;
+
+ scoped_refptr<PersistentCookieStore> store_;
+
+ base::Time last_time_seen_;
+
+ // Minimum delay after updating a cookie's LastAccessDate before we will
+ // update it again.
+ const base::TimeDelta last_access_threshold_;
+
+ // Approximate date of access time of least recently accessed cookie
+ // in |cookies_|. Note that this is not guaranteed to be accurate, only a)
+ // to be before or equal to the actual time, and b) to be accurate
+ // immediately after a garbage collection that scans through all the cookies.
+ // This value is used to determine whether global garbage collection might
+ // find cookies to purge.
+ // Note: The default Time() constructor will create a value that compares
+ // earlier than any other time value, which is wanted. Thus this
+ // value is not initialized.
+ base::Time earliest_access_time_;
+
+ // During loading, holds the set of all loaded cookie creation times. Used to
+ // avoid ever letting cookies with duplicate creation times into the store;
+ // that way we don't have to worry about what sections of code are safe
+ // to call while it's in that state.
+ std::set<int64> creation_times_;
+
+ std::vector<std::string> cookieable_schemes_;
+
+ scoped_refptr<Delegate> delegate_;
+
+ // Lock for thread-safety
+ base::Lock lock_;
+
+ base::Time last_statistic_record_time_;
+
+ bool keep_expired_cookies_;
+ bool persist_session_cookies_;
+
+ static bool enable_file_scheme_;
+
+ DISALLOW_COPY_AND_ASSIGN(CookieMonster);
+};
+
+class NET_EXPORT CookieMonster::CanonicalCookie {
+ public:
+
+ // These constructors do no validation or canonicalization of their inputs;
+ // the resulting CanonicalCookies should not be relied on to be canonical
+ // unless the caller has done appropriate validation and canonicalization
+ // themselves.
+ CanonicalCookie();
+ CanonicalCookie(const GURL& url,
+ const std::string& name,
+ const std::string& value,
+ const std::string& domain,
+ const std::string& path,
+ const std::string& mac_key,
+ const std::string& mac_algorithm,
+ const base::Time& creation,
+ const base::Time& expiration,
+ const base::Time& last_access,
+ bool secure,
+ bool httponly,
+ bool has_expires,
+ bool is_persistent);
+
+ // This constructor does canonicalization but not validation.
+ // The result of this constructor should not be relied on in contexts
+ // in which pre-validation of the ParsedCookie has not been done.
+ CanonicalCookie(const GURL& url, const ParsedCookie& pc);
+
+ ~CanonicalCookie();
+
+ // Supports the default copy constructor.
+
+ // Creates a canonical cookie from parsed cookie.
+ // Canonicalizes and validates inputs. May return NULL if an attribute
+ // value is invalid.
+ static CanonicalCookie* Create(const GURL& url,
+ const ParsedCookie& pc);
+
+ // Creates a canonical cookie from unparsed attribute values.
+ // Canonicalizes and validates inputs. May return NULL if an attribute
+ // value is invalid.
+ static CanonicalCookie* Create(const GURL& url,
+ const std::string& name,
+ const std::string& value,
+ const std::string& domain,
+ const std::string& path,
+ const std::string& mac_key,
+ const std::string& mac_algorithm,
+ const base::Time& creation,
+ const base::Time& expiration,
+ bool secure,
+ bool http_only,
+ bool is_persistent);
+
+ const std::string& Source() const { return source_; }
+ const std::string& Name() const { return name_; }
+ const std::string& Value() const { return value_; }
+ const std::string& Domain() const { return domain_; }
+ const std::string& Path() const { return path_; }
+ const std::string& MACKey() const { return mac_key_; }
+ const std::string& MACAlgorithm() const { return mac_algorithm_; }
+ const base::Time& CreationDate() const { return creation_date_; }
+ const base::Time& LastAccessDate() const { return last_access_date_; }
+ bool DoesExpire() const { return has_expires_; }
+ bool IsPersistent() const { return is_persistent_; }
+ const base::Time& ExpiryDate() const { return expiry_date_; }
+ bool IsSecure() const { return secure_; }
+ bool IsHttpOnly() const { return httponly_; }
+ bool IsDomainCookie() const {
+ return !domain_.empty() && domain_[0] == '.'; }
+ bool IsHostCookie() const { return !IsDomainCookie(); }
+
+ bool IsExpired(const base::Time& current) {
+ return has_expires_ && current >= expiry_date_;
+ }
+
+ // Are the cookies considered equivalent in the eyes of RFC 2965.
+ // The RFC says that name must match (case-sensitive), domain must
+ // match (case insensitive), and path must match (case sensitive).
+ // For the case insensitive domain compare, we rely on the domain
+ // having been canonicalized (in
+ // GetCookieDomainWithString->CanonicalizeHost).
+ bool IsEquivalent(const CanonicalCookie& ecc) const {
+ // It seems like it would make sense to take secure and httponly into
+ // account, but the RFC doesn't specify this.
+ // NOTE: Keep this logic in-sync with TrimDuplicateCookiesForHost().
+ return (name_ == ecc.Name() && domain_ == ecc.Domain()
+ && path_ == ecc.Path());
+ }
+
+ void SetLastAccessDate(const base::Time& date) {
+ last_access_date_ = date;
+ }
+
+ bool IsOnPath(const std::string& url_path) const;
+ bool IsDomainMatch(const std::string& scheme, const std::string& host) const;
+
+ std::string DebugString() const;
+
+ // Returns the cookie source when cookies are set for |url|. This function
+ // is public for unit test purposes only.
+ static std::string GetCookieSourceFromURL(const GURL& url);
+
+ private:
+ // Gives the session cookie an expiration time if needed
+ void SetSessionCookieExpiryTime();
+
+ // The source member of a canonical cookie is the origin of the URL that tried
+ // to set this cookie, minus the port number if any. This field is not
+ // persistent though; its only used in the in-tab cookies dialog to show the
+ // user the source URL. This is used for both allowed and blocked cookies.
+ // When a CanonicalCookie is constructed from the backing store (common case)
+ // this field will be null. CanonicalCookie consumers should not rely on
+ // this field unless they guarantee that the creator of those
+ // CanonicalCookies properly initialized the field.
+ // TODO(abarth): We might need to make this field persistent for MAC cookies.
+ std::string source_;
+ std::string name_;
+ std::string value_;
+ std::string domain_;
+ std::string path_;
+ std::string mac_key_; // TODO(abarth): Persist to disk.
+ std::string mac_algorithm_; // TODO(abarth): Persist to disk.
+ base::Time creation_date_;
+ base::Time expiry_date_;
+ base::Time last_access_date_;
+ bool secure_;
+ bool httponly_;
+ bool has_expires_;
+ bool is_persistent_;
+};
+
+class CookieMonster::Delegate
+ : public base::RefCountedThreadSafe<CookieMonster::Delegate> {
+ public:
+ // The publicly relevant reasons a cookie might be changed.
+ enum ChangeCause {
+ // The cookie was changed directly by a consumer's action.
+ CHANGE_COOKIE_EXPLICIT,
+ // The cookie was automatically removed due to an insert operation that
+ // overwrote it.
+ CHANGE_COOKIE_OVERWRITE,
+ // The cookie was automatically removed as it expired.
+ CHANGE_COOKIE_EXPIRED,
+ // The cookie was automatically evicted during garbage collection.
+ CHANGE_COOKIE_EVICTED,
+ // The cookie was overwritten with an already-expired expiration date.
+ CHANGE_COOKIE_EXPIRED_OVERWRITE
+ };
+
+ // Will be called when a cookie is added or removed. The function is passed
+ // the respective |cookie| which was added to or removed from the cookies.
+ // If |removed| is true, the cookie was deleted, and |cause| will be set
+ // to the reason for it's removal. If |removed| is false, the cookie was
+ // added, and |cause| will be set to CHANGE_COOKIE_EXPLICIT.
+ //
+ // As a special case, note that updating a cookie's properties is implemented
+ // as a two step process: the cookie to be updated is first removed entirely,
+ // generating a notification with cause CHANGE_COOKIE_OVERWRITE. Afterwards,
+ // a new cookie is written with the updated values, generating a notification
+ // with cause CHANGE_COOKIE_EXPLICIT.
+ virtual void OnCookieChanged(const CookieMonster::CanonicalCookie& cookie,
+ bool removed,
+ ChangeCause cause) = 0;
+ protected:
+ friend class base::RefCountedThreadSafe<CookieMonster::Delegate>;
+ virtual ~Delegate() {}
+};
+
+class NET_EXPORT CookieMonster::ParsedCookie {
+ public:
+ typedef std::pair<std::string, std::string> TokenValuePair;
+ typedef std::vector<TokenValuePair> PairList;
+
+ // The maximum length of a cookie string we will try to parse
+ static const size_t kMaxCookieSize = 4096;
+ // The maximum number of Token/Value pairs. Shouldn't have more than 8.
+ static const int kMaxPairs = 16;
+
+ // Construct from a cookie string like "BLAH=1; path=/; domain=.google.com"
+ ParsedCookie(const std::string& cookie_line);
+ ~ParsedCookie();
+
+ // You should not call any other methods on the class if !IsValid
+ bool IsValid() const { return is_valid_; }
+
+ const std::string& Name() const { return pairs_[0].first; }
+ const std::string& Token() const { return Name(); }
+ const std::string& Value() const { return pairs_[0].second; }
+
+ bool HasPath() const { return path_index_ != 0; }
+ const std::string& Path() const { return pairs_[path_index_].second; }
+ bool HasDomain() const { return domain_index_ != 0; }
+ const std::string& Domain() const { return pairs_[domain_index_].second; }
+ bool HasMACKey() const { return mac_key_index_ != 0; }
+ const std::string& MACKey() const { return pairs_[mac_key_index_].second; }
+ bool HasMACAlgorithm() const { return mac_algorithm_index_ != 0; }
+ const std::string& MACAlgorithm() const {
+ return pairs_[mac_algorithm_index_].second;
+ }
+ bool HasExpires() const { return expires_index_ != 0; }
+ const std::string& Expires() const { return pairs_[expires_index_].second; }
+ bool HasMaxAge() const { return maxage_index_ != 0; }
+ const std::string& MaxAge() const { return pairs_[maxage_index_].second; }
+ bool IsSecure() const { return secure_index_ != 0; }
+ bool IsHttpOnly() const { return httponly_index_ != 0; }
+
+ // Returns the number of attributes, for example, returning 2 for:
+ // "BLAH=hah; path=/; domain=.google.com"
+ size_t NumberOfAttributes() const { return pairs_.size() - 1; }
+
+ // For debugging only!
+ std::string DebugString() const;
+
+ // Returns an iterator pointing to the first terminator character found in
+ // the given string.
+ static std::string::const_iterator FindFirstTerminator(const std::string& s);
+
+ // Given iterators pointing to the beginning and end of a string segment,
+ // returns as output arguments token_start and token_end to the start and end
+ // positions of a cookie attribute token name parsed from the segment, and
+ // updates the segment iterator to point to the next segment to be parsed.
+ // If no token is found, the function returns false.
+ static bool ParseToken(std::string::const_iterator* it,
+ const std::string::const_iterator& end,
+ std::string::const_iterator* token_start,
+ std::string::const_iterator* token_end);
+
+ // Given iterators pointing to the beginning and end of a string segment,
+ // returns as output arguments value_start and value_end to the start and end
+ // positions of a cookie attribute value parsed from the segment, and updates
+ // the segment iterator to point to the next segment to be parsed.
+ static void ParseValue(std::string::const_iterator* it,
+ const std::string::const_iterator& end,
+ std::string::const_iterator* value_start,
+ std::string::const_iterator* value_end);
+
+ // Same as the above functions, except the input is assumed to contain the
+ // desired token/value and nothing else.
+ static std::string ParseTokenString(const std::string& token);
+ static std::string ParseValueString(const std::string& value);
+
+ private:
+ static const char kTerminator[];
+ static const int kTerminatorLen;
+ static const char kWhitespace[];
+ static const char kValueSeparator[];
+ static const char kTokenSeparator[];
+
+ void ParseTokenValuePairs(const std::string& cookie_line);
+ void SetupAttributes();
+
+ PairList pairs_;
+ bool is_valid_;
+ // These will default to 0, but that should never be valid since the
+ // 0th index is the user supplied token/value, not an attribute.
+ // We're really never going to have more than like 8 attributes, so we
+ // could fit these into 3 bits each if we're worried about size...
+ size_t path_index_;
+ size_t domain_index_;
+ size_t mac_key_index_;
+ size_t mac_algorithm_index_;
+ size_t expires_index_;
+ size_t maxage_index_;
+ size_t secure_index_;
+ size_t httponly_index_;
+
+ DISALLOW_COPY_AND_ASSIGN(ParsedCookie);
+};
+
+typedef base::RefCountedThreadSafe<CookieMonster::PersistentCookieStore>
+ RefcountedPersistentCookieStore;
+
+class CookieMonster::PersistentCookieStore
+ : public RefcountedPersistentCookieStore {
+ public:
+ virtual ~PersistentCookieStore() {}
+
+ typedef base::Callback<void(const std::vector<
+ CookieMonster::CanonicalCookie*>&)> LoadedCallback;
+
+ // Initializes the store and retrieves the existing cookies. This will be
+ // called only once at startup. The callback will return all the cookies
+ // that are not yet returned to CookieMonster by previous priority loads.
+ virtual void Load(const LoadedCallback& loaded_callback) = 0;
+
+ // Does a priority load of all cookies for the domain key (eTLD+1). The
+ // callback will return all the cookies that are not yet returned by previous
+ // loads, which includes cookies for the requested domain key if they are not
+ // already returned, plus all cookies that are chain-loaded and not yet
+ // returned to CookieMonster.
+ virtual void LoadCookiesForKey(const std::string& key,
+ const LoadedCallback& loaded_callback) = 0;
+
+ virtual void AddCookie(const CanonicalCookie& cc) = 0;
+ virtual void UpdateCookieAccessTime(const CanonicalCookie& cc) = 0;
+ virtual void DeleteCookie(const CanonicalCookie& cc) = 0;
+
+ // Sets the value of the user preference whether the persistent storage
+ // must be deleted upon destruction.
+ virtual void SetClearLocalStateOnExit(bool clear_local_state) = 0;
+
+ // Flushes the store and posts |callback| when complete.
+ virtual void Flush(const base::Closure& callback) = 0;
+
+ protected:
+ PersistentCookieStore() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PersistentCookieStore);
+};
+
+class CookieList : public std::vector<CookieMonster::CanonicalCookie> {
+};
+
+} // namespace net
+
+#endif // NET_COOKIES_COOKIE_MONSTER_H_
diff --git a/net/base/cookie_monster_perftest.cc b/net/cookies/cookie_monster_perftest.cc
index a425138..eeab92f 100644
--- a/net/base/cookie_monster_perftest.cc
+++ b/net/cookies/cookie_monster_perftest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 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.
@@ -10,8 +10,8 @@
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "googleurl/src/gurl.h"
-#include "net/base/cookie_monster.h"
-#include "net/base/cookie_monster_store_test.h"
+#include "net/cookies/cookie_monster.h"
+#include "net/cookies/cookie_monster_store_test.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
diff --git a/net/base/cookie_monster_store_test.cc b/net/cookies/cookie_monster_store_test.cc
index e916e28..822aacc 100644
--- a/net/base/cookie_monster_store_test.cc
+++ b/net/cookies/cookie_monster_store_test.cc
@@ -1,8 +1,8 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 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 "net/base/cookie_monster_store_test.h"
+#include "net/cookies/cookie_monster_store_test.h"
#include "base/bind.h"
#include "base/message_loop.h"
diff --git a/net/cookies/cookie_monster_store_test.h b/net/cookies/cookie_monster_store_test.h
new file mode 100644
index 0000000..a05ddd3
--- /dev/null
+++ b/net/cookies/cookie_monster_store_test.h
@@ -0,0 +1,206 @@
+// Copyright (c) 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.
+
+// This file contains test infrastructure for multiple files
+// (current cookie_monster_unittest.cc and cookie_monster_perftest.cc)
+// that need to test out CookieMonster interactions with the backing store.
+// It should only be included by test code.
+
+#ifndef NET_COOKIES_COOKIE_MONSTER_STORE_TEST_H_
+#define NET_COOKIES_COOKIE_MONSTER_STORE_TEST_H_
+#pragma once
+
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+#include "net/cookies/cookie_monster.h"
+
+namespace base {
+class Time;
+}
+
+namespace net {
+
+// Wrapper class for posting a loaded callback. Since the Callback class is not
+// reference counted, we cannot post a callback to the message loop directly,
+// instead we post a LoadedCallbackTask.
+class LoadedCallbackTask
+ : public base::RefCountedThreadSafe<LoadedCallbackTask> {
+ public:
+ typedef CookieMonster::PersistentCookieStore::LoadedCallback LoadedCallback;
+
+ LoadedCallbackTask(LoadedCallback loaded_callback,
+ std::vector<CookieMonster::CanonicalCookie*> cookies);
+ ~LoadedCallbackTask();
+
+ void Run() {
+ loaded_callback_.Run(cookies_);
+ }
+
+ private:
+ LoadedCallback loaded_callback_;
+ std::vector<CookieMonster::CanonicalCookie*> cookies_;
+
+ DISALLOW_COPY_AND_ASSIGN(LoadedCallbackTask);
+}; // Wrapper class LoadedCallbackTask
+
+// Describes a call to one of the 3 functions of PersistentCookieStore.
+struct CookieStoreCommand {
+ enum Type {
+ ADD,
+ UPDATE_ACCESS_TIME,
+ REMOVE,
+ };
+
+ CookieStoreCommand(Type type,
+ const CookieMonster::CanonicalCookie& cookie)
+ : type(type),
+ cookie(cookie) {}
+
+ Type type;
+ CookieMonster::CanonicalCookie cookie;
+};
+
+// Implementation of PersistentCookieStore that captures the
+// received commands and saves them to a list.
+// The result of calls to Load() can be configured using SetLoadExpectation().
+class MockPersistentCookieStore
+ : public CookieMonster::PersistentCookieStore {
+ public:
+ typedef std::vector<CookieStoreCommand> CommandList;
+
+ MockPersistentCookieStore();
+ virtual ~MockPersistentCookieStore();
+
+ void SetLoadExpectation(
+ bool return_value,
+ const std::vector<CookieMonster::CanonicalCookie*>& result);
+
+ const CommandList& commands() const {
+ return commands_;
+ }
+
+ virtual void Load(const LoadedCallback& loaded_callback) OVERRIDE;
+
+ virtual void LoadCookiesForKey(const std::string& key,
+ const LoadedCallback& loaded_callback) OVERRIDE;
+
+ virtual void AddCookie(const CookieMonster::CanonicalCookie& cookie) OVERRIDE;
+
+ virtual void UpdateCookieAccessTime(
+ const CookieMonster::CanonicalCookie& cookie) OVERRIDE;
+
+ virtual void DeleteCookie(
+ const CookieMonster::CanonicalCookie& cookie) OVERRIDE;
+
+ virtual void Flush(const base::Closure& callback) OVERRIDE;
+
+ // No files are created so nothing to clear either
+ virtual void SetClearLocalStateOnExit(bool clear_local_state) OVERRIDE;
+
+ private:
+ CommandList commands_;
+
+ // Deferred result to use when Load() is called.
+ bool load_return_value_;
+ std::vector<CookieMonster::CanonicalCookie*> load_result_;
+ // Indicates if the store has been fully loaded to avoid returning duplicate
+ // cookies.
+ bool loaded_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockPersistentCookieStore);
+};
+
+// Mock for CookieMonster::Delegate
+class MockCookieMonsterDelegate : public CookieMonster::Delegate {
+ public:
+ typedef std::pair<CookieMonster::CanonicalCookie, bool>
+ CookieNotification;
+
+ MockCookieMonsterDelegate();
+
+ const std::vector<CookieNotification>& changes() const { return changes_; }
+
+ void reset() { changes_.clear(); }
+
+ virtual void OnCookieChanged(
+ const CookieMonster::CanonicalCookie& cookie,
+ bool removed,
+ CookieMonster::Delegate::ChangeCause cause) OVERRIDE;
+
+ private:
+ virtual ~MockCookieMonsterDelegate();
+
+ std::vector<CookieNotification> changes_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockCookieMonsterDelegate);
+};
+
+// Helper to build a single CanonicalCookie.
+CookieMonster::CanonicalCookie BuildCanonicalCookie(
+ const std::string& key,
+ const std::string& cookie_line,
+ const base::Time& creation_time);
+
+// Helper to build a list of CanonicalCookie*s.
+void AddCookieToList(
+ const std::string& key,
+ const std::string& cookie_line,
+ const base::Time& creation_time,
+ std::vector<CookieMonster::CanonicalCookie*>* out_list);
+
+// Just act like a backing database. Keep cookie information from
+// Add/Update/Delete and regurgitate it when Load is called.
+class MockSimplePersistentCookieStore
+ : public CookieMonster::PersistentCookieStore {
+ public:
+ MockSimplePersistentCookieStore();
+ virtual ~MockSimplePersistentCookieStore();
+
+ virtual void Load(const LoadedCallback& loaded_callback) OVERRIDE;
+
+ virtual void LoadCookiesForKey(const std::string& key,
+ const LoadedCallback& loaded_callback) OVERRIDE;
+
+ virtual void AddCookie(
+ const CookieMonster::CanonicalCookie& cookie) OVERRIDE;
+
+ virtual void UpdateCookieAccessTime(
+ const CookieMonster::CanonicalCookie& cookie) OVERRIDE;
+
+ virtual void DeleteCookie(
+ const CookieMonster::CanonicalCookie& cookie) OVERRIDE;
+
+ virtual void Flush(const base::Closure& callback) OVERRIDE;
+
+ virtual void SetClearLocalStateOnExit(bool clear_local_state) OVERRIDE;
+
+ private:
+ typedef std::map<int64, CookieMonster::CanonicalCookie>
+ CanonicalCookieMap;
+
+ CanonicalCookieMap cookies_;
+
+ // Indicates if the store has been fully loaded to avoid return duplicate
+ // cookies in subsequent load requests
+ bool loaded_;
+};
+
+// Helper function for creating a CookieMonster backed by a
+// MockSimplePersistentCookieStore for garbage collection testing.
+//
+// Fill the store through import with |num_cookies| cookies, |num_old_cookies|
+// with access time Now()-days_old, the rest with access time Now().
+// Do two SetCookies(). Return whether each of the two SetCookies() took
+// longer than |gc_perf_micros| to complete, and how many cookie were
+// left in the store afterwards.
+CookieMonster* CreateMonsterFromStoreForGC(
+ int num_cookies,
+ int num_old_cookies,
+ int days_old);
+
+} // namespace net
+
+#endif // NET_COOKIES_COOKIE_MONSTER_STORE_TEST_H_
diff --git a/net/base/cookie_monster_unittest.cc b/net/cookies/cookie_monster_unittest.cc
index 541a2b1..24390bc 100644
--- a/net/base/cookie_monster_unittest.cc
+++ b/net/cookies/cookie_monster_unittest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "net/base/cookie_store_unittest.h"
+#include "net/cookies/cookie_store_unittest.h"
#include <time.h>
#include <string>
@@ -18,9 +18,9 @@
#include "base/threading/thread.h"
#include "base/time.h"
#include "googleurl/src/gurl.h"
-#include "net/base/cookie_monster.h"
-#include "net/base/cookie_monster_store_test.h" // For CookieStore mock
-#include "net/base/cookie_util.h"
+#include "net/cookies/cookie_monster.h"
+#include "net/cookies/cookie_monster_store_test.h" // For CookieStore mock
+#include "net/cookies/cookie_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/net/cookies/cookie_options.h b/net/cookies/cookie_options.h
new file mode 100644
index 0000000..a59054a
--- /dev/null
+++ b/net/cookies/cookie_options.h
@@ -0,0 +1,40 @@
+// Copyright (c) 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.
+
+// Brought to you by number 42.
+
+#ifndef NET_COOKIES_COOKIE_OPTIONS_H_
+#define NET_COOKIES_COOKIE_OPTIONS_H_
+#pragma once
+
+namespace net {
+
+class CookieOptions {
+ public:
+ // Default is to exclude httponly, which means:
+ // - reading operations will not return httponly cookies.
+ // - writing operations will not write httponly cookies.
+ CookieOptions()
+ : exclude_httponly_(true),
+ force_session_(false) {
+ }
+
+ void set_exclude_httponly() { exclude_httponly_ = true; }
+ void set_include_httponly() { exclude_httponly_ = false; }
+ bool exclude_httponly() const { return exclude_httponly_; }
+
+ // Forces a cookie to be saved as a session cookie. If the expiration time of
+ // the cookie is in the past, i.e. the cookie would end up being deleted, this
+ // option is ignored. See CookieMonsterTest.ForceSessionOnly.
+ void set_force_session() { force_session_ = true; }
+ bool force_session() const { return force_session_; }
+
+ private:
+ bool exclude_httponly_;
+ bool force_session_;
+};
+} // namespace net
+
+#endif // NET_COOKIES_COOKIE_OPTIONS_H_
+
diff --git a/net/base/cookie_store.cc b/net/cookies/cookie_store.cc
index a806d6c..25060904 100644
--- a/net/base/cookie_store.cc
+++ b/net/cookies/cookie_store.cc
@@ -1,10 +1,10 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 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 "net/base/cookie_store.h"
+#include "net/cookies/cookie_store.h"
-#include "net/base/cookie_options.h"
+#include "net/cookies/cookie_options.h"
namespace net {
diff --git a/net/cookies/cookie_store.h b/net/cookies/cookie_store.h
new file mode 100644
index 0000000..b9772d5
--- /dev/null
+++ b/net/cookies/cookie_store.h
@@ -0,0 +1,113 @@
+// Copyright (c) 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.
+
+// Brought to you by number 42.
+
+#ifndef NET_COOKIES_COOKIE_STORE_H_
+#define NET_COOKIES_COOKIE_STORE_H_
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/time.h"
+#include "net/cookies/cookie_options.h"
+#include "net/base/net_export.h"
+
+class GURL;
+
+namespace net {
+
+class CookieMonster;
+
+// An interface for storing and retrieving cookies. Implementations need to
+// be thread safe as its methods can be accessed from IO as well as UI threads.
+class NET_EXPORT CookieStore : public base::RefCountedThreadSafe<CookieStore> {
+ public:
+ // This struct contains additional consumer-specific information that might
+ // be stored with cookies; currently just MAC information, see:
+ // http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac
+ struct NET_EXPORT CookieInfo {
+ CookieInfo();
+ ~CookieInfo();
+
+ // The name of the cookie.
+ std::string name;
+ // TODO(abarth): Add value if any clients need it.
+
+ // The time at which the cookie was created.
+ base::Time creation_date;
+
+ // The value of the MAC-Key and MAC-Algorithm attributes, if present.
+ std::string mac_key;
+ std::string mac_algorithm;
+ };
+
+ // Callback definitions.
+ typedef base::Callback <void(
+ const std::string& cookie_line,
+ const std::vector<CookieInfo>& cookie_infos)> GetCookieInfoCallback;
+ typedef base::Callback<void(const std::string& cookie)>
+ GetCookiesCallback;
+ typedef base::Callback<void(bool success)> SetCookiesCallback;
+ typedef base::Callback<void(int num_deleted)> DeleteCallback;
+
+
+ // Sets a single cookie. Expects a cookie line, like "a=1; domain=b.com".
+ //
+ // Fails either if the cookie is invalid or if this is a non-HTTPONLY cookie
+ // and it would overwrite an existing HTTPONLY cookie.
+ // Returns true if the cookie is successfully set.
+ virtual void SetCookieWithOptionsAsync(
+ const GURL& url,
+ const std::string& cookie_line,
+ const CookieOptions& options,
+ const SetCookiesCallback& callback) = 0;
+
+ // TODO(???): what if the total size of all the cookies >4k, can we have a
+ // header that big or do we need multiple Cookie: headers?
+ // Note: Some sites, such as Facebook, occasionally use Cookie headers >4k.
+ //
+ // Simple interface, gets a cookie string "a=b; c=d" for the given URL.
+ // Use options to access httponly cookies.
+ virtual void GetCookiesWithOptionsAsync(
+ const GURL& url, const CookieOptions& options,
+ const GetCookiesCallback& callback) = 0;
+
+ // This function is similar to GetCookiesWithOptions same functionality as
+ // GetCookiesWithOptions except that it additionally provides detailed
+ // information about the cookie contained in the cookie line. See |struct
+ // CookieInfo| above for details.
+ virtual void GetCookiesWithInfoAsync(
+ const GURL& url,
+ const CookieOptions& options,
+ const GetCookieInfoCallback& callback) = 0;
+
+ // Deletes the passed in cookie for the specified URL.
+ virtual void DeleteCookieAsync(const GURL& url,
+ const std::string& cookie_name,
+ const base::Closure& callback) = 0;
+
+ // Deletes all of the cookies that have a creation_date greater than or equal
+ // to |delete_begin| and less than |delete_end|
+ // Returns the number of cookies that have been deleted.
+ virtual void DeleteAllCreatedBetweenAsync(const base::Time& delete_begin,
+ const base::Time& delete_end,
+ const DeleteCallback& callback) = 0;
+
+ // Returns the underlying CookieMonster.
+ virtual CookieMonster* GetCookieMonster() = 0;
+
+ protected:
+ friend class base::RefCountedThreadSafe<CookieStore>;
+ CookieStore();
+ virtual ~CookieStore();
+};
+
+} // namespace net
+
+#endif // NET_COOKIES_COOKIE_STORE_H_
diff --git a/net/base/cookie_store_test_callbacks.cc b/net/cookies/cookie_store_test_callbacks.cc
index e16df06..0d4cb5c 100644
--- a/net/base/cookie_store_test_callbacks.cc
+++ b/net/cookies/cookie_store_test_callbacks.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "net/base/cookie_store_test_callbacks.h"
+#include "net/cookies/cookie_store_test_callbacks.h"
#include "base/message_loop.h"
#include "base/threading/thread.h"
diff --git a/net/cookies/cookie_store_test_callbacks.h b/net/cookies/cookie_store_test_callbacks.h
new file mode 100644
index 0000000..d201d32
--- /dev/null
+++ b/net/cookies/cookie_store_test_callbacks.h
@@ -0,0 +1,137 @@
+// Copyright (c) 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 NET_COOKIES_COOKIE_STORE_TEST_CALLBACKS_H_
+#define NET_COOKIES_COOKIE_STORE_TEST_CALLBACKS_H_
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "net/cookies/cookie_store.h"
+
+class MessageLoop;
+
+namespace base {
+class Thread;
+}
+
+namespace net {
+
+// Defines common behaviour for the callbacks from GetCookies, SetCookies, etc.
+// Asserts that the current thread is the expected invocation thread, sends a
+// quit to the thread in which it was constructed.
+class CookieCallback {
+ public:
+ // Indicates whether the callback has been called.
+ bool did_run() { return did_run_; }
+
+ protected:
+ // Constructs a callback that expects to be called in the given thread and
+ // will, upon execution, send a QUIT to the constructing thread.
+ explicit CookieCallback(base::Thread* run_in_thread);
+
+ // Constructs a callback that expects to be called in current thread and will
+ // send a QUIT to the constructing thread.
+ CookieCallback();
+
+ // Tests whether the current thread was the caller's thread.
+ // Sends a QUIT to the constructing thread.
+ void CallbackEpilogue();
+
+ private:
+ bool did_run_;
+ base::Thread* run_in_thread_;
+ MessageLoop* run_in_loop_;
+ MessageLoop* parent_loop_;
+ MessageLoop* loop_to_quit_;
+};
+
+// Callback implementations for the asynchronous CookieStore methods.
+
+class SetCookieCallback : public CookieCallback {
+ public:
+ SetCookieCallback();
+ explicit SetCookieCallback(base::Thread* run_in_thread);
+
+ void Run(bool result) {
+ result_ = result;
+ CallbackEpilogue();
+ }
+
+ bool result() { return result_; }
+
+ private:
+ bool result_;
+};
+
+class GetCookieStringCallback : public CookieCallback {
+ public:
+ GetCookieStringCallback();
+ explicit GetCookieStringCallback(base::Thread* run_in_thread);
+
+ void Run(const std::string& cookie) {
+ cookie_ = cookie;
+ CallbackEpilogue();
+ }
+
+ const std::string& cookie() { return cookie_; }
+
+ private:
+ std::string cookie_;
+};
+
+class GetCookiesWithInfoCallback : public CookieCallback {
+ public:
+ GetCookiesWithInfoCallback();
+ explicit GetCookiesWithInfoCallback(base::Thread* run_in_thread);
+ ~GetCookiesWithInfoCallback();
+
+ void Run(
+ const std::string& cookie_line,
+ const std::vector<CookieStore::CookieInfo>& cookie_info) {
+ cookie_line_ = cookie_line;
+ cookie_info_ = cookie_info;
+ CallbackEpilogue();
+ }
+
+ const std::string& cookie_line() { return cookie_line_; }
+ const std::vector<CookieStore::CookieInfo>& cookie_info() {
+ return cookie_info_;
+ }
+
+ private:
+ std::string cookie_line_;
+ std::vector<CookieStore::CookieInfo> cookie_info_;
+};
+
+class DeleteCallback : public CookieCallback {
+ public:
+ DeleteCallback();
+ explicit DeleteCallback(base::Thread* run_in_thread);
+
+ void Run(int num_deleted) {
+ num_deleted_ = num_deleted;
+ CallbackEpilogue();
+ }
+
+ int num_deleted() { return num_deleted_; }
+
+ private:
+ int num_deleted_;
+};
+
+class DeleteCookieCallback : public CookieCallback {
+ public:
+ DeleteCookieCallback();
+ explicit DeleteCookieCallback(base::Thread* run_in_thread);
+
+ void Run() {
+ CallbackEpilogue();
+ }
+};
+
+} // namespace net
+
+#endif // NET_COOKIES_COOKIE_STORE_TEST_CALLBACKS_H_
diff --git a/net/base/cookie_store_test_helpers.cc b/net/cookies/cookie_store_test_helpers.cc
index 832e3da..e764c9c 100644
--- a/net/base/cookie_store_test_helpers.cc
+++ b/net/cookies/cookie_store_test_helpers.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "net/base/cookie_store_test_helpers.h"
+#include "net/cookies/cookie_store_test_helpers.h"
#include "base/bind.h"
#include "base/message_loop.h"
diff --git a/net/cookies/cookie_store_test_helpers.h b/net/cookies/cookie_store_test_helpers.h
new file mode 100644
index 0000000..4e7ce27
--- /dev/null
+++ b/net/cookies/cookie_store_test_helpers.h
@@ -0,0 +1,105 @@
+// Copyright (c) 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 NET_COOKIES_COOKIE_STORE_TEST_HELPERS_H_
+#define NET_COOKIES_COOKIE_STORE_TEST_HELPERS_H_
+#pragma once
+
+#include "net/cookies/cookie_monster.h"
+
+#include <string>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+class DelayedCookieMonster : public CookieStore {
+ public:
+ DelayedCookieMonster();
+
+ // Call the asynchronous CookieMonster function, expect it to immediately
+ // invoke the internal callback.
+ // Post a delayed task to invoke the original callback with the results.
+
+ virtual void SetCookieWithOptionsAsync(
+ const GURL& url,
+ const std::string& cookie_line,
+ const CookieOptions& options,
+ const CookieMonster::SetCookiesCallback& callback) OVERRIDE;
+
+ virtual void GetCookiesWithOptionsAsync(
+ const GURL& url, const CookieOptions& options,
+ const CookieMonster::GetCookiesCallback& callback) OVERRIDE;
+
+ virtual void GetCookiesWithInfoAsync(
+ const GURL& url,
+ const CookieOptions& options,
+ const CookieMonster::GetCookieInfoCallback& callback) OVERRIDE;
+
+ virtual bool SetCookieWithOptions(const GURL& url,
+ const std::string& cookie_line,
+ const CookieOptions& options);
+
+ virtual std::string GetCookiesWithOptions(const GURL& url,
+ const CookieOptions& options);
+
+ virtual void GetCookiesWithInfo(const GURL& url,
+ const CookieOptions& options,
+ std::string* cookie_line,
+ std::vector<CookieInfo>* cookie_infos);
+
+ virtual void DeleteCookie(const GURL& url,
+ const std::string& cookie_name);
+
+ virtual void DeleteCookieAsync(const GURL& url,
+ const std::string& cookie_name,
+ const base::Closure& callback) OVERRIDE;
+
+ virtual void DeleteAllCreatedBetweenAsync(
+ const base::Time& delete_begin,
+ const base::Time& delete_end,
+ const DeleteCallback& callback) OVERRIDE;
+
+ virtual CookieMonster* GetCookieMonster() OVERRIDE;
+
+ private:
+
+ // Be called immediately from CookieMonster.
+
+ void GetCookiesInternalCallback(
+ const std::string& cookie_line,
+ const std::vector<CookieStore::CookieInfo>& cookie_info);
+
+ void SetCookiesInternalCallback(bool result);
+
+ void GetCookiesWithOptionsInternalCallback(const std::string& cookie);
+
+ // Invoke the original callbacks.
+
+ void InvokeGetCookiesCallback(
+ const CookieMonster::GetCookieInfoCallback& callback);
+
+ void InvokeSetCookiesCallback(
+ const CookieMonster::SetCookiesCallback& callback);
+
+ void InvokeGetCookieStringCallback(
+ const CookieMonster::GetCookiesCallback& callback);
+
+ friend class base::RefCountedThreadSafe<DelayedCookieMonster>;
+ virtual ~DelayedCookieMonster();
+
+ scoped_refptr<CookieMonster> cookie_monster_;
+
+ bool did_run_;
+ bool result_;
+ std::string cookie_;
+ std::string cookie_line_;
+ std::vector<CookieStore::CookieInfo> cookie_info_;
+};
+
+} // namespace net
+
+#endif // NET_COOKIES_COOKIE_STORE_TEST_HELPERS_H_
diff --git a/net/cookies/cookie_store_unittest.h b/net/cookies/cookie_store_unittest.h
new file mode 100644
index 0000000..e1d23f8
--- /dev/null
+++ b/net/cookies/cookie_store_unittest.h
@@ -0,0 +1,1055 @@
+// Copyright (c) 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 NET_COOKIES_COOKIE_STORE_UNITTEST_H_
+#define NET_COOKIES_COOKIE_STORE_UNITTEST_H_
+#pragma once
+
+#include "base/bind.h"
+#include "base/message_loop.h"
+#include "base/string_tokenizer.h"
+#include "base/threading/thread.h"
+#include "googleurl/src/gurl.h"
+#include "net/cookies/cookie_monster.h"
+#include "net/cookies/cookie_store.h"
+#include "net/cookies/cookie_store_test_callbacks.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// This file declares unittest templates that can be used to test common
+// behavior of any CookieStore implementation.
+// See cookie_monster_unittest.cc for an example of an implementation.
+
+namespace net {
+
+using base::Thread;
+
+const int kTimeout = 1000;
+
+const char kUrlFtp[] = "ftp://ftp.google.izzle/";
+const char kUrlGoogle[] = "http://www.google.izzle";
+const char kUrlGoogleFoo[] = "http://www.google.izzle/foo";
+const char kUrlGoogleBar[] = "http://www.google.izzle/bar";
+const char kUrlGoogleSecure[] = "https://www.google.izzle";
+const char kValidCookieLine[] = "A=B; path=/";
+const char kValidDomainCookieLine[] = "A=B; path=/; domain=google.izzle";
+
+// The CookieStoreTestTraits must have the following members:
+// struct CookieStoreTestTraits {
+// // Factory function.
+// static scoped_refptr<CookieStore> Create();
+//
+// // The cookie store is a CookieMonster. Only used to test
+// // GetCookieMonster().
+// static const bool is_cookie_monster;
+//
+// // The cookie store supports cookies with the exclude_httponly() option.
+// static const bool supports_http_only;
+//
+// // The cookie store supports the GetCookiesWithInfoAsync() method.
+// static const bool supports_cookies_with_info;
+//
+// // The cookie store is able to make the difference between the ".com"
+// // and the "com" domains.
+// static const bool supports_non_dotted_domains;
+//
+// // The cookie store handles the domains with trailing dots (such as "com.")
+// // correctly.
+// static const bool supports_trailing_dots;
+//
+// // The cookie store rejects cookies for invalid schemes such as ftp.
+// static const bool filters_schemes;
+//
+// // The cookie store has a bug happening when a path is a substring of
+// // another.
+// static const bool has_path_prefix_bug;
+//
+// // Time to wait between two cookie insertions to ensure that cookies have
+// // different creation times.
+// static const int creation_time_granularity_in_ms;
+// };
+
+template <class CookieStoreTestTraits>
+class CookieStoreTest : public testing::Test {
+ protected:
+ CookieStoreTest()
+ : url_google_(kUrlGoogle),
+ url_google_secure_(kUrlGoogleSecure),
+ url_google_foo_(kUrlGoogleFoo),
+ url_google_bar_(kUrlGoogleBar) {
+ // This test may be used outside of the net test suite, and thus may not
+ // have a message loop.
+ if (!MessageLoop::current())
+ message_loop_.reset(new MessageLoop);
+ weak_factory_.reset(
+ new base::WeakPtrFactory<MessageLoop>(MessageLoop::current()));
+ }
+
+ // Helper methods for the asynchronous Cookie Store API that call the
+ // asynchronous method and then pump the loop until the callback is invoked,
+ // finally returning the value.
+
+ std::string GetCookies(CookieStore* cs, const GURL& url) {
+ DCHECK(cs);
+ CookieOptions options;
+ if (!CookieStoreTestTraits::supports_http_only)
+ options.set_include_httponly();
+ GetCookieStringCallback callback;
+ cs->GetCookiesWithOptionsAsync(
+ url, options,
+ base::Bind(&GetCookieStringCallback::Run, base::Unretained(&callback)));
+ RunFor(kTimeout);
+ EXPECT_TRUE(callback.did_run());
+ return callback.cookie();
+ }
+
+ std::string GetCookiesWithOptions(CookieStore* cs,
+ const GURL& url,
+ const CookieOptions& options) {
+ DCHECK(cs);
+ GetCookieStringCallback callback;
+ cs->GetCookiesWithOptionsAsync(
+ url, options, base::Bind(&GetCookieStringCallback::Run,
+ base::Unretained(&callback)));
+ RunFor(kTimeout);
+ EXPECT_TRUE(callback.did_run());
+ return callback.cookie();
+ }
+
+ void GetCookiesWithInfo(CookieStore* cs,
+ const GURL& url,
+ const CookieOptions& options,
+ std::string* cookie_line,
+ std::vector<CookieStore::CookieInfo>* cookie_info) {
+ DCHECK(cs);
+ DCHECK(cookie_line);
+ DCHECK(cookie_info);
+ GetCookiesWithInfoCallback callback;
+ cs->GetCookiesWithInfoAsync(
+ url, options, base::Bind(&GetCookiesWithInfoCallback::Run,
+ base::Unretained(&callback)));
+ RunFor(kTimeout);
+ EXPECT_TRUE(callback.did_run());
+ *cookie_line = callback.cookie_line();
+ *cookie_info = callback.cookie_info();
+ }
+
+ bool SetCookieWithOptions(CookieStore* cs,
+ const GURL& url,
+ const std::string& cookie_line,
+ const CookieOptions& options) {
+ DCHECK(cs);
+ SetCookieCallback callback;
+ cs->SetCookieWithOptionsAsync(
+ url, cookie_line, options,
+ base::Bind(&SetCookieCallback::Run, base::Unretained(&callback)));
+ RunFor(kTimeout);
+ EXPECT_TRUE(callback.did_run());
+ return callback.result();
+ }
+
+ bool SetCookie(CookieStore* cs,
+ const GURL& url,
+ const std::string& cookie_line) {
+ CookieOptions options;
+ if (!CookieStoreTestTraits::supports_http_only)
+ options.set_include_httponly();
+ return SetCookieWithOptions(cs, url, cookie_line, options);
+ }
+
+ void DeleteCookie(CookieStore* cs,
+ const GURL& url,
+ const std::string& cookie_name) {
+ DCHECK(cs);
+ DeleteCookieCallback callback;
+ cs->DeleteCookieAsync(
+ url, cookie_name,
+ base::Bind(&DeleteCookieCallback::Run, base::Unretained(&callback)));
+ RunFor(kTimeout);
+ EXPECT_TRUE(callback.did_run());
+ }
+
+ int DeleteCreatedBetween(CookieStore* cs,
+ const base::Time& delete_begin,
+ const base::Time& delete_end) {
+ DCHECK(cs);
+ DeleteCallback callback;
+ cs->DeleteAllCreatedBetweenAsync(
+ delete_begin, delete_end,
+ base::Bind(&DeleteCallback::Run, base::Unretained(&callback)));
+ RunFor(kTimeout);
+ EXPECT_TRUE(callback.did_run());
+ return callback.num_deleted();
+ }
+
+ void RunFor(int ms) {
+ // Runs the test thread message loop for up to |ms| milliseconds.
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE, base::Bind(&MessageLoop::Quit, weak_factory_->GetWeakPtr()),
+ base::TimeDelta::FromMilliseconds(ms));
+ MessageLoop::current()->Run();
+ weak_factory_->InvalidateWeakPtrs();
+ }
+
+ scoped_refptr<CookieStore> GetCookieStore() {
+ return CookieStoreTestTraits::Create();
+ }
+
+ // Compares two cookie lines.
+ void MatchCookieLines(const std::string& line1, const std::string& line2) {
+ EXPECT_EQ(TokenizeCookieLine(line1), TokenizeCookieLine(line2));
+ }
+
+ // Check the cookie line by polling until equality or a timeout is reached.
+ void MatchCookieLineWithTimeout(CookieStore* cs,
+ const GURL& url,
+ const std::string& line) {
+ std::string cookies = GetCookies(cs, url);
+ bool matched = (TokenizeCookieLine(line) == TokenizeCookieLine(cookies));
+ base::Time polling_end_date = base::Time::Now() +
+ base::TimeDelta::FromMilliseconds(
+ CookieStoreTestTraits::creation_time_granularity_in_ms);
+
+ while (!matched && base::Time::Now() <= polling_end_date) {
+ base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
+ cookies = GetCookies(cs, url);
+ matched = (TokenizeCookieLine(line) == TokenizeCookieLine(cookies));
+ }
+
+ EXPECT_TRUE(matched) << "\"" << cookies
+ << "\" does not match \"" << line << "\"";
+ }
+
+ GURL url_google_;
+ GURL url_google_secure_;
+ GURL url_google_foo_;
+ GURL url_google_bar_;
+
+ scoped_ptr<base::WeakPtrFactory<MessageLoop> > weak_factory_;
+ scoped_ptr<MessageLoop> message_loop_;
+
+ private:
+ // Returns a set of strings of type "name=value". Fails in case of duplicate.
+ std::set<std::string> TokenizeCookieLine(const std::string& line) {
+ std::set<std::string> tokens;
+ StringTokenizer tokenizer(line, " ;");
+ while (tokenizer.GetNext())
+ EXPECT_TRUE(tokens.insert(tokenizer.token()).second);
+ return tokens;
+ }
+};
+
+TYPED_TEST_CASE_P(CookieStoreTest);
+
+TYPED_TEST_P(CookieStoreTest, TypeTest) {
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+ EXPECT_EQ(cs->GetCookieMonster(),
+ (TypeParam::is_cookie_monster) ?
+ static_cast<CookieMonster*>(cs.get()) : NULL);
+}
+
+TYPED_TEST_P(CookieStoreTest, DomainTest) {
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+ EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "A=B"));
+ this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_));
+ EXPECT_TRUE(this->SetCookie(cs, this->url_google_,
+ "C=D; domain=.google.izzle"));
+ this->MatchCookieLines("A=B; C=D", this->GetCookies(cs, this->url_google_));
+
+ // Verify that A=B was set as a host cookie rather than a domain
+ // cookie -- should not be accessible from a sub sub-domain.
+ this->MatchCookieLines("C=D",
+ this->GetCookies(cs, GURL("http://foo.www.google.izzle")));
+
+ // Test and make sure we find domain cookies on the same domain.
+ EXPECT_TRUE(this->SetCookie(cs, this->url_google_,
+ "E=F; domain=.www.google.izzle"));
+ this->MatchCookieLines("A=B; C=D; E=F",
+ this->GetCookies(cs, this->url_google_));
+
+ // Test setting a domain= that doesn't start w/ a dot, should
+ // treat it as a domain cookie, as if there was a pre-pended dot.
+ EXPECT_TRUE(this->SetCookie(cs, this->url_google_,
+ "G=H; domain=www.google.izzle"));
+ this->MatchCookieLines("A=B; C=D; E=F; G=H",
+ this->GetCookies(cs, this->url_google_));
+
+ // Test domain enforcement, should fail on a sub-domain or something too deep.
+ EXPECT_FALSE(this->SetCookie(cs, this->url_google_, "I=J; domain=.izzle"));
+ this->MatchCookieLines("", this->GetCookies(cs, GURL("http://a.izzle")));
+ EXPECT_FALSE(this->SetCookie(cs, this->url_google_,
+ "K=L; domain=.bla.www.google.izzle"));
+ this->MatchCookieLines("C=D; E=F; G=H",
+ this->GetCookies(cs, GURL("http://bla.www.google.izzle")));
+ this->MatchCookieLines("A=B; C=D; E=F; G=H",
+ this->GetCookies(cs, this->url_google_));
+}
+
+// FireFox recognizes domains containing trailing periods as valid.
+// IE and Safari do not. Assert the expected policy here.
+TYPED_TEST_P(CookieStoreTest, DomainWithTrailingDotTest) {
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+ EXPECT_FALSE(this->SetCookie(cs, this->url_google_,
+ "a=1; domain=.www.google.com."));
+ EXPECT_FALSE(this->SetCookie(cs, this->url_google_,
+ "b=2; domain=.www.google.com.."));
+ this->MatchCookieLines("", this->GetCookies(cs, this->url_google_));
+}
+
+// Test that cookies can bet set on higher level domains.
+// http://b/issue?id=896491
+TYPED_TEST_P(CookieStoreTest, ValidSubdomainTest) {
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+ GURL url_abcd("http://a.b.c.d.com");
+ GURL url_bcd("http://b.c.d.com");
+ GURL url_cd("http://c.d.com");
+ GURL url_d("http://d.com");
+
+ EXPECT_TRUE(this->SetCookie(cs, url_abcd, "a=1; domain=.a.b.c.d.com"));
+ EXPECT_TRUE(this->SetCookie(cs, url_abcd, "b=2; domain=.b.c.d.com"));
+ EXPECT_TRUE(this->SetCookie(cs, url_abcd, "c=3; domain=.c.d.com"));
+ EXPECT_TRUE(this->SetCookie(cs, url_abcd, "d=4; domain=.d.com"));
+
+ this->MatchCookieLines("a=1; b=2; c=3; d=4", this->GetCookies(cs, url_abcd));
+ this->MatchCookieLines("b=2; c=3; d=4", this->GetCookies(cs, url_bcd));
+ this->MatchCookieLines("c=3; d=4", this->GetCookies(cs, url_cd));
+ this->MatchCookieLines("d=4", this->GetCookies(cs, url_d));
+
+ // Check that the same cookie can exist on different sub-domains.
+ EXPECT_TRUE(this->SetCookie(cs, url_bcd, "X=bcd; domain=.b.c.d.com"));
+ EXPECT_TRUE(this->SetCookie(cs, url_bcd, "X=cd; domain=.c.d.com"));
+ this->MatchCookieLines("b=2; c=3; d=4; X=bcd; X=cd",
+ this->GetCookies(cs, url_bcd));
+ this->MatchCookieLines("c=3; d=4; X=cd", this->GetCookies(cs, url_cd));
+}
+
+// Test that setting a cookie which specifies an invalid domain has
+// no side-effect. An invalid domain in this context is one which does
+// not match the originating domain.
+// http://b/issue?id=896472
+TYPED_TEST_P(CookieStoreTest, InvalidDomainTest) {
+ {
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+ GURL url_foobar("http://foo.bar.com");
+
+ // More specific sub-domain than allowed.
+ EXPECT_FALSE(this->SetCookie(cs, url_foobar,
+ "a=1; domain=.yo.foo.bar.com"));
+
+ EXPECT_FALSE(this->SetCookie(cs, url_foobar, "b=2; domain=.foo.com"));
+ EXPECT_FALSE(this->SetCookie(cs, url_foobar, "c=3; domain=.bar.foo.com"));
+
+ // Different TLD, but the rest is a substring.
+ EXPECT_FALSE(this->SetCookie(cs, url_foobar,
+ "d=4; domain=.foo.bar.com.net"));
+
+ // A substring that isn't really a parent domain.
+ EXPECT_FALSE(this->SetCookie(cs, url_foobar, "e=5; domain=ar.com"));
+
+ // Completely invalid domains:
+ EXPECT_FALSE(this->SetCookie(cs, url_foobar, "f=6; domain=."));
+ EXPECT_FALSE(this->SetCookie(cs, url_foobar, "g=7; domain=/"));
+ EXPECT_FALSE(this->SetCookie(cs, url_foobar,
+ "h=8; domain=http://foo.bar.com"));
+ EXPECT_FALSE(this->SetCookie(cs, url_foobar, "i=9; domain=..foo.bar.com"));
+ EXPECT_FALSE(this->SetCookie(cs, url_foobar, "j=10; domain=..bar.com"));
+
+ // Make sure there isn't something quirky in the domain canonicalization
+ // that supports full URL semantics.
+ EXPECT_FALSE(this->SetCookie(cs, url_foobar,
+ "k=11; domain=.foo.bar.com?blah"));
+ EXPECT_FALSE(this->SetCookie(cs, url_foobar,
+ "l=12; domain=.foo.bar.com/blah"));
+ EXPECT_FALSE(this->SetCookie(cs, url_foobar,
+ "m=13; domain=.foo.bar.com:80"));
+ EXPECT_FALSE(this->SetCookie(cs, url_foobar,
+ "n=14; domain=.foo.bar.com:"));
+ EXPECT_FALSE(this->SetCookie(cs, url_foobar,
+ "o=15; domain=.foo.bar.com#sup"));
+
+ this->MatchCookieLines("", this->GetCookies(cs, url_foobar));
+ }
+
+ {
+ // Make sure the cookie code hasn't gotten its subdomain string handling
+ // reversed, missed a suffix check, etc. It's important here that the two
+ // hosts below have the same domain + registry.
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+ GURL url_foocom("http://foo.com.com");
+ EXPECT_FALSE(this->SetCookie(cs, url_foocom,
+ "a=1; domain=.foo.com.com.com"));
+ this->MatchCookieLines("", this->GetCookies(cs, url_foocom));
+ }
+}
+
+// Test the behavior of omitting dot prefix from domain, should
+// function the same as FireFox.
+// http://b/issue?id=889898
+TYPED_TEST_P(CookieStoreTest, DomainWithoutLeadingDotTest) {
+ { // The omission of dot results in setting a domain cookie.
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+ GURL url_hosted("http://manage.hosted.filefront.com");
+ GURL url_filefront("http://www.filefront.com");
+ EXPECT_TRUE(this->SetCookie(cs, url_hosted,
+ "sawAd=1; domain=filefront.com"));
+ this->MatchCookieLines("sawAd=1", this->GetCookies(cs, url_hosted));
+ this->MatchCookieLines("sawAd=1", this->GetCookies(cs, url_filefront));
+ }
+
+ { // Even when the domains match exactly, don't consider it host cookie.
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+ GURL url("http://www.google.com");
+ EXPECT_TRUE(this->SetCookie(cs, url, "a=1; domain=www.google.com"));
+ this->MatchCookieLines("a=1", this->GetCookies(cs, url));
+ this->MatchCookieLines("a=1",
+ this->GetCookies(cs, GURL("http://sub.www.google.com")));
+ this->MatchCookieLines("",
+ this->GetCookies(cs, GURL("http://something-else.com")));
+ }
+}
+
+// Test that the domain specified in cookie string is treated case-insensitive
+// http://b/issue?id=896475.
+TYPED_TEST_P(CookieStoreTest, CaseInsensitiveDomainTest) {
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+ GURL url("http://www.google.com");
+ EXPECT_TRUE(this->SetCookie(cs, url, "a=1; domain=.GOOGLE.COM"));
+ EXPECT_TRUE(this->SetCookie(cs, url, "b=2; domain=.wWw.gOOgLE.coM"));
+ this->MatchCookieLines("a=1; b=2", this->GetCookies(cs, url));
+}
+
+TYPED_TEST_P(CookieStoreTest, TestIpAddress) {
+ GURL url_ip("http://1.2.3.4/weee");
+ {
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+ EXPECT_TRUE(this->SetCookie(cs, url_ip, kValidCookieLine));
+ this->MatchCookieLines("A=B", this->GetCookies(cs, url_ip));
+ }
+
+ { // IP addresses should not be able to set domain cookies.
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+ EXPECT_FALSE(this->SetCookie(cs, url_ip, "b=2; domain=.1.2.3.4"));
+ EXPECT_FALSE(this->SetCookie(cs, url_ip, "c=3; domain=.3.4"));
+ this->MatchCookieLines("", this->GetCookies(cs, url_ip));
+ // It should be allowed to set a cookie if domain= matches the IP address
+ // exactly. This matches IE/Firefox, even though it seems a bit wrong.
+ EXPECT_FALSE(this->SetCookie(cs, url_ip, "b=2; domain=1.2.3.3"));
+ this->MatchCookieLines("", this->GetCookies(cs, url_ip));
+ EXPECT_TRUE(this->SetCookie(cs, url_ip, "b=2; domain=1.2.3.4"));
+ this->MatchCookieLines("b=2", this->GetCookies(cs, url_ip));
+ }
+}
+
+// Test host cookies, and setting of cookies on TLD.
+TYPED_TEST_P(CookieStoreTest, TestNonDottedAndTLD) {
+ {
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+ GURL url("http://com/");
+ // Allow setting on "com", (but only as a host cookie).
+ EXPECT_TRUE(this->SetCookie(cs, url, "a=1"));
+ EXPECT_FALSE(this->SetCookie(cs, url, "b=2; domain=.com"));
+ EXPECT_FALSE(this->SetCookie(cs, url, "c=3; domain=com"));
+ this->MatchCookieLines("a=1", this->GetCookies(cs, url));
+ // Make sure it doesn't show up for a normal .com, it should be a host
+ // not a domain cookie.
+ this->MatchCookieLines("",
+ this->GetCookies(cs, GURL("http://hopefully-no-cookies.com/")));
+ if (TypeParam::supports_non_dotted_domains) {
+ this->MatchCookieLines("", this->GetCookies(cs, GURL("http://.com/")));
+ }
+ }
+
+ {
+ // http://com. should be treated the same as http://com.
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+ GURL url("http://com./index.html");
+ if (TypeParam::supports_trailing_dots) {
+ EXPECT_TRUE(this->SetCookie(cs, url, "a=1"));
+ this->MatchCookieLines("a=1", this->GetCookies(cs, url));
+ this->MatchCookieLines("",
+ this->GetCookies(cs, GURL("http://hopefully-no-cookies.com./")));
+ } else {
+ EXPECT_FALSE(this->SetCookie(cs, url, "a=1"));
+ }
+ }
+
+ { // Should not be able to set host cookie from a subdomain.
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+ GURL url("http://a.b");
+ EXPECT_FALSE(this->SetCookie(cs, url, "a=1; domain=.b"));
+ EXPECT_FALSE(this->SetCookie(cs, url, "b=2; domain=b"));
+ this->MatchCookieLines("", this->GetCookies(cs, url));
+ }
+
+ { // Same test as above, but explicitly on a known TLD (com).
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+ GURL url("http://google.com");
+ EXPECT_FALSE(this->SetCookie(cs, url, "a=1; domain=.com"));
+ EXPECT_FALSE(this->SetCookie(cs, url, "b=2; domain=com"));
+ this->MatchCookieLines("", this->GetCookies(cs, url));
+ }
+
+ { // Make sure can't set cookie on TLD which is dotted.
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+ GURL url("http://google.co.uk");
+ EXPECT_FALSE(this->SetCookie(cs, url, "a=1; domain=.co.uk"));
+ EXPECT_FALSE(this->SetCookie(cs, url, "b=2; domain=.uk"));
+ this->MatchCookieLines("", this->GetCookies(cs, url));
+ this->MatchCookieLines("",
+ this->GetCookies(cs, GURL("http://something-else.co.uk")));
+ this->MatchCookieLines("",
+ this->GetCookies(cs, GURL("http://something-else.uk")));
+ }
+
+ { // Intranet URLs should only be able to set host cookies.
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+ GURL url("http://b");
+ EXPECT_TRUE(this->SetCookie(cs, url, "a=1"));
+ EXPECT_FALSE(this->SetCookie(cs, url, "b=2; domain=.b"));
+ EXPECT_FALSE(this->SetCookie(cs, url, "c=3; domain=b"));
+ this->MatchCookieLines("a=1", this->GetCookies(cs, url));
+ }
+}
+
+// Test reading/writing cookies when the domain ends with a period,
+// as in "www.google.com."
+TYPED_TEST_P(CookieStoreTest, TestHostEndsWithDot) {
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+ GURL url("http://www.google.com");
+ GURL url_with_dot("http://www.google.com.");
+ EXPECT_TRUE(this->SetCookie(cs, url, "a=1"));
+ this->MatchCookieLines("a=1", this->GetCookies(cs, url));
+
+ if (TypeParam::supports_trailing_dots) {
+ // Do not share cookie space with the dot version of domain.
+ // Note: this is not what FireFox does, but it _is_ what IE+Safari do.
+ EXPECT_FALSE(this->SetCookie(cs, url, "b=2; domain=.www.google.com."));
+ this->MatchCookieLines("a=1", this->GetCookies(cs, url));
+
+ EXPECT_TRUE(this->SetCookie(cs, url_with_dot, "b=2; domain=.google.com."));
+ this->MatchCookieLines("b=2", this->GetCookies(cs, url_with_dot));
+ } else {
+ EXPECT_TRUE(this->SetCookie(cs, url, "b=2; domain=.www.google.com."));
+ EXPECT_FALSE(this->SetCookie(cs, url_with_dot, "b=2; domain=.google.com."));
+ }
+
+ // Make sure there weren't any side effects.
+ this->MatchCookieLines("",
+ this->GetCookies(cs, GURL("http://hopefully-no-cookies.com/")));
+ this->MatchCookieLines("", this->GetCookies(cs, GURL("http://.com/")));
+}
+
+TYPED_TEST_P(CookieStoreTest, InvalidScheme) {
+ if (!TypeParam::filters_schemes)
+ return;
+
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+ EXPECT_FALSE(this->SetCookie(cs, GURL(kUrlFtp), kValidCookieLine));
+}
+
+TYPED_TEST_P(CookieStoreTest, InvalidScheme_Read) {
+ if (!TypeParam::filters_schemes)
+ return;
+
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+ EXPECT_TRUE(this->SetCookie(cs, GURL(kUrlGoogle), kValidDomainCookieLine));
+ this->MatchCookieLines("", this->GetCookies(cs, GURL(kUrlFtp)));
+}
+
+TYPED_TEST_P(CookieStoreTest, PathTest) {
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+ std::string url("http://www.google.izzle");
+ EXPECT_TRUE(this->SetCookie(cs, GURL(url), "A=B; path=/wee"));
+ this->MatchCookieLines("A=B", this->GetCookies(cs, GURL(url + "/wee")));
+ this->MatchCookieLines("A=B", this->GetCookies(cs, GURL(url + "/wee/")));
+ this->MatchCookieLines("A=B", this->GetCookies(cs, GURL(url + "/wee/war")));
+ this->MatchCookieLines("A=B",
+ this->GetCookies(cs, GURL(url + "/wee/war/more/more")));
+ if (!TypeParam::has_path_prefix_bug)
+ this->MatchCookieLines("", this->GetCookies(cs, GURL(url + "/weehee")));
+ this->MatchCookieLines("", this->GetCookies(cs, GURL(url + "/")));
+
+ // If we add a 0 length path, it should default to /
+ EXPECT_TRUE(this->SetCookie(cs, GURL(url), "A=C; path="));
+ this->MatchCookieLines("A=B; A=C", this->GetCookies(cs, GURL(url + "/wee")));
+ this->MatchCookieLines("A=C", this->GetCookies(cs, GURL(url + "/")));
+}
+
+TYPED_TEST_P(CookieStoreTest, HttpOnlyTest) {
+ if (!TypeParam::supports_http_only)
+ return;
+
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+ CookieOptions options;
+ options.set_include_httponly();
+
+ // Create a httponly cookie.
+ EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "A=B; httponly",
+ options));
+
+ // Check httponly read protection.
+ this->MatchCookieLines("", this->GetCookies(cs, this->url_google_));
+ this->MatchCookieLines("A=B",
+ this->GetCookiesWithOptions(cs, this->url_google_, options));
+
+ // Check httponly overwrite protection.
+ EXPECT_FALSE(this->SetCookie(cs, this->url_google_, "A=C"));
+ this->MatchCookieLines("", this->GetCookies(cs, this->url_google_));
+ this->MatchCookieLines("A=B",
+ this->GetCookiesWithOptions(cs, this->url_google_, options));
+ EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "A=C",
+ options));
+ this->MatchCookieLines("A=C", this->GetCookies(cs, this->url_google_));
+
+ // Check httponly create protection.
+ EXPECT_FALSE(this->SetCookie(cs, this->url_google_, "B=A; httponly"));
+ this->MatchCookieLines("A=C",
+ this->GetCookiesWithOptions(cs, this->url_google_, options));
+ EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "B=A; httponly",
+ options));
+ this->MatchCookieLines("A=C; B=A",
+ this->GetCookiesWithOptions(cs, this->url_google_, options));
+ this->MatchCookieLines("A=C", this->GetCookies(cs, this->url_google_));
+}
+
+TYPED_TEST_P(CookieStoreTest, TestGetCookiesWithInfo) {
+ if (!TypeParam::supports_cookies_with_info)
+ return;
+
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+ CookieOptions options;
+
+ EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "A=B",
+ options));
+ EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_,
+ "C=D; Mac-Key=390jfn0awf3; Mac-Algorithm=hmac-sha-1", options));
+
+ this->MatchCookieLines("A=B; C=D",
+ this->GetCookiesWithOptions(cs, this->url_google_, options));
+
+ std::string cookie_line;
+ std::vector<CookieStore::CookieInfo> cookie_infos;
+
+ this->GetCookiesWithInfo(cs, this->url_google_, options, &cookie_line,
+ &cookie_infos);
+
+ EXPECT_EQ("A=B; C=D", cookie_line);
+
+ EXPECT_EQ(2U, cookie_infos.size());
+
+ EXPECT_EQ("A", cookie_infos[0].name);
+ EXPECT_EQ("", cookie_infos[0].mac_key);
+ EXPECT_EQ("", cookie_infos[0].mac_algorithm);
+
+ EXPECT_EQ("C", cookie_infos[1].name);
+ EXPECT_EQ("390jfn0awf3", cookie_infos[1].mac_key);
+ EXPECT_EQ("hmac-sha-1", cookie_infos[1].mac_algorithm);
+}
+
+TYPED_TEST_P(CookieStoreTest, TestCookieDeletion) {
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+
+ // Create a session cookie.
+ EXPECT_TRUE(this->SetCookie(cs, this->url_google_, kValidCookieLine));
+ this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_));
+ // Delete it via Max-Age.
+ EXPECT_TRUE(this->SetCookie(cs, this->url_google_,
+ std::string(kValidCookieLine) + "; max-age=0"));
+ this->MatchCookieLineWithTimeout(cs, this->url_google_, "");
+
+ // Create a session cookie.
+ EXPECT_TRUE(this->SetCookie(cs, this->url_google_, kValidCookieLine));
+ this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_));
+ // Delete it via Expires.
+ EXPECT_TRUE(this->SetCookie(cs, this->url_google_,
+ std::string(kValidCookieLine) +
+ "; expires=Mon, 18-Apr-1977 22:50:13 GMT"));
+ this->MatchCookieLines("", this->GetCookies(cs, this->url_google_));
+
+ // Create a persistent cookie.
+ EXPECT_TRUE(this->SetCookie(cs, this->url_google_,
+ std::string(kValidCookieLine) +
+ "; expires=Mon, 18-Apr-22 22:50:13 GMT"));
+
+ this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_));
+ // Delete it via Max-Age.
+ EXPECT_TRUE(this->SetCookie(cs, this->url_google_,
+ std::string(kValidCookieLine) + "; max-age=0"));
+ this->MatchCookieLineWithTimeout(cs, this->url_google_, "");
+
+ // Create a persistent cookie.
+ EXPECT_TRUE(this->SetCookie(cs, this->url_google_,
+ std::string(kValidCookieLine) +
+ "; expires=Mon, 18-Apr-22 22:50:13 GMT"));
+ this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_));
+ // Delete it via Expires.
+ EXPECT_TRUE(this->SetCookie(cs, this->url_google_,
+ std::string(kValidCookieLine) +
+ "; expires=Mon, 18-Apr-1977 22:50:13 GMT"));
+ this->MatchCookieLines("", this->GetCookies(cs, this->url_google_));
+
+ // Create a persistent cookie.
+ EXPECT_TRUE(this->SetCookie(cs, this->url_google_,
+ std::string(kValidCookieLine) +
+ "; expires=Mon, 18-Apr-22 22:50:13 GMT"));
+ this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_));
+ // Delete it via Expires, with a unix epoch of 0.
+ EXPECT_TRUE(this->SetCookie(cs, this->url_google_,
+ std::string(kValidCookieLine) +
+ "; expires=Thu, 1-Jan-1970 00:00:00 GMT"));
+ this->MatchCookieLines("", this->GetCookies(cs, this->url_google_));
+}
+
+TYPED_TEST_P(CookieStoreTest, TestDeleteAllCreatedBetween) {
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+ const base::Time last_month = base::Time::Now() -
+ base::TimeDelta::FromDays(30);
+ const base::Time last_minute = base::Time::Now() -
+ base::TimeDelta::FromMinutes(1);
+ const base::Time next_minute = base::Time::Now() +
+ base::TimeDelta::FromMinutes(1);
+ const base::Time next_month = base::Time::Now() +
+ base::TimeDelta::FromDays(30);
+
+ // Add a cookie.
+ EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "A=B"));
+ // Check that the cookie is in the store.
+ this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_));
+
+ // Remove cookies in empty intervals.
+ EXPECT_EQ(0, this->DeleteCreatedBetween(cs, last_month, last_minute));
+ EXPECT_EQ(0, this->DeleteCreatedBetween(cs, next_minute, next_month));
+ // Check that the cookie is still there.
+ this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_));
+
+ // Remove the cookie with an interval defined by two dates.
+ EXPECT_EQ(1, this->DeleteCreatedBetween(cs, last_minute, next_minute));
+ // Check that the cookie disappeared.
+ this->MatchCookieLines("", this->GetCookies(cs, this->url_google_));
+
+ // Add another cookie.
+ EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "C=D"));
+ // Check that the cookie is in the store.
+ this->MatchCookieLines("C=D", this->GetCookies(cs, this->url_google_));
+
+ // Remove the cookie with a null ending time.
+ EXPECT_EQ(1, this->DeleteCreatedBetween(cs, last_minute, base::Time()));
+ // Check that the cookie disappeared.
+ this->MatchCookieLines("", this->GetCookies(cs, this->url_google_));
+}
+
+TYPED_TEST_P(CookieStoreTest, TestSecure) {
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+
+ EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "A=B"));
+ this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_));
+ this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_secure_));
+
+ EXPECT_TRUE(this->SetCookie(cs, this->url_google_secure_, "A=B; secure"));
+ // The secure should overwrite the non-secure.
+ this->MatchCookieLines("", this->GetCookies(cs, this->url_google_));
+ this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_secure_));
+
+ EXPECT_TRUE(this->SetCookie(cs, this->url_google_secure_, "D=E; secure"));
+ this->MatchCookieLines("", this->GetCookies(cs, this->url_google_));
+ this->MatchCookieLines("A=B; D=E",
+ this->GetCookies(cs, this->url_google_secure_));
+
+ EXPECT_TRUE(this->SetCookie(cs, this->url_google_secure_, "A=B"));
+ // The non-secure should overwrite the secure.
+ this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_));
+ this->MatchCookieLines("D=E; A=B",
+ this->GetCookies(cs, this->url_google_secure_));
+}
+
+static const int kLastAccessThresholdMilliseconds = 200;
+
+// Formerly NetUtilTest.CookieTest back when we used wininet's cookie handling.
+TYPED_TEST_P(CookieStoreTest, NetUtilCookieTest) {
+ const GURL test_url("http://mojo.jojo.google.izzle/");
+
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+
+ EXPECT_TRUE(this->SetCookie(cs, test_url, "foo=bar"));
+ std::string value = this->GetCookies(cs, test_url);
+ this->MatchCookieLines("foo=bar", value);
+
+ // test that we can retrieve all cookies:
+ EXPECT_TRUE(this->SetCookie(cs, test_url, "x=1"));
+ EXPECT_TRUE(this->SetCookie(cs, test_url, "y=2"));
+
+ std::string result = this->GetCookies(cs, test_url);
+ EXPECT_FALSE(result.empty());
+ EXPECT_NE(result.find("x=1"), std::string::npos) << result;
+ EXPECT_NE(result.find("y=2"), std::string::npos) << result;
+}
+
+TYPED_TEST_P(CookieStoreTest, OverwritePersistentCookie) {
+ GURL url_google("http://www.google.com/");
+ GURL url_chromium("http://chromium.org");
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+
+ // Insert a cookie "a" for path "/path1"
+ EXPECT_TRUE(
+ this->SetCookie(cs, url_google, "a=val1; path=/path1; "
+ "expires=Mon, 18-Apr-22 22:50:13 GMT"));
+
+ // Insert a cookie "b" for path "/path1"
+ EXPECT_TRUE(
+ this->SetCookie(cs, url_google, "b=val1; path=/path1; "
+ "expires=Mon, 18-Apr-22 22:50:14 GMT"));
+
+ // Insert a cookie "b" for path "/path1", that is httponly. This should
+ // overwrite the non-http-only version.
+ CookieOptions allow_httponly;
+ allow_httponly.set_include_httponly();
+ EXPECT_TRUE(
+ this->SetCookieWithOptions(cs, url_google,
+ "b=val2; path=/path1; httponly; "
+ "expires=Mon, 18-Apr-22 22:50:14 GMT",
+ allow_httponly));
+
+ // Insert a cookie "a" for path "/path1". This should overwrite.
+ EXPECT_TRUE(this->SetCookie(cs, url_google,
+ "a=val33; path=/path1; "
+ "expires=Mon, 18-Apr-22 22:50:14 GMT"));
+
+ // Insert a cookie "a" for path "/path2". This should NOT overwrite
+ // cookie "a", since the path is different.
+ EXPECT_TRUE(this->SetCookie(cs, url_google,
+ "a=val9; path=/path2; "
+ "expires=Mon, 18-Apr-22 22:50:14 GMT"));
+
+ // Insert a cookie "a" for path "/path1", but this time for "chromium.org".
+ // Although the name and path match, the hostnames do not, so shouldn't
+ // overwrite.
+ EXPECT_TRUE(this->SetCookie(cs, url_chromium,
+ "a=val99; path=/path1; "
+ "expires=Mon, 18-Apr-22 22:50:14 GMT"));
+
+ if (TypeParam::supports_http_only) {
+ this->MatchCookieLines("a=val33",
+ this->GetCookies(cs, GURL("http://www.google.com/path1")));
+ } else {
+ this->MatchCookieLines("a=val33; b=val2",
+ this->GetCookies(cs, GURL("http://www.google.com/path1")));
+ }
+ this->MatchCookieLines("a=val9",
+ this->GetCookies(cs, GURL("http://www.google.com/path2")));
+ this->MatchCookieLines("a=val99",
+ this->GetCookies(cs, GURL("http://chromium.org/path1")));
+}
+
+TYPED_TEST_P(CookieStoreTest, CookieOrdering) {
+ // Put a random set of cookies into a store and make sure they're returned in
+ // the right order.
+ // Cookies should be sorted by path length and creation time, as per RFC6265.
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+ EXPECT_TRUE(this->SetCookie(cs, GURL("http://d.c.b.a.google.com/aa/x.html"),
+ "c=1"));
+ EXPECT_TRUE(this->SetCookie(cs, GURL("http://b.a.google.com/aa/bb/cc/x.html"),
+ "d=1; domain=b.a.google.com"));
+ base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(
+ TypeParam::creation_time_granularity_in_ms));
+ EXPECT_TRUE(this->SetCookie(cs, GURL("http://b.a.google.com/aa/bb/cc/x.html"),
+ "a=4; domain=b.a.google.com"));
+ base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(
+ TypeParam::creation_time_granularity_in_ms));
+ EXPECT_TRUE(this->SetCookie(cs,
+ GURL("http://c.b.a.google.com/aa/bb/cc/x.html"),
+ "e=1; domain=c.b.a.google.com"));
+ EXPECT_TRUE(this->SetCookie(cs,
+ GURL("http://d.c.b.a.google.com/aa/bb/x.html"),
+ "b=1"));
+ EXPECT_TRUE(this->SetCookie(cs, GURL("http://news.bbc.co.uk/midpath/x.html"),
+ "g=10"));
+ EXPECT_EQ("d=1; a=4; e=1; b=1; c=1",
+ this->GetCookies(cs, GURL("http://d.c.b.a.google.com/aa/bb/cc/dd")));
+}
+
+REGISTER_TYPED_TEST_CASE_P(CookieStoreTest,
+ TypeTest, DomainTest, DomainWithTrailingDotTest, ValidSubdomainTest,
+ InvalidDomainTest, DomainWithoutLeadingDotTest, CaseInsensitiveDomainTest,
+ TestIpAddress, TestNonDottedAndTLD, TestHostEndsWithDot, InvalidScheme,
+ InvalidScheme_Read, PathTest, HttpOnlyTest, TestGetCookiesWithInfo,
+ TestCookieDeletion, TestDeleteAllCreatedBetween, TestSecure,
+ NetUtilCookieTest, OverwritePersistentCookie, CookieOrdering);
+
+template<class CookieStoreTestTraits>
+class MultiThreadedCookieStoreTest :
+ public CookieStoreTest<CookieStoreTestTraits> {
+ public:
+ MultiThreadedCookieStoreTest() : other_thread_("CMTthread") {}
+
+ // Helper methods for calling the asynchronous CookieStore methods
+ // from a different thread.
+
+ void GetCookiesTask(CookieStore* cs,
+ const GURL& url,
+ GetCookieStringCallback* callback) {
+ CookieOptions options;
+ if (!CookieStoreTestTraits::supports_http_only)
+ options.set_include_httponly();
+ cs->GetCookiesWithOptionsAsync(
+ url, options,
+ base::Bind(&GetCookieStringCallback::Run, base::Unretained(callback)));
+ }
+
+ void GetCookiesWithOptionsTask(CookieStore* cs,
+ const GURL& url,
+ const CookieOptions& options,
+ GetCookieStringCallback* callback) {
+ cs->GetCookiesWithOptionsAsync(
+ url, options,
+ base::Bind(&GetCookieStringCallback::Run, base::Unretained(callback)));
+ }
+
+ void GetCookiesWithInfoTask(CookieStore* cs,
+ const GURL& url,
+ const CookieOptions& options,
+ GetCookiesWithInfoCallback* callback) {
+ cs->GetCookiesWithInfoAsync(
+ url, options,
+ base::Bind(&GetCookiesWithInfoCallback::Run,
+ base::Unretained(callback)));
+ }
+
+ void SetCookieWithOptionsTask(CookieStore* cs,
+ const GURL& url,
+ const std::string& cookie_line,
+ const CookieOptions& options,
+ SetCookieCallback* callback) {
+ cs->SetCookieWithOptionsAsync(
+ url, cookie_line, options,
+ base::Bind(&SetCookieCallback::Run, base::Unretained(callback)));
+ }
+
+ void DeleteCookieTask(CookieStore* cs,
+ const GURL& url,
+ const std::string& cookie_name,
+ DeleteCookieCallback* callback) {
+ cs->DeleteCookieAsync(
+ url, cookie_name,
+ base::Bind(&DeleteCookieCallback::Run, base::Unretained(callback)));
+ }
+
+ protected:
+ void RunOnOtherThread(const base::Closure& task) {
+ other_thread_.Start();
+ other_thread_.message_loop()->PostTask(FROM_HERE, task);
+ CookieStoreTest<CookieStoreTestTraits>::RunFor(kTimeout);
+ other_thread_.Stop();
+ }
+
+ Thread other_thread_;
+};
+
+TYPED_TEST_CASE_P(MultiThreadedCookieStoreTest);
+
+// TODO(ycxiao): Eventually, we will need to create a separate thread, create
+// the cookie store on that thread (or at least its store, i.e., the DB
+// thread).
+TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckGetCookies) {
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+ EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "A=B"));
+ this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_));
+ GetCookieStringCallback callback(&this->other_thread_);
+ base::Closure task = base::Bind(
+ &net::MultiThreadedCookieStoreTest<TypeParam>::GetCookiesTask,
+ base::Unretained(this),
+ cs, this->url_google_, &callback);
+ this->RunOnOtherThread(task);
+ EXPECT_TRUE(callback.did_run());
+ EXPECT_EQ("A=B", callback.cookie());
+}
+
+TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckGetCookiesWithOptions) {
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+ CookieOptions options;
+ if (!TypeParam::supports_http_only)
+ options.set_include_httponly();
+ EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "A=B"));
+ this->MatchCookieLines("A=B",
+ this->GetCookiesWithOptions(cs, this->url_google_, options));
+ GetCookieStringCallback callback(&this->other_thread_);
+ base::Closure task = base::Bind(
+ &net::MultiThreadedCookieStoreTest<TypeParam>::GetCookiesWithOptionsTask,
+ base::Unretained(this),
+ cs, this->url_google_, options, &callback);
+ this->RunOnOtherThread(task);
+ EXPECT_TRUE(callback.did_run());
+ EXPECT_EQ("A=B", callback.cookie());
+}
+
+TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckGetCookiesWithInfo) {
+ if (!TypeParam::supports_cookies_with_info)
+ return;
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+ CookieOptions options;
+ std::string cookie_line;
+ std::vector<CookieStore::CookieInfo> cookie_infos;
+ EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "A=B"));
+ this->GetCookiesWithInfo(cs, this->url_google_, options, &cookie_line,
+ &cookie_infos);
+ this->MatchCookieLines("A=B", cookie_line);
+ EXPECT_EQ(1U, cookie_infos.size());
+ EXPECT_EQ("A", cookie_infos[0].name);
+ EXPECT_EQ("", cookie_infos[0].mac_key);
+ EXPECT_EQ("", cookie_infos[0].mac_algorithm);
+ GetCookiesWithInfoCallback callback(&this->other_thread_);
+ base::Closure task = base::Bind(
+ &net::MultiThreadedCookieStoreTest<TypeParam>::GetCookiesWithInfoTask,
+ base::Unretained(this), cs, this->url_google_, options, &callback);
+ this->RunOnOtherThread(task);
+ EXPECT_TRUE(callback.did_run());
+ this->MatchCookieLines("A=B", callback.cookie_line());
+ EXPECT_EQ(1U, callback.cookie_info().size());
+ EXPECT_EQ("A", callback.cookie_info()[0].name);
+ EXPECT_EQ("", callback.cookie_info()[0].mac_key);
+ EXPECT_EQ("", callback.cookie_info()[0].mac_algorithm);
+}
+
+TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckSetCookieWithOptions) {
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+ CookieOptions options;
+ if (!TypeParam::supports_http_only)
+ options.set_include_httponly();
+ EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "A=B",
+ options));
+ SetCookieCallback callback(&this->other_thread_);
+ base::Closure task = base::Bind(
+ &net::MultiThreadedCookieStoreTest<TypeParam>::SetCookieWithOptionsTask,
+ base::Unretained(this),
+ cs, this->url_google_, "A=B", options, &callback);
+ this->RunOnOtherThread(task);
+ EXPECT_TRUE(callback.did_run());
+ EXPECT_TRUE(callback.result());
+}
+
+TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckDeleteCookie) {
+ scoped_refptr<CookieStore> cs(this->GetCookieStore());
+ CookieOptions options;
+ if (!TypeParam::supports_http_only)
+ options.set_include_httponly();
+ EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "A=B",
+ options));
+ this->DeleteCookie(cs, this->url_google_, "A");
+ EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "A=B",
+ options));
+ DeleteCookieCallback callback(&this->other_thread_);
+ base::Closure task = base::Bind(
+ &net::MultiThreadedCookieStoreTest<TypeParam>::DeleteCookieTask,
+ base::Unretained(this),
+ cs, this->url_google_, "A", &callback);
+ this->RunOnOtherThread(task);
+ EXPECT_TRUE(callback.did_run());
+}
+
+REGISTER_TYPED_TEST_CASE_P(MultiThreadedCookieStoreTest,
+ ThreadCheckGetCookies, ThreadCheckGetCookiesWithOptions,
+ ThreadCheckGetCookiesWithInfo, ThreadCheckSetCookieWithOptions,
+ ThreadCheckDeleteCookie);
+
+} // namespace net
+
+#endif // NET_COOKIES_COOKIE_STORE_UNITTEST_H_
diff --git a/net/base/cookie_util.cc b/net/cookies/cookie_util.cc
index 8d8a0c3..6e1833f 100644
--- a/net/base/cookie_util.cc
+++ b/net/cookies/cookie_util.cc
@@ -1,8 +1,8 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 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 "net/base/cookie_util.h"
+#include "net/cookies/cookie_util.h"
#include "base/logging.h"
#include "googleurl/src/gurl.h"
diff --git a/net/cookies/cookie_util.h b/net/cookies/cookie_util.h
new file mode 100644
index 0000000..4c6e72f
--- /dev/null
+++ b/net/cookies/cookie_util.h
@@ -0,0 +1,40 @@
+// Copyright (c) 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 NET_COOKIES_COOKIE_UTIL_H_
+#define NET_COOKIES_COOKIE_UTIL_H_
+#pragma once
+
+#include <string>
+
+#include "net/base/net_export.h"
+
+class GURL;
+
+namespace net {
+namespace cookie_util {
+
+// Returns the effective TLD+1 for a given host. This only makes sense for http
+// and https schemes. For other schemes, the host will be returned unchanged
+// (minus any leading period).
+NET_EXPORT std::string GetEffectiveDomain(const std::string& scheme,
+ const std::string& host);
+
+// Determine the actual cookie domain based on the domain string passed
+// (if any) and the URL from which the cookie came.
+// On success returns true, and sets cookie_domain to either a
+// -host cookie domain (ex: "google.com")
+// -domain cookie domain (ex: ".google.com")
+NET_EXPORT bool GetCookieDomainWithString(const GURL& url,
+ const std::string& domain_string,
+ std::string* result);
+
+// Returns true if a domain string represents a host-only cookie,
+// i.e. it doesn't begin with a leading '.' character.
+NET_EXPORT bool DomainIsHostOnly(const std::string& domain_string);
+
+} // namspace cookie_util
+} // namespace net
+
+#endif // NET_COOKIES_COOKIE_UTIL_H_
diff --git a/net/base/cookie_util_unittest.cc b/net/cookies/cookie_util_unittest.cc
index 4c3db80..5d2a420 100644
--- a/net/base/cookie_util_unittest.cc
+++ b/net/cookies/cookie_util_unittest.cc
@@ -3,7 +3,7 @@
// found in the LICENSE file.
#include "base/basictypes.h"
-#include "net/base/cookie_util.h"
+#include "net/cookies/cookie_util.h"
#include "testing/gtest/include/gtest/gtest.h"
TEST(CookieUtilTest, TestDomainIsHostOnly) {
diff --git a/net/net.gyp b/net/net.gyp
index 1087bfe..13b2b8c 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -75,13 +75,6 @@
'base/completion_callback.h',
'base/connection_type_histograms.cc',
'base/connection_type_histograms.h',
- 'base/cookie_monster.cc',
- 'base/cookie_monster.h',
- 'base/cookie_options.h',
- 'base/cookie_store.cc',
- 'base/cookie_store.h',
- 'base/cookie_util.cc',
- 'base/cookie_util.h',
'base/crl_set.cc',
'base/crl_set.h',
'base/crypto_module.h',
@@ -276,6 +269,13 @@
'base/x509_util_openssl.h',
'base/zap.cc',
'base/zap.h',
+ 'cookies/cookie_monster.cc',
+ 'cookies/cookie_monster.h',
+ 'cookies/cookie_options.h',
+ 'cookies/cookie_store.cc',
+ 'cookies/cookie_store.h',
+ 'cookies/cookie_util.cc',
+ 'cookies/cookie_util.h',
'disk_cache/addr.cc',
'disk_cache/addr.h',
'disk_cache/backend_impl.cc',
@@ -1023,9 +1023,6 @@
'base/big_endian_unittest.cc',
'base/cert_database_nss_unittest.cc',
'base/cert_verifier_unittest.cc',
- 'base/cookie_monster_unittest.cc',
- 'base/cookie_store_unittest.h',
- 'base/cookie_util_unittest.cc',
'base/crl_set_unittest.cc',
'base/data_url_unittest.cc',
'base/default_origin_bound_cert_store_unittest.cc',
@@ -1079,6 +1076,9 @@
'base/x509_cert_types_unittest.cc',
'base/x509_util_nss_unittest.cc',
'base/x509_util_openssl_unittest.cc',
+ 'cookies/cookie_monster_unittest.cc',
+ 'cookies/cookie_store_unittest.h',
+ 'cookies/cookie_util_unittest.cc',
'disk_cache/addr_unittest.cc',
'disk_cache/backend_unittest.cc',
'disk_cache/bitmap_unittest.cc',
@@ -1428,7 +1428,7 @@
'../testing/gtest.gyp:gtest',
],
'sources': [
- 'base/cookie_monster_perftest.cc',
+ 'cookies/cookie_monster_perftest.cc',
'disk_cache/disk_cache_perftest.cc',
'proxy/proxy_resolver_perftest.cc',
],
@@ -1510,12 +1510,6 @@
'sources': [
'base/cert_test_util.cc',
'base/cert_test_util.h',
- 'base/cookie_monster_store_test.cc',
- 'base/cookie_monster_store_test.h',
- 'base/cookie_store_test_callbacks.cc',
- 'base/cookie_store_test_callbacks.h',
- 'base/cookie_store_test_helpers.cc',
- 'base/cookie_store_test_helpers.h',
'base/mock_file_stream.cc',
'base/mock_file_stream.h',
'base/mock_host_resolver.cc',
@@ -1524,6 +1518,12 @@
'base/net_test_suite.h',
'base/test_completion_callback.cc',
'base/test_completion_callback.h',
+ 'cookies/cookie_monster_store_test.cc',
+ 'cookies/cookie_monster_store_test.h',
+ 'cookies/cookie_store_test_callbacks.cc',
+ 'cookies/cookie_store_test_callbacks.h',
+ 'cookies/cookie_store_test_helpers.cc',
+ 'cookies/cookie_store_test_helpers.h',
'disk_cache/disk_cache_test_base.cc',
'disk_cache/disk_cache_test_base.h',
'disk_cache/disk_cache_test_util.cc',