OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Portions of this code based on Mozilla: | 5 // Portions of this code based on Mozilla: |
6 // (netwerk/cookie/src/nsCookieService.cpp) | 6 // (netwerk/cookie/src/nsCookieService.cpp) |
7 /* ***** BEGIN LICENSE BLOCK ***** | 7 /* ***** BEGIN LICENSE BLOCK ***** |
8 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 | 8 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
9 * | 9 * |
10 * The contents of this file are subject to the Mozilla Public License Version | 10 * The contents of this file are subject to the Mozilla Public License Version |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
56 #include "base/memory/scoped_vector.h" | 56 #include "base/memory/scoped_vector.h" |
57 #include "base/message_loop/message_loop.h" | 57 #include "base/message_loop/message_loop.h" |
58 #include "base/message_loop/message_loop_proxy.h" | 58 #include "base/message_loop/message_loop_proxy.h" |
59 #include "base/metrics/histogram.h" | 59 #include "base/metrics/histogram.h" |
60 #include "base/strings/string_util.h" | 60 #include "base/strings/string_util.h" |
61 #include "base/strings/stringprintf.h" | 61 #include "base/strings/stringprintf.h" |
62 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" | 62 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
63 #include "net/cookies/canonical_cookie.h" | 63 #include "net/cookies/canonical_cookie.h" |
64 #include "net/cookies/cookie_util.h" | 64 #include "net/cookies/cookie_util.h" |
65 #include "net/cookies/parsed_cookie.h" | 65 #include "net/cookies/parsed_cookie.h" |
66 #include "url/gurl.h" | |
67 | 66 |
68 using base::Time; | 67 using base::Time; |
69 using base::TimeDelta; | 68 using base::TimeDelta; |
70 using base::TimeTicks; | 69 using base::TimeTicks; |
71 | 70 |
72 // In steady state, most cookie requests can be satisfied by the in memory | 71 // In steady state, most cookie requests can be satisfied by the in memory |
73 // cookie monster store. However, if a request comes in during the initial | 72 // cookie monster store. However, if a request comes in during the initial |
74 // cookie load, it must be delayed until that load completes. That is done by | 73 // cookie load, it must be delayed until that load completes. That is done by |
75 // queueing it on CookieMonster::tasks_pending_ and running it when notification | 74 // queueing it on CookieMonster::tasks_pending_ and running it when notification |
76 // of cookie load completion is received via CookieMonster::OnLoaded. This | 75 // of cookie load completion is received via CookieMonster::OnLoaded. This |
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 // In Mozilla if you set a cookie like AAAA, it will have an empty token | 299 // In Mozilla if you set a cookie like AAAA, it will have an empty token |
301 // and a value of AAAA. When it sends the cookie back, it will send AAAA, | 300 // and a value of AAAA. When it sends the cookie back, it will send AAAA, |
302 // so we need to avoid sending =AAAA for a blank token value. | 301 // so we need to avoid sending =AAAA for a blank token value. |
303 if (!(*it)->Name().empty()) | 302 if (!(*it)->Name().empty()) |
304 cookie_line += (*it)->Name() + "="; | 303 cookie_line += (*it)->Name() + "="; |
305 cookie_line += (*it)->Value(); | 304 cookie_line += (*it)->Value(); |
306 } | 305 } |
307 return cookie_line; | 306 return cookie_line; |
308 } | 307 } |
309 | 308 |
| 309 void RunAsync(scoped_refptr<base::TaskRunner> proxy, |
| 310 const CookieStore::CookieChangedCallback& callback) { |
| 311 proxy->PostTask(FROM_HERE, callback); |
| 312 } |
| 313 |
310 } // namespace | 314 } // namespace |
311 | 315 |
312 CookieMonster::CookieMonster(PersistentCookieStore* store, | 316 CookieMonster::CookieMonster(PersistentCookieStore* store, |
313 CookieMonsterDelegate* delegate) | 317 CookieMonsterDelegate* delegate) |
314 : initialized_(false), | 318 : initialized_(false), |
315 loaded_(store == NULL), | 319 loaded_(store == NULL), |
316 store_(store), | 320 store_(store), |
317 last_access_threshold_( | 321 last_access_threshold_( |
318 TimeDelta::FromSeconds(kDefaultAccessUpdateThresholdSeconds)), | 322 TimeDelta::FromSeconds(kDefaultAccessUpdateThresholdSeconds)), |
319 delegate_(delegate), | 323 delegate_(delegate), |
(...skipping 576 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
896 const std::string& path, | 900 const std::string& path, |
897 const Time& expiration_time, | 901 const Time& expiration_time, |
898 bool secure, | 902 bool secure, |
899 bool http_only, | 903 bool http_only, |
900 CookiePriority priority, | 904 CookiePriority priority, |
901 const SetCookiesCallback& callback) { | 905 const SetCookiesCallback& callback) { |
902 scoped_refptr<SetCookieWithDetailsTask> task = | 906 scoped_refptr<SetCookieWithDetailsTask> task = |
903 new SetCookieWithDetailsTask(this, url, name, value, domain, path, | 907 new SetCookieWithDetailsTask(this, url, name, value, domain, path, |
904 expiration_time, secure, http_only, priority, | 908 expiration_time, secure, http_only, priority, |
905 callback); | 909 callback); |
906 | |
907 DoCookieTaskForURL(task, url); | 910 DoCookieTaskForURL(task, url); |
908 } | 911 } |
909 | 912 |
910 void CookieMonster::GetAllCookiesAsync(const GetCookieListCallback& callback) { | 913 void CookieMonster::GetAllCookiesAsync(const GetCookieListCallback& callback) { |
911 scoped_refptr<GetAllCookiesTask> task = | 914 scoped_refptr<GetAllCookiesTask> task = |
912 new GetAllCookiesTask(this, callback); | 915 new GetAllCookiesTask(this, callback); |
913 | 916 |
914 DoCookieTask(task); | 917 DoCookieTask(task); |
915 } | 918 } |
916 | 919 |
(...skipping 889 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1806 return false; | 1809 return false; |
1807 } | 1810 } |
1808 return SetCanonicalCookie(&cc, creation_time, options); | 1811 return SetCanonicalCookie(&cc, creation_time, options); |
1809 } | 1812 } |
1810 | 1813 |
1811 bool CookieMonster::SetCanonicalCookie(scoped_ptr<CanonicalCookie>* cc, | 1814 bool CookieMonster::SetCanonicalCookie(scoped_ptr<CanonicalCookie>* cc, |
1812 const Time& creation_time, | 1815 const Time& creation_time, |
1813 const CookieOptions& options) { | 1816 const CookieOptions& options) { |
1814 const std::string key(GetKey((*cc)->Domain())); | 1817 const std::string key(GetKey((*cc)->Domain())); |
1815 bool already_expired = (*cc)->IsExpired(creation_time); | 1818 bool already_expired = (*cc)->IsExpired(creation_time); |
| 1819 |
1816 if (DeleteAnyEquivalentCookie(key, **cc, options.exclude_httponly(), | 1820 if (DeleteAnyEquivalentCookie(key, **cc, options.exclude_httponly(), |
1817 already_expired)) { | 1821 already_expired)) { |
1818 VLOG(kVlogSetCookies) << "SetCookie() not clobbering httponly cookie"; | 1822 VLOG(kVlogSetCookies) << "SetCookie() not clobbering httponly cookie"; |
1819 return false; | 1823 return false; |
1820 } | 1824 } |
1821 | 1825 |
1822 VLOG(kVlogSetCookies) << "SetCookie() key: " << key << " cc: " | 1826 VLOG(kVlogSetCookies) << "SetCookie() key: " << key << " cc: " |
1823 << (*cc)->DebugString(); | 1827 << (*cc)->DebugString(); |
1824 | 1828 |
1825 // Realize that we might be setting an expired cookie, and the only point | 1829 // Realize that we might be setting an expired cookie, and the only point |
1826 // was to delete the cookie which we've already done. | 1830 // was to delete the cookie which we've already done. |
1827 if (!already_expired || keep_expired_cookies_) { | 1831 if (!already_expired || keep_expired_cookies_) { |
1828 // See InitializeHistograms() for details. | 1832 // See InitializeHistograms() for details. |
1829 if ((*cc)->IsPersistent()) { | 1833 if ((*cc)->IsPersistent()) { |
1830 histogram_expiration_duration_minutes_->Add( | 1834 histogram_expiration_duration_minutes_->Add( |
1831 ((*cc)->ExpiryDate() - creation_time).InMinutes()); | 1835 ((*cc)->ExpiryDate() - creation_time).InMinutes()); |
1832 } | 1836 } |
1833 | 1837 |
1834 InternalInsertCookie(key, cc->release(), true); | 1838 { |
| 1839 CanonicalCookie cookie = *(cc->get()); |
| 1840 InternalInsertCookie(key, cc->release(), true); |
| 1841 RunCallbacks(cookie); |
| 1842 } |
1835 } else { | 1843 } else { |
1836 VLOG(kVlogSetCookies) << "SetCookie() not storing already expired cookie."; | 1844 VLOG(kVlogSetCookies) << "SetCookie() not storing already expired cookie."; |
1837 } | 1845 } |
1838 | 1846 |
1839 // We assume that hopefully setting a cookie will be less common than | 1847 // We assume that hopefully setting a cookie will be less common than |
1840 // querying a cookie. Since setting a cookie can put us over our limits, | 1848 // querying a cookie. Since setting a cookie can put us over our limits, |
1841 // make sure that we garbage collect... We can also make the assumption that | 1849 // make sure that we garbage collect... We can also make the assumption that |
1842 // if a cookie was set, in the common case it will be used soon after, | 1850 // if a cookie was set, in the common case it will be used soon after, |
1843 // and we will purge the expired cookies in GetCookies(). | 1851 // and we will purge the expired cookies in GetCookies(). |
1844 GarbageCollect(creation_time, key); | 1852 GarbageCollect(creation_time, key); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1889 if ((cc->IsPersistent() || persist_session_cookies_) && store_.get() && | 1897 if ((cc->IsPersistent() || persist_session_cookies_) && store_.get() && |
1890 sync_to_store) | 1898 sync_to_store) |
1891 store_->DeleteCookie(*cc); | 1899 store_->DeleteCookie(*cc); |
1892 if (delegate_.get()) { | 1900 if (delegate_.get()) { |
1893 ChangeCausePair mapping = ChangeCauseMapping[deletion_cause]; | 1901 ChangeCausePair mapping = ChangeCauseMapping[deletion_cause]; |
1894 | 1902 |
1895 if (mapping.notify) | 1903 if (mapping.notify) |
1896 delegate_->OnCookieChanged(*cc, true, mapping.cause); | 1904 delegate_->OnCookieChanged(*cc, true, mapping.cause); |
1897 } | 1905 } |
1898 cookies_.erase(it); | 1906 cookies_.erase(it); |
| 1907 RunCallbacks(*cc); |
1899 delete cc; | 1908 delete cc; |
1900 } | 1909 } |
1901 | 1910 |
1902 // Domain expiry behavior is unchanged by key/expiry scheme (the | 1911 // Domain expiry behavior is unchanged by key/expiry scheme (the |
1903 // meaning of the key is different, but that's not visible to this routine). | 1912 // meaning of the key is different, but that's not visible to this routine). |
1904 int CookieMonster::GarbageCollect(const Time& current, | 1913 int CookieMonster::GarbageCollect(const Time& current, |
1905 const std::string& key) { | 1914 const std::string& key) { |
1906 lock_.AssertAcquired(); | 1915 lock_.AssertAcquired(); |
1907 | 1916 |
1908 int num_deleted = 0; | 1917 int num_deleted = 0; |
(...skipping 387 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2296 } | 2305 } |
2297 | 2306 |
2298 return true; | 2307 return true; |
2299 } | 2308 } |
2300 | 2309 |
2301 bool CookieMonster::loaded() { | 2310 bool CookieMonster::loaded() { |
2302 base::AutoLock autolock(lock_); | 2311 base::AutoLock autolock(lock_); |
2303 return loaded_; | 2312 return loaded_; |
2304 } | 2313 } |
2305 | 2314 |
| 2315 scoped_ptr<CookieStore::CookieChangedSubscription> |
| 2316 CookieMonster::AddCallbackForCookie( |
| 2317 const GURL& gurl, |
| 2318 const std::string& name, |
| 2319 const CookieChangedCallback& callback) { |
| 2320 base::AutoLock autolock(lock_); |
| 2321 std::pair<GURL, std::string> key(gurl, name); |
| 2322 if (hook_map_.count(key) == 0) |
| 2323 hook_map_[key] = make_linked_ptr(new CookieChangedCallbackList()); |
| 2324 return hook_map_[key]->Add(base::Bind( |
| 2325 &RunAsync, base::MessageLoopProxy::current(), callback)); |
| 2326 } |
| 2327 |
| 2328 void CookieMonster::RunCallbacks(const CanonicalCookie& cookie) { |
| 2329 lock_.AssertAcquired(); |
| 2330 CookieOptions opts; |
| 2331 opts.set_include_httponly(); |
| 2332 // Note that the callbacks in hook_map_ are wrapped with MakeAsync(), so they |
| 2333 // are guaranteed to not take long - they just post a RunAsync task back to |
| 2334 // the appropriate thread's message loop and return. It is important that this |
| 2335 // method not run user-supplied callbacks directly, since the CookieMonster |
| 2336 // lock is held and it is easy to accidentally introduce deadlocks. |
| 2337 for (CookieChangedHookMap::iterator it = hook_map_.begin(); |
| 2338 it != hook_map_.end(); ++it) { |
| 2339 std::pair<GURL, std::string> key = it->first; |
| 2340 if (cookie.IncludeForRequestURL(key.first, opts) && |
| 2341 cookie.Name() == key.second) { |
| 2342 it->second->Notify(); |
| 2343 } |
| 2344 } |
| 2345 } |
| 2346 |
2306 } // namespace net | 2347 } // namespace net |
OLD | NEW |