Home | History | Annotate | Download | only in prerender
      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