Index: net/cookies/cookie_monster.cc |
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc |
index dd64cce8e41e3636009d234d7875eb3707eb167b..285022714a95f3b30e9139773fe33814da18b8e9 100644 |
--- a/net/cookies/cookie_monster.cc |
+++ b/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; |
@@ -307,6 +306,11 @@ std::string BuildCookieLine(const CanonicalCookieVector& cookies) { |
return cookie_line; |
} |
+void RunAsync(scoped_refptr<base::TaskRunner> proxy, |
+ const CookieStore::CookieChangedCallback& callback) { |
+ proxy->PostTask(FROM_HERE, callback); |
+} |
+ |
} // namespace |
CookieMonster::CookieMonster(PersistentCookieStore* store, |
@@ -903,7 +907,6 @@ void CookieMonster::SetCookieWithDetailsAsync( |
new SetCookieWithDetailsTask(this, url, name, value, domain, path, |
expiration_time, secure, http_only, priority, |
callback); |
- |
DoCookieTaskForURL(task, url); |
} |
@@ -1813,6 +1816,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"; |
@@ -1831,7 +1835,11 @@ 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); |
+ RunCallbacks(cookie); |
+ } |
} else { |
VLOG(kVlogSetCookies) << "SetCookie() not storing already expired cookie."; |
} |
@@ -1896,6 +1904,7 @@ void CookieMonster::InternalDeleteCookie(CookieMap::iterator it, |
delegate_->OnCookieChanged(*cc, true, mapping.cause); |
} |
cookies_.erase(it); |
+ RunCallbacks(*cc); |
delete cc; |
} |
@@ -2303,4 +2312,40 @@ 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); |
+ CookieChangedCallback wrapped = base::Bind( |
+ &RunAsync, base::MessageLoopProxy::current(), callback); |
+ if (hook_map_.count(key) == 0) { |
+ linked_ptr<CookieChangedCallbackList> list( |
+ new CookieChangedCallbackList()); |
+ hook_map_[key] = list; |
erikwright (departed)
2014/10/24 20:11:10
hook_map_[key] = make_linked_ptr(new CookieChanged
|
+ } |
+ return hook_map_[key]->Add(wrapped); |
erikwright (departed)
2014/10/24 20:11:10
I would inline the call to base::Bind here. No nee
|
+} |
+ |
+void CookieMonster::RunCallbacks(const CanonicalCookie& cookie) { |
+ 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(); |
+ } |
+ } |
+} |
+ |
} // namespace net |