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 kGlobalCookieListURL[] = "chrome://cookielist";
     27 }
     28 
     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));
     34 }
     35 
     36 BrowsingDataCookieHelper::~BrowsingDataCookieHelper() {
     37 }
     38 
     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());
     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(BrowserThread::CurrentlyOn(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(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));
     69   } else {
     70     OnFetchComplete(net::CookieList());
     71   }
     72 }
     73 
     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));
     79 }
     80 
     81 void BrowsingDataCookieHelper::NotifyInUIThread(
     82     const net::CookieList& cookies) {
     83   DCHECK(BrowserThread::CurrentlyOn(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(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());
     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 CannedBrowsingDataCookieHelper* CannedBrowsingDataCookieHelper::Clone() {
    112   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    113   CannedBrowsingDataCookieHelper* clone =
    114       new CannedBrowsingDataCookieHelper(request_context_getter());
    115 
    116   for (OriginCookieListMap::iterator it = origin_cookie_list_map_.begin();
    117        it != origin_cookie_list_map_.end();
    118        ++it) {
    119     net::CookieList* cookies = clone->GetCookiesFor(it->first);
    120     cookies->insert(cookies->begin(), it->second->begin(), it->second->end());
    121   }
    122   return clone;
    123 }
    124 
    125 void CannedBrowsingDataCookieHelper::AddReadCookies(
    126     const GURL& frame_url,
    127     const GURL& 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);
    133   }
    134 }
    135 
    136 void CannedBrowsingDataCookieHelper::AddChangedCookie(
    137     const GURL& frame_url,
    138     const GURL& 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));
    143   if (cookie.get())
    144     AddCookie(frame_url, *cookie);
    145 }
    146 
    147 void CannedBrowsingDataCookieHelper::Reset() {
    148   STLDeleteContainerPairSecondPointers(origin_cookie_list_map_.begin(),
    149                                        origin_cookie_list_map_.end());
    150   origin_cookie_list_map_.clear();
    151 }
    152 
    153 bool CannedBrowsingDataCookieHelper::empty() const {
    154   for (OriginCookieListMap::const_iterator it =
    155            origin_cookie_list_map_.begin();
    156        it != origin_cookie_list_map_.end();
    157        ++it) {
    158     if (!it->second->empty())
    159       return false;
    160   }
    161   return true;
    162 }
    163 
    164 
    165 size_t CannedBrowsingDataCookieHelper::GetCookieCount() const {
    166   size_t count = 0;
    167   for (OriginCookieListMap::const_iterator it = origin_cookie_list_map_.begin();
    168        it != origin_cookie_list_map_.end();
    169        ++it) {
    170     count += it->second->size();
    171   }
    172   return count;
    173 }
    174 
    175 
    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();
    182        ++it) {
    183     cookie_list.insert(cookie_list.begin(),
    184                        it->second->begin(),
    185                        it->second->end());
    186   }
    187   callback.Run(cookie_list);
    188 }
    189 
    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);
    200       return true;
    201     }
    202   }
    203   return false;
    204 }
    205 
    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));
    214     return cookies;
    215   }
    216   return it->second;
    217 }
    218 
    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
    224   // multiple lists.
    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);
    241 }
    242