Chromium Code Reviews| 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 CookieChangedCallback wrapped = base::Bind( | |
| 2323 &RunAsync, base::MessageLoopProxy::current(), callback); | |
| 2324 if (hook_map_.count(key) == 0) { | |
| 2325 linked_ptr<CookieChangedCallbackList> list( | |
| 2326 new CookieChangedCallbackList()); | |
| 2327 hook_map_[key] = list; | |
|
erikwright (departed)
2014/10/24 20:11:10
hook_map_[key] = make_linked_ptr(new CookieChanged
| |
| 2328 } | |
| 2329 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
| |
| 2330 } | |
| 2331 | |
| 2332 void CookieMonster::RunCallbacks(const CanonicalCookie& cookie) { | |
| 2333 lock_.AssertAcquired(); | |
| 2334 CookieOptions opts; | |
| 2335 opts.set_include_httponly(); | |
| 2336 // Note that the callbacks in hook_map_ are wrapped with MakeAsync(), so they | |
| 2337 // are guaranteed to not take long - they just post a RunAsync task back to | |
| 2338 // the appropriate thread's message loop and return. It is important that this | |
| 2339 // method not run user-supplied callbacks directly, since the CookieMonster | |
| 2340 // lock is held and it is easy to accidentally introduce deadlocks. | |
| 2341 for (CookieChangedHookMap::iterator it = hook_map_.begin(); | |
| 2342 it != hook_map_.end(); ++it) { | |
| 2343 std::pair<GURL, std::string> key = it->first; | |
| 2344 if (cookie.IncludeForRequestURL(key.first, opts) && | |
| 2345 cookie.Name() == key.second) { | |
| 2346 it->second->Notify(); | |
| 2347 } | |
| 2348 } | |
| 2349 } | |
| 2350 | |
| 2306 } // namespace net | 2351 } // namespace net |
| OLD | NEW |