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.
5 #include "chrome/browser/browsing_data/browsing_data_cookie_helper.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"
23 using content::BrowserThread
;
26 const char kGlobalCookieListURL
[] = "chrome://cookielist";
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
));
36 BrowsingDataCookieHelper::~BrowsingDataCookieHelper() {
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());
46 completion_callback_
= callback
;
47 BrowserThread::PostTask(
48 BrowserThread::IO
, FROM_HERE
,
49 base::Bind(&BrowsingDataCookieHelper::FetchCookiesOnIOThread
, this));
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
,
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));
70 OnFetchComplete(net::CookieList());
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
));
81 void BrowsingDataCookieHelper::NotifyInUIThread(
82 const net::CookieList
& cookies
) {
83 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
86 completion_callback_
.Run(cookies
);
87 completion_callback_
.Reset();
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());
102 CannedBrowsingDataCookieHelper::CannedBrowsingDataCookieHelper(
103 net::URLRequestContextGetter
* request_context_getter
)
104 : BrowsingDataCookieHelper(request_context_getter
) {
107 CannedBrowsingDataCookieHelper::~CannedBrowsingDataCookieHelper() {
111 CannedBrowsingDataCookieHelper
* CannedBrowsingDataCookieHelper::Clone() {
112 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
113 CannedBrowsingDataCookieHelper
* clone
=
114 new CannedBrowsingDataCookieHelper(request_context_getter());
116 for (OriginCookieListMap::iterator it
= origin_cookie_list_map_
.begin();
117 it
!= origin_cookie_list_map_
.end();
119 net::CookieList
* cookies
= clone
->GetCookiesFor(it
->first
);
120 cookies
->insert(cookies
->begin(), it
->second
->begin(), it
->second
->end());
125 void CannedBrowsingDataCookieHelper::AddReadCookies(
126 const GURL
& frame_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
);
136 void CannedBrowsingDataCookieHelper::AddChangedCookie(
137 const GURL
& frame_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
));
144 AddCookie(frame_url
, *cookie
);
147 void CannedBrowsingDataCookieHelper::Reset() {
148 STLDeleteContainerPairSecondPointers(origin_cookie_list_map_
.begin(),
149 origin_cookie_list_map_
.end());
150 origin_cookie_list_map_
.clear();
153 bool CannedBrowsingDataCookieHelper::empty() const {
154 for (OriginCookieListMap::const_iterator it
=
155 origin_cookie_list_map_
.begin();
156 it
!= origin_cookie_list_map_
.end();
158 if (!it
->second
->empty())
165 size_t CannedBrowsingDataCookieHelper::GetCookieCount() const {
167 for (OriginCookieListMap::const_iterator it
= origin_cookie_list_map_
.begin();
168 it
!= origin_cookie_list_map_
.end();
170 count
+= it
->second
->size();
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();
183 cookie_list
.insert(cookie_list
.begin(),
187 callback
.Run(cookie_list
);
190 bool CannedBrowsingDataCookieHelper::DeleteMatchingCookie(
191 const net::CanonicalCookie
& add_cookie
,
192 net::CookieList
* cookie_list
) {
193 typedef net::CookieList::iterator cookie_iterator
;
194 for (cookie_iterator cookie
= cookie_list
->begin();
195 cookie
!= cookie_list
->end(); ++cookie
) {
196 if (cookie
->Name() == add_cookie
.Name() &&
197 cookie
->Domain() == add_cookie
.Domain()&&
198 cookie
->Path() == add_cookie
.Path()) {
199 cookie_list
->erase(cookie
);
206 net::CookieList
* CannedBrowsingDataCookieHelper::GetCookiesFor(
207 const GURL
& first_party_origin
) {
208 OriginCookieListMap::iterator it
=
209 origin_cookie_list_map_
.find(first_party_origin
);
210 if (it
== origin_cookie_list_map_
.end()) {
211 net::CookieList
* cookies
= new net::CookieList();
212 origin_cookie_list_map_
.insert(
213 std::pair
<GURL
, net::CookieList
*>(first_party_origin
, cookies
));
219 void CannedBrowsingDataCookieHelper::AddCookie(
220 const GURL
& frame_url
,
221 const net::CanonicalCookie
& cookie
) {
222 // Storing cookies in separate cookie lists per frame origin makes the
223 // GetCookieCount method count a cookie multiple times if it is stored in
225 // E.g. let "example.com" be redirected to "www.example.com". A cookie set
226 // with the cookie string "A=B; Domain=.example.com" would be sent to both
227 // hosts. This means it would be stored in the separate cookie lists for both
228 // hosts ("example.com", "www.example.com"). The method GetCookieCount would
229 // count this cookie twice. To prevent this, we us a single global cookie
230 // list as a work-around to store all added cookies. Per frame URL cookie
231 // lists are currently not used. In the future they will be used for
232 // collecting cookies per origin in redirect chains.
233 // TODO(markusheintz): A) Change the GetCookiesCount method to prevent
234 // counting cookies multiple times if they are stored in multiple cookie
235 // lists. B) Replace the GetCookieFor method call below with:
236 // "GetCookiesFor(frame_url.GetOrigin());"
237 net::CookieList
* cookie_list
=
238 GetCookiesFor(GURL(kGlobalCookieListURL
));
239 DeleteMatchingCookie(cookie
, cookie_list
);
240 cookie_list
->push_back(cookie
);