Index: net/cookies/cookie_monster.cc |
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc |
index 6947756a30db9d1cb90b3c5860df2742148c264a..f68f0c9b37c58fdd61f5801cbeaf8338bb9ae85f 100644 |
--- a/net/cookies/cookie_monster.cc |
+++ b/net/cookies/cookie_monster.cc |
@@ -163,6 +163,53 @@ bool LRACookieSorter(const CookieMonster::CookieMap::iterator& it1, |
return it1->second->CreationDate() < it2->second->CreationDate(); |
} |
+// Compare cookies using name, domain and path, so that "equivalent" cookies |
+// (per RFC 2965) are equal to each other. |
+int PartialDiffCookieOrdering(const net::CanonicalCookie& a, |
+ const net::CanonicalCookie& b) { |
+ int diff = a.Name().compare(b.Name()); |
+ if (diff != 0) |
+ return diff; |
+ |
+ diff = a.Domain().compare(b.Domain()); |
+ if (diff != 0) |
+ return diff; |
+ |
+ return a.Path().compare(b.Path()); |
+} |
+ |
+bool PartialDiffCookieSorter(const net::CanonicalCookie& a, |
+ const net::CanonicalCookie& b) { |
+ return PartialDiffCookieOrdering(a, b) < 0; |
+} |
+ |
+// This is a stricter ordering than PartialDiffCookieOrdering, where all fields |
+// are used except the last access time and the creation date. |
+bool FullDiffCookieSorter(const net::CanonicalCookie& a, |
+ const net::CanonicalCookie& b) { |
+ int diff = PartialDiffCookieOrdering(a, b); |
+ if (diff != 0) |
+ return diff < 0; |
+ |
+ DCHECK(a.IsEquivalent(b)); |
+ |
+ // Compare other fields. |
+ diff = a.Value().compare(b.Value()); |
+ if (diff != 0) |
+ return diff < 0; |
+ |
+ if (a.ExpiryDate() != b.ExpiryDate()) |
+ return a.ExpiryDate() < b.ExpiryDate(); |
+ |
+ if (a.IsSecure() != b.IsSecure()) |
+ return a.IsSecure(); |
+ |
+ if (a.IsHttpOnly() != b.IsHttpOnly()) |
+ return a.IsHttpOnly(); |
+ |
+ return a.Priority() < b.Priority(); |
+} |
+ |
// Our strategy to find duplicates is: |
// (1) Build a map from (cookiename, cookiepath) to |
// {list of cookies with this signature, sorted by creation time}. |
@@ -764,6 +811,49 @@ void CookieMonster::SetCookieWithOptionsTask::Run() { |
} |
} |
+// Task class for SetAllCookies call. |
+class CookieMonster::SetAllCookiesTask : public CookieMonsterTask { |
+ public: |
+ SetAllCookiesTask(CookieMonster* cookie_monster, |
+ const CookieList& list, |
+ const SetCookiesCallback& callback) |
+ : CookieMonsterTask(cookie_monster), list_(list), callback_(callback) {} |
+ |
+ // CookieMonsterTask: |
+ void Run() override; |
+ |
+ protected: |
+ ~SetAllCookiesTask() override {} |
+ |
+ private: |
+ CookieList list_; |
+ SetCookiesCallback callback_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(SetAllCookiesTask); |
+}; |
+ |
+void CookieMonster::SetAllCookiesTask::Run() { |
+ CookieList positive_diff; |
+ CookieList negative_diff; |
+ CookieList old_cookies = this->cookie_monster()->GetAllCookies(); |
+ this->cookie_monster()->ComputeCookieDiff(&old_cookies, &list_, |
+ &positive_diff, &negative_diff); |
+ |
+ for (CookieList::const_iterator it = negative_diff.begin(); |
+ it != negative_diff.end(); ++it) { |
+ this->cookie_monster()->DeleteCanonicalCookie(*it); |
+ } |
+ |
+ bool result = true; |
+ if (positive_diff.size() > 0) |
+ result = this->cookie_monster()->SetCanonicalCookies(list_); |
+ |
+ if (!callback_.is_null()) { |
+ this->InvokeCallback(base::Bind(&SetCookiesCallback::Run, |
+ base::Unretained(&callback_), result)); |
+ } |
+} |
+ |
// Task class for GetCookiesWithOptions call. |
class CookieMonster::GetCookiesWithOptionsTask : public CookieMonsterTask { |
public: |
@@ -985,6 +1075,13 @@ void CookieMonster::DeleteCanonicalCookieAsync( |
DoCookieTask(task); |
} |
+void CookieMonster::SetAllCookiesAsync(const CookieList& list, |
+ const SetCookiesCallback& callback) { |
+ scoped_refptr<SetAllCookiesTask> task = |
+ new SetAllCookiesTask(this, list, callback); |
+ DoCookieTask(task); |
+} |
+ |
void CookieMonster::SetCookieWithOptionsAsync( |
const GURL& url, |
const std::string& cookie_line, |
@@ -1843,6 +1940,21 @@ bool CookieMonster::SetCanonicalCookie(scoped_ptr<CanonicalCookie>* cc, |
return true; |
} |
+bool CookieMonster::SetCanonicalCookies(const CookieList& list) { |
+ base::AutoLock autolock(lock_); |
+ |
+ net::CookieOptions options; |
+ options.set_include_httponly(); |
+ |
+ for (CookieList::const_iterator it = list.begin(); it != list.end(); ++it) { |
+ scoped_ptr<CanonicalCookie> canonical_cookie(new CanonicalCookie(*it)); |
+ if (!SetCanonicalCookie(&canonical_cookie, it->CreationDate(), options)) |
+ return false; |
+ } |
+ |
+ return true; |
+} |
+ |
void CookieMonster::InternalUpdateCookieAccessTime(CanonicalCookie* cc, |
const Time& current) { |
lock_.AssertAcquired(); |
@@ -2226,6 +2338,37 @@ Time CookieMonster::CurrentTime() { |
last_time_seen_.ToInternalValue() + 1)); |
} |
+void CookieMonster::ComputeCookieDiff(CookieList* old_cookies, |
+ CookieList* new_cookies, |
+ CookieList* cookies_to_add, |
+ CookieList* cookies_to_delete) { |
+ DCHECK(old_cookies); |
+ DCHECK(new_cookies); |
+ DCHECK(cookies_to_add); |
+ DCHECK(cookies_to_delete); |
+ DCHECK(cookies_to_add->empty()); |
+ DCHECK(cookies_to_delete->empty()); |
+ |
+ // Sort both lists. |
+ std::sort(old_cookies->begin(), old_cookies->end(), FullDiffCookieSorter); |
+ std::sort(new_cookies->begin(), new_cookies->end(), FullDiffCookieSorter); |
+ |
+ // Compute the cookies to be deleted. |
+ // It is OK to call set_difference using PartialDiffCookieSorter even though |
erikwright (departed)
2015/03/13 13:59:01
// A set ordered by FullDiffCookieSorter is also o
droger
2015/03/16 13:03:50
Comment updated.
Unfortunately it seems that std::
|
+ // the list was sorted using FullDiffCookieSorter. |
+ std::set_difference( |
erikwright (departed)
2015/03/13 13:59:01
How about the following comment.
// Select any ol
droger
2015/03/16 13:03:50
Done.
|
+ old_cookies->begin(), old_cookies->end(), new_cookies->begin(), |
+ new_cookies->end(), |
+ std::inserter(*cookies_to_delete, cookies_to_delete->begin()), |
+ PartialDiffCookieSorter); |
+ |
+ // Compute the cookies to be added. |
+ std::set_difference(new_cookies->begin(), new_cookies->end(), |
erikwright (departed)
2015/03/13 13:59:01
// Select any new cookie for addition (or update)
droger
2015/03/16 13:03:50
Done.
|
+ old_cookies->begin(), old_cookies->end(), |
+ std::inserter(*cookies_to_add, cookies_to_add->begin()), |
+ FullDiffCookieSorter); |
+} |
+ |
scoped_ptr<CookieStore::CookieChangedSubscription> |
CookieMonster::AddCallbackForCookie(const GURL& gurl, |
const std::string& name, |