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