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 3 // found in the LICENSE file. 4 5 #include "chrome/browser/browsing_data/browsing_data_cookie_helper.h" 6 7 #include "utility" 8 9 #include "base/bind.h" 10 #include "base/logging.h" 11 #include "base/memory/scoped_ptr.h" 12 #include "base/stl_util.h" 13 #include "chrome/browser/profiles/profile.h" 14 #include "content/public/browser/browser_thread.h" 15 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" 16 #include "net/cookies/canonical_cookie.h" 17 #include "net/cookies/cookie_util.h" 18 #include "net/cookies/parsed_cookie.h" 19 #include "net/url_request/url_request_context.h" 20 #include "net/url_request/url_request_context_getter.h" 21 #include "url/gurl.h" 22 23 using content::BrowserThread; 24 25 namespace { 26 const char kGlobalCookieSetURL[] = "chrome://cookieset"; 27 } 28 29 BrowsingDataCookieHelper::BrowsingDataCookieHelper( 30 net::URLRequestContextGetter* request_context_getter) 31 : is_fetching_(false), 32 request_context_getter_(request_context_getter) { 33 DCHECK_CURRENTLY_ON(BrowserThread::UI); 34 } 35 36 BrowsingDataCookieHelper::~BrowsingDataCookieHelper() { 37 } 38 39 void BrowsingDataCookieHelper::StartFetching( 40 const base::Callback<void(const net::CookieList& cookies)>& callback) { 41 DCHECK_CURRENTLY_ON(BrowserThread::UI); 42 DCHECK(!is_fetching_); 43 DCHECK(!callback.is_null()); 44 DCHECK(completion_callback_.is_null()); 45 is_fetching_ = true; 46 completion_callback_ = callback; 47 BrowserThread::PostTask( 48 BrowserThread::IO, FROM_HERE, 49 base::Bind(&BrowsingDataCookieHelper::FetchCookiesOnIOThread, this)); 50 } 51 52 void BrowsingDataCookieHelper::DeleteCookie( 53 const net::CanonicalCookie& cookie) { 54 DCHECK_CURRENTLY_ON(BrowserThread::UI); 55 BrowserThread::PostTask( 56 BrowserThread::IO, FROM_HERE, 57 base::Bind(&BrowsingDataCookieHelper::DeleteCookieOnIOThread, 58 this, cookie)); 59 } 60 61 void BrowsingDataCookieHelper::FetchCookiesOnIOThread() { 62 DCHECK_CURRENTLY_ON(BrowserThread::IO); 63 scoped_refptr<net::CookieMonster> cookie_monster = 64 request_context_getter_->GetURLRequestContext()-> 65 cookie_store()->GetCookieMonster(); 66 if (cookie_monster.get()) { 67 cookie_monster->GetAllCookiesAsync( 68 base::Bind(&BrowsingDataCookieHelper::OnFetchComplete, this)); 69 } else { 70 OnFetchComplete(net::CookieList()); 71 } 72 } 73 74 void BrowsingDataCookieHelper::OnFetchComplete(const net::CookieList& cookies) { 75 DCHECK_CURRENTLY_ON(BrowserThread::IO); 76 BrowserThread::PostTask( 77 BrowserThread::UI, FROM_HERE, 78 base::Bind(&BrowsingDataCookieHelper::NotifyInUIThread, this, cookies)); 79 } 80 81 void BrowsingDataCookieHelper::NotifyInUIThread( 82 const net::CookieList& cookies) { 83 DCHECK_CURRENTLY_ON(BrowserThread::UI); 84 DCHECK(is_fetching_); 85 is_fetching_ = false; 86 completion_callback_.Run(cookies); 87 completion_callback_.Reset(); 88 } 89 90 void BrowsingDataCookieHelper::DeleteCookieOnIOThread( 91 const net::CanonicalCookie& cookie) { 92 DCHECK_CURRENTLY_ON(BrowserThread::IO); 93 scoped_refptr<net::CookieMonster> cookie_monster = 94 request_context_getter_->GetURLRequestContext()-> 95 cookie_store()->GetCookieMonster(); 96 if (cookie_monster.get()) { 97 cookie_monster->DeleteCanonicalCookieAsync( 98 cookie, net::CookieMonster::DeleteCookieCallback()); 99 } 100 } 101 102 CannedBrowsingDataCookieHelper::CannedBrowsingDataCookieHelper( 103 net::URLRequestContextGetter* request_context_getter) 104 : BrowsingDataCookieHelper(request_context_getter) { 105 } 106 107 CannedBrowsingDataCookieHelper::~CannedBrowsingDataCookieHelper() { 108 Reset(); 109 } 110 111 void CannedBrowsingDataCookieHelper::AddReadCookies( 112 const GURL& frame_url, 113 const GURL& url, 114 const net::CookieList& cookie_list) { 115 typedef net::CookieList::const_iterator cookie_iterator; 116 for (cookie_iterator add_cookie = cookie_list.begin(); 117 add_cookie != cookie_list.end(); ++add_cookie) { 118 AddCookie(frame_url, *add_cookie); 119 } 120 } 121 122 void CannedBrowsingDataCookieHelper::AddChangedCookie( 123 const GURL& frame_url, 124 const GURL& url, 125 const std::string& cookie_line, 126 const net::CookieOptions& options) { 127 scoped_ptr<net::CanonicalCookie> cookie(net::CanonicalCookie::Create( 128 url, cookie_line, base::Time::Now(), options)); 129 if (cookie.get()) 130 AddCookie(frame_url, *cookie); 131 } 132 133 void CannedBrowsingDataCookieHelper::Reset() { 134 STLDeleteContainerPairSecondPointers(origin_cookie_set_map_.begin(), 135 origin_cookie_set_map_.end()); 136 origin_cookie_set_map_.clear(); 137 } 138 139 bool CannedBrowsingDataCookieHelper::empty() const { 140 for (OriginCookieSetMap::const_iterator it = origin_cookie_set_map_.begin(); 141 it != origin_cookie_set_map_.end(); 142 ++it) { 143 if (!it->second->empty()) 144 return false; 145 } 146 return true; 147 } 148 149 150 size_t CannedBrowsingDataCookieHelper::GetCookieCount() const { 151 size_t count = 0; 152 for (OriginCookieSetMap::const_iterator it = origin_cookie_set_map_.begin(); 153 it != origin_cookie_set_map_.end(); 154 ++it) { 155 count += it->second->size(); 156 } 157 return count; 158 } 159 160 161 void CannedBrowsingDataCookieHelper::StartFetching( 162 const net::CookieMonster::GetCookieListCallback& callback) { 163 DCHECK_CURRENTLY_ON(BrowserThread::UI); 164 net::CookieList cookie_list; 165 for (OriginCookieSetMap::iterator it = origin_cookie_set_map_.begin(); 166 it != origin_cookie_set_map_.end(); 167 ++it) { 168 cookie_list.insert(cookie_list.begin(), 169 it->second->begin(), 170 it->second->end()); 171 } 172 callback.Run(cookie_list); 173 } 174 175 void CannedBrowsingDataCookieHelper::DeleteCookie( 176 const net::CanonicalCookie& cookie) { 177 for (OriginCookieSetMap::iterator it = origin_cookie_set_map_.begin(); 178 it != origin_cookie_set_map_.end(); 179 ++it) { 180 DeleteMatchingCookie(cookie, it->second); 181 } 182 BrowsingDataCookieHelper::DeleteCookie(cookie); 183 } 184 185 bool CannedBrowsingDataCookieHelper::DeleteMatchingCookie( 186 const net::CanonicalCookie& add_cookie, 187 canonical_cookie::CookieHashSet* cookie_set) { 188 return cookie_set->erase(add_cookie) > 0; 189 } 190 191 canonical_cookie::CookieHashSet* CannedBrowsingDataCookieHelper::GetCookiesFor( 192 const GURL& first_party_origin) { 193 OriginCookieSetMap::iterator it = 194 origin_cookie_set_map_.find(first_party_origin); 195 if (it == origin_cookie_set_map_.end()) { 196 canonical_cookie::CookieHashSet* cookies = 197 new canonical_cookie::CookieHashSet; 198 origin_cookie_set_map_.insert( 199 std::pair<GURL, canonical_cookie::CookieHashSet*>(first_party_origin, 200 cookies)); 201 return cookies; 202 } 203 return it->second; 204 } 205 206 void CannedBrowsingDataCookieHelper::AddCookie( 207 const GURL& frame_url, 208 const net::CanonicalCookie& cookie) { 209 // Storing cookies in separate cookie sets per frame origin makes the 210 // GetCookieCount method count a cookie multiple times if it is stored in 211 // multiple sets. 212 // E.g. let "example.com" be redirected to "www.example.com". A cookie set 213 // with the cookie string "A=B; Domain=.example.com" would be sent to both 214 // hosts. This means it would be stored in the separate cookie sets for both 215 // hosts ("example.com", "www.example.com"). The method GetCookieCount would 216 // count this cookie twice. To prevent this, we us a single global cookie 217 // set as a work-around to store all added cookies. Per frame URL cookie 218 // sets are currently not used. In the future they will be used for 219 // collecting cookies per origin in redirect chains. 220 // TODO(markusheintz): A) Change the GetCookiesCount method to prevent 221 // counting cookies multiple times if they are stored in multiple cookie 222 // sets. B) Replace the GetCookieFor method call below with: 223 // "GetCookiesFor(frame_url.GetOrigin());" 224 CR_DEFINE_STATIC_LOCAL(const GURL, origin_cookie_url, (kGlobalCookieSetURL)); 225 canonical_cookie::CookieHashSet* cookie_set = 226 GetCookiesFor(origin_cookie_url); 227 DeleteMatchingCookie(cookie, cookie_set); 228 cookie_set->insert(cookie); 229 } 230