diff options
author | Zeno Albisser <zeno.albisser@theqtcompany.com> | 2014-12-05 15:04:29 +0100 |
---|---|---|
committer | Andras Becsi <andras.becsi@theqtcompany.com> | 2014-12-09 10:49:28 +0100 |
commit | af6588f8d723931a298c995fa97259bb7f7deb55 (patch) | |
tree | 060ca707847ba1735f01af2372e0d5e494dc0366 /chromium/net/cookies | |
parent | 2fff84d821cc7b1c785f6404e0f8091333283e74 (diff) | |
download | qtwebengine-chromium-af6588f8d723931a298c995fa97259bb7f7deb55.tar.gz |
BASELINE: Update chromium to 40.0.2214.28 and ninja to 1.5.3.
Change-Id: I759465284fd64d59ad120219cbe257f7402c4181
Reviewed-by: Andras Becsi <andras.becsi@theqtcompany.com>
Diffstat (limited to 'chromium/net/cookies')
-rw-r--r-- | chromium/net/cookies/canonical_cookie.cc | 2 | ||||
-rw-r--r-- | chromium/net/cookies/canonical_cookie.h | 2 | ||||
-rw-r--r-- | chromium/net/cookies/cookie_constants.cc | 2 | ||||
-rw-r--r-- | chromium/net/cookies/cookie_monster.cc | 112 | ||||
-rw-r--r-- | chromium/net/cookies/cookie_monster.h | 70 | ||||
-rw-r--r-- | chromium/net/cookies/cookie_monster_perftest.cc | 2 | ||||
-rw-r--r-- | chromium/net/cookies/cookie_monster_store_test.h | 49 | ||||
-rw-r--r-- | chromium/net/cookies/cookie_monster_unittest.cc | 175 | ||||
-rw-r--r-- | chromium/net/cookies/cookie_store.h | 27 | ||||
-rw-r--r-- | chromium/net/cookies/cookie_store_test_helpers.cc | 9 | ||||
-rw-r--r-- | chromium/net/cookies/cookie_store_test_helpers.h | 40 | ||||
-rw-r--r-- | chromium/net/cookies/cookie_util.cc | 54 | ||||
-rw-r--r-- | chromium/net/cookies/cookie_util.h | 23 | ||||
-rw-r--r-- | chromium/net/cookies/cookie_util_unittest.cc | 89 | ||||
-rw-r--r-- | chromium/net/cookies/parsed_cookie.cc | 10 | ||||
-rw-r--r-- | chromium/net/cookies/parsed_cookie.h | 2 | ||||
-rw-r--r-- | chromium/net/cookies/parsed_cookie_unittest.cc | 21 |
17 files changed, 553 insertions, 136 deletions
diff --git a/chromium/net/cookies/canonical_cookie.cc b/chromium/net/cookies/canonical_cookie.cc index 54a9565a9c6..f0b3b3fa5fc 100644 --- a/chromium/net/cookies/canonical_cookie.cc +++ b/chromium/net/cookies/canonical_cookie.cc @@ -394,7 +394,7 @@ std::string CanonicalCookie::DebugString() const { static_cast<int64>(creation_date_.ToTimeT())); } -CanonicalCookie* CanonicalCookie::Duplicate() { +CanonicalCookie* CanonicalCookie::Duplicate() const { CanonicalCookie* cc = new CanonicalCookie(); cc->source_ = source_; cc->name_ = name_; diff --git a/chromium/net/cookies/canonical_cookie.h b/chromium/net/cookies/canonical_cookie.h index a5567405242..19ed388368f 100644 --- a/chromium/net/cookies/canonical_cookie.h +++ b/chromium/net/cookies/canonical_cookie.h @@ -126,7 +126,7 @@ class NET_EXPORT CanonicalCookie { std::string DebugString() const; // Returns a duplicate of this cookie. - CanonicalCookie* Duplicate(); + CanonicalCookie* Duplicate() const; // Returns the cookie source when cookies are set for |url|. This function // is public for unit test purposes only. diff --git a/chromium/net/cookies/cookie_constants.cc b/chromium/net/cookies/cookie_constants.cc index 1771c20e4bd..0afe6ef8580 100644 --- a/chromium/net/cookies/cookie_constants.cc +++ b/chromium/net/cookies/cookie_constants.cc @@ -31,7 +31,7 @@ NET_EXPORT const std::string CookiePriorityToString(CookiePriority priority) { NET_EXPORT CookiePriority StringToCookiePriority(const std::string& priority) { std::string priority_comp(priority); - StringToLowerASCII(&priority_comp); + base::StringToLowerASCII(&priority_comp); if (priority_comp == kPriorityHigh) return COOKIE_PRIORITY_HIGH; diff --git a/chromium/net/cookies/cookie_monster.cc b/chromium/net/cookies/cookie_monster.cc index 7aed8f8d0f7..c3f118d5471 100644 --- a/chromium/net/cookies/cookie_monster.cc +++ b/chromium/net/cookies/cookie_monster.cc @@ -63,7 +63,6 @@ #include "net/cookies/canonical_cookie.h" #include "net/cookies/cookie_util.h" #include "net/cookies/parsed_cookie.h" -#include "url/gurl.h" using base::Time; using base::TimeDelta; @@ -217,7 +216,7 @@ void SortLeastRecentlyAccessed( // Predicate to support PartitionCookieByPriority(). struct CookiePriorityEqualsTo : std::unary_function<const CookieMonster::CookieMap::iterator, bool> { - CookiePriorityEqualsTo(CookiePriority priority) + explicit CookiePriorityEqualsTo(CookiePriority priority) : priority_(priority) {} bool operator()(const CookieMonster::CookieMap::iterator it) const { @@ -307,6 +306,13 @@ std::string BuildCookieLine(const CanonicalCookieVector& cookies) { return cookie_line; } +void RunAsync(scoped_refptr<base::TaskRunner> proxy, + const CookieStore::CookieChangedCallback& callback, + const CanonicalCookie& cookie, + bool removed) { + proxy->PostTask(FROM_HERE, base::Bind(callback, cookie, removed)); +} + } // namespace CookieMonster::CookieMonster(PersistentCookieStore* store, @@ -428,10 +434,10 @@ class CookieMonster::SetCookieWithDetailsTask : public CookieMonsterTask { } // CookieMonsterTask: - virtual void Run() OVERRIDE; + void Run() override; protected: - virtual ~SetCookieWithDetailsTask() {} + ~SetCookieWithDetailsTask() override {} private: GURL url_; @@ -468,10 +474,10 @@ class CookieMonster::GetAllCookiesTask : public CookieMonsterTask { } // CookieMonsterTask - virtual void Run() OVERRIDE; + void Run() override; protected: - virtual ~GetAllCookiesTask() {} + ~GetAllCookiesTask() override {} private: GetCookieListCallback callback_; @@ -503,10 +509,10 @@ class CookieMonster::GetAllCookiesForURLWithOptionsTask } // CookieMonsterTask: - virtual void Run() OVERRIDE; + void Run() override; protected: - virtual ~GetAllCookiesForURLWithOptionsTask() {} + ~GetAllCookiesForURLWithOptionsTask() override {} private: GURL url_; @@ -544,7 +550,7 @@ class CookieMonster::DeleteTask : public CookieMonsterTask { } // CookieMonsterTask: - virtual void Run() OVERRIDE; + virtual void Run() override; private: // Runs the delete task and returns a result. @@ -596,10 +602,10 @@ class CookieMonster::DeleteAllTask : public DeleteTask<int> { } // DeleteTask: - virtual int RunDeleteTask() OVERRIDE; + int RunDeleteTask() override; protected: - virtual ~DeleteAllTask() {} + ~DeleteAllTask() override {} private: DISALLOW_COPY_AND_ASSIGN(DeleteAllTask); @@ -622,10 +628,10 @@ class CookieMonster::DeleteAllCreatedBetweenTask : public DeleteTask<int> { } // DeleteTask: - virtual int RunDeleteTask() OVERRIDE; + int RunDeleteTask() override; protected: - virtual ~DeleteAllCreatedBetweenTask() {} + ~DeleteAllCreatedBetweenTask() override {} private: Time delete_begin_; @@ -650,10 +656,10 @@ class CookieMonster::DeleteAllForHostTask : public DeleteTask<int> { } // DeleteTask: - virtual int RunDeleteTask() OVERRIDE; + int RunDeleteTask() override; protected: - virtual ~DeleteAllForHostTask() {} + ~DeleteAllForHostTask() override {} private: GURL url_; @@ -682,10 +688,10 @@ class CookieMonster::DeleteAllCreatedBetweenForHostTask } // DeleteTask: - virtual int RunDeleteTask() OVERRIDE; + int RunDeleteTask() override; protected: - virtual ~DeleteAllCreatedBetweenForHostTask() {} + ~DeleteAllCreatedBetweenForHostTask() override {} private: Time delete_begin_; @@ -711,10 +717,10 @@ class CookieMonster::DeleteCanonicalCookieTask : public DeleteTask<bool> { } // DeleteTask: - virtual bool RunDeleteTask() OVERRIDE; + bool RunDeleteTask() override; protected: - virtual ~DeleteCanonicalCookieTask() {} + ~DeleteCanonicalCookieTask() override {} private: CanonicalCookie cookie_; @@ -742,10 +748,10 @@ class CookieMonster::SetCookieWithOptionsTask : public CookieMonsterTask { } // CookieMonsterTask: - virtual void Run() OVERRIDE; + void Run() override; protected: - virtual ~SetCookieWithOptionsTask() {} + ~SetCookieWithOptionsTask() override {} private: GURL url_; @@ -779,10 +785,10 @@ class CookieMonster::GetCookiesWithOptionsTask : public CookieMonsterTask { } // CookieMonsterTask: - virtual void Run() OVERRIDE; + void Run() override; protected: - virtual ~GetCookiesWithOptionsTask() {} + ~GetCookiesWithOptionsTask() override {} private: GURL url_; @@ -814,10 +820,10 @@ class CookieMonster::DeleteCookieTask : public DeleteTask<void> { } // DeleteTask: - virtual void RunDeleteTask() OVERRIDE; + void RunDeleteTask() override; protected: - virtual ~DeleteCookieTask() {} + ~DeleteCookieTask() override {} private: GURL url_; @@ -839,13 +845,12 @@ class CookieMonster::DeleteSessionCookiesTask : public DeleteTask<int> { } // DeleteTask: - virtual int RunDeleteTask() OVERRIDE; + int RunDeleteTask() override; protected: - virtual ~DeleteSessionCookiesTask() {} + ~DeleteSessionCookiesTask() override {} private: - DISALLOW_COPY_AND_ASSIGN(DeleteSessionCookiesTask); }; @@ -866,10 +871,10 @@ class CookieMonster::HasCookiesForETLDP1Task : public CookieMonsterTask { } // CookieMonsterTask: - virtual void Run() OVERRIDE; + void Run() override; protected: - virtual ~HasCookiesForETLDP1Task() {} + ~HasCookiesForETLDP1Task() override {} private: std::string etldp1_; @@ -904,7 +909,6 @@ void CookieMonster::SetCookieWithDetailsAsync( new SetCookieWithDetailsTask(this, url, name, value, domain, path, expiration_time, secure, http_only, priority, callback); - DoCookieTaskForURL(task, url); } @@ -1102,7 +1106,7 @@ bool CookieMonster::SetCookieWithDetails(const GURL& url, return SetCanonicalCookie(&cc, creation_time, options); } -bool CookieMonster::InitializeFrom(const CookieList& list) { +bool CookieMonster::ImportCookies(const CookieList& list) { base::AutoLock autolock(lock_); InitIfNecessary(); for (net::CookieList::const_iterator iter = list.begin(); @@ -1264,7 +1268,7 @@ bool CookieMonster::DeleteCanonicalCookie(const CanonicalCookie& cookie) { return false; } -void CookieMonster::SetCookieableSchemes(const char* schemes[], +void CookieMonster::SetCookieableSchemes(const char* const schemes[], size_t num_schemes) { base::AutoLock autolock(lock_); @@ -1668,7 +1672,7 @@ int CookieMonster::TrimDuplicateCookiesForKey( } // Note: file must be the last scheme. -const char* CookieMonster::kDefaultCookieableSchemes[] = +const char* const CookieMonster::kDefaultCookieableSchemes[] = { "http", "https", "ws", "wss", "file" }; const int CookieMonster::kDefaultCookieableSchemesCount = arraysize(kDefaultCookieableSchemes); @@ -1780,6 +1784,7 @@ CookieMonster::CookieMap::iterator CookieMonster::InternalInsertCookie( delegate_->OnCookieChanged( *cc, false, CookieMonsterDelegate::CHANGE_COOKIE_EXPLICIT); } + RunCallbacks(*cc, false); return inserted; } @@ -1814,6 +1819,7 @@ bool CookieMonster::SetCanonicalCookie(scoped_ptr<CanonicalCookie>* cc, const CookieOptions& options) { const std::string key(GetKey((*cc)->Domain())); bool already_expired = (*cc)->IsExpired(creation_time); + if (DeleteAnyEquivalentCookie(key, **cc, options.exclude_httponly(), already_expired)) { VLOG(kVlogSetCookies) << "SetCookie() not clobbering httponly cookie"; @@ -1832,7 +1838,10 @@ bool CookieMonster::SetCanonicalCookie(scoped_ptr<CanonicalCookie>* cc, ((*cc)->ExpiryDate() - creation_time).InMinutes()); } - InternalInsertCookie(key, cc->release(), true); + { + CanonicalCookie cookie = *(cc->get()); + InternalInsertCookie(key, cc->release(), true); + } } else { VLOG(kVlogSetCookies) << "SetCookie() not storing already expired cookie."; } @@ -1896,6 +1905,7 @@ void CookieMonster::InternalDeleteCookie(CookieMap::iterator it, if (mapping.notify) delegate_->OnCookieChanged(*cc, true, mapping.cause); } + RunCallbacks(*cc, true); cookies_.erase(it); delete cc; } @@ -2304,4 +2314,36 @@ bool CookieMonster::loaded() { return loaded_; } +scoped_ptr<CookieStore::CookieChangedSubscription> +CookieMonster::AddCallbackForCookie( + const GURL& gurl, + const std::string& name, + const CookieChangedCallback& callback) { + base::AutoLock autolock(lock_); + std::pair<GURL, std::string> key(gurl, name); + if (hook_map_.count(key) == 0) + hook_map_[key] = make_linked_ptr(new CookieChangedCallbackList()); + return hook_map_[key]->Add( + base::Bind(&RunAsync, base::MessageLoopProxy::current(), callback)); +} + +void CookieMonster::RunCallbacks(const CanonicalCookie& cookie, bool removed) { + lock_.AssertAcquired(); + CookieOptions opts; + opts.set_include_httponly(); + // Note that the callbacks in hook_map_ are wrapped with MakeAsync(), so they + // are guaranteed to not take long - they just post a RunAsync task back to + // the appropriate thread's message loop and return. It is important that this + // method not run user-supplied callbacks directly, since the CookieMonster + // lock is held and it is easy to accidentally introduce deadlocks. + for (CookieChangedHookMap::iterator it = hook_map_.begin(); + it != hook_map_.end(); ++it) { + std::pair<GURL, std::string> key = it->first; + if (cookie.IncludeForRequestURL(key.first, opts) && + cookie.Name() == key.second) { + it->second->Notify(cookie, removed); + } + } +} + } // namespace net diff --git a/chromium/net/cookies/cookie_monster.h b/chromium/net/cookies/cookie_monster.h index b719c32b595..18d1b8a0bb5 100644 --- a/chromium/net/cookies/cookie_monster.h +++ b/chromium/net/cookies/cookie_monster.h @@ -18,6 +18,7 @@ #include "base/basictypes.h" #include "base/callback_forward.h" #include "base/gtest_prod_util.h" +#include "base/memory/linked_ptr.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/synchronization/lock.h" @@ -26,8 +27,7 @@ #include "net/cookies/canonical_cookie.h" #include "net/cookies/cookie_constants.h" #include "net/cookies/cookie_store.h" - -class GURL; +#include "url/gurl.h" namespace base { class Histogram; @@ -146,8 +146,9 @@ class NET_EXPORT CookieMonster : public CookieStore { CookieMonsterDelegate* delegate, int last_access_threshold_milliseconds); - // Helper function that adds all cookies from |list| into this instance. - bool InitializeFrom(const CookieList& list); + // Helper function that adds all cookies from |list| into this instance, + // overwriting any equivalent cookies. + bool ImportCookies(const CookieList& list); typedef base::Callback<void(const CookieList& cookies)> GetCookieListCallback; typedef base::Callback<void(bool success)> DeleteCookieCallback; @@ -208,7 +209,7 @@ class NET_EXPORT CookieMonster : public CookieStore { // Resets the list of cookieable schemes to the supplied schemes. // 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); + void SetCookieableSchemes(const char* const schemes[], size_t num_schemes); // Resets the list of cookieable schemes to kDefaultCookieableSchemes with or // without 'file' being included. @@ -238,38 +239,34 @@ class NET_EXPORT CookieMonster : public CookieStore { // 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; + 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; + void GetCookiesWithOptionsAsync(const GURL& url, + const CookieOptions& options, + const GetCookiesCallback& callback) override; // Invokes GetAllCookiesForURLWithOptions with options set to include HTTP // only cookies. - virtual void GetAllCookiesForURLAsync( - const GURL& url, - const GetCookieListCallback& callback) OVERRIDE; + void GetAllCookiesForURLAsync(const GURL& url, + const GetCookieListCallback& 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; + 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; + void DeleteAllCreatedBetweenAsync(const base::Time& delete_begin, + const base::Time& delete_end, + const DeleteCallback& callback) override; // Deletes all of the cookies that match the host of the given URL // regardless of path and that have a creation_date greater than or @@ -277,15 +274,15 @@ class NET_EXPORT CookieMonster : public CookieStore { // 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. - virtual void DeleteAllCreatedBetweenForHostAsync( + void DeleteAllCreatedBetweenForHostAsync( const base::Time delete_begin, const base::Time delete_end, const GURL& url, - const DeleteCallback& callback) OVERRIDE; + const DeleteCallback& callback) override; - virtual void DeleteSessionCookiesAsync(const DeleteCallback&) OVERRIDE; + void DeleteSessionCookiesAsync(const DeleteCallback&) override; - virtual CookieMonster* GetCookieMonster() OVERRIDE; + 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 @@ -304,7 +301,7 @@ class NET_EXPORT CookieMonster : public CookieStore { bool IsCookieableScheme(const std::string& scheme); // The default list of schemes the cookie monster can handle. - static const char* kDefaultCookieableSchemes[]; + static const char* const kDefaultCookieableSchemes[]; static const int kDefaultCookieableSchemesCount; // Copies all keys for the given |key| to another cookie monster |other|. @@ -318,6 +315,11 @@ class NET_EXPORT CookieMonster : public CookieStore { // See comment on keys before the CookieMap typedef. std::string GetKey(const std::string& domain) const; + scoped_ptr<CookieChangedSubscription> AddCallbackForCookie( + const GURL& url, + const std::string& name, + const CookieChangedCallback& callback) override; + bool loaded(); private: @@ -407,7 +409,7 @@ class NET_EXPORT CookieMonster : public CookieStore { // Record statistics every kRecordStatisticsIntervalSeconds of uptime. static const int kRecordStatisticsIntervalSeconds = 10 * 60; - virtual ~CookieMonster(); + ~CookieMonster() override; // The following are synchronous calls to which the asynchronous methods // delegate either immediately (if the store is loaded) or through a deferred @@ -618,6 +620,10 @@ class NET_EXPORT CookieMonster : public CookieStore { void DoCookieTaskForURL(const scoped_refptr<CookieMonsterTask>& task_item, const GURL& url); + // Run all cookie changed callbacks that are monitoring |cookie|. + // |removed| is true if the cookie was deleted. + void RunCallbacks(const CanonicalCookie& cookie, bool removed); + // Histogram variables; see CookieMonster::InitializeHistograms() in // cookie_monster.cc for details. base::HistogramBase* histogram_expiration_duration_minutes_; @@ -698,6 +704,10 @@ class NET_EXPORT CookieMonster : public CookieStore { // instance are reset back to defaults. static bool default_enable_file_scheme_; + typedef std::map<std::pair<GURL, std::string>, + linked_ptr<CookieChangedCallbackList>> CookieChangedHookMap; + CookieChangedHookMap hook_map_; + DISALLOW_COPY_AND_ASSIGN(CookieMonster); }; diff --git a/chromium/net/cookies/cookie_monster_perftest.cc b/chromium/net/cookies/cookie_monster_perftest.cc index 2bc0be8480c..6e799adbe2b 100644 --- a/chromium/net/cookies/cookie_monster_perftest.cc +++ b/chromium/net/cookies/cookie_monster_perftest.cc @@ -363,7 +363,7 @@ TEST_F(CookieMonsterTest, TestGCTimes) { 0, }, }; - for (int ci = 0; ci < static_cast<int>(ARRAYSIZE_UNSAFE(test_cases)); ++ci) { + for (int ci = 0; ci < static_cast<int>(arraysize(test_cases)); ++ci) { const TestCase& test_case(test_cases[ci]); scoped_refptr<CookieMonster> cm( CreateMonsterFromStoreForGC( diff --git a/chromium/net/cookies/cookie_monster_store_test.h b/chromium/net/cookies/cookie_monster_store_test.h index efbcbe5bd56..4a3f9a96f8b 100644 --- a/chromium/net/cookies/cookie_monster_store_test.h +++ b/chromium/net/cookies/cookie_monster_store_test.h @@ -82,25 +82,23 @@ class MockPersistentCookieStore return commands_; } - virtual void Load(const LoadedCallback& loaded_callback) OVERRIDE; + void Load(const LoadedCallback& loaded_callback) override; - virtual void LoadCookiesForKey(const std::string& key, - const LoadedCallback& loaded_callback) OVERRIDE; + void LoadCookiesForKey(const std::string& key, + const LoadedCallback& loaded_callback) override; - virtual void AddCookie(const CanonicalCookie& cookie) OVERRIDE; + void AddCookie(const CanonicalCookie& cookie) override; - virtual void UpdateCookieAccessTime( - const CanonicalCookie& cookie) OVERRIDE; + void UpdateCookieAccessTime(const CanonicalCookie& cookie) override; - virtual void DeleteCookie( - const CanonicalCookie& cookie) OVERRIDE; + void DeleteCookie(const CanonicalCookie& cookie) override; - virtual void Flush(const base::Closure& callback) OVERRIDE; + void Flush(const base::Closure& callback) override; - virtual void SetForceKeepSessionState() OVERRIDE; + void SetForceKeepSessionState() override; protected: - virtual ~MockPersistentCookieStore(); + ~MockPersistentCookieStore() override; private: CommandList commands_; @@ -127,15 +125,14 @@ class MockCookieMonsterDelegate : public CookieMonsterDelegate { void reset() { changes_.clear(); } - virtual void OnCookieChanged( - const CanonicalCookie& cookie, - bool removed, - CookieMonsterDelegate::ChangeCause cause) OVERRIDE; + void OnCookieChanged(const CanonicalCookie& cookie, + bool removed, + CookieMonsterDelegate::ChangeCause cause) override; - virtual void OnLoaded() OVERRIDE; + void OnLoaded() override; private: - virtual ~MockCookieMonsterDelegate(); + ~MockCookieMonsterDelegate() override; std::vector<CookieNotification> changes_; @@ -161,23 +158,23 @@ class MockSimplePersistentCookieStore public: MockSimplePersistentCookieStore(); - virtual void Load(const LoadedCallback& loaded_callback) OVERRIDE; + void Load(const LoadedCallback& loaded_callback) override; - virtual void LoadCookiesForKey(const std::string& key, - const LoadedCallback& loaded_callback) OVERRIDE; + void LoadCookiesForKey(const std::string& key, + const LoadedCallback& loaded_callback) override; - virtual void AddCookie(const CanonicalCookie& cookie) OVERRIDE; + void AddCookie(const CanonicalCookie& cookie) override; - virtual void UpdateCookieAccessTime(const CanonicalCookie& cookie) OVERRIDE; + void UpdateCookieAccessTime(const CanonicalCookie& cookie) override; - virtual void DeleteCookie(const CanonicalCookie& cookie) OVERRIDE; + void DeleteCookie(const CanonicalCookie& cookie) override; - virtual void Flush(const base::Closure& callback) OVERRIDE; + void Flush(const base::Closure& callback) override; - virtual void SetForceKeepSessionState() OVERRIDE; + void SetForceKeepSessionState() override; protected: - virtual ~MockSimplePersistentCookieStore(); + ~MockSimplePersistentCookieStore() override; private: typedef std::map<int64, CanonicalCookie> CanonicalCookieMap; diff --git a/chromium/net/cookies/cookie_monster_unittest.cc b/chromium/net/cookies/cookie_monster_unittest.cc index e7fb6b0875c..633bca59493 100644 --- a/chromium/net/cookies/cookie_monster_unittest.cc +++ b/chromium/net/cookies/cookie_monster_unittest.cc @@ -12,6 +12,7 @@ #include "base/bind.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include "base/memory/scoped_vector.h" #include "base/message_loop/message_loop.h" #include "base/metrics/histogram.h" #include "base/metrics/histogram_samples.h" @@ -1391,7 +1392,7 @@ TEST_F(CookieMonsterTest, DeleteCookieByName) { } } -TEST_F(CookieMonsterTest, InitializeFromCookieMonster) { +TEST_F(CookieMonsterTest, ImportCookiesFromCookieMonster) { scoped_refptr<CookieMonster> cm_1(new CookieMonster(NULL, NULL)); CookieOptions options; @@ -1407,7 +1408,7 @@ TEST_F(CookieMonsterTest, InitializeFromCookieMonster) { CookieList cookies_1 = GetAllCookies(cm_1.get()); scoped_refptr<CookieMonster> cm_2(new CookieMonster(NULL, NULL)); - ASSERT_TRUE(cm_2->InitializeFrom(cookies_1)); + ASSERT_TRUE(cm_2->ImportCookies(cookies_1)); CookieList cookies_2 = GetAllCookies(cm_2.get()); size_t expected_size = 3; @@ -1958,7 +1959,7 @@ TEST_F(CookieMonsterTest, BackingStoreCommunication) { { scoped_refptr<CookieMonster> cmout(new CookieMonster(store.get(), NULL)); for (const CookiesInputInfo* p = input_info; - p < &input_info[ARRAYSIZE_UNSAFE(input_info)]; + p < &input_info[arraysize(input_info)]; p++) { EXPECT_TRUE(SetCookieWithDetails(cmout.get(), p->url, @@ -2112,7 +2113,7 @@ TEST_F(CookieMonsterTest, MAYBE_GarbageCollectionTriggers) { } }; - for (int ci = 0; ci < static_cast<int>(ARRAYSIZE_UNSAFE(test_cases)); ++ci) { + for (int ci = 0; ci < static_cast<int>(arraysize(test_cases)); ++ci) { const TestCase *test_case = &test_cases[ci]; scoped_refptr<CookieMonster> cm( CreateMonsterFromStoreForGC( @@ -2165,7 +2166,7 @@ class FlushablePersistentStore : public CookieMonster::PersistentCookieStore { public: FlushablePersistentStore() : flush_count_(0) {} - virtual void Load(const LoadedCallback& loaded_callback) OVERRIDE { + void Load(const LoadedCallback& loaded_callback) override { std::vector<CanonicalCookie*> out_cookies; base::MessageLoop::current()->PostTask( FROM_HERE, @@ -2173,18 +2174,17 @@ class FlushablePersistentStore : public CookieMonster::PersistentCookieStore { new net::LoadedCallbackTask(loaded_callback, out_cookies))); } - virtual void LoadCookiesForKey( - const std::string& key, - const LoadedCallback& loaded_callback) OVERRIDE { + void LoadCookiesForKey(const std::string& key, + const LoadedCallback& loaded_callback) override { Load(loaded_callback); } - virtual void AddCookie(const CanonicalCookie&) OVERRIDE {} - virtual void UpdateCookieAccessTime(const CanonicalCookie&) OVERRIDE {} - virtual void DeleteCookie(const CanonicalCookie&) OVERRIDE {} - virtual void SetForceKeepSessionState() OVERRIDE {} + void AddCookie(const CanonicalCookie&) override {} + void UpdateCookieAccessTime(const CanonicalCookie&) override {} + void DeleteCookie(const CanonicalCookie&) override {} + void SetForceKeepSessionState() override {} - virtual void Flush(const base::Closure& callback) OVERRIDE { + void Flush(const base::Closure& callback) override { ++flush_count_; if (!callback.is_null()) callback.Run(); @@ -2195,7 +2195,7 @@ class FlushablePersistentStore : public CookieMonster::PersistentCookieStore { } private: - virtual ~FlushablePersistentStore() {} + ~FlushablePersistentStore() override {} volatile int flush_count_; }; @@ -2738,4 +2738,151 @@ TEST_F(CookieMonsterTest, ControlCharacterPurge) { EXPECT_EQ("foo=bar; hello=world", GetCookies(cm.get(), url)); } +class CookieMonsterNotificationTest : public CookieMonsterTest { + public: + CookieMonsterNotificationTest() + : test_url_("http://www.google.com/foo"), + store_(new MockPersistentCookieStore), + monster_(new CookieMonster(store_.get(), NULL)) {} + + ~CookieMonsterNotificationTest() override {} + + CookieMonster* monster() { return monster_.get(); } + + protected: + const GURL test_url_; + + private: + scoped_refptr<MockPersistentCookieStore> store_; + scoped_refptr<CookieMonster> monster_; +}; + +void RecordCookieChanges(std::vector<net::CanonicalCookie>* out_cookies, + std::vector<bool>* out_removes, + const net::CanonicalCookie& cookie, + bool removed) { + DCHECK(out_cookies); + out_cookies->push_back(cookie); + if (out_removes) + out_removes->push_back(removed); +} + +TEST_F(CookieMonsterNotificationTest, NoNotifyWithNoCookie) { + std::vector<net::CanonicalCookie> cookies; + scoped_ptr<CookieStore::CookieChangedSubscription> sub( + monster()->AddCallbackForCookie(test_url_, "abc", + base::Bind(&RecordCookieChanges, &cookies, nullptr))); + base::MessageLoop::current()->RunUntilIdle(); + EXPECT_EQ(0U, cookies.size()); +} + +TEST_F(CookieMonsterNotificationTest, NoNotifyWithInitialCookie) { + std::vector<net::CanonicalCookie> cookies; + SetCookie(monster(), test_url_, "abc=def"); + base::MessageLoop::current()->RunUntilIdle(); + scoped_ptr<CookieStore::CookieChangedSubscription> sub( + monster()->AddCallbackForCookie(test_url_, "abc", + base::Bind(&RecordCookieChanges, &cookies, nullptr))); + base::MessageLoop::current()->RunUntilIdle(); + EXPECT_EQ(0U, cookies.size()); +} + +TEST_F(CookieMonsterNotificationTest, NotifyOnSet) { + std::vector<net::CanonicalCookie> cookies; + std::vector<bool> removes; + scoped_ptr<CookieStore::CookieChangedSubscription> sub( + monster()->AddCallbackForCookie(test_url_, "abc", + base::Bind(&RecordCookieChanges, &cookies, &removes))); + SetCookie(monster(), test_url_, "abc=def"); + base::MessageLoop::current()->RunUntilIdle(); + EXPECT_EQ(1U, cookies.size()); + EXPECT_EQ(1U, removes.size()); + + EXPECT_EQ("abc", cookies[0].Name()); + EXPECT_EQ("def", cookies[0].Value()); + EXPECT_FALSE(removes[0]); +} + +TEST_F(CookieMonsterNotificationTest, NotifyOnDelete) { + std::vector<net::CanonicalCookie> cookies; + std::vector<bool> removes; + scoped_ptr<CookieStore::CookieChangedSubscription> sub( + monster()->AddCallbackForCookie(test_url_, "abc", + base::Bind(&RecordCookieChanges, &cookies, &removes))); + SetCookie(monster(), test_url_, "abc=def"); + base::MessageLoop::current()->RunUntilIdle(); + EXPECT_EQ(1U, cookies.size()); + EXPECT_EQ(1U, removes.size()); + + DeleteCookie(monster(), test_url_, "abc"); + base::MessageLoop::current()->RunUntilIdle(); + EXPECT_EQ(2U, cookies.size()); + EXPECT_EQ(2U, removes.size()); + + EXPECT_EQ("abc", cookies[1].Name()); + EXPECT_EQ("def", cookies[1].Value()); + EXPECT_TRUE(removes[1]); +} + +TEST_F(CookieMonsterNotificationTest, NotifyOnUpdate) { + std::vector<net::CanonicalCookie> cookies; + std::vector<bool> removes; + scoped_ptr<CookieStore::CookieChangedSubscription> sub( + monster()->AddCallbackForCookie(test_url_, "abc", + base::Bind(&RecordCookieChanges, &cookies, &removes))); + SetCookie(monster(), test_url_, "abc=def"); + base::MessageLoop::current()->RunUntilIdle(); + EXPECT_EQ(1U, cookies.size()); + + // Replacing an existing cookie is actually a two-phase delete + set + // operation, so we get an extra notification. + SetCookie(monster(), test_url_, "abc=ghi"); + base::MessageLoop::current()->RunUntilIdle(); + + EXPECT_EQ(3U, cookies.size()); + EXPECT_EQ(3U, removes.size()); + + EXPECT_EQ("abc", cookies[1].Name()); + EXPECT_EQ("def", cookies[1].Value()); + EXPECT_TRUE(removes[1]); + + EXPECT_EQ("abc", cookies[2].Name()); + EXPECT_EQ("ghi", cookies[2].Value()); + EXPECT_FALSE(removes[2]); +} + +TEST_F(CookieMonsterNotificationTest, MultipleNotifies) { + std::vector<net::CanonicalCookie> cookies0; + std::vector<net::CanonicalCookie> cookies1; + scoped_ptr<CookieStore::CookieChangedSubscription> sub0( + monster()->AddCallbackForCookie(test_url_, "abc", + base::Bind(&RecordCookieChanges, &cookies0, nullptr))); + scoped_ptr<CookieStore::CookieChangedSubscription> sub1( + monster()->AddCallbackForCookie(test_url_, "def", + base::Bind(&RecordCookieChanges, &cookies1, nullptr))); + SetCookie(monster(), test_url_, "abc=def"); + base::MessageLoop::current()->RunUntilIdle(); + EXPECT_EQ(1U, cookies0.size()); + EXPECT_EQ(0U, cookies1.size()); + SetCookie(monster(), test_url_, "def=abc"); + base::MessageLoop::current()->RunUntilIdle(); + EXPECT_EQ(1U, cookies0.size()); + EXPECT_EQ(1U, cookies1.size()); +} + +TEST_F(CookieMonsterNotificationTest, MultipleSameNotifies) { + std::vector<net::CanonicalCookie> cookies0; + std::vector<net::CanonicalCookie> cookies1; + scoped_ptr<CookieStore::CookieChangedSubscription> sub0( + monster()->AddCallbackForCookie(test_url_, "abc", + base::Bind(&RecordCookieChanges, &cookies0, nullptr))); + scoped_ptr<CookieStore::CookieChangedSubscription> sub1( + monster()->AddCallbackForCookie(test_url_, "abc", + base::Bind(&RecordCookieChanges, &cookies1, nullptr))); + SetCookie(monster(), test_url_, "abc=def"); + base::MessageLoop::current()->RunUntilIdle(); + EXPECT_EQ(1U, cookies0.size()); + EXPECT_EQ(1U, cookies0.size()); +} + } // namespace net diff --git a/chromium/net/cookies/cookie_store.h b/chromium/net/cookies/cookie_store.h index b2552a6cf0e..9f5e1f191be 100644 --- a/chromium/net/cookies/cookie_store.h +++ b/chromium/net/cookies/cookie_store.h @@ -12,6 +12,7 @@ #include "base/basictypes.h" #include "base/callback.h" +#include "base/callback_list.h" #include "base/memory/ref_counted.h" #include "base/time/time.h" #include "net/base/net_export.h" @@ -33,6 +34,11 @@ class NET_EXPORT CookieStore : public base::RefCountedThreadSafe<CookieStore> { typedef base::Callback<void(const std::string& cookie)> GetCookiesCallback; typedef base::Callback<void(bool success)> SetCookiesCallback; typedef base::Callback<void(int num_deleted)> DeleteCallback; + typedef base::Callback<void(const CanonicalCookie& cookie, bool removed)> + CookieChangedCallback; + typedef base::CallbackList<void(const CanonicalCookie& cookie, bool removed)> + CookieChangedCallbackList; + typedef CookieChangedCallbackList::Subscription CookieChangedSubscription; // Sets a single cookie. Expects a cookie line, like "a=1; domain=b.com". // @@ -91,6 +97,27 @@ class NET_EXPORT CookieStore : public base::RefCountedThreadSafe<CookieStore> { // Returns the underlying CookieMonster. virtual CookieMonster* GetCookieMonster() = 0; + // Add a callback to be notified when the set of cookies named |name| that + // would be sent for a request to |url| changes. The returned handle is + // guaranteed not to hold a hard reference to the CookieStore object. + // + // |callback| will be called when a cookie is added or removed. |callback| is + // passed the respective |cookie| which was added to or removed from the + // cookies and a boolean indicating if the cookies was removed or not. + // + // Note that |callback| is called twice when a cookie is updated: once for + // the removal of the existing cookie and once for the adding the new cookie. + // + // Note that this method consumes memory and CPU per (url, name) pair ever + // registered that are still consumed even after all subscriptions for that + // (url, name) pair are removed. If this method ever needs to support an + // unbounded amount of such pairs, this contract needs to change and + // implementors need to be improved to not behave this way. + virtual scoped_ptr<CookieChangedSubscription> AddCallbackForCookie( + const GURL& url, + const std::string& name, + const CookieChangedCallback& callback) = 0; + protected: friend class base::RefCountedThreadSafe<CookieStore>; CookieStore(); diff --git a/chromium/net/cookies/cookie_store_test_helpers.cc b/chromium/net/cookies/cookie_store_test_helpers.cc index fdf2c1f1ee8..bcf8c897c70 100644 --- a/chromium/net/cookies/cookie_store_test_helpers.cc +++ b/chromium/net/cookies/cookie_store_test_helpers.cc @@ -135,4 +135,13 @@ CookieMonster* DelayedCookieMonster::GetCookieMonster() { return cookie_monster_.get(); } +scoped_ptr<CookieStore::CookieChangedSubscription> +DelayedCookieMonster::AddCallbackForCookie( + const GURL& url, + const std::string& name, + const CookieChangedCallback& callback) { + ADD_FAILURE(); + return scoped_ptr<CookieStore::CookieChangedSubscription>(); +} + } // namespace net diff --git a/chromium/net/cookies/cookie_store_test_helpers.h b/chromium/net/cookies/cookie_store_test_helpers.h index 84b83bc062c..760b847846c 100644 --- a/chromium/net/cookies/cookie_store_test_helpers.h +++ b/chromium/net/cookies/cookie_store_test_helpers.h @@ -23,20 +23,19 @@ class DelayedCookieMonster : public CookieStore { // invoke the internal callback. // Post a delayed task to invoke the original callback with the results. - virtual void SetCookieWithOptionsAsync( + void SetCookieWithOptionsAsync( const GURL& url, const std::string& cookie_line, const CookieOptions& options, - const CookieMonster::SetCookiesCallback& callback) OVERRIDE; + const CookieMonster::SetCookiesCallback& callback) override; - virtual void GetCookiesWithOptionsAsync( + void GetCookiesWithOptionsAsync( const GURL& url, const CookieOptions& options, - const CookieMonster::GetCookiesCallback& callback) OVERRIDE; + const CookieMonster::GetCookiesCallback& callback) override; - virtual void GetAllCookiesForURLAsync( - const GURL& url, - const GetCookieListCallback& callback) OVERRIDE; + void GetAllCookiesForURLAsync(const GURL& url, + const GetCookieListCallback& callback) override; virtual bool SetCookieWithOptions(const GURL& url, const std::string& cookie_line, @@ -48,24 +47,27 @@ class DelayedCookieMonster : public CookieStore { 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; + 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; + void DeleteAllCreatedBetweenAsync(const base::Time& delete_begin, + const base::Time& delete_end, + const DeleteCallback& callback) override; - virtual void DeleteAllCreatedBetweenForHostAsync( + void DeleteAllCreatedBetweenForHostAsync( const base::Time delete_begin, const base::Time delete_end, const GURL& url, - const DeleteCallback& callback) OVERRIDE; + const DeleteCallback& callback) override; + + void DeleteSessionCookiesAsync(const DeleteCallback&) override; - virtual void DeleteSessionCookiesAsync(const DeleteCallback&) OVERRIDE; + CookieMonster* GetCookieMonster() override; - virtual CookieMonster* GetCookieMonster() OVERRIDE; + scoped_ptr<CookieStore::CookieChangedSubscription> + AddCallbackForCookie(const GURL& url, const std::string& name, + const CookieChangedCallback& callback) override; private: @@ -84,7 +86,7 @@ class DelayedCookieMonster : public CookieStore { const CookieMonster::GetCookiesCallback& callback); friend class base::RefCountedThreadSafe<DelayedCookieMonster>; - virtual ~DelayedCookieMonster(); + ~DelayedCookieMonster() override; scoped_refptr<CookieMonster> cookie_monster_; diff --git a/chromium/net/cookies/cookie_util.cc b/chromium/net/cookies/cookie_util.cc index 3c80566e7a3..958801839f2 100644 --- a/chromium/net/cookies/cookie_util.cc +++ b/chromium/net/cookies/cookie_util.cc @@ -210,6 +210,60 @@ GURL CookieOriginToURL(const std::string& domain, bool is_https) { return GURL(scheme + "://" + host); } +void ParseRequestCookieLine(const std::string& header_value, + ParsedRequestCookies* parsed_cookies) { + std::string::const_iterator i = header_value.begin(); + while (i != header_value.end()) { + // Here we are at the beginning of a cookie. + + // Eat whitespace. + while (i != header_value.end() && *i == ' ') ++i; + if (i == header_value.end()) return; + + // Find cookie name. + std::string::const_iterator cookie_name_beginning = i; + while (i != header_value.end() && *i != '=') ++i; + base::StringPiece cookie_name(cookie_name_beginning, i); + + // Find cookie value. + base::StringPiece cookie_value; + // Cookies may have no value, in this case '=' may or may not be there. + if (i != header_value.end() && i + 1 != header_value.end()) { + ++i; // Skip '='. + std::string::const_iterator cookie_value_beginning = i; + if (*i == '"') { + ++i; // Skip '"'. + while (i != header_value.end() && *i != '"') ++i; + if (i == header_value.end()) return; + ++i; // Skip '"'. + cookie_value = base::StringPiece(cookie_value_beginning, i); + // i points to character after '"', potentially a ';'. + } else { + while (i != header_value.end() && *i != ';') ++i; + cookie_value = base::StringPiece(cookie_value_beginning, i); + // i points to ';' or end of string. + } + } + parsed_cookies->push_back(std::make_pair(cookie_name, cookie_value)); + // Eat ';'. + if (i != header_value.end()) ++i; + } +} + +std::string SerializeRequestCookieLine( + const ParsedRequestCookies& parsed_cookies) { + std::string buffer; + for (ParsedRequestCookies::const_iterator i = parsed_cookies.begin(); + i != parsed_cookies.end(); ++i) { + if (!buffer.empty()) + buffer.append("; "); + buffer.append(i->first.begin(), i->first.end()); + buffer.push_back('='); + buffer.append(i->second.begin(), i->second.end()); + } + return buffer; +} + } // namespace cookie_utils } // namespace net diff --git a/chromium/net/cookies/cookie_util.h b/chromium/net/cookies/cookie_util.h index aaaf27d41aa..0bf1452af86 100644 --- a/chromium/net/cookies/cookie_util.h +++ b/chromium/net/cookies/cookie_util.h @@ -6,7 +6,10 @@ #define NET_COOKIES_COOKIE_UTIL_H_ #include <string> +#include <utility> +#include <vector> +#include "base/strings/string_piece.h" #include "base/time/time.h" #include "net/base/net_export.h" @@ -40,7 +43,25 @@ NET_EXPORT base::Time ParseCookieTime(const std::string& time_string); // Convenience for converting a cookie origin (domain and https pair) to a URL. NET_EXPORT GURL CookieOriginToURL(const std::string& domain, bool is_https); -} // namspace cookie_util +// A ParsedRequestCookie consists of the key and value of the cookie. +typedef std::pair<base::StringPiece, base::StringPiece> ParsedRequestCookie; +typedef std::vector<ParsedRequestCookie> ParsedRequestCookies; + +// Assumes that |header_value| is the cookie header value of a HTTP Request +// following the cookie-string schema of RFC 6265, section 4.2.1, and returns +// cookie name/value pairs. If cookie values are presented in double quotes, +// these will appear in |parsed_cookies| as well. Assumes that the cookie +// header is written by Chromium and therefore well-formed. +NET_EXPORT void ParseRequestCookieLine(const std::string& header_value, + ParsedRequestCookies* parsed_cookies); + +// Writes all cookies of |parsed_cookies| into a HTTP Request header value +// that belongs to the "Cookie" header. The entries of |parsed_cookies| must +// already be appropriately escaped. +NET_EXPORT std::string SerializeRequestCookieLine( + const ParsedRequestCookies& parsed_cookies); + +} // namespace cookie_util } // namespace net #endif // NET_COOKIES_COOKIE_UTIL_H_ diff --git a/chromium/net/cookies/cookie_util_unittest.cc b/chromium/net/cookies/cookie_util_unittest.cc index f297afdd076..fc2763146c9 100644 --- a/chromium/net/cookies/cookie_util_unittest.cc +++ b/chromium/net/cookies/cookie_util_unittest.cc @@ -2,10 +2,49 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <string> +#include <utility> +#include <vector> + #include "base/basictypes.h" #include "net/cookies/cookie_util.h" #include "testing/gtest/include/gtest/gtest.h" +namespace { + +struct RequestCookieParsingTest { + std::string str; + std::vector<std::pair<std::string, std::string> > parsed; +}; + +net::cookie_util::ParsedRequestCookies MakeParsedRequestCookies( + const std::vector<std::pair<std::string, std::string> >& data) { + net::cookie_util::ParsedRequestCookies parsed; + for (size_t i = 0; i < data.size(); i++) { + parsed.push_back(std::make_pair(base::StringPiece(data[i].first), + base::StringPiece(data[i].second))); + } + return parsed; +} + +void CheckParse( + const std::string& str, + const std::vector<std::pair<std::string, std::string> >& parsed_expected) { + net::cookie_util::ParsedRequestCookies parsed; + net::cookie_util::ParseRequestCookieLine(str, &parsed); + EXPECT_EQ(MakeParsedRequestCookies(parsed_expected), parsed); +} + +void CheckSerialize( + const std::vector<std::pair<std::string, std::string> >& parsed, + const std::string& str_expected) { + net::cookie_util::ParsedRequestCookies prc = + MakeParsedRequestCookies(parsed); + EXPECT_EQ(str_expected, net::cookie_util::SerializeRequestCookieLine(prc)); +} + +} // namespace + TEST(CookieUtilTest, TestDomainIsHostOnly) { const struct { const char* str; @@ -16,7 +55,7 @@ TEST(CookieUtilTest, TestDomainIsHostOnly) { { ".google.com", false } }; - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { + for (size_t i = 0; i < arraysize(tests); ++i) { EXPECT_EQ(tests[i].is_host_only, net::cookie_util::DomainIsHostOnly(tests[i].str)); } @@ -99,7 +138,7 @@ TEST(CookieUtilTest, TestCookieDateParsing) { }; base::Time parsed_time; - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { + for (size_t i = 0; i < arraysize(tests); ++i) { parsed_time = net::cookie_util::ParseCookieTime(tests[i].str); if (!tests[i].valid) { EXPECT_FALSE(!parsed_time.is_null()) << tests[i].str; @@ -109,3 +148,49 @@ TEST(CookieUtilTest, TestCookieDateParsing) { EXPECT_EQ(tests[i].epoch, parsed_time.ToTimeT()) << tests[i].str; } } + +TEST(CookieUtilTest, TestRequestCookieParsing) { + std::vector<RequestCookieParsingTest> tests; + + // Simple case. + tests.push_back(RequestCookieParsingTest()); + tests.back().str = "key=value"; + tests.back().parsed.push_back(std::make_pair(std::string("key"), + std::string("value"))); + // Multiple key/value pairs. + tests.push_back(RequestCookieParsingTest()); + tests.back().str = "key1=value1; key2=value2"; + tests.back().parsed.push_back(std::make_pair(std::string("key1"), + std::string("value1"))); + tests.back().parsed.push_back(std::make_pair(std::string("key2"), + std::string("value2"))); + // Empty value. + tests.push_back(RequestCookieParsingTest()); + tests.back().str = "key=; otherkey=1234"; + tests.back().parsed.push_back(std::make_pair(std::string("key"), + std::string())); + tests.back().parsed.push_back(std::make_pair(std::string("otherkey"), + std::string("1234"))); + // Special characters (including equals signs) in value. + tests.push_back(RequestCookieParsingTest()); + tests.back().str = "key=; a2=s=(./&t=:&u=a#$; a3=+~"; + tests.back().parsed.push_back(std::make_pair(std::string("key"), + std::string())); + tests.back().parsed.push_back(std::make_pair(std::string("a2"), + std::string("s=(./&t=:&u=a#$"))); + tests.back().parsed.push_back(std::make_pair(std::string("a3"), + std::string("+~"))); + // Quoted value. + tests.push_back(RequestCookieParsingTest()); + tests.back().str = "key=\"abcdef\"; otherkey=1234"; + tests.back().parsed.push_back(std::make_pair(std::string("key"), + std::string("\"abcdef\""))); + tests.back().parsed.push_back(std::make_pair(std::string("otherkey"), + std::string("1234"))); + + for (size_t i = 0; i < tests.size(); i++) { + SCOPED_TRACE(testing::Message() << "Test " << i); + CheckParse(tests[i].str, tests[i].parsed); + CheckSerialize(tests[i].parsed, tests[i].str); + } +} diff --git a/chromium/net/cookies/parsed_cookie.cc b/chromium/net/cookies/parsed_cookie.cc index 60e0bbb6618..2c72c3b8cd7 100644 --- a/chromium/net/cookies/parsed_cookie.cc +++ b/chromium/net/cookies/parsed_cookie.cc @@ -137,7 +137,7 @@ bool IsValidCookieValue(const std::string& value) { } bool IsControlCharacter(unsigned char c) { - return (c >= 0) && (c <= 31); + return c <= 31; } bool IsValidCookieAttributeValue(const std::string& value) { @@ -391,7 +391,7 @@ void ParsedCookie::ParseTokenValuePairs(const std::string& cookie_line) { // From RFC2109: "Attributes (names) (attr) are case-insensitive." if (pair_num != 0) - StringToLowerASCII(&pair.first); + base::StringToLowerASCII(&pair.first); // Ignore Set-Cookie directives contaning control characters. See // http://crbug.com/238041. if (!IsValidCookieAttributeValue(pair.first) || @@ -410,6 +410,12 @@ void ParsedCookie::ParseTokenValuePairs(const std::string& cookie_line) { } void ParsedCookie::SetupAttributes() { + // Ignore Set-Cookie directive where name and value are both empty. + if (pairs_[0].first.empty() && pairs_[0].second.empty()) { + pairs_.clear(); + return; + } + // We skip over the first token/value, the user supplied one. for (size_t i = 1; i < pairs_.size(); ++i) { if (pairs_[i].first == kPathTokenName) { diff --git a/chromium/net/cookies/parsed_cookie.h b/chromium/net/cookies/parsed_cookie.h index 93b2c23853b..8a8e135ad69 100644 --- a/chromium/net/cookies/parsed_cookie.h +++ b/chromium/net/cookies/parsed_cookie.h @@ -25,6 +25,8 @@ class NET_EXPORT ParsedCookie { static const int kMaxPairs = 16; // Construct from a cookie string like "BLAH=1; path=/; domain=.google.com" + // Format is according to RFC 6265. Cookies with both name and value empty + // will be considered invalid. ParsedCookie(const std::string& cookie_line); ~ParsedCookie(); diff --git a/chromium/net/cookies/parsed_cookie_unittest.cc b/chromium/net/cookies/parsed_cookie_unittest.cc index 23e3768afe6..0f5715511a5 100644 --- a/chromium/net/cookies/parsed_cookie_unittest.cc +++ b/chromium/net/cookies/parsed_cookie_unittest.cc @@ -18,6 +18,21 @@ TEST(ParsedCookieTest, TestBasic) { EXPECT_EQ("b", pc.Value()); } +TEST(ParsedCookieTest, TestEmpty) { + ParsedCookie pc1("=; path=/; secure;"); + EXPECT_FALSE(pc1.IsValid()); + ParsedCookie pc2("= ; path=/; secure;"); + EXPECT_FALSE(pc2.IsValid()); + ParsedCookie pc3(" =; path=/; secure;"); + EXPECT_FALSE(pc3.IsValid()); + ParsedCookie pc4(" = ; path=/; secure;"); + EXPECT_FALSE(pc4.IsValid()); + ParsedCookie pc5(" ; path=/; secure;"); + EXPECT_FALSE(pc5.IsValid()); + ParsedCookie pc6("; path=/; secure;"); + EXPECT_FALSE(pc6.IsValid()); +} + TEST(ParsedCookieTest, TestQuoted) { // These are some quoting cases which the major browsers all // handle differently. I've tested Internet Explorer 6, Opera 9.6, @@ -184,13 +199,13 @@ TEST(ParsedCookieTest, TrailingWhitespace) { TEST(ParsedCookieTest, TooManyPairs) { std::string blankpairs; - blankpairs.resize(ParsedCookie::kMaxPairs - 1, ';'); + blankpairs.resize(ParsedCookie::kMaxPairs - 2, ';'); - ParsedCookie pc1(blankpairs + "secure"); + ParsedCookie pc1("a=b;" + blankpairs + "secure"); EXPECT_TRUE(pc1.IsValid()); EXPECT_TRUE(pc1.IsSecure()); - ParsedCookie pc2(blankpairs + ";secure"); + ParsedCookie pc2("a=b;" + blankpairs + ";secure"); EXPECT_TRUE(pc2.IsValid()); EXPECT_FALSE(pc2.IsSecure()); } |