Home | History | Annotate | Download | only in browser
      1 // Copyright (c) 2011 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/cookies_tree_model.h"
      6 
      7 #include <algorithm>
      8 #include <functional>
      9 #include <vector>
     10 
     11 #include "base/callback.h"
     12 #include "base/memory/linked_ptr.h"
     13 #include "base/string_util.h"
     14 #include "base/utf_string_conversions.h"
     15 #include "chrome/browser/extensions/extension_service.h"
     16 #include "content/browser/in_process_webkit/webkit_context.h"
     17 #include "grit/app_resources.h"
     18 #include "grit/generated_resources.h"
     19 #include "grit/theme_resources.h"
     20 #include "net/base/cookie_monster.h"
     21 #include "net/base/registry_controlled_domain.h"
     22 #include "net/url_request/url_request_context.h"
     23 #include "third_party/skia/include/core/SkBitmap.h"
     24 #include "ui/base/l10n/l10n_util.h"
     25 #include "ui/base/resource/resource_bundle.h"
     26 
     27 static const char kFileOriginNodeName[] = "file://";
     28 
     29 ///////////////////////////////////////////////////////////////////////////////
     30 // CookieTreeNode, public:
     31 
     32 void CookieTreeNode::DeleteStoredObjects() {
     33   std::for_each(children().begin(),
     34                 children().end(),
     35                 std::mem_fun(&CookieTreeNode::DeleteStoredObjects));
     36 }
     37 
     38 CookiesTreeModel* CookieTreeNode::GetModel() const {
     39   if (parent())
     40     return parent()->GetModel();
     41   else
     42     return NULL;
     43 }
     44 
     45 ///////////////////////////////////////////////////////////////////////////////
     46 // CookieTreeCookieNode, public:
     47 
     48 CookieTreeCookieNode::CookieTreeCookieNode(
     49     net::CookieMonster::CanonicalCookie* cookie)
     50     : CookieTreeNode(UTF8ToUTF16(cookie->Name())),
     51       cookie_(cookie) {
     52 }
     53 
     54 CookieTreeCookieNode::~CookieTreeCookieNode() {}
     55 
     56 void CookieTreeCookieNode::DeleteStoredObjects() {
     57   // notify CookieMonster that we should delete this cookie
     58   // We have stored a copy of all the cookies in the model, and our model is
     59   // never re-calculated. Thus, we just need to delete the nodes from our
     60   // model, and tell CookieMonster to delete the cookies. We can keep the
     61   // vector storing the cookies in-tact and not delete from there (that would
     62   // invalidate our pointers), and the fact that it contains semi out-of-date
     63   // data is not problematic as we don't re-build the model based on that.
     64   GetModel()->cookie_monster_->DeleteCanonicalCookie(*cookie_);
     65 }
     66 
     67 CookieTreeNode::DetailedInfo CookieTreeCookieNode::GetDetailedInfo() const {
     68   return DetailedInfo(parent()->parent()->GetTitle(),
     69                       DetailedInfo::TYPE_COOKIE,
     70                       cookie_, NULL, NULL, NULL, NULL, NULL);
     71 }
     72 
     73 namespace {
     74 // comparison functor, for use in CookieTreeRootNode
     75 class OriginNodeComparator {
     76  public:
     77   bool operator() (const CookieTreeNode* lhs,
     78                    const CookieTreeNode* rhs) {
     79     // We want to order by registry controlled domain, so we would get
     80     // google.com, ad.google.com, www.google.com,
     81     // microsoft.com, ad.microsoft.com. CanonicalizeHost transforms the origins
     82     // into a form like google.com.www so that string comparisons work.
     83     return (CanonicalizeHost(lhs->GetTitle()) <
     84             CanonicalizeHost(rhs->GetTitle()));
     85   }
     86 
     87  private:
     88   static std::string CanonicalizeHost(const string16& host16) {
     89     // The canonicalized representation makes the registry controlled domain
     90     // come first, and then adds subdomains in reverse order, e.g.
     91     // 1.mail.google.com would become google.com.mail.1, and then a standard
     92     // string comparison works to order hosts by registry controlled domain
     93     // first. Leading dots are ignored, ".google.com" is the same as
     94     // "google.com".
     95 
     96     std::string host = UTF16ToUTF8(host16);
     97     std::string retval = net::RegistryControlledDomainService::
     98         GetDomainAndRegistry(host);
     99     if (!retval.length())  // Is an IP address or other special origin.
    100       return host;
    101 
    102     std::string::size_type position = host.rfind(retval);
    103 
    104     // The host may be the registry controlled domain, in which case fail fast.
    105     if (position == 0 || position == std::string::npos)
    106       return host;
    107 
    108     // If host is www.google.com, retval will contain google.com at this point.
    109     // Start operating to the left of the registry controlled domain, e.g. in
    110     // the www.google.com example, start at index 3.
    111     --position;
    112 
    113     // If position == 0, that means it's a dot; this will be ignored to treat
    114     // ".google.com" the same as "google.com".
    115     while (position > 0) {
    116       retval += std::string(".");
    117       // Copy up to the next dot. host[position] is a dot so start after it.
    118       std::string::size_type next_dot = host.rfind(".", position - 1);
    119       if (next_dot == std::string::npos) {
    120         retval += host.substr(0, position);
    121         break;
    122       }
    123       retval += host.substr(next_dot + 1, position - (next_dot + 1));
    124       position = next_dot;
    125     }
    126     return retval;
    127   }
    128 };
    129 
    130 }  // namespace
    131 
    132 ///////////////////////////////////////////////////////////////////////////////
    133 // CookieTreeAppCacheNode, public:
    134 
    135 CookieTreeAppCacheNode::CookieTreeAppCacheNode(
    136     const appcache::AppCacheInfo* appcache_info)
    137     : CookieTreeNode(UTF8ToUTF16(appcache_info->manifest_url.spec())),
    138       appcache_info_(appcache_info) {
    139 }
    140 
    141 void CookieTreeAppCacheNode::DeleteStoredObjects() {
    142   DCHECK(GetModel()->appcache_helper_);
    143   GetModel()->appcache_helper_->DeleteAppCacheGroup(
    144       appcache_info_->manifest_url);
    145 }
    146 
    147 CookieTreeNode::DetailedInfo CookieTreeAppCacheNode::GetDetailedInfo() const {
    148   return DetailedInfo(parent()->parent()->GetTitle(),
    149                       DetailedInfo::TYPE_APPCACHE,
    150                       NULL, NULL, NULL, NULL, appcache_info_, NULL);
    151 }
    152 
    153 ///////////////////////////////////////////////////////////////////////////////
    154 // CookieTreeDatabaseNode, public:
    155 
    156 CookieTreeDatabaseNode::CookieTreeDatabaseNode(
    157     BrowsingDataDatabaseHelper::DatabaseInfo* database_info)
    158     : CookieTreeNode(database_info->database_name.empty() ?
    159           l10n_util::GetStringUTF16(IDS_COOKIES_WEB_DATABASE_UNNAMED_NAME) :
    160           UTF8ToUTF16(database_info->database_name)),
    161       database_info_(database_info) {
    162 }
    163 
    164 CookieTreeDatabaseNode::~CookieTreeDatabaseNode() {}
    165 
    166 void CookieTreeDatabaseNode::DeleteStoredObjects() {
    167   GetModel()->database_helper_->DeleteDatabase(
    168       database_info_->origin_identifier, database_info_->database_name);
    169 }
    170 
    171 CookieTreeNode::DetailedInfo CookieTreeDatabaseNode::GetDetailedInfo() const {
    172   return DetailedInfo(parent()->parent()->GetTitle(),
    173                       DetailedInfo::TYPE_DATABASE,
    174                       NULL, database_info_, NULL, NULL, NULL, NULL);
    175 }
    176 
    177 ///////////////////////////////////////////////////////////////////////////////
    178 // CookieTreeLocalStorageNode, public:
    179 
    180 CookieTreeLocalStorageNode::CookieTreeLocalStorageNode(
    181     BrowsingDataLocalStorageHelper::LocalStorageInfo* local_storage_info)
    182     : CookieTreeNode(UTF8ToUTF16(
    183           local_storage_info->origin.empty() ?
    184               local_storage_info->database_identifier :
    185               local_storage_info->origin)),
    186       local_storage_info_(local_storage_info) {
    187 }
    188 
    189 CookieTreeLocalStorageNode::~CookieTreeLocalStorageNode() {}
    190 
    191 void CookieTreeLocalStorageNode::DeleteStoredObjects() {
    192   GetModel()->local_storage_helper_->DeleteLocalStorageFile(
    193       local_storage_info_->file_path);
    194 }
    195 
    196 CookieTreeNode::DetailedInfo
    197 CookieTreeLocalStorageNode::GetDetailedInfo() const {
    198   return DetailedInfo(parent()->parent()->GetTitle(),
    199                       DetailedInfo::TYPE_LOCAL_STORAGE,
    200                       NULL, NULL, local_storage_info_, NULL, NULL, NULL);
    201 }
    202 
    203 ///////////////////////////////////////////////////////////////////////////////
    204 // CookieTreeSessionStorageNode, public:
    205 
    206 CookieTreeSessionStorageNode::CookieTreeSessionStorageNode(
    207     BrowsingDataLocalStorageHelper::LocalStorageInfo* session_storage_info)
    208     : CookieTreeNode(UTF8ToUTF16(
    209           session_storage_info->origin.empty() ?
    210               session_storage_info->database_identifier :
    211               session_storage_info->origin)),
    212       session_storage_info_(session_storage_info) {
    213 }
    214 
    215 CookieTreeSessionStorageNode::~CookieTreeSessionStorageNode() {}
    216 
    217 CookieTreeNode::DetailedInfo
    218 CookieTreeSessionStorageNode::GetDetailedInfo() const {
    219   return DetailedInfo(parent()->parent()->GetTitle(),
    220                       DetailedInfo::TYPE_SESSION_STORAGE,
    221                       NULL, NULL, NULL, session_storage_info_, NULL, NULL);
    222 }
    223 
    224 ///////////////////////////////////////////////////////////////////////////////
    225 // CookieTreeIndexedDBNode, public:
    226 
    227 CookieTreeIndexedDBNode::CookieTreeIndexedDBNode(
    228     BrowsingDataIndexedDBHelper::IndexedDBInfo* indexed_db_info)
    229     : CookieTreeNode(UTF8ToUTF16(
    230           indexed_db_info->origin.empty() ?
    231               indexed_db_info->database_identifier :
    232               indexed_db_info->origin)),
    233       indexed_db_info_(indexed_db_info) {
    234 }
    235 
    236 CookieTreeIndexedDBNode::~CookieTreeIndexedDBNode() {}
    237 
    238 void CookieTreeIndexedDBNode::DeleteStoredObjects() {
    239   GetModel()->indexed_db_helper_->DeleteIndexedDBFile(
    240       indexed_db_info_->file_path);
    241 }
    242 
    243 CookieTreeNode::DetailedInfo CookieTreeIndexedDBNode::GetDetailedInfo() const {
    244   return DetailedInfo(parent()->parent()->GetTitle(),
    245                       DetailedInfo::TYPE_INDEXED_DB,
    246                       NULL, NULL, NULL, NULL, NULL, indexed_db_info_);
    247 }
    248 
    249 ///////////////////////////////////////////////////////////////////////////////
    250 // CookieTreeRootNode, public:
    251 
    252 CookieTreeRootNode::CookieTreeRootNode(CookiesTreeModel* model)
    253     : model_(model) {
    254 }
    255 
    256 CookieTreeRootNode::~CookieTreeRootNode() {}
    257 
    258 CookieTreeOriginNode* CookieTreeRootNode::GetOrCreateOriginNode(
    259     const GURL& url) {
    260   CookieTreeOriginNode origin_node(url);
    261 
    262   // First see if there is an existing match.
    263   std::vector<CookieTreeNode*>::iterator origin_node_iterator =
    264       lower_bound(children().begin(),
    265                   children().end(),
    266                   &origin_node,
    267                   OriginNodeComparator());
    268 
    269   if (origin_node_iterator != children().end() &&
    270       WideToUTF16Hack(CookieTreeOriginNode::TitleForUrl(url)) ==
    271       (*origin_node_iterator)->GetTitle())
    272     return static_cast<CookieTreeOriginNode*>(*origin_node_iterator);
    273   // Node doesn't exist, create a new one and insert it into the (ordered)
    274   // children.
    275   CookieTreeOriginNode* retval = new CookieTreeOriginNode(url);
    276   DCHECK(model_);
    277   model_->Add(this, retval, (origin_node_iterator - children().begin()));
    278   return retval;
    279 }
    280 
    281 CookiesTreeModel* CookieTreeRootNode::GetModel() const {
    282   return model_;
    283 }
    284 
    285 CookieTreeNode::DetailedInfo CookieTreeRootNode::GetDetailedInfo() const {
    286   return DetailedInfo(string16(),
    287                       DetailedInfo::TYPE_ROOT,
    288                       NULL, NULL, NULL, NULL, NULL, NULL);
    289 }
    290 
    291 ///////////////////////////////////////////////////////////////////////////////
    292 // CookieTreeOriginNode, public:
    293 
    294 // static
    295 std::wstring CookieTreeOriginNode::TitleForUrl(
    296     const GURL& url) {
    297   return UTF8ToWide(url.SchemeIsFile() ? kFileOriginNodeName : url.host());
    298 }
    299 
    300 CookieTreeOriginNode::CookieTreeOriginNode(const GURL& url)
    301     : CookieTreeNode(WideToUTF16Hack(TitleForUrl(url))),
    302       cookies_child_(NULL),
    303       databases_child_(NULL),
    304       local_storages_child_(NULL),
    305       session_storages_child_(NULL),
    306       appcaches_child_(NULL),
    307       indexed_dbs_child_(NULL),
    308       url_(url) {}
    309 
    310 CookieTreeOriginNode::~CookieTreeOriginNode() {}
    311 
    312 CookieTreeNode::DetailedInfo CookieTreeOriginNode::GetDetailedInfo() const {
    313   return DetailedInfo(GetTitle(),
    314                       DetailedInfo::TYPE_ORIGIN,
    315                       NULL, NULL, NULL, NULL, NULL, NULL);
    316 }
    317 
    318 CookieTreeCookiesNode* CookieTreeOriginNode::GetOrCreateCookiesNode() {
    319   if (cookies_child_)
    320     return cookies_child_;
    321   cookies_child_ = new CookieTreeCookiesNode;
    322   AddChildSortedByTitle(cookies_child_);
    323   return cookies_child_;
    324 }
    325 
    326 CookieTreeDatabasesNode* CookieTreeOriginNode::GetOrCreateDatabasesNode() {
    327   if (databases_child_)
    328     return databases_child_;
    329   databases_child_ = new CookieTreeDatabasesNode;
    330   AddChildSortedByTitle(databases_child_);
    331   return databases_child_;
    332 }
    333 
    334 CookieTreeLocalStoragesNode*
    335     CookieTreeOriginNode::GetOrCreateLocalStoragesNode() {
    336   if (local_storages_child_)
    337     return local_storages_child_;
    338   local_storages_child_ = new CookieTreeLocalStoragesNode;
    339   AddChildSortedByTitle(local_storages_child_);
    340   return local_storages_child_;
    341 }
    342 
    343 CookieTreeSessionStoragesNode*
    344     CookieTreeOriginNode::GetOrCreateSessionStoragesNode() {
    345   if (session_storages_child_)
    346     return session_storages_child_;
    347   session_storages_child_ = new CookieTreeSessionStoragesNode;
    348   AddChildSortedByTitle(session_storages_child_);
    349   return session_storages_child_;
    350 }
    351 
    352 CookieTreeAppCachesNode* CookieTreeOriginNode::GetOrCreateAppCachesNode() {
    353   if (appcaches_child_)
    354     return appcaches_child_;
    355   appcaches_child_ = new CookieTreeAppCachesNode;
    356   AddChildSortedByTitle(appcaches_child_);
    357   return appcaches_child_;
    358 }
    359 
    360 CookieTreeIndexedDBsNode* CookieTreeOriginNode::GetOrCreateIndexedDBsNode() {
    361   if (indexed_dbs_child_)
    362     return indexed_dbs_child_;
    363   indexed_dbs_child_ = new CookieTreeIndexedDBsNode;
    364   AddChildSortedByTitle(indexed_dbs_child_);
    365   return indexed_dbs_child_;
    366 }
    367 
    368 void CookieTreeOriginNode::CreateContentException(
    369     HostContentSettingsMap* content_settings, ContentSetting setting) const {
    370   if (CanCreateContentException()) {
    371     content_settings->AddExceptionForURL(url_,
    372                                          CONTENT_SETTINGS_TYPE_COOKIES,
    373                                          "",
    374                                          setting);
    375   }
    376 }
    377 
    378 bool CookieTreeOriginNode::CanCreateContentException() const {
    379   return !url_.SchemeIsFile();
    380 }
    381 
    382 ///////////////////////////////////////////////////////////////////////////////
    383 // CookieTreeCookiesNode, public:
    384 
    385 CookieTreeCookiesNode::CookieTreeCookiesNode()
    386     : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_COOKIES)) {
    387 }
    388 
    389 CookieTreeCookiesNode::~CookieTreeCookiesNode() {
    390 }
    391 
    392 CookieTreeNode::DetailedInfo CookieTreeCookiesNode::GetDetailedInfo() const {
    393   return DetailedInfo(parent()->GetTitle(),
    394                       DetailedInfo::TYPE_COOKIES,
    395                       NULL, NULL, NULL, NULL, NULL, NULL);
    396 }
    397 
    398 ///////////////////////////////////////////////////////////////////////////////
    399 // CookieTreeAppCachesNode, public:
    400 
    401 CookieTreeAppCachesNode::CookieTreeAppCachesNode()
    402     : CookieTreeNode(l10n_util::GetStringUTF16(
    403                          IDS_COOKIES_APPLICATION_CACHES)) {
    404 }
    405 
    406 CookieTreeAppCachesNode::~CookieTreeAppCachesNode() {}
    407 
    408 CookieTreeNode::DetailedInfo CookieTreeAppCachesNode::GetDetailedInfo() const {
    409   return DetailedInfo(parent()->GetTitle(),
    410                       DetailedInfo::TYPE_APPCACHES,
    411                       NULL, NULL, NULL, NULL, NULL, NULL);
    412 }
    413 
    414 ///////////////////////////////////////////////////////////////////////////////
    415 // CookieTreeDatabasesNode, public:
    416 
    417 CookieTreeDatabasesNode::CookieTreeDatabasesNode()
    418     : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_WEB_DATABASES)) {
    419 }
    420 
    421 CookieTreeDatabasesNode::~CookieTreeDatabasesNode() {}
    422 
    423 CookieTreeNode::DetailedInfo CookieTreeDatabasesNode::GetDetailedInfo() const {
    424   return DetailedInfo(parent()->GetTitle(),
    425                       DetailedInfo::TYPE_DATABASES,
    426                       NULL, NULL, NULL, NULL, NULL, NULL);
    427 }
    428 
    429 ///////////////////////////////////////////////////////////////////////////////
    430 // CookieTreeLocalStoragesNode, public:
    431 
    432 CookieTreeLocalStoragesNode::CookieTreeLocalStoragesNode()
    433     : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_LOCAL_STORAGE)) {
    434 }
    435 
    436 CookieTreeLocalStoragesNode::~CookieTreeLocalStoragesNode() {}
    437 
    438 CookieTreeNode::DetailedInfo
    439 CookieTreeLocalStoragesNode::GetDetailedInfo() const {
    440   return DetailedInfo(parent()->GetTitle(),
    441                       DetailedInfo::TYPE_LOCAL_STORAGES,
    442                       NULL, NULL, NULL, NULL, NULL, NULL);
    443 }
    444 
    445 ///////////////////////////////////////////////////////////////////////////////
    446 // CookieTreeSessionStoragesNode, public:
    447 
    448 CookieTreeSessionStoragesNode::CookieTreeSessionStoragesNode()
    449     : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_SESSION_STORAGE)) {
    450 }
    451 
    452 CookieTreeSessionStoragesNode::~CookieTreeSessionStoragesNode() {}
    453 
    454 CookieTreeNode::DetailedInfo
    455 CookieTreeSessionStoragesNode::GetDetailedInfo() const {
    456   return DetailedInfo(parent()->GetTitle(),
    457                       DetailedInfo::TYPE_SESSION_STORAGES,
    458                       NULL, NULL, NULL, NULL, NULL, NULL);
    459 }
    460 
    461 ///////////////////////////////////////////////////////////////////////////////
    462 // CookieTreeIndexedDBsNode, public:
    463 
    464 CookieTreeIndexedDBsNode::CookieTreeIndexedDBsNode()
    465     : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_INDEXED_DBS)) {
    466 }
    467 
    468 CookieTreeIndexedDBsNode::~CookieTreeIndexedDBsNode() {}
    469 
    470 CookieTreeNode::DetailedInfo
    471 CookieTreeIndexedDBsNode::GetDetailedInfo() const {
    472   return DetailedInfo(parent()->GetTitle(),
    473                       DetailedInfo::TYPE_INDEXED_DBS,
    474                       NULL, NULL, NULL, NULL, NULL, NULL);
    475 }
    476 
    477 ///////////////////////////////////////////////////////////////////////////////
    478 // CookieTreeNode, protected
    479 
    480 bool CookieTreeNode::NodeTitleComparator::operator() (
    481     const CookieTreeNode* lhs, const CookieTreeNode* rhs) {
    482   const CookieTreeNode* left =
    483       static_cast<const CookieTreeNode*>(lhs);
    484   const CookieTreeNode* right =
    485       static_cast<const CookieTreeNode*>(rhs);
    486   return (left->GetTitle() < right->GetTitle());
    487 }
    488 
    489 void CookieTreeNode::AddChildSortedByTitle(CookieTreeNode* new_child) {
    490   std::vector<CookieTreeNode*>::iterator iter =
    491       lower_bound(children().begin(),
    492                   children().end(),
    493                   new_child,
    494                   NodeTitleComparator());
    495   GetModel()->Add(this, new_child, iter - children().begin());
    496 }
    497 
    498 ///////////////////////////////////////////////////////////////////////////////
    499 // CookiesTreeModel, public:
    500 
    501 CookiesTreeModel::CookiesTreeModel(
    502     net::CookieMonster* cookie_monster,
    503     BrowsingDataDatabaseHelper* database_helper,
    504     BrowsingDataLocalStorageHelper* local_storage_helper,
    505     BrowsingDataLocalStorageHelper* session_storage_helper,
    506     BrowsingDataAppCacheHelper* appcache_helper,
    507     BrowsingDataIndexedDBHelper* indexed_db_helper,
    508     bool use_cookie_source)
    509     : ALLOW_THIS_IN_INITIALIZER_LIST(ui::TreeNodeModel<CookieTreeNode>(
    510           new CookieTreeRootNode(this))),
    511       cookie_monster_(cookie_monster),
    512       appcache_helper_(appcache_helper),
    513       database_helper_(database_helper),
    514       local_storage_helper_(local_storage_helper),
    515       session_storage_helper_(session_storage_helper),
    516       indexed_db_helper_(indexed_db_helper),
    517       batch_update_(0),
    518       use_cookie_source_(use_cookie_source) {
    519   LoadCookies();
    520   DCHECK(database_helper_);
    521   database_helper_->StartFetching(NewCallback(
    522       this, &CookiesTreeModel::OnDatabaseModelInfoLoaded));
    523   DCHECK(local_storage_helper_);
    524   local_storage_helper_->StartFetching(NewCallback(
    525       this, &CookiesTreeModel::OnLocalStorageModelInfoLoaded));
    526   if (session_storage_helper_) {
    527     session_storage_helper_->StartFetching(NewCallback(
    528         this, &CookiesTreeModel::OnSessionStorageModelInfoLoaded));
    529   }
    530 
    531   // TODO(michaeln): when all of the ui impls have been updated,
    532   // make this a required parameter.
    533   if (appcache_helper_) {
    534     appcache_helper_->StartFetching(NewCallback(
    535         this, &CookiesTreeModel::OnAppCacheModelInfoLoaded));
    536   }
    537 
    538   if (indexed_db_helper_) {
    539     indexed_db_helper_->StartFetching(NewCallback(
    540         this, &CookiesTreeModel::OnIndexedDBModelInfoLoaded));
    541   }
    542 }
    543 
    544 CookiesTreeModel::~CookiesTreeModel() {
    545   database_helper_->CancelNotification();
    546   local_storage_helper_->CancelNotification();
    547   if (session_storage_helper_)
    548     session_storage_helper_->CancelNotification();
    549   if (appcache_helper_)
    550     appcache_helper_->CancelNotification();
    551   if (indexed_db_helper_)
    552     indexed_db_helper_->CancelNotification();
    553 }
    554 
    555 ///////////////////////////////////////////////////////////////////////////////
    556 // CookiesTreeModel, TreeModel methods (public):
    557 
    558 // TreeModel methods:
    559 // Returns the set of icons for the nodes in the tree. You only need override
    560 // this if you don't want to use the default folder icons.
    561 void CookiesTreeModel::GetIcons(std::vector<SkBitmap>* icons) {
    562   icons->push_back(*ResourceBundle::GetSharedInstance().GetBitmapNamed(
    563       IDR_OMNIBOX_HTTP));
    564   icons->push_back(*ResourceBundle::GetSharedInstance().GetBitmapNamed(
    565       IDR_COOKIE_ICON));
    566   icons->push_back(*ResourceBundle::GetSharedInstance().GetBitmapNamed(
    567       IDR_COOKIE_STORAGE_ICON));
    568 }
    569 
    570 // Returns the index of the icon to use for |node|. Return -1 to use the
    571 // default icon. The index is relative to the list of icons returned from
    572 // GetIcons.
    573 int CookiesTreeModel::GetIconIndex(ui::TreeModelNode* node) {
    574   CookieTreeNode* ct_node = static_cast<CookieTreeNode*>(node);
    575   switch (ct_node->GetDetailedInfo().node_type) {
    576     case CookieTreeNode::DetailedInfo::TYPE_ORIGIN:
    577       return ORIGIN;
    578     case CookieTreeNode::DetailedInfo::TYPE_COOKIE:
    579       return COOKIE;
    580     case CookieTreeNode::DetailedInfo::TYPE_DATABASE:
    581       return DATABASE;
    582     case CookieTreeNode::DetailedInfo::TYPE_LOCAL_STORAGE:
    583       return DATABASE;  // close enough
    584     case CookieTreeNode::DetailedInfo::TYPE_SESSION_STORAGE:
    585       return DATABASE;  // ditto
    586     case CookieTreeNode::DetailedInfo::TYPE_APPCACHE:
    587       return DATABASE;  // ditto
    588     case CookieTreeNode::DetailedInfo::TYPE_INDEXED_DB:
    589       return DATABASE;  // ditto
    590     default:
    591       break;
    592   }
    593   return -1;
    594 }
    595 
    596 void CookiesTreeModel::LoadCookies() {
    597   LoadCookiesWithFilter(std::wstring());
    598 }
    599 
    600 void CookiesTreeModel::LoadCookiesWithFilter(const std::wstring& filter) {
    601   // mmargh mmargh mmargh! delicious!
    602 
    603   all_cookies_ = cookie_monster_->GetAllCookies();
    604   CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
    605   for (CookieList::iterator it = all_cookies_.begin();
    606        it != all_cookies_.end(); ++it) {
    607     std::string source_string = it->Source();
    608     if (source_string.empty() || !use_cookie_source_) {
    609       std::string domain = it->Domain();
    610       if (domain.length() > 1 && domain[0] == '.')
    611         domain = domain.substr(1);
    612 
    613       // We treat secure cookies just the same as normal ones.
    614       source_string = std::string(chrome::kHttpScheme) +
    615           chrome::kStandardSchemeSeparator + domain + "/";
    616     }
    617 
    618     GURL source(source_string);
    619     if (!filter.size() ||
    620         (CookieTreeOriginNode::TitleForUrl(source).find(filter) !=
    621          std::string::npos)) {
    622       CookieTreeOriginNode* origin_node =
    623           root->GetOrCreateOriginNode(source);
    624       CookieTreeCookiesNode* cookies_node =
    625           origin_node->GetOrCreateCookiesNode();
    626       CookieTreeCookieNode* new_cookie = new CookieTreeCookieNode(&*it);
    627       cookies_node->AddCookieNode(new_cookie);
    628     }
    629   }
    630 }
    631 
    632 void CookiesTreeModel::DeleteAllStoredObjects() {
    633   NotifyObserverBeginBatch();
    634   CookieTreeNode* root = GetRoot();
    635   root->DeleteStoredObjects();
    636   int num_children = root->child_count();
    637   for (int i = num_children - 1; i >= 0; --i)
    638     delete Remove(root, root->GetChild(i));
    639   NotifyObserverTreeNodeChanged(root);
    640   NotifyObserverEndBatch();
    641 }
    642 
    643 void CookiesTreeModel::DeleteCookieNode(CookieTreeNode* cookie_node) {
    644   if (cookie_node == GetRoot())
    645     return;
    646   cookie_node->DeleteStoredObjects();
    647   CookieTreeNode* parent_node = cookie_node->parent();
    648   delete Remove(parent_node, cookie_node);
    649   if (parent_node->child_count() == 0)
    650     DeleteCookieNode(parent_node);
    651 }
    652 
    653 void CookiesTreeModel::UpdateSearchResults(const std::wstring& filter) {
    654   CookieTreeNode* root = GetRoot();
    655   int num_children = root->child_count();
    656   NotifyObserverBeginBatch();
    657   for (int i = num_children - 1; i >= 0; --i)
    658     delete Remove(root, root->GetChild(i));
    659   LoadCookiesWithFilter(filter);
    660   PopulateDatabaseInfoWithFilter(filter);
    661   PopulateLocalStorageInfoWithFilter(filter);
    662   PopulateSessionStorageInfoWithFilter(filter);
    663   PopulateAppCacheInfoWithFilter(filter);
    664   PopulateIndexedDBInfoWithFilter(filter);
    665   NotifyObserverTreeNodeChanged(root);
    666   NotifyObserverEndBatch();
    667 }
    668 
    669 void CookiesTreeModel::AddCookiesTreeObserver(Observer* observer) {
    670   cookies_observer_list_.AddObserver(observer);
    671   // Call super so that TreeNodeModel can notify, too.
    672   ui::TreeNodeModel<CookieTreeNode>::AddObserver(observer);
    673 }
    674 
    675 void CookiesTreeModel::RemoveCookiesTreeObserver(Observer* observer) {
    676   cookies_observer_list_.RemoveObserver(observer);
    677   // Call super so that TreeNodeModel doesn't have dead pointers.
    678   ui::TreeNodeModel<CookieTreeNode>::RemoveObserver(observer);
    679 }
    680 
    681 void CookiesTreeModel::OnAppCacheModelInfoLoaded() {
    682   appcache_info_ = appcache_helper_->info_collection();
    683   PopulateAppCacheInfoWithFilter(std::wstring());
    684 }
    685 
    686 void CookiesTreeModel::PopulateAppCacheInfoWithFilter(
    687     const std::wstring& filter) {
    688   using appcache::AppCacheInfo;
    689   using appcache::AppCacheInfoVector;
    690   typedef std::map<GURL, AppCacheInfoVector> InfoByOrigin;
    691 
    692   if (!appcache_info_ || appcache_info_->infos_by_origin.empty())
    693     return;
    694 
    695   CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
    696   NotifyObserverBeginBatch();
    697   for (InfoByOrigin::const_iterator origin =
    698            appcache_info_->infos_by_origin.begin();
    699        origin != appcache_info_->infos_by_origin.end(); ++origin) {
    700     std::wstring origin_node_name = UTF8ToWide(origin->first.host());
    701     if (filter.empty() ||
    702         (origin_node_name.find(filter) != std::wstring::npos)) {
    703       CookieTreeOriginNode* origin_node =
    704           root->GetOrCreateOriginNode(origin->first);
    705       CookieTreeAppCachesNode* appcaches_node =
    706           origin_node->GetOrCreateAppCachesNode();
    707 
    708       for (AppCacheInfoVector::const_iterator info = origin->second.begin();
    709            info != origin->second.end(); ++info) {
    710         appcaches_node->AddAppCacheNode(
    711             new CookieTreeAppCacheNode(&(*info)));
    712       }
    713     }
    714   }
    715   NotifyObserverTreeNodeChanged(root);
    716   NotifyObserverEndBatch();
    717 }
    718 
    719 void CookiesTreeModel::OnDatabaseModelInfoLoaded(
    720     const DatabaseInfoList& database_info) {
    721   database_info_list_ = database_info;
    722   PopulateDatabaseInfoWithFilter(std::wstring());
    723 }
    724 
    725 void CookiesTreeModel::PopulateDatabaseInfoWithFilter(
    726     const std::wstring& filter) {
    727   if (database_info_list_.empty())
    728     return;
    729   CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
    730   NotifyObserverBeginBatch();
    731   for (DatabaseInfoList::iterator database_info = database_info_list_.begin();
    732        database_info != database_info_list_.end();
    733        ++database_info) {
    734     GURL origin(database_info->origin);
    735 
    736     if (!filter.size() ||
    737         (CookieTreeOriginNode::TitleForUrl(origin).find(filter) !=
    738          std::wstring::npos)) {
    739       CookieTreeOriginNode* origin_node =
    740           root->GetOrCreateOriginNode(origin);
    741       CookieTreeDatabasesNode* databases_node =
    742           origin_node->GetOrCreateDatabasesNode();
    743       databases_node->AddDatabaseNode(
    744           new CookieTreeDatabaseNode(&(*database_info)));
    745     }
    746   }
    747   NotifyObserverTreeNodeChanged(root);
    748   NotifyObserverEndBatch();
    749 }
    750 
    751 void CookiesTreeModel::OnLocalStorageModelInfoLoaded(
    752     const LocalStorageInfoList& local_storage_info) {
    753   local_storage_info_list_ = local_storage_info;
    754   PopulateLocalStorageInfoWithFilter(std::wstring());
    755 }
    756 
    757 void CookiesTreeModel::PopulateLocalStorageInfoWithFilter(
    758     const std::wstring& filter) {
    759   if (local_storage_info_list_.empty())
    760     return;
    761   CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
    762   NotifyObserverBeginBatch();
    763   for (LocalStorageInfoList::iterator local_storage_info =
    764        local_storage_info_list_.begin();
    765        local_storage_info != local_storage_info_list_.end();
    766        ++local_storage_info) {
    767     GURL origin(local_storage_info->origin);
    768 
    769     if (!filter.size() ||
    770         (CookieTreeOriginNode::TitleForUrl(origin).find(filter) !=
    771          std::wstring::npos)) {
    772       CookieTreeOriginNode* origin_node =
    773           root->GetOrCreateOriginNode(origin);
    774       CookieTreeLocalStoragesNode* local_storages_node =
    775           origin_node->GetOrCreateLocalStoragesNode();
    776       local_storages_node->AddLocalStorageNode(
    777           new CookieTreeLocalStorageNode(&(*local_storage_info)));
    778     }
    779   }
    780   NotifyObserverTreeNodeChanged(root);
    781   NotifyObserverEndBatch();
    782 }
    783 
    784 void CookiesTreeModel::OnSessionStorageModelInfoLoaded(
    785     const LocalStorageInfoList& session_storage_info) {
    786   session_storage_info_list_ = session_storage_info;
    787   PopulateSessionStorageInfoWithFilter(std::wstring());
    788 }
    789 
    790 void CookiesTreeModel::PopulateSessionStorageInfoWithFilter(
    791     const std::wstring& filter) {
    792   if (session_storage_info_list_.empty())
    793     return;
    794   CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
    795   NotifyObserverBeginBatch();
    796   for (LocalStorageInfoList::iterator session_storage_info =
    797        session_storage_info_list_.begin();
    798        session_storage_info != session_storage_info_list_.end();
    799        ++session_storage_info) {
    800     GURL origin(session_storage_info->origin);
    801 
    802     if (!filter.size() ||
    803         (CookieTreeOriginNode::TitleForUrl(origin).find(filter) !=
    804          std::wstring::npos)) {
    805       CookieTreeOriginNode* origin_node =
    806           root->GetOrCreateOriginNode(origin);
    807       CookieTreeSessionStoragesNode* session_storages_node =
    808           origin_node->GetOrCreateSessionStoragesNode();
    809       session_storages_node->AddSessionStorageNode(
    810           new CookieTreeSessionStorageNode(&(*session_storage_info)));
    811     }
    812   }
    813   NotifyObserverTreeNodeChanged(root);
    814   NotifyObserverEndBatch();
    815 }
    816 
    817 void CookiesTreeModel::OnIndexedDBModelInfoLoaded(
    818     const IndexedDBInfoList& indexed_db_info) {
    819   indexed_db_info_list_ = indexed_db_info;
    820   PopulateIndexedDBInfoWithFilter(std::wstring());
    821 }
    822 
    823 void CookiesTreeModel::PopulateIndexedDBInfoWithFilter(
    824     const std::wstring& filter) {
    825   if (indexed_db_info_list_.empty())
    826     return;
    827   CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
    828   NotifyObserverBeginBatch();
    829   for (IndexedDBInfoList::iterator indexed_db_info =
    830        indexed_db_info_list_.begin();
    831        indexed_db_info != indexed_db_info_list_.end();
    832        ++indexed_db_info) {
    833     GURL origin(indexed_db_info->origin);
    834 
    835     if (!filter.size() ||
    836         (CookieTreeOriginNode::TitleForUrl(origin).find(filter) !=
    837          std::wstring::npos)) {
    838       CookieTreeOriginNode* origin_node =
    839           root->GetOrCreateOriginNode(origin);
    840       CookieTreeIndexedDBsNode* indexed_dbs_node =
    841           origin_node->GetOrCreateIndexedDBsNode();
    842       indexed_dbs_node->AddIndexedDBNode(
    843           new CookieTreeIndexedDBNode(&(*indexed_db_info)));
    844     }
    845   }
    846   NotifyObserverTreeNodeChanged(root);
    847   NotifyObserverEndBatch();
    848 }
    849 
    850 void CookiesTreeModel::NotifyObserverBeginBatch() {
    851   // Only notify the model once if we're batching in a nested manner.
    852   if (batch_update_++ == 0) {
    853     FOR_EACH_OBSERVER(Observer,
    854                       cookies_observer_list_,
    855                       TreeModelBeginBatch(this));
    856   }
    857 }
    858 
    859 void CookiesTreeModel::NotifyObserverEndBatch() {
    860   // Only notify the observers if this is the outermost call to EndBatch() if
    861   // called in a nested manner.
    862   if (--batch_update_ == 0) {
    863     FOR_EACH_OBSERVER(Observer,
    864                       cookies_observer_list_,
    865                       TreeModelEndBatch(this));
    866   }
    867 }
    868