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. 4 5 #include "chrome/browser/prerender/prerender_cookie_store.h" 6 7 #include "base/logging.h" 8 #include "base/stl_util.h" 9 #include "content/public/browser/browser_thread.h" 10 11 using content::BrowserThread; 12 13 namespace prerender { 14 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_.get() != NULL); 25 DCHECK(default_cookie_monster_->loaded()); 26 } 27 28 PrerenderCookieStore::~PrerenderCookieStore() { 29 } 30 31 void PrerenderCookieStore::SetCookieWithOptionsAsync( 32 const GURL& url, 33 const std::string& cookie_line, 34 const net::CookieOptions& options, 35 const SetCookiesCallback& callback) { 36 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 37 38 CookieOperation op; 39 op.op = COOKIE_OP_SET_COOKIE_WITH_OPTIONS_ASYNC; 40 op.url = url; 41 op.cookie_line = cookie_line; 42 op.options = options; 43 44 GetCookieStoreForCookieOpAndLog(op)-> 45 SetCookieWithOptionsAsync(url, cookie_line, options, callback); 46 } 47 48 void PrerenderCookieStore::GetCookiesWithOptionsAsync( 49 const GURL& url, 50 const net::CookieOptions& options, 51 const GetCookiesCallback& callback) { 52 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 53 CookieOperation op; 54 op.op = COOKIE_OP_GET_COOKIES_WITH_OPTIONS_ASYNC; 55 op.url = url; 56 op.options = options; 57 58 GetCookieStoreForCookieOpAndLog(op)-> 59 GetCookiesWithOptionsAsync(url, options, callback); 60 } 61 62 void PrerenderCookieStore::GetAllCookiesForURLAsync( 63 const GURL& url, 64 const GetCookieListCallback& callback) { 65 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 66 67 CookieOperation op; 68 op.op = COOKIE_OP_GET_ALL_COOKIES_FOR_URL_ASYNC; 69 op.url = url; 70 71 GetCookieStoreForCookieOpAndLog(op)->GetAllCookiesForURLAsync(url, callback); 72 } 73 74 75 void PrerenderCookieStore::DeleteCookieAsync(const GURL& url, 76 const std::string& cookie_name, 77 const base::Closure& callback) { 78 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 79 80 CookieOperation op; 81 op.op = COOKIE_OP_DELETE_COOKIE_ASYNC; 82 op.url = url; 83 op.cookie_name = cookie_name; 84 85 GetCookieStoreForCookieOpAndLog(op)->DeleteCookieAsync(url, cookie_name, 86 callback); 87 } 88 89 void PrerenderCookieStore::DeleteAllCreatedBetweenAsync( 90 const base::Time& delete_begin, 91 const base::Time& delete_end, 92 const DeleteCallback& callback) { 93 NOTREACHED(); 94 } 95 96 void PrerenderCookieStore::DeleteAllCreatedBetweenForHostAsync( 97 const base::Time delete_begin, 98 const base::Time delete_end, 99 const GURL& url, 100 const DeleteCallback& callback) { 101 NOTREACHED(); 102 } 103 104 void PrerenderCookieStore::DeleteSessionCookiesAsync(const DeleteCallback&) { 105 NOTREACHED(); 106 } 107 108 net::CookieMonster* PrerenderCookieStore::GetCookieMonster() { 109 NOTREACHED(); 110 return NULL; 111 } 112 113 net::CookieStore* PrerenderCookieStore::GetCookieStoreForCookieOpAndLog( 114 const CookieOperation& op) { 115 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 116 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); 120 121 if (in_forwarding_mode_) 122 return default_cookie_monster_.get(); 123 124 DCHECK(changes_cookie_monster_.get() != NULL); 125 126 cookie_ops_.push_back(op); 127 128 bool key_copied = ContainsKey(copied_keys_, key); 129 130 if (key_copied) 131 return changes_cookie_monster_.get(); 132 133 if (is_read_only) { 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_.get(); 138 } 139 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. 142 143 bool copy_success = 144 default_cookie_monster_->CopyCookiesForKeyToOtherCookieMonster( 145 key, changes_cookie_monster_.get()); 146 147 // The copy must succeed. 148 DCHECK(copy_success); 149 150 copied_keys_.insert(key); 151 152 return changes_cookie_monster_.get(); 153 } 154 155 void PrerenderCookieStore::ApplyChanges(std::vector<GURL>* cookie_change_urls) { 156 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 157 158 if (in_forwarding_mode_) 159 return; 160 161 // Apply all changes to the underlying cookie store. 162 for (std::vector<CookieOperation>::const_iterator it = cookie_ops_.begin(); 163 it != cookie_ops_.end(); 164 ++it) { 165 switch (it->op) { 166 case COOKIE_OP_SET_COOKIE_WITH_OPTIONS_ASYNC: 167 cookie_change_urls->push_back(it->url); 168 default_cookie_monster_->SetCookieWithOptionsAsync( 169 it->url, it->cookie_line, it->options, SetCookiesCallback()); 170 break; 171 case COOKIE_OP_GET_COOKIES_WITH_OPTIONS_ASYNC: 172 default_cookie_monster_->GetCookiesWithOptionsAsync( 173 it->url, it->options, GetCookiesCallback()); 174 break; 175 case COOKIE_OP_GET_ALL_COOKIES_FOR_URL_ASYNC: 176 default_cookie_monster_->GetAllCookiesForURLAsync( 177 it->url, GetCookieListCallback()); 178 break; 179 case COOKIE_OP_DELETE_COOKIE_ASYNC: 180 cookie_change_urls->push_back(it->url); 181 default_cookie_monster_->DeleteCookieAsync( 182 it->url, it->cookie_name, base::Closure()); 183 break; 184 case COOKIE_OP_MAX: 185 NOTREACHED(); 186 } 187 } 188 189 in_forwarding_mode_ = true; 190 copied_keys_.clear(); 191 cookie_ops_.clear(); 192 changes_cookie_monster_ = NULL; 193 } 194 195 void PrerenderCookieStore::OnCookieChangedForURL( 196 net::CookieMonster* cookie_monster, 197 const GURL& url) { 198 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 199 200 // If the cookie was changed in a different cookie monster than the one 201 // being decorated, there is nothing to do). 202 if (cookie_monster != default_cookie_monster_.get()) 203 return; 204 205 if (in_forwarding_mode_) 206 return; 207 208 // If we have encountered a conflict before, it has already been recorded 209 // and the cb has been issued, so nothing to do. 210 if (cookie_conflict_) 211 return; 212 213 std::string key = default_cookie_monster_->GetKey(url.host()); 214 215 // If the key for the cookie which was modified was neither read nor written, 216 // nothing to do. 217 if ((!ContainsKey(read_keys_, key)) && (!ContainsKey(copied_keys_, key))) 218 return; 219 220 // There was a conflict in cookies. Call the conflict callback, which should 221 // cancel the prerender if necessary (i.e. if it hasn't already been 222 // cancelled for some other reason). 223 // Notice that there is a race here with swapping in the prerender, but this 224 // is the same issue that occurs when two tabs modify cookies for the 225 // same domain concurrently. Therefore, there is no need to do anything 226 // special to prevent this race condition. 227 cookie_conflict_ = true; 228 if (!cookie_conflict_cb_.is_null()) { 229 BrowserThread::PostTask( 230 BrowserThread::UI, 231 FROM_HERE, 232 cookie_conflict_cb_); 233 } 234 } 235 236 PrerenderCookieStore::CookieOperation::CookieOperation() { 237 } 238 239 PrerenderCookieStore::CookieOperation::~CookieOperation() { 240 } 241 242 } // namespace prerender 243