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 kGlobalCookieListURL[] = "chrome://cookielist";
27 }
28
BrowsingDataCookieHelper(net::URLRequestContextGetter * request_context_getter)29 BrowsingDataCookieHelper::BrowsingDataCookieHelper(
30 net::URLRequestContextGetter* request_context_getter)
31 : is_fetching_(false),
32 request_context_getter_(request_context_getter) {
33 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
34 }
35
~BrowsingDataCookieHelper()36 BrowsingDataCookieHelper::~BrowsingDataCookieHelper() {
37 }
38
StartFetching(const base::Callback<void (const net::CookieList & cookies)> & callback)39 void BrowsingDataCookieHelper::StartFetching(
40 const base::Callback<void(const net::CookieList& cookies)>& callback) {
41 DCHECK(BrowserThread::CurrentlyOn(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
DeleteCookie(const net::CanonicalCookie & cookie)52 void BrowsingDataCookieHelper::DeleteCookie(
53 const net::CanonicalCookie& cookie) {
54 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
55 BrowserThread::PostTask(
56 BrowserThread::IO, FROM_HERE,
57 base::Bind(&BrowsingDataCookieHelper::DeleteCookieOnIOThread,
58 this, cookie));
59 }
60
FetchCookiesOnIOThread()61 void BrowsingDataCookieHelper::FetchCookiesOnIOThread() {
62 DCHECK(BrowserThread::CurrentlyOn(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
OnFetchComplete(const net::CookieList & cookies)74 void BrowsingDataCookieHelper::OnFetchComplete(const net::CookieList& cookies) {
75 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
76 BrowserThread::PostTask(
77 BrowserThread::UI, FROM_HERE,
78 base::Bind(&BrowsingDataCookieHelper::NotifyInUIThread, this, cookies));
79 }
80
NotifyInUIThread(const net::CookieList & cookies)81 void BrowsingDataCookieHelper::NotifyInUIThread(
82 const net::CookieList& cookies) {
83 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
84 DCHECK(is_fetching_);
85 is_fetching_ = false;
86 completion_callback_.Run(cookies);
87 completion_callback_.Reset();
88 }
89
DeleteCookieOnIOThread(const net::CanonicalCookie & cookie)90 void BrowsingDataCookieHelper::DeleteCookieOnIOThread(
91 const net::CanonicalCookie& cookie) {
92 DCHECK(BrowserThread::CurrentlyOn(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
CannedBrowsingDataCookieHelper(net::URLRequestContextGetter * request_context_getter)102 CannedBrowsingDataCookieHelper::CannedBrowsingDataCookieHelper(
103 net::URLRequestContextGetter* request_context_getter)
104 : BrowsingDataCookieHelper(request_context_getter) {
105 }
106
~CannedBrowsingDataCookieHelper()107 CannedBrowsingDataCookieHelper::~CannedBrowsingDataCookieHelper() {
108 Reset();
109 }
110
Clone()111 CannedBrowsingDataCookieHelper* CannedBrowsingDataCookieHelper::Clone() {
112 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
113 CannedBrowsingDataCookieHelper* clone =
114 new CannedBrowsingDataCookieHelper(request_context_getter());
115
116 for (OriginCookieListMap::iterator it = origin_cookie_list_map_.begin();
117 it != origin_cookie_list_map_.end();
118 ++it) {
119 net::CookieList* cookies = clone->GetCookiesFor(it->first);
120 cookies->insert(cookies->begin(), it->second->begin(), it->second->end());
121 }
122 return clone;
123 }
124
AddReadCookies(const GURL & frame_url,const GURL & url,const net::CookieList & cookie_list)125 void CannedBrowsingDataCookieHelper::AddReadCookies(
126 const GURL& frame_url,
127 const GURL& url,
128 const net::CookieList& cookie_list) {
129 typedef net::CookieList::const_iterator cookie_iterator;
130 for (cookie_iterator add_cookie = cookie_list.begin();
131 add_cookie != cookie_list.end(); ++add_cookie) {
132 AddCookie(frame_url, *add_cookie);
133 }
134 }
135
AddChangedCookie(const GURL & frame_url,const GURL & url,const std::string & cookie_line,const net::CookieOptions & options)136 void CannedBrowsingDataCookieHelper::AddChangedCookie(
137 const GURL& frame_url,
138 const GURL& url,
139 const std::string& cookie_line,
140 const net::CookieOptions& options) {
141 scoped_ptr<net::CanonicalCookie> cookie(net::CanonicalCookie::Create(
142 url, cookie_line, base::Time::Now(), options));
143 if (cookie.get())
144 AddCookie(frame_url, *cookie);
145 }
146
Reset()147 void CannedBrowsingDataCookieHelper::Reset() {
148 STLDeleteContainerPairSecondPointers(origin_cookie_list_map_.begin(),
149 origin_cookie_list_map_.end());
150 origin_cookie_list_map_.clear();
151 }
152
empty() const153 bool CannedBrowsingDataCookieHelper::empty() const {
154 for (OriginCookieListMap::const_iterator it =
155 origin_cookie_list_map_.begin();
156 it != origin_cookie_list_map_.end();
157 ++it) {
158 if (!it->second->empty())
159 return false;
160 }
161 return true;
162 }
163
164
GetCookieCount() const165 size_t CannedBrowsingDataCookieHelper::GetCookieCount() const {
166 size_t count = 0;
167 for (OriginCookieListMap::const_iterator it = origin_cookie_list_map_.begin();
168 it != origin_cookie_list_map_.end();
169 ++it) {
170 count += it->second->size();
171 }
172 return count;
173 }
174
175
StartFetching(const net::CookieMonster::GetCookieListCallback & callback)176 void CannedBrowsingDataCookieHelper::StartFetching(
177 const net::CookieMonster::GetCookieListCallback& callback) {
178 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
179 net::CookieList cookie_list;
180 for (OriginCookieListMap::iterator it = origin_cookie_list_map_.begin();
181 it != origin_cookie_list_map_.end();
182 ++it) {
183 cookie_list.insert(cookie_list.begin(),
184 it->second->begin(),
185 it->second->end());
186 }
187 callback.Run(cookie_list);
188 }
189
DeleteCookie(const net::CanonicalCookie & cookie)190 void CannedBrowsingDataCookieHelper::DeleteCookie(
191 const net::CanonicalCookie& cookie) {
192 for (OriginCookieListMap::iterator it = origin_cookie_list_map_.begin();
193 it != origin_cookie_list_map_.end();
194 ++it) {
195 DeleteMatchingCookie(cookie, it->second);
196 }
197 BrowsingDataCookieHelper::DeleteCookie(cookie);
198 }
199
DeleteMatchingCookie(const net::CanonicalCookie & add_cookie,net::CookieList * cookie_list)200 bool CannedBrowsingDataCookieHelper::DeleteMatchingCookie(
201 const net::CanonicalCookie& add_cookie,
202 net::CookieList* cookie_list) {
203 typedef net::CookieList::iterator cookie_iterator;
204 for (cookie_iterator cookie = cookie_list->begin();
205 cookie != cookie_list->end(); ++cookie) {
206 if (cookie->Name() == add_cookie.Name() &&
207 cookie->Domain() == add_cookie.Domain()&&
208 cookie->Path() == add_cookie.Path()) {
209 cookie_list->erase(cookie);
210 return true;
211 }
212 }
213 return false;
214 }
215
GetCookiesFor(const GURL & first_party_origin)216 net::CookieList* CannedBrowsingDataCookieHelper::GetCookiesFor(
217 const GURL& first_party_origin) {
218 OriginCookieListMap::iterator it =
219 origin_cookie_list_map_.find(first_party_origin);
220 if (it == origin_cookie_list_map_.end()) {
221 net::CookieList* cookies = new net::CookieList();
222 origin_cookie_list_map_.insert(
223 std::pair<GURL, net::CookieList*>(first_party_origin, cookies));
224 return cookies;
225 }
226 return it->second;
227 }
228
AddCookie(const GURL & frame_url,const net::CanonicalCookie & cookie)229 void CannedBrowsingDataCookieHelper::AddCookie(
230 const GURL& frame_url,
231 const net::CanonicalCookie& cookie) {
232 // Storing cookies in separate cookie lists per frame origin makes the
233 // GetCookieCount method count a cookie multiple times if it is stored in
234 // multiple lists.
235 // E.g. let "example.com" be redirected to "www.example.com". A cookie set
236 // with the cookie string "A=B; Domain=.example.com" would be sent to both
237 // hosts. This means it would be stored in the separate cookie lists for both
238 // hosts ("example.com", "www.example.com"). The method GetCookieCount would
239 // count this cookie twice. To prevent this, we us a single global cookie
240 // list as a work-around to store all added cookies. Per frame URL cookie
241 // lists are currently not used. In the future they will be used for
242 // collecting cookies per origin in redirect chains.
243 // TODO(markusheintz): A) Change the GetCookiesCount method to prevent
244 // counting cookies multiple times if they are stored in multiple cookie
245 // lists. B) Replace the GetCookieFor method call below with:
246 // "GetCookiesFor(frame_url.GetOrigin());"
247 net::CookieList* cookie_list =
248 GetCookiesFor(GURL(kGlobalCookieListURL));
249 DeleteMatchingCookie(cookie, cookie_list);
250 cookie_list->push_back(cookie);
251 }
252