summaryrefslogtreecommitdiff
path: root/chromium/net/cookies
diff options
context:
space:
mode:
authorZeno Albisser <zeno.albisser@theqtcompany.com>2014-12-05 15:04:29 +0100
committerAndras Becsi <andras.becsi@theqtcompany.com>2014-12-09 10:49:28 +0100
commitaf6588f8d723931a298c995fa97259bb7f7deb55 (patch)
tree060ca707847ba1735f01af2372e0d5e494dc0366 /chromium/net/cookies
parent2fff84d821cc7b1c785f6404e0f8091333283e74 (diff)
downloadqtwebengine-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.cc2
-rw-r--r--chromium/net/cookies/canonical_cookie.h2
-rw-r--r--chromium/net/cookies/cookie_constants.cc2
-rw-r--r--chromium/net/cookies/cookie_monster.cc112
-rw-r--r--chromium/net/cookies/cookie_monster.h70
-rw-r--r--chromium/net/cookies/cookie_monster_perftest.cc2
-rw-r--r--chromium/net/cookies/cookie_monster_store_test.h49
-rw-r--r--chromium/net/cookies/cookie_monster_unittest.cc175
-rw-r--r--chromium/net/cookies/cookie_store.h27
-rw-r--r--chromium/net/cookies/cookie_store_test_helpers.cc9
-rw-r--r--chromium/net/cookies/cookie_store_test_helpers.h40
-rw-r--r--chromium/net/cookies/cookie_util.cc54
-rw-r--r--chromium/net/cookies/cookie_util.h23
-rw-r--r--chromium/net/cookies/cookie_util_unittest.cc89
-rw-r--r--chromium/net/cookies/parsed_cookie.cc10
-rw-r--r--chromium/net/cookies/parsed_cookie.h2
-rw-r--r--chromium/net/cookies/parsed_cookie_unittest.cc21
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());
}