1 // Copyright 2014 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/prerender/prerender_cookie_store.h"
7 #include "base/logging.h"
8 #include "base/stl_util.h"
9 #include "content/public/browser/browser_thread.h"
11 using content::BrowserThread
;
15 PrerenderCookieStore::PrerenderCookieStore(
16 scoped_refptr
<net::CookieMonster
> default_cookie_monster
,
17 const base::Closure
& cookie_conflict_cb
)
18 : in_forwarding_mode_(false),
19 default_cookie_monster_(default_cookie_monster
),
20 changes_cookie_monster_(new net::CookieMonster(NULL
, NULL
)),
21 cookie_conflict_cb_(cookie_conflict_cb
),
22 cookie_conflict_(false) {
23 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
24 DCHECK(default_cookie_monster_
!= NULL
);
25 DCHECK(default_cookie_monster_
->loaded());
28 PrerenderCookieStore::~PrerenderCookieStore() {
31 void PrerenderCookieStore::SetCookieWithOptionsAsync(
33 const std::string
& cookie_line
,
34 const net::CookieOptions
& options
,
35 const SetCookiesCallback
& callback
) {
36 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
39 op
.op
= COOKIE_OP_SET_COOKIE_WITH_OPTIONS_ASYNC
;
41 op
.cookie_line
= cookie_line
;
44 GetCookieStoreForCookieOpAndLog(op
)->
45 SetCookieWithOptionsAsync(url
, cookie_line
, options
, callback
);
48 void PrerenderCookieStore::GetCookiesWithOptionsAsync(
50 const net::CookieOptions
& options
,
51 const GetCookiesCallback
& callback
) {
52 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
54 op
.op
= COOKIE_OP_GET_COOKIES_WITH_OPTIONS_ASYNC
;
58 GetCookieStoreForCookieOpAndLog(op
)->
59 GetCookiesWithOptionsAsync(url
, options
, callback
);
62 void PrerenderCookieStore::GetAllCookiesForURLAsync(
64 const GetCookieListCallback
& callback
) {
65 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
68 op
.op
= COOKIE_OP_GET_ALL_COOKIES_FOR_URL_ASYNC
;
71 GetCookieStoreForCookieOpAndLog(op
)->GetAllCookiesForURLAsync(url
, callback
);
75 void PrerenderCookieStore::DeleteCookieAsync(const GURL
& url
,
76 const std::string
& cookie_name
,
77 const base::Closure
& callback
) {
78 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
81 op
.op
= COOKIE_OP_DELETE_COOKIE_ASYNC
;
83 op
.cookie_name
= cookie_name
;
85 GetCookieStoreForCookieOpAndLog(op
)->DeleteCookieAsync(url
, cookie_name
,
89 void PrerenderCookieStore::DeleteAllCreatedBetweenAsync(
90 const base::Time
& delete_begin
,
91 const base::Time
& delete_end
,
92 const DeleteCallback
& callback
) {
96 void PrerenderCookieStore::DeleteAllCreatedBetweenForHostAsync(
97 const base::Time delete_begin
,
98 const base::Time delete_end
,
100 const DeleteCallback
& callback
) {
104 void PrerenderCookieStore::DeleteSessionCookiesAsync(const DeleteCallback
&) {
108 net::CookieMonster
* PrerenderCookieStore::GetCookieMonster() {
113 net::CookieStore
* PrerenderCookieStore::GetCookieStoreForCookieOpAndLog(
114 const CookieOperation
& op
) {
115 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
117 std::string key
= default_cookie_monster_
->GetKey(op
.url
.host());
118 bool is_read_only
= (op
.op
== COOKIE_OP_GET_COOKIES_WITH_OPTIONS_ASYNC
||
119 op
.op
== COOKIE_OP_GET_ALL_COOKIES_FOR_URL_ASYNC
);
121 if (in_forwarding_mode_
)
122 return default_cookie_monster_
;
124 DCHECK(changes_cookie_monster_
!= NULL
);
126 cookie_ops_
.push_back(op
);
128 bool key_copied
= ContainsKey(copied_keys_
, key
);
131 return changes_cookie_monster_
;
134 // Insert this key into the set of read keys, if it doesn't exist yet.
135 if (!ContainsKey(read_keys_
, key
))
136 read_keys_
.insert(key
);
137 return default_cookie_monster_
;
140 // If this method hasn't returned yet, the key has not been copied yet,
141 // and we must copy it due to the requested write operation.
143 bool copy_success
= default_cookie_monster_
->
144 CopyCookiesForKeyToOtherCookieMonster(key
, changes_cookie_monster_
);
146 // The copy must succeed.
147 DCHECK(copy_success
);
149 copied_keys_
.insert(key
);
151 return changes_cookie_monster_
;
154 void PrerenderCookieStore::ApplyChanges(std::vector
<GURL
>* cookie_change_urls
) {
155 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
157 if (in_forwarding_mode_
)
160 // Apply all changes to the underlying cookie store.
161 for (std::vector
<CookieOperation
>::const_iterator it
= cookie_ops_
.begin();
162 it
!= cookie_ops_
.end();
165 case COOKIE_OP_SET_COOKIE_WITH_OPTIONS_ASYNC
:
166 cookie_change_urls
->push_back(it
->url
);
167 default_cookie_monster_
->SetCookieWithOptionsAsync(
168 it
->url
, it
->cookie_line
, it
->options
, SetCookiesCallback());
170 case COOKIE_OP_GET_COOKIES_WITH_OPTIONS_ASYNC
:
171 default_cookie_monster_
->GetCookiesWithOptionsAsync(
172 it
->url
, it
->options
, GetCookiesCallback());
174 case COOKIE_OP_GET_ALL_COOKIES_FOR_URL_ASYNC
:
175 default_cookie_monster_
->GetAllCookiesForURLAsync(
176 it
->url
, GetCookieListCallback());
178 case COOKIE_OP_DELETE_COOKIE_ASYNC
:
179 cookie_change_urls
->push_back(it
->url
);
180 default_cookie_monster_
->DeleteCookieAsync(
181 it
->url
, it
->cookie_name
, base::Closure());
188 in_forwarding_mode_
= true;
189 copied_keys_
.clear();
191 changes_cookie_monster_
= NULL
;
194 void PrerenderCookieStore::OnCookieChangedForURL(
195 net::CookieMonster
* cookie_monster
,
197 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
199 // If the cookie was changed in a different cookie monster than the one
200 // being decorated, there is nothing to do).
201 if (cookie_monster
!= default_cookie_monster_
)
204 if (in_forwarding_mode_
)
207 // If we have encountered a conflict before, it has already been recorded
208 // and the cb has been issued, so nothing to do.
209 if (cookie_conflict_
)
212 std::string key
= default_cookie_monster_
->GetKey(url
.host());
214 // If the key for the cookie which was modified was neither read nor written,
216 if ((!ContainsKey(read_keys_
, key
)) && (!ContainsKey(copied_keys_
, key
)))
219 // There was a conflict in cookies. Call the conflict callback, which should
220 // cancel the prerender if necessary (i.e. if it hasn't already been
221 // cancelled for some other reason).
222 // Notice that there is a race here with swapping in the prerender, but this
223 // is the same issue that occurs when two tabs modify cookies for the
224 // same domain concurrently. Therefore, there is no need to do anything
225 // special to prevent this race condition.
226 cookie_conflict_
= true;
227 if (!cookie_conflict_cb_
.is_null()) {
228 BrowserThread::PostTask(
231 cookie_conflict_cb_
);
235 PrerenderCookieStore::CookieOperation::CookieOperation() {
238 PrerenderCookieStore::CookieOperation::~CookieOperation() {
241 } // namespace prerender