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/cookies_tree_model.h"
      6 
      7 #include <algorithm>
      8 #include <functional>
      9 #include <map>
     10 #include <vector>
     11 
     12 #include "base/bind.h"
     13 #include "base/memory/linked_ptr.h"
     14 #include "base/strings/string_util.h"
     15 #include "base/strings/utf_string_conversions.h"
     16 #include "chrome/browser/browsing_data/browsing_data_channel_id_helper.h"
     17 #include "chrome/browser/browsing_data/browsing_data_cookie_helper.h"
     18 #include "chrome/browser/browsing_data/browsing_data_flash_lso_helper.h"
     19 #include "chrome/browser/content_settings/cookie_settings.h"
     20 #include "chrome/grit/generated_resources.h"
     21 #include "content/public/common/url_constants.h"
     22 #include "grit/theme_resources.h"
     23 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
     24 #include "net/cookies/canonical_cookie.h"
     25 #include "net/url_request/url_request_context.h"
     26 #include "ui/base/l10n/l10n_util.h"
     27 #include "ui/base/resource/resource_bundle.h"
     28 #include "ui/gfx/image/image_skia.h"
     29 #include "ui/resources/grit/ui_resources.h"
     30 
     31 #if defined(ENABLE_EXTENSIONS)
     32 #include "chrome/browser/extensions/extension_special_storage_policy.h"
     33 #include "extensions/common/extension_set.h"
     34 #endif
     35 
     36 namespace {
     37 
     38 struct NodeTitleComparator {
     39   bool operator()(const CookieTreeNode* lhs, const CookieTreeNode* rhs) {
     40     return lhs->GetTitle() < rhs->GetTitle();
     41   }
     42 };
     43 
     44 // Comparison functor, for use in CookieTreeRootNode.
     45 struct HostNodeComparator {
     46   bool operator()(const CookieTreeNode* lhs, const CookieTreeNode* rhs) {
     47     // This comparator is only meant to compare CookieTreeHostNode types. Make
     48     // sure we check this, as the static cast below is dangerous if we get the
     49     // wrong object type.
     50     CHECK_EQ(CookieTreeNode::DetailedInfo::TYPE_HOST,
     51              lhs->GetDetailedInfo().node_type);
     52     CHECK_EQ(CookieTreeNode::DetailedInfo::TYPE_HOST,
     53              rhs->GetDetailedInfo().node_type);
     54 
     55     const CookieTreeHostNode* ltn =
     56         static_cast<const CookieTreeHostNode*>(lhs);
     57     const CookieTreeHostNode* rtn =
     58         static_cast<const CookieTreeHostNode*>(rhs);
     59 
     60     // We want to order by registry controlled domain, so we would get
     61     // google.com, ad.google.com, www.google.com,
     62     // microsoft.com, ad.microsoft.com. CanonicalizeHost transforms the origins
     63     // into a form like google.com.www so that string comparisons work.
     64     return (ltn->canonicalized_host() <
     65             rtn->canonicalized_host());
     66   }
     67 };
     68 
     69 std::string CanonicalizeHost(const GURL& url) {
     70   // The canonicalized representation makes the registry controlled domain
     71   // come first, and then adds subdomains in reverse order, e.g.
     72   // 1.mail.google.com would become google.com.mail.1, and then a standard
     73   // string comparison works to order hosts by registry controlled domain
     74   // first. Leading dots are ignored, ".google.com" is the same as
     75   // "google.com".
     76 
     77   if (url.SchemeIsFile()) {
     78     return std::string(url::kFileScheme) +
     79            url::kStandardSchemeSeparator;
     80   }
     81 
     82   std::string host = url.host();
     83   std::string retval =
     84       net::registry_controlled_domains::GetDomainAndRegistry(
     85           host,
     86           net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
     87   if (!retval.length())  // Is an IP address or other special origin.
     88     return host;
     89 
     90   std::string::size_type position = host.rfind(retval);
     91 
     92   // The host may be the registry controlled domain, in which case fail fast.
     93   if (position == 0 || position == std::string::npos)
     94     return host;
     95 
     96   // If host is www.google.com, retval will contain google.com at this point.
     97   // Start operating to the left of the registry controlled domain, e.g. in
     98   // the www.google.com example, start at index 3.
     99   --position;
    100 
    101   // If position == 0, that means it's a dot; this will be ignored to treat
    102   // ".google.com" the same as "google.com".
    103   while (position > 0) {
    104     retval += std::string(".");
    105     // Copy up to the next dot. host[position] is a dot so start after it.
    106     std::string::size_type next_dot = host.rfind(".", position - 1);
    107     if (next_dot == std::string::npos) {
    108       retval += host.substr(0, position);
    109       break;
    110     }
    111     retval += host.substr(next_dot + 1, position - (next_dot + 1));
    112     position = next_dot;
    113   }
    114   return retval;
    115 }
    116 
    117 #if defined(ENABLE_EXTENSIONS)
    118 bool TypeIsProtected(CookieTreeNode::DetailedInfo::NodeType type) {
    119   switch (type) {
    120     case CookieTreeNode::DetailedInfo::TYPE_COOKIE:
    121       return false;
    122     case CookieTreeNode::DetailedInfo::TYPE_DATABASE:
    123       return true;
    124     case CookieTreeNode::DetailedInfo::TYPE_LOCAL_STORAGE:
    125       return true;
    126     case CookieTreeNode::DetailedInfo::TYPE_SESSION_STORAGE:
    127       return true;
    128     case CookieTreeNode::DetailedInfo::TYPE_APPCACHE:
    129       return true;
    130     case CookieTreeNode::DetailedInfo::TYPE_INDEXED_DB:
    131       return true;
    132     case CookieTreeNode::DetailedInfo::TYPE_FILE_SYSTEM:
    133       return true;
    134     case CookieTreeNode::DetailedInfo::TYPE_QUOTA:
    135       return false;
    136     case CookieTreeNode::DetailedInfo::TYPE_CHANNEL_ID:
    137       return false;
    138     case CookieTreeNode::DetailedInfo::TYPE_SERVICE_WORKER:
    139       return true;
    140     case CookieTreeNode::DetailedInfo::TYPE_FLASH_LSO:
    141       return false;
    142     default:
    143       break;
    144   }
    145   return false;
    146 }
    147 #endif
    148 
    149 // This function returns the local data container associated with a leaf tree
    150 // node. The app node is assumed to be 3 levels above the leaf because of the
    151 // following structure:
    152 //   root -> origin -> storage type -> leaf node
    153 LocalDataContainer* GetLocalDataContainerForNode(CookieTreeNode* node) {
    154   CookieTreeHostNode* host = static_cast<CookieTreeHostNode*>(
    155       node->parent()->parent());
    156   CHECK_EQ(host->GetDetailedInfo().node_type,
    157            CookieTreeNode::DetailedInfo::TYPE_HOST);
    158   return node->GetModel()->data_container();
    159 }
    160 
    161 }  // namespace
    162 
    163 CookieTreeNode::DetailedInfo::DetailedInfo()
    164     : node_type(TYPE_NONE),
    165       cookie(NULL),
    166       database_info(NULL),
    167       local_storage_info(NULL),
    168       session_storage_info(NULL),
    169       appcache_info(NULL),
    170       indexed_db_info(NULL),
    171       file_system_info(NULL),
    172       quota_info(NULL),
    173       channel_id(NULL),
    174       service_worker_info(NULL) {
    175 }
    176 
    177 CookieTreeNode::DetailedInfo::~DetailedInfo() {}
    178 
    179 CookieTreeNode::DetailedInfo& CookieTreeNode::DetailedInfo::Init(
    180     NodeType type) {
    181   DCHECK_EQ(TYPE_NONE, node_type);
    182   node_type = type;
    183   return *this;
    184 }
    185 
    186 CookieTreeNode::DetailedInfo& CookieTreeNode::DetailedInfo::InitHost() {
    187   Init(TYPE_HOST);
    188   return *this;
    189 }
    190 
    191 CookieTreeNode::DetailedInfo& CookieTreeNode::DetailedInfo::InitCookie(
    192     const net::CanonicalCookie* cookie) {
    193   Init(TYPE_COOKIE);
    194   this->cookie = cookie;
    195   return *this;
    196 }
    197 
    198 CookieTreeNode::DetailedInfo& CookieTreeNode::DetailedInfo::InitDatabase(
    199     const BrowsingDataDatabaseHelper::DatabaseInfo* database_info) {
    200   Init(TYPE_DATABASE);
    201   this->database_info = database_info;
    202   origin = database_info->identifier.ToOrigin();
    203   return *this;
    204 }
    205 
    206 CookieTreeNode::DetailedInfo& CookieTreeNode::DetailedInfo::InitLocalStorage(
    207     const BrowsingDataLocalStorageHelper::LocalStorageInfo*
    208     local_storage_info) {
    209   Init(TYPE_LOCAL_STORAGE);
    210   this->local_storage_info = local_storage_info;
    211   origin = local_storage_info->origin_url;
    212   return *this;
    213 }
    214 
    215 CookieTreeNode::DetailedInfo& CookieTreeNode::DetailedInfo::InitSessionStorage(
    216     const BrowsingDataLocalStorageHelper::LocalStorageInfo*
    217     session_storage_info) {
    218   Init(TYPE_SESSION_STORAGE);
    219   this->session_storage_info = session_storage_info;
    220   origin = session_storage_info->origin_url;
    221   return *this;
    222 }
    223 
    224 CookieTreeNode::DetailedInfo& CookieTreeNode::DetailedInfo::InitAppCache(
    225     const GURL& origin,
    226     const content::AppCacheInfo* appcache_info) {
    227   Init(TYPE_APPCACHE);
    228   this->appcache_info = appcache_info;
    229   this->origin = origin;
    230   return *this;
    231 }
    232 
    233 CookieTreeNode::DetailedInfo& CookieTreeNode::DetailedInfo::InitIndexedDB(
    234     const content::IndexedDBInfo* indexed_db_info) {
    235   Init(TYPE_INDEXED_DB);
    236   this->indexed_db_info = indexed_db_info;
    237   this->origin = indexed_db_info->origin_;
    238   return *this;
    239 }
    240 
    241 CookieTreeNode::DetailedInfo& CookieTreeNode::DetailedInfo::InitFileSystem(
    242     const BrowsingDataFileSystemHelper::FileSystemInfo* file_system_info) {
    243   Init(TYPE_FILE_SYSTEM);
    244   this->file_system_info = file_system_info;
    245   this->origin = file_system_info->origin;
    246   return *this;
    247 }
    248 
    249 CookieTreeNode::DetailedInfo& CookieTreeNode::DetailedInfo::InitQuota(
    250     const BrowsingDataQuotaHelper::QuotaInfo* quota_info) {
    251   Init(TYPE_QUOTA);
    252   this->quota_info = quota_info;
    253   return *this;
    254 }
    255 
    256 CookieTreeNode::DetailedInfo& CookieTreeNode::DetailedInfo::InitChannelID(
    257     const net::ChannelIDStore::ChannelID* channel_id) {
    258   Init(TYPE_CHANNEL_ID);
    259   this->channel_id = channel_id;
    260   return *this;
    261 }
    262 
    263 CookieTreeNode::DetailedInfo& CookieTreeNode::DetailedInfo::InitServiceWorker(
    264     const content::ServiceWorkerUsageInfo* service_worker_info) {
    265   Init(TYPE_SERVICE_WORKER);
    266   this->service_worker_info = service_worker_info;
    267   this->origin = service_worker_info->origin;
    268   return *this;
    269 }
    270 
    271 CookieTreeNode::DetailedInfo& CookieTreeNode::DetailedInfo::InitFlashLSO(
    272     const std::string& flash_lso_domain) {
    273   Init(TYPE_FLASH_LSO);
    274   this->flash_lso_domain = flash_lso_domain;
    275   return *this;
    276 }
    277 
    278 ///////////////////////////////////////////////////////////////////////////////
    279 // CookieTreeNode, public:
    280 
    281 void CookieTreeNode::DeleteStoredObjects() {
    282   std::for_each(children().begin(),
    283                 children().end(),
    284                 std::mem_fun(&CookieTreeNode::DeleteStoredObjects));
    285 }
    286 
    287 CookiesTreeModel* CookieTreeNode::GetModel() const {
    288   if (parent())
    289     return parent()->GetModel();
    290   else
    291     return NULL;
    292 }
    293 
    294 ///////////////////////////////////////////////////////////////////////////////
    295 // CookieTreeCookieNode, public:
    296 
    297 CookieTreeCookieNode::CookieTreeCookieNode(
    298     std::list<net::CanonicalCookie>::iterator cookie)
    299     : CookieTreeNode(base::UTF8ToUTF16(cookie->Name())),
    300       cookie_(cookie) {
    301 }
    302 
    303 CookieTreeCookieNode::~CookieTreeCookieNode() {}
    304 
    305 void CookieTreeCookieNode::DeleteStoredObjects() {
    306   LocalDataContainer* container = GetLocalDataContainerForNode(this);
    307   container->cookie_helper_->DeleteCookie(*cookie_);
    308   container->cookie_list_.erase(cookie_);
    309 }
    310 
    311 CookieTreeNode::DetailedInfo CookieTreeCookieNode::GetDetailedInfo() const {
    312   return DetailedInfo().InitCookie(&*cookie_);
    313 }
    314 
    315 ///////////////////////////////////////////////////////////////////////////////
    316 // CookieTreeAppCacheNode, public:
    317 
    318 CookieTreeAppCacheNode::CookieTreeAppCacheNode(
    319     const GURL& origin_url,
    320     std::list<content::AppCacheInfo>::iterator appcache_info)
    321     : CookieTreeNode(base::UTF8ToUTF16(appcache_info->manifest_url.spec())),
    322       origin_url_(origin_url),
    323       appcache_info_(appcache_info) {
    324 }
    325 
    326 CookieTreeAppCacheNode::~CookieTreeAppCacheNode() {
    327 }
    328 
    329 void CookieTreeAppCacheNode::DeleteStoredObjects() {
    330   LocalDataContainer* container = GetLocalDataContainerForNode(this);
    331 
    332   if (container) {
    333     DCHECK(container->appcache_helper_.get());
    334     container->appcache_helper_
    335         ->DeleteAppCacheGroup(appcache_info_->manifest_url);
    336     container->appcache_info_[origin_url_].erase(appcache_info_);
    337   }
    338 }
    339 
    340 CookieTreeNode::DetailedInfo CookieTreeAppCacheNode::GetDetailedInfo() const {
    341   return DetailedInfo().InitAppCache(origin_url_, &*appcache_info_);
    342 }
    343 
    344 ///////////////////////////////////////////////////////////////////////////////
    345 // CookieTreeDatabaseNode, public:
    346 
    347 CookieTreeDatabaseNode::CookieTreeDatabaseNode(
    348     std::list<BrowsingDataDatabaseHelper::DatabaseInfo>::iterator database_info)
    349     : CookieTreeNode(database_info->database_name.empty() ?
    350           l10n_util::GetStringUTF16(IDS_COOKIES_WEB_DATABASE_UNNAMED_NAME) :
    351           base::UTF8ToUTF16(database_info->database_name)),
    352       database_info_(database_info) {
    353 }
    354 
    355 CookieTreeDatabaseNode::~CookieTreeDatabaseNode() {}
    356 
    357 void CookieTreeDatabaseNode::DeleteStoredObjects() {
    358   LocalDataContainer* container = GetLocalDataContainerForNode(this);
    359 
    360   if (container) {
    361     container->database_helper_->DeleteDatabase(
    362         database_info_->identifier.ToString(), database_info_->database_name);
    363     container->database_info_list_.erase(database_info_);
    364   }
    365 }
    366 
    367 CookieTreeNode::DetailedInfo CookieTreeDatabaseNode::GetDetailedInfo() const {
    368   return DetailedInfo().InitDatabase(&*database_info_);
    369 }
    370 
    371 ///////////////////////////////////////////////////////////////////////////////
    372 // CookieTreeLocalStorageNode, public:
    373 
    374 CookieTreeLocalStorageNode::CookieTreeLocalStorageNode(
    375     std::list<BrowsingDataLocalStorageHelper::LocalStorageInfo>::iterator
    376         local_storage_info)
    377     : CookieTreeNode(base::UTF8ToUTF16(local_storage_info->origin_url.spec())),
    378       local_storage_info_(local_storage_info) {
    379 }
    380 
    381 CookieTreeLocalStorageNode::~CookieTreeLocalStorageNode() {}
    382 
    383 void CookieTreeLocalStorageNode::DeleteStoredObjects() {
    384   LocalDataContainer* container = GetLocalDataContainerForNode(this);
    385 
    386   if (container) {
    387     container->local_storage_helper_->DeleteOrigin(
    388         local_storage_info_->origin_url);
    389     container->local_storage_info_list_.erase(local_storage_info_);
    390   }
    391 }
    392 
    393 CookieTreeNode::DetailedInfo
    394 CookieTreeLocalStorageNode::GetDetailedInfo() const {
    395   return DetailedInfo().InitLocalStorage(
    396       &*local_storage_info_);
    397 }
    398 
    399 ///////////////////////////////////////////////////////////////////////////////
    400 // CookieTreeSessionStorageNode, public:
    401 
    402 CookieTreeSessionStorageNode::CookieTreeSessionStorageNode(
    403     std::list<BrowsingDataLocalStorageHelper::LocalStorageInfo>::iterator
    404         session_storage_info)
    405     : CookieTreeNode(
    406           base::UTF8ToUTF16(session_storage_info->origin_url.spec())),
    407       session_storage_info_(session_storage_info) {
    408 }
    409 
    410 CookieTreeSessionStorageNode::~CookieTreeSessionStorageNode() {}
    411 
    412 void CookieTreeSessionStorageNode::DeleteStoredObjects() {
    413   LocalDataContainer* container = GetLocalDataContainerForNode(this);
    414 
    415   if (container) {
    416     // TODO(rsesek): There's no easy way to get the namespace_id for a session
    417     // storage, nor is there an easy way to clear session storage just by
    418     // origin. This is probably okay since session storage is not persistent.
    419     // http://crbug.com/168996
    420     container->session_storage_info_list_.erase(session_storage_info_);
    421   }
    422 }
    423 
    424 CookieTreeNode::DetailedInfo
    425 CookieTreeSessionStorageNode::GetDetailedInfo() const {
    426   return DetailedInfo().InitSessionStorage(&*session_storage_info_);
    427 }
    428 
    429 ///////////////////////////////////////////////////////////////////////////////
    430 // CookieTreeIndexedDBNode, public:
    431 
    432 CookieTreeIndexedDBNode::CookieTreeIndexedDBNode(
    433     std::list<content::IndexedDBInfo>::iterator
    434         indexed_db_info)
    435     : CookieTreeNode(base::UTF8ToUTF16(
    436           indexed_db_info->origin_.spec())),
    437       indexed_db_info_(indexed_db_info) {
    438 }
    439 
    440 CookieTreeIndexedDBNode::~CookieTreeIndexedDBNode() {}
    441 
    442 void CookieTreeIndexedDBNode::DeleteStoredObjects() {
    443   LocalDataContainer* container = GetLocalDataContainerForNode(this);
    444 
    445   if (container) {
    446     container->indexed_db_helper_->DeleteIndexedDB(
    447         indexed_db_info_->origin_);
    448     container->indexed_db_info_list_.erase(indexed_db_info_);
    449   }
    450 }
    451 
    452 CookieTreeNode::DetailedInfo CookieTreeIndexedDBNode::GetDetailedInfo() const {
    453   return DetailedInfo().InitIndexedDB(&*indexed_db_info_);
    454 }
    455 
    456 ///////////////////////////////////////////////////////////////////////////////
    457 // CookieTreeFileSystemNode, public:
    458 
    459 CookieTreeFileSystemNode::CookieTreeFileSystemNode(
    460     std::list<BrowsingDataFileSystemHelper::FileSystemInfo>::iterator
    461         file_system_info)
    462     : CookieTreeNode(base::UTF8ToUTF16(
    463           file_system_info->origin.spec())),
    464       file_system_info_(file_system_info) {
    465 }
    466 
    467 CookieTreeFileSystemNode::~CookieTreeFileSystemNode() {}
    468 
    469 void CookieTreeFileSystemNode::DeleteStoredObjects() {
    470   LocalDataContainer* container = GetLocalDataContainerForNode(this);
    471 
    472   if (container) {
    473     container->file_system_helper_->DeleteFileSystemOrigin(
    474         file_system_info_->origin);
    475     container->file_system_info_list_.erase(file_system_info_);
    476   }
    477 }
    478 
    479 CookieTreeNode::DetailedInfo CookieTreeFileSystemNode::GetDetailedInfo() const {
    480   return DetailedInfo().InitFileSystem(&*file_system_info_);
    481 }
    482 
    483 ///////////////////////////////////////////////////////////////////////////////
    484 // CookieTreeQuotaNode, public:
    485 
    486 CookieTreeQuotaNode::CookieTreeQuotaNode(
    487     std::list<BrowsingDataQuotaHelper::QuotaInfo>::iterator quota_info)
    488     : CookieTreeNode(base::UTF8ToUTF16(quota_info->host)),
    489       quota_info_(quota_info) {
    490 }
    491 
    492 CookieTreeQuotaNode::~CookieTreeQuotaNode() {}
    493 
    494 void CookieTreeQuotaNode::DeleteStoredObjects() {
    495   // Calling this function may cause unexpected over-quota state of origin.
    496   // However, it'll caused no problem, just prevent usage growth of the origin.
    497   LocalDataContainer* container = GetModel()->data_container();
    498 
    499   if (container) {
    500     container->quota_helper_->RevokeHostQuota(quota_info_->host);
    501     container->quota_info_list_.erase(quota_info_);
    502   }
    503 }
    504 
    505 CookieTreeNode::DetailedInfo CookieTreeQuotaNode::GetDetailedInfo() const {
    506   return DetailedInfo().InitQuota(&*quota_info_);
    507 }
    508 
    509 ///////////////////////////////////////////////////////////////////////////////
    510 // CookieTreeChannelIDNode, public:
    511 
    512 CookieTreeChannelIDNode::CookieTreeChannelIDNode(
    513       net::ChannelIDStore::ChannelIDList::iterator channel_id)
    514     : CookieTreeNode(base::ASCIIToUTF16(channel_id->server_identifier())),
    515       channel_id_(channel_id) {
    516 }
    517 
    518 CookieTreeChannelIDNode::~CookieTreeChannelIDNode() {}
    519 
    520 void CookieTreeChannelIDNode::DeleteStoredObjects() {
    521   LocalDataContainer* container = GetLocalDataContainerForNode(this);
    522 
    523   if (container) {
    524     container->channel_id_helper_->DeleteChannelID(
    525         channel_id_->server_identifier());
    526     container->channel_id_list_.erase(channel_id_);
    527   }
    528 }
    529 
    530 CookieTreeNode::DetailedInfo
    531 CookieTreeChannelIDNode::GetDetailedInfo() const {
    532   return DetailedInfo().InitChannelID(&*channel_id_);
    533 }
    534 
    535 ///////////////////////////////////////////////////////////////////////////////
    536 // CookieTreeServiceWorkerNode, public:
    537 
    538 CookieTreeServiceWorkerNode::CookieTreeServiceWorkerNode(
    539     std::list<content::ServiceWorkerUsageInfo>::iterator service_worker_info)
    540     : CookieTreeNode(base::UTF8ToUTF16(service_worker_info->origin.spec())),
    541       service_worker_info_(service_worker_info) {
    542 }
    543 
    544 CookieTreeServiceWorkerNode::~CookieTreeServiceWorkerNode() {
    545 }
    546 
    547 void CookieTreeServiceWorkerNode::DeleteStoredObjects() {
    548   LocalDataContainer* container = GetLocalDataContainerForNode(this);
    549 
    550   if (container) {
    551     container->service_worker_helper_->DeleteServiceWorkers(
    552         service_worker_info_->origin);
    553     container->service_worker_info_list_.erase(service_worker_info_);
    554   }
    555 }
    556 
    557 CookieTreeNode::DetailedInfo CookieTreeServiceWorkerNode::GetDetailedInfo()
    558     const {
    559   return DetailedInfo().InitServiceWorker(&*service_worker_info_);
    560 }
    561 
    562 ///////////////////////////////////////////////////////////////////////////////
    563 // CookieTreeRootNode, public:
    564 
    565 CookieTreeRootNode::CookieTreeRootNode(CookiesTreeModel* model)
    566     : model_(model) {
    567 }
    568 
    569 CookieTreeRootNode::~CookieTreeRootNode() {}
    570 
    571 CookieTreeHostNode* CookieTreeRootNode::GetOrCreateHostNode(
    572     const GURL& url) {
    573   scoped_ptr<CookieTreeHostNode> host_node(
    574       new CookieTreeHostNode(url));
    575 
    576   // First see if there is an existing match.
    577   std::vector<CookieTreeNode*>::iterator host_node_iterator =
    578         std::lower_bound(children().begin(), children().end(), host_node.get(),
    579                          HostNodeComparator());
    580   if (host_node_iterator != children().end() &&
    581       CookieTreeHostNode::TitleForUrl(url) ==
    582       (*host_node_iterator)->GetTitle())
    583     return static_cast<CookieTreeHostNode*>(*host_node_iterator);
    584   // Node doesn't exist, insert the new one into the (ordered) children.
    585   DCHECK(model_);
    586   model_->Add(this, host_node.get(),
    587               (host_node_iterator - children().begin()));
    588   return host_node.release();
    589 }
    590 
    591 CookiesTreeModel* CookieTreeRootNode::GetModel() const {
    592   return model_;
    593 }
    594 
    595 CookieTreeNode::DetailedInfo CookieTreeRootNode::GetDetailedInfo() const {
    596   return DetailedInfo().Init(DetailedInfo::TYPE_ROOT);
    597 }
    598 
    599 ///////////////////////////////////////////////////////////////////////////////
    600 // CookieTreeHostNode, public:
    601 
    602 // static
    603 base::string16 CookieTreeHostNode::TitleForUrl(const GURL& url) {
    604   const std::string file_origin_node_name(
    605       std::string(url::kFileScheme) + url::kStandardSchemeSeparator);
    606   return base::UTF8ToUTF16(url.SchemeIsFile() ? file_origin_node_name
    607                                               : url.host());
    608 }
    609 
    610 CookieTreeHostNode::CookieTreeHostNode(const GURL& url)
    611     : CookieTreeNode(TitleForUrl(url)),
    612       cookies_child_(NULL),
    613       databases_child_(NULL),
    614       local_storages_child_(NULL),
    615       session_storages_child_(NULL),
    616       appcaches_child_(NULL),
    617       indexed_dbs_child_(NULL),
    618       file_systems_child_(NULL),
    619       quota_child_(NULL),
    620       channel_ids_child_(NULL),
    621       service_workers_child_(NULL),
    622       flash_lso_child_(NULL),
    623       url_(url),
    624       canonicalized_host_(CanonicalizeHost(url)) {
    625 }
    626 
    627 CookieTreeHostNode::~CookieTreeHostNode() {}
    628 
    629 const std::string CookieTreeHostNode::GetHost() const {
    630   const std::string file_origin_node_name(
    631       std::string(url::kFileScheme) + url::kStandardSchemeSeparator);
    632   return url_.SchemeIsFile() ? file_origin_node_name : url_.host();
    633 }
    634 
    635 CookieTreeNode::DetailedInfo CookieTreeHostNode::GetDetailedInfo() const {
    636   return DetailedInfo().InitHost();
    637 }
    638 
    639 CookieTreeCookiesNode* CookieTreeHostNode::GetOrCreateCookiesNode() {
    640   if (cookies_child_)
    641     return cookies_child_;
    642   cookies_child_ = new CookieTreeCookiesNode;
    643   AddChildSortedByTitle(cookies_child_);
    644   return cookies_child_;
    645 }
    646 
    647 CookieTreeDatabasesNode* CookieTreeHostNode::GetOrCreateDatabasesNode() {
    648   if (databases_child_)
    649     return databases_child_;
    650   databases_child_ = new CookieTreeDatabasesNode;
    651   AddChildSortedByTitle(databases_child_);
    652   return databases_child_;
    653 }
    654 
    655 CookieTreeLocalStoragesNode*
    656     CookieTreeHostNode::GetOrCreateLocalStoragesNode() {
    657   if (local_storages_child_)
    658     return local_storages_child_;
    659   local_storages_child_ = new CookieTreeLocalStoragesNode;
    660   AddChildSortedByTitle(local_storages_child_);
    661   return local_storages_child_;
    662 }
    663 
    664 CookieTreeSessionStoragesNode*
    665     CookieTreeHostNode::GetOrCreateSessionStoragesNode() {
    666   if (session_storages_child_)
    667     return session_storages_child_;
    668   session_storages_child_ = new CookieTreeSessionStoragesNode;
    669   AddChildSortedByTitle(session_storages_child_);
    670   return session_storages_child_;
    671 }
    672 
    673 CookieTreeAppCachesNode* CookieTreeHostNode::GetOrCreateAppCachesNode() {
    674   if (appcaches_child_)
    675     return appcaches_child_;
    676   appcaches_child_ = new CookieTreeAppCachesNode;
    677   AddChildSortedByTitle(appcaches_child_);
    678   return appcaches_child_;
    679 }
    680 
    681 CookieTreeIndexedDBsNode* CookieTreeHostNode::GetOrCreateIndexedDBsNode() {
    682   if (indexed_dbs_child_)
    683     return indexed_dbs_child_;
    684   indexed_dbs_child_ = new CookieTreeIndexedDBsNode;
    685   AddChildSortedByTitle(indexed_dbs_child_);
    686   return indexed_dbs_child_;
    687 }
    688 
    689 CookieTreeFileSystemsNode* CookieTreeHostNode::GetOrCreateFileSystemsNode() {
    690   if (file_systems_child_)
    691     return file_systems_child_;
    692   file_systems_child_ = new CookieTreeFileSystemsNode;
    693   AddChildSortedByTitle(file_systems_child_);
    694   return file_systems_child_;
    695 }
    696 
    697 CookieTreeQuotaNode* CookieTreeHostNode::UpdateOrCreateQuotaNode(
    698     std::list<BrowsingDataQuotaHelper::QuotaInfo>::iterator quota_info) {
    699   if (quota_child_)
    700     return quota_child_;
    701   quota_child_ = new CookieTreeQuotaNode(quota_info);
    702   AddChildSortedByTitle(quota_child_);
    703   return quota_child_;
    704 }
    705 
    706 CookieTreeChannelIDsNode*
    707 CookieTreeHostNode::GetOrCreateChannelIDsNode() {
    708   if (channel_ids_child_)
    709     return channel_ids_child_;
    710   channel_ids_child_ = new CookieTreeChannelIDsNode;
    711   AddChildSortedByTitle(channel_ids_child_);
    712   return channel_ids_child_;
    713 }
    714 
    715 CookieTreeServiceWorkersNode*
    716 CookieTreeHostNode::GetOrCreateServiceWorkersNode() {
    717   if (service_workers_child_)
    718     return service_workers_child_;
    719   service_workers_child_ = new CookieTreeServiceWorkersNode;
    720   AddChildSortedByTitle(service_workers_child_);
    721   return service_workers_child_;
    722 }
    723 
    724 CookieTreeFlashLSONode* CookieTreeHostNode::GetOrCreateFlashLSONode(
    725     const std::string& domain) {
    726   DCHECK_EQ(GetHost(), domain);
    727   if (flash_lso_child_)
    728     return flash_lso_child_;
    729   flash_lso_child_ = new CookieTreeFlashLSONode(domain);
    730   AddChildSortedByTitle(flash_lso_child_);
    731   return flash_lso_child_;
    732 }
    733 
    734 void CookieTreeHostNode::CreateContentException(
    735     CookieSettings* cookie_settings, ContentSetting setting) const {
    736   DCHECK(setting == CONTENT_SETTING_ALLOW ||
    737          setting == CONTENT_SETTING_BLOCK ||
    738          setting == CONTENT_SETTING_SESSION_ONLY);
    739   if (CanCreateContentException()) {
    740     cookie_settings->ResetCookieSetting(
    741         ContentSettingsPattern::FromURLNoWildcard(url_),
    742         ContentSettingsPattern::Wildcard());
    743     cookie_settings->SetCookieSetting(
    744         ContentSettingsPattern::FromURL(url_),
    745         ContentSettingsPattern::Wildcard(), setting);
    746   }
    747 }
    748 
    749 bool CookieTreeHostNode::CanCreateContentException() const {
    750   return !url_.SchemeIsFile();
    751 }
    752 
    753 ///////////////////////////////////////////////////////////////////////////////
    754 // CookieTreeCookiesNode, public:
    755 
    756 CookieTreeCookiesNode::CookieTreeCookiesNode()
    757     : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_COOKIES)) {
    758 }
    759 
    760 CookieTreeCookiesNode::~CookieTreeCookiesNode() {
    761 }
    762 
    763 CookieTreeNode::DetailedInfo CookieTreeCookiesNode::GetDetailedInfo() const {
    764   return DetailedInfo().Init(DetailedInfo::TYPE_COOKIES);
    765 }
    766 
    767 ///////////////////////////////////////////////////////////////////////////////
    768 // CookieTreeAppCachesNode, public:
    769 
    770 CookieTreeAppCachesNode::CookieTreeAppCachesNode()
    771     : CookieTreeNode(l10n_util::GetStringUTF16(
    772                          IDS_COOKIES_APPLICATION_CACHES)) {
    773 }
    774 
    775 CookieTreeAppCachesNode::~CookieTreeAppCachesNode() {}
    776 
    777 CookieTreeNode::DetailedInfo CookieTreeAppCachesNode::GetDetailedInfo() const {
    778   return DetailedInfo().Init(DetailedInfo::TYPE_APPCACHES);
    779 }
    780 
    781 ///////////////////////////////////////////////////////////////////////////////
    782 // CookieTreeDatabasesNode, public:
    783 
    784 CookieTreeDatabasesNode::CookieTreeDatabasesNode()
    785     : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_WEB_DATABASES)) {
    786 }
    787 
    788 CookieTreeDatabasesNode::~CookieTreeDatabasesNode() {}
    789 
    790 CookieTreeNode::DetailedInfo CookieTreeDatabasesNode::GetDetailedInfo() const {
    791   return DetailedInfo().Init(DetailedInfo::TYPE_DATABASES);
    792 }
    793 
    794 ///////////////////////////////////////////////////////////////////////////////
    795 // CookieTreeLocalStoragesNode, public:
    796 
    797 CookieTreeLocalStoragesNode::CookieTreeLocalStoragesNode()
    798     : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_LOCAL_STORAGE)) {
    799 }
    800 
    801 CookieTreeLocalStoragesNode::~CookieTreeLocalStoragesNode() {}
    802 
    803 CookieTreeNode::DetailedInfo
    804 CookieTreeLocalStoragesNode::GetDetailedInfo() const {
    805   return DetailedInfo().Init(DetailedInfo::TYPE_LOCAL_STORAGES);
    806 }
    807 
    808 ///////////////////////////////////////////////////////////////////////////////
    809 // CookieTreeSessionStoragesNode, public:
    810 
    811 CookieTreeSessionStoragesNode::CookieTreeSessionStoragesNode()
    812     : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_SESSION_STORAGE)) {
    813 }
    814 
    815 CookieTreeSessionStoragesNode::~CookieTreeSessionStoragesNode() {}
    816 
    817 CookieTreeNode::DetailedInfo
    818 CookieTreeSessionStoragesNode::GetDetailedInfo() const {
    819   return DetailedInfo().Init(DetailedInfo::TYPE_SESSION_STORAGES);
    820 }
    821 
    822 ///////////////////////////////////////////////////////////////////////////////
    823 // CookieTreeIndexedDBsNode, public:
    824 
    825 CookieTreeIndexedDBsNode::CookieTreeIndexedDBsNode()
    826     : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_INDEXED_DBS)) {
    827 }
    828 
    829 CookieTreeIndexedDBsNode::~CookieTreeIndexedDBsNode() {}
    830 
    831 CookieTreeNode::DetailedInfo
    832 CookieTreeIndexedDBsNode::GetDetailedInfo() const {
    833   return DetailedInfo().Init(DetailedInfo::TYPE_INDEXED_DBS);
    834 }
    835 
    836 ///////////////////////////////////////////////////////////////////////////////
    837 // CookieTreeFileSystemsNode, public:
    838 
    839 CookieTreeFileSystemsNode::CookieTreeFileSystemsNode()
    840     : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_FILE_SYSTEMS)) {
    841 }
    842 
    843 CookieTreeFileSystemsNode::~CookieTreeFileSystemsNode() {}
    844 
    845 CookieTreeNode::DetailedInfo
    846 CookieTreeFileSystemsNode::GetDetailedInfo() const {
    847   return DetailedInfo().Init(DetailedInfo::TYPE_FILE_SYSTEMS);
    848 }
    849 
    850 ///////////////////////////////////////////////////////////////////////////////
    851 // CookieTreeChannelIDsNode, public:
    852 
    853 CookieTreeChannelIDsNode::CookieTreeChannelIDsNode()
    854     : CookieTreeNode(
    855         l10n_util::GetStringUTF16(IDS_COOKIES_CHANNEL_IDS)) {
    856 }
    857 
    858 CookieTreeChannelIDsNode::~CookieTreeChannelIDsNode() {}
    859 
    860 CookieTreeNode::DetailedInfo
    861 CookieTreeChannelIDsNode::GetDetailedInfo() const {
    862   return DetailedInfo().Init(DetailedInfo::TYPE_CHANNEL_IDS);
    863 }
    864 
    865 void CookieTreeNode::AddChildSortedByTitle(CookieTreeNode* new_child) {
    866   DCHECK(new_child);
    867   std::vector<CookieTreeNode*>::iterator iter =
    868       std::lower_bound(children().begin(), children().end(), new_child,
    869                        NodeTitleComparator());
    870   GetModel()->Add(this, new_child, iter - children().begin());
    871 }
    872 
    873 ///////////////////////////////////////////////////////////////////////////////
    874 // CookieTreeServiceWorkersNode, public:
    875 
    876 CookieTreeServiceWorkersNode::CookieTreeServiceWorkersNode()
    877     : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_SERVICE_WORKERS)) {
    878 }
    879 
    880 CookieTreeServiceWorkersNode::~CookieTreeServiceWorkersNode() {
    881 }
    882 
    883 CookieTreeNode::DetailedInfo CookieTreeServiceWorkersNode::GetDetailedInfo()
    884     const {
    885   return DetailedInfo().Init(DetailedInfo::TYPE_SERVICE_WORKERS);
    886 }
    887 
    888 ///////////////////////////////////////////////////////////////////////////////
    889 // CookieTreeFlashLSONode
    890 CookieTreeFlashLSONode::CookieTreeFlashLSONode(
    891     const std::string& domain)
    892     : domain_(domain) {}
    893 CookieTreeFlashLSONode::~CookieTreeFlashLSONode() {}
    894 
    895 void CookieTreeFlashLSONode::DeleteStoredObjects() {
    896   // We are one level below the host node.
    897   CookieTreeHostNode* host = static_cast<CookieTreeHostNode*>(parent());
    898   CHECK_EQ(host->GetDetailedInfo().node_type,
    899            CookieTreeNode::DetailedInfo::TYPE_HOST);
    900   LocalDataContainer* container = GetModel()->data_container();
    901   container->flash_lso_helper_->DeleteFlashLSOsForSite(domain_);
    902 }
    903 
    904 CookieTreeNode::DetailedInfo CookieTreeFlashLSONode::GetDetailedInfo() const {
    905   return DetailedInfo().InitFlashLSO(domain_);
    906 }
    907 
    908 ///////////////////////////////////////////////////////////////////////////////
    909 // ScopedBatchUpdateNotifier
    910 CookiesTreeModel::ScopedBatchUpdateNotifier::ScopedBatchUpdateNotifier(
    911   CookiesTreeModel* model, CookieTreeNode* node)
    912       : model_(model), node_(node), batch_in_progress_(false) {
    913 }
    914 
    915 CookiesTreeModel::ScopedBatchUpdateNotifier::~ScopedBatchUpdateNotifier() {
    916   if (batch_in_progress_) {
    917     model_->NotifyObserverTreeNodeChanged(node_);
    918     model_->NotifyObserverEndBatch();
    919   }
    920 }
    921 
    922 void CookiesTreeModel::ScopedBatchUpdateNotifier::StartBatchUpdate() {
    923   if (!batch_in_progress_) {
    924     model_->NotifyObserverBeginBatch();
    925     batch_in_progress_ = true;
    926   }
    927 }
    928 
    929 ///////////////////////////////////////////////////////////////////////////////
    930 // CookiesTreeModel, public:
    931 CookiesTreeModel::CookiesTreeModel(
    932     LocalDataContainer* data_container,
    933     ExtensionSpecialStoragePolicy* special_storage_policy,
    934     bool group_by_cookie_source)
    935     : ui::TreeNodeModel<CookieTreeNode>(new CookieTreeRootNode(this)),
    936       data_container_(data_container),
    937 #if defined(ENABLE_EXTENSIONS)
    938       special_storage_policy_(special_storage_policy),
    939 #endif
    940       group_by_cookie_source_(group_by_cookie_source),
    941       batch_update_(0) {
    942   data_container_->Init(this);
    943 }
    944 
    945 CookiesTreeModel::~CookiesTreeModel() {
    946 }
    947 
    948 ///////////////////////////////////////////////////////////////////////////////
    949 // CookiesTreeModel, TreeModel methods (public):
    950 
    951 // TreeModel methods:
    952 // Returns the set of icons for the nodes in the tree. You only need override
    953 // this if you don't want to use the default folder icons.
    954 void CookiesTreeModel::GetIcons(std::vector<gfx::ImageSkia>* icons) {
    955   icons->push_back(*ResourceBundle::GetSharedInstance().GetNativeImageNamed(
    956       IDR_DEFAULT_FAVICON).ToImageSkia());
    957   icons->push_back(*ResourceBundle::GetSharedInstance().GetNativeImageNamed(
    958       IDR_COOKIE_ICON).ToImageSkia());
    959   icons->push_back(*ResourceBundle::GetSharedInstance().GetNativeImageNamed(
    960       IDR_COOKIE_STORAGE_ICON).ToImageSkia());
    961 }
    962 
    963 // Returns the index of the icon to use for |node|. Return -1 to use the
    964 // default icon. The index is relative to the list of icons returned from
    965 // GetIcons.
    966 int CookiesTreeModel::GetIconIndex(ui::TreeModelNode* node) {
    967   CookieTreeNode* ct_node = static_cast<CookieTreeNode*>(node);
    968   switch (ct_node->GetDetailedInfo().node_type) {
    969     case CookieTreeNode::DetailedInfo::TYPE_HOST:
    970       return ORIGIN;
    971     case CookieTreeNode::DetailedInfo::TYPE_COOKIE:
    972       return COOKIE;
    973     case CookieTreeNode::DetailedInfo::TYPE_DATABASE:
    974       return DATABASE;
    975     case CookieTreeNode::DetailedInfo::TYPE_LOCAL_STORAGE:
    976       return DATABASE;  // close enough
    977     case CookieTreeNode::DetailedInfo::TYPE_SESSION_STORAGE:
    978       return DATABASE;  // ditto
    979     case CookieTreeNode::DetailedInfo::TYPE_APPCACHE:
    980       return DATABASE;  // ditto
    981     case CookieTreeNode::DetailedInfo::TYPE_INDEXED_DB:
    982       return DATABASE;  // ditto
    983     case CookieTreeNode::DetailedInfo::TYPE_FILE_SYSTEM:
    984       return DATABASE;  // ditto
    985     case CookieTreeNode::DetailedInfo::TYPE_QUOTA:
    986       return -1;
    987     case CookieTreeNode::DetailedInfo::TYPE_CHANNEL_ID:
    988       return COOKIE;  // It's kinda like a cookie?
    989     case CookieTreeNode::DetailedInfo::TYPE_SERVICE_WORKER:
    990       return DATABASE;  // Just like appcache
    991     default:
    992       break;
    993   }
    994   return -1;
    995 }
    996 
    997 void CookiesTreeModel::DeleteAllStoredObjects() {
    998   NotifyObserverBeginBatch();
    999   CookieTreeNode* root = GetRoot();
   1000   root->DeleteStoredObjects();
   1001   int num_children = root->child_count();
   1002   for (int i = num_children - 1; i >= 0; --i)
   1003     delete Remove(root, root->GetChild(i));
   1004   NotifyObserverTreeNodeChanged(root);
   1005   NotifyObserverEndBatch();
   1006 }
   1007 
   1008 void CookiesTreeModel::DeleteCookieNode(CookieTreeNode* cookie_node) {
   1009   if (cookie_node == GetRoot())
   1010     return;
   1011   cookie_node->DeleteStoredObjects();
   1012   CookieTreeNode* parent_node = cookie_node->parent();
   1013   delete Remove(parent_node, cookie_node);
   1014   if (parent_node->empty())
   1015     DeleteCookieNode(parent_node);
   1016 }
   1017 
   1018 void CookiesTreeModel::UpdateSearchResults(const base::string16& filter) {
   1019   CookieTreeNode* root = GetRoot();
   1020   ScopedBatchUpdateNotifier notifier(this, root);
   1021   int num_children = root->child_count();
   1022   notifier.StartBatchUpdate();
   1023   for (int i = num_children - 1; i >= 0; --i)
   1024     delete Remove(root, root->GetChild(i));
   1025 
   1026   PopulateCookieInfoWithFilter(data_container(), &notifier, filter);
   1027   PopulateDatabaseInfoWithFilter(data_container(), &notifier, filter);
   1028   PopulateLocalStorageInfoWithFilter(data_container(), &notifier, filter);
   1029   PopulateSessionStorageInfoWithFilter(data_container(), &notifier, filter);
   1030   PopulateAppCacheInfoWithFilter(data_container(), &notifier, filter);
   1031   PopulateIndexedDBInfoWithFilter(data_container(), &notifier, filter);
   1032   PopulateFileSystemInfoWithFilter(data_container(), &notifier, filter);
   1033   PopulateQuotaInfoWithFilter(data_container(), &notifier, filter);
   1034   PopulateChannelIDInfoWithFilter(data_container(), &notifier, filter);
   1035   PopulateServiceWorkerUsageInfoWithFilter(data_container(), &notifier, filter);
   1036 }
   1037 
   1038 #if defined(ENABLE_EXTENSIONS)
   1039 const extensions::ExtensionSet* CookiesTreeModel::ExtensionsProtectingNode(
   1040     const CookieTreeNode& cookie_node) {
   1041   if (!special_storage_policy_.get())
   1042     return NULL;
   1043 
   1044   CookieTreeNode::DetailedInfo info = cookie_node.GetDetailedInfo();
   1045 
   1046   if (!TypeIsProtected(info.node_type))
   1047     return NULL;
   1048 
   1049   DCHECK(!info.origin.is_empty());
   1050   return special_storage_policy_->ExtensionsProtectingOrigin(info.origin);
   1051 }
   1052 #endif
   1053 
   1054 void CookiesTreeModel::AddCookiesTreeObserver(Observer* observer) {
   1055   cookies_observer_list_.AddObserver(observer);
   1056   // Call super so that TreeNodeModel can notify, too.
   1057   ui::TreeNodeModel<CookieTreeNode>::AddObserver(observer);
   1058 }
   1059 
   1060 void CookiesTreeModel::RemoveCookiesTreeObserver(Observer* observer) {
   1061   cookies_observer_list_.RemoveObserver(observer);
   1062   // Call super so that TreeNodeModel doesn't have dead pointers.
   1063   ui::TreeNodeModel<CookieTreeNode>::RemoveObserver(observer);
   1064 }
   1065 
   1066 void CookiesTreeModel::PopulateAppCacheInfo(LocalDataContainer* container) {
   1067   ScopedBatchUpdateNotifier notifier(this, GetRoot());
   1068   PopulateAppCacheInfoWithFilter(container, &notifier, base::string16());
   1069 }
   1070 
   1071 void CookiesTreeModel::PopulateCookieInfo(LocalDataContainer* container) {
   1072   ScopedBatchUpdateNotifier notifier(this, GetRoot());
   1073   PopulateCookieInfoWithFilter(container, &notifier, base::string16());
   1074 }
   1075 
   1076 void CookiesTreeModel::PopulateDatabaseInfo(LocalDataContainer* container) {
   1077   ScopedBatchUpdateNotifier notifier(this, GetRoot());
   1078   PopulateDatabaseInfoWithFilter(container, &notifier, base::string16());
   1079 }
   1080 
   1081 void CookiesTreeModel::PopulateLocalStorageInfo(LocalDataContainer* container) {
   1082   ScopedBatchUpdateNotifier notifier(this, GetRoot());
   1083   PopulateLocalStorageInfoWithFilter(container, &notifier, base::string16());
   1084 }
   1085 
   1086 void CookiesTreeModel::PopulateSessionStorageInfo(
   1087       LocalDataContainer* container) {
   1088   ScopedBatchUpdateNotifier notifier(this, GetRoot());
   1089   PopulateSessionStorageInfoWithFilter(container, &notifier, base::string16());
   1090 }
   1091 
   1092 void CookiesTreeModel::PopulateIndexedDBInfo(LocalDataContainer* container) {
   1093   ScopedBatchUpdateNotifier notifier(this, GetRoot());
   1094   PopulateIndexedDBInfoWithFilter(container, &notifier, base::string16());
   1095 }
   1096 
   1097 void CookiesTreeModel::PopulateFileSystemInfo(LocalDataContainer* container) {
   1098   ScopedBatchUpdateNotifier notifier(this, GetRoot());
   1099   PopulateFileSystemInfoWithFilter(container, &notifier, base::string16());
   1100 }
   1101 
   1102 void CookiesTreeModel::PopulateQuotaInfo(LocalDataContainer* container) {
   1103   ScopedBatchUpdateNotifier notifier(this, GetRoot());
   1104   PopulateQuotaInfoWithFilter(container, &notifier, base::string16());
   1105 }
   1106 
   1107 void CookiesTreeModel::PopulateChannelIDInfo(
   1108       LocalDataContainer* container) {
   1109   ScopedBatchUpdateNotifier notifier(this, GetRoot());
   1110   PopulateChannelIDInfoWithFilter(container, &notifier, base::string16());
   1111 }
   1112 
   1113 void CookiesTreeModel::PopulateServiceWorkerUsageInfo(
   1114     LocalDataContainer* container) {
   1115   ScopedBatchUpdateNotifier notifier(this, GetRoot());
   1116   PopulateServiceWorkerUsageInfoWithFilter(
   1117       container, &notifier, base::string16());
   1118 }
   1119 
   1120 void CookiesTreeModel::PopulateFlashLSOInfo(
   1121       LocalDataContainer* container) {
   1122   ScopedBatchUpdateNotifier notifier(this, GetRoot());
   1123   PopulateFlashLSOInfoWithFilter(container, &notifier, base::string16());
   1124 }
   1125 
   1126 void CookiesTreeModel::PopulateAppCacheInfoWithFilter(
   1127     LocalDataContainer* container,
   1128     ScopedBatchUpdateNotifier* notifier,
   1129     const base::string16& filter) {
   1130   using content::AppCacheInfo;
   1131   typedef std::map<GURL, std::list<AppCacheInfo> > InfoByOrigin;
   1132   CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
   1133 
   1134   if (container->appcache_info_.empty())
   1135     return;
   1136 
   1137   notifier->StartBatchUpdate();
   1138   for (InfoByOrigin::iterator origin = container->appcache_info_.begin();
   1139        origin != container->appcache_info_.end(); ++origin) {
   1140     base::string16 host_node_name = base::UTF8ToUTF16(origin->first.host());
   1141     if (filter.empty() ||
   1142         (host_node_name.find(filter) != base::string16::npos)) {
   1143       CookieTreeHostNode* host_node = root->GetOrCreateHostNode(origin->first);
   1144       CookieTreeAppCachesNode* appcaches_node =
   1145           host_node->GetOrCreateAppCachesNode();
   1146 
   1147       for (std::list<AppCacheInfo>::iterator info = origin->second.begin();
   1148            info != origin->second.end(); ++info) {
   1149         appcaches_node->AddAppCacheNode(
   1150             new CookieTreeAppCacheNode(origin->first, info));
   1151       }
   1152     }
   1153   }
   1154 }
   1155 
   1156 void CookiesTreeModel::PopulateCookieInfoWithFilter(
   1157     LocalDataContainer* container,
   1158     ScopedBatchUpdateNotifier* notifier,
   1159     const base::string16& filter) {
   1160   CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
   1161 
   1162   notifier->StartBatchUpdate();
   1163   for (CookieList::iterator it = container->cookie_list_.begin();
   1164        it != container->cookie_list_.end(); ++it) {
   1165     std::string source_string = it->Source();
   1166     if (source_string.empty() || !group_by_cookie_source_) {
   1167       std::string domain = it->Domain();
   1168       if (domain.length() > 1 && domain[0] == '.')
   1169         domain = domain.substr(1);
   1170 
   1171       // We treat secure cookies just the same as normal ones.
   1172       source_string = std::string(url::kHttpScheme) +
   1173           url::kStandardSchemeSeparator + domain + "/";
   1174     }
   1175 
   1176     GURL source(source_string);
   1177     if (filter.empty() || (CookieTreeHostNode::TitleForUrl(source)
   1178                                .find(filter) != base::string16::npos)) {
   1179       CookieTreeHostNode* host_node = root->GetOrCreateHostNode(source);
   1180       CookieTreeCookiesNode* cookies_node =
   1181           host_node->GetOrCreateCookiesNode();
   1182       CookieTreeCookieNode* new_cookie = new CookieTreeCookieNode(it);
   1183       cookies_node->AddCookieNode(new_cookie);
   1184     }
   1185   }
   1186 }
   1187 
   1188 void CookiesTreeModel::PopulateDatabaseInfoWithFilter(
   1189     LocalDataContainer* container,
   1190     ScopedBatchUpdateNotifier* notifier,
   1191     const base::string16& filter) {
   1192   CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
   1193 
   1194   if (container->database_info_list_.empty())
   1195     return;
   1196 
   1197   notifier->StartBatchUpdate();
   1198   for (DatabaseInfoList::iterator database_info =
   1199            container->database_info_list_.begin();
   1200        database_info != container->database_info_list_.end();
   1201        ++database_info) {
   1202     GURL origin(database_info->identifier.ToOrigin());
   1203 
   1204     if (filter.empty() || (CookieTreeHostNode::TitleForUrl(origin)
   1205                                .find(filter) != base::string16::npos)) {
   1206       CookieTreeHostNode* host_node = root->GetOrCreateHostNode(origin);
   1207       CookieTreeDatabasesNode* databases_node =
   1208           host_node->GetOrCreateDatabasesNode();
   1209       databases_node->AddDatabaseNode(
   1210           new CookieTreeDatabaseNode(database_info));
   1211     }
   1212   }
   1213 }
   1214 
   1215 void CookiesTreeModel::PopulateLocalStorageInfoWithFilter(
   1216     LocalDataContainer* container,
   1217     ScopedBatchUpdateNotifier* notifier,
   1218     const base::string16& filter) {
   1219   CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
   1220 
   1221   if (container->local_storage_info_list_.empty())
   1222     return;
   1223 
   1224   notifier->StartBatchUpdate();
   1225   for (LocalStorageInfoList::iterator local_storage_info =
   1226            container->local_storage_info_list_.begin();
   1227        local_storage_info != container->local_storage_info_list_.end();
   1228        ++local_storage_info) {
   1229     const GURL& origin(local_storage_info->origin_url);
   1230 
   1231     if (filter.empty() || (CookieTreeHostNode::TitleForUrl(origin)
   1232                                .find(filter) != std::string::npos)) {
   1233       CookieTreeHostNode* host_node = root->GetOrCreateHostNode(origin);
   1234       CookieTreeLocalStoragesNode* local_storages_node =
   1235           host_node->GetOrCreateLocalStoragesNode();
   1236       local_storages_node->AddLocalStorageNode(
   1237           new CookieTreeLocalStorageNode(local_storage_info));
   1238     }
   1239   }
   1240 }
   1241 
   1242 void CookiesTreeModel::PopulateSessionStorageInfoWithFilter(
   1243     LocalDataContainer* container,
   1244     ScopedBatchUpdateNotifier* notifier,
   1245     const base::string16& filter) {
   1246   CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
   1247 
   1248   if (container->session_storage_info_list_.empty())
   1249     return;
   1250 
   1251   notifier->StartBatchUpdate();
   1252   for (LocalStorageInfoList::iterator session_storage_info =
   1253            container->session_storage_info_list_.begin();
   1254        session_storage_info != container->session_storage_info_list_.end();
   1255        ++session_storage_info) {
   1256     const GURL& origin = session_storage_info->origin_url;
   1257 
   1258     if (filter.empty() || (CookieTreeHostNode::TitleForUrl(origin)
   1259                                .find(filter) != base::string16::npos)) {
   1260       CookieTreeHostNode* host_node = root->GetOrCreateHostNode(origin);
   1261       CookieTreeSessionStoragesNode* session_storages_node =
   1262           host_node->GetOrCreateSessionStoragesNode();
   1263       session_storages_node->AddSessionStorageNode(
   1264           new CookieTreeSessionStorageNode(session_storage_info));
   1265     }
   1266   }
   1267 }
   1268 
   1269 void CookiesTreeModel::PopulateIndexedDBInfoWithFilter(
   1270     LocalDataContainer* container,
   1271     ScopedBatchUpdateNotifier* notifier,
   1272     const base::string16& filter) {
   1273   CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
   1274 
   1275   if (container->indexed_db_info_list_.empty())
   1276     return;
   1277 
   1278   notifier->StartBatchUpdate();
   1279   for (IndexedDBInfoList::iterator indexed_db_info =
   1280            container->indexed_db_info_list_.begin();
   1281        indexed_db_info != container->indexed_db_info_list_.end();
   1282        ++indexed_db_info) {
   1283     const GURL& origin = indexed_db_info->origin_;
   1284 
   1285     if (filter.empty() || (CookieTreeHostNode::TitleForUrl(origin)
   1286                                .find(filter) != base::string16::npos)) {
   1287       CookieTreeHostNode* host_node = root->GetOrCreateHostNode(origin);
   1288       CookieTreeIndexedDBsNode* indexed_dbs_node =
   1289           host_node->GetOrCreateIndexedDBsNode();
   1290       indexed_dbs_node->AddIndexedDBNode(
   1291           new CookieTreeIndexedDBNode(indexed_db_info));
   1292     }
   1293   }
   1294 }
   1295 
   1296 void CookiesTreeModel::PopulateChannelIDInfoWithFilter(
   1297     LocalDataContainer* container,
   1298     ScopedBatchUpdateNotifier* notifier,
   1299     const base::string16& filter) {
   1300   CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
   1301 
   1302   if (container->channel_id_list_.empty())
   1303     return;
   1304 
   1305   notifier->StartBatchUpdate();
   1306   for (ChannelIDList::iterator channel_id_info =
   1307            container->channel_id_list_.begin();
   1308        channel_id_info != container->channel_id_list_.end();
   1309        ++channel_id_info) {
   1310     GURL origin(channel_id_info->server_identifier());
   1311     if (!origin.is_valid()) {
   1312       // Channel ID.  Make a valid URL to satisfy the
   1313       // CookieTreeRootNode::GetOrCreateHostNode interface.
   1314       origin = GURL(std::string(url::kHttpsScheme) +
   1315           url::kStandardSchemeSeparator +
   1316           channel_id_info->server_identifier() + "/");
   1317     }
   1318     base::string16 title = CookieTreeHostNode::TitleForUrl(origin);
   1319     if (filter.empty() || title.find(filter) != base::string16::npos) {
   1320       CookieTreeHostNode* host_node = root->GetOrCreateHostNode(origin);
   1321       CookieTreeChannelIDsNode* channel_ids_node =
   1322           host_node->GetOrCreateChannelIDsNode();
   1323       channel_ids_node->AddChannelIDNode(
   1324           new CookieTreeChannelIDNode(channel_id_info));
   1325     }
   1326   }
   1327 }
   1328 
   1329 void CookiesTreeModel::PopulateServiceWorkerUsageInfoWithFilter(
   1330     LocalDataContainer* container,
   1331     ScopedBatchUpdateNotifier* notifier,
   1332     const base::string16& filter) {
   1333   CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
   1334 
   1335   if (container->service_worker_info_list_.empty())
   1336     return;
   1337 
   1338   notifier->StartBatchUpdate();
   1339   for (ServiceWorkerUsageInfoList::iterator service_worker_info =
   1340            container->service_worker_info_list_.begin();
   1341        service_worker_info != container->service_worker_info_list_.end();
   1342        ++service_worker_info) {
   1343     const GURL& origin = service_worker_info->origin;
   1344 
   1345     if (filter.empty() || (CookieTreeHostNode::TitleForUrl(origin)
   1346                                .find(filter) != base::string16::npos)) {
   1347       CookieTreeHostNode* host_node = root->GetOrCreateHostNode(origin);
   1348       CookieTreeServiceWorkersNode* service_workers_node =
   1349           host_node->GetOrCreateServiceWorkersNode();
   1350       service_workers_node->AddServiceWorkerNode(
   1351           new CookieTreeServiceWorkerNode(service_worker_info));
   1352     }
   1353   }
   1354 }
   1355 
   1356 void CookiesTreeModel::PopulateFileSystemInfoWithFilter(
   1357     LocalDataContainer* container,
   1358     ScopedBatchUpdateNotifier* notifier,
   1359     const base::string16& filter) {
   1360   CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
   1361 
   1362   if (container->file_system_info_list_.empty())
   1363     return;
   1364 
   1365   notifier->StartBatchUpdate();
   1366   for (FileSystemInfoList::iterator file_system_info =
   1367            container->file_system_info_list_.begin();
   1368        file_system_info != container->file_system_info_list_.end();
   1369        ++file_system_info) {
   1370     GURL origin(file_system_info->origin);
   1371 
   1372     if (filter.empty() || (CookieTreeHostNode::TitleForUrl(origin)
   1373                                .find(filter) != base::string16::npos)) {
   1374       CookieTreeHostNode* host_node = root->GetOrCreateHostNode(origin);
   1375       CookieTreeFileSystemsNode* file_systems_node =
   1376           host_node->GetOrCreateFileSystemsNode();
   1377       file_systems_node->AddFileSystemNode(
   1378           new CookieTreeFileSystemNode(file_system_info));
   1379     }
   1380   }
   1381 }
   1382 
   1383 void CookiesTreeModel::PopulateQuotaInfoWithFilter(
   1384     LocalDataContainer* container,
   1385     ScopedBatchUpdateNotifier* notifier,
   1386     const base::string16& filter) {
   1387   CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
   1388 
   1389   if (container->quota_info_list_.empty())
   1390     return;
   1391 
   1392   notifier->StartBatchUpdate();
   1393   for (QuotaInfoList::iterator quota_info = container->quota_info_list_.begin();
   1394        quota_info != container->quota_info_list_.end();
   1395        ++quota_info) {
   1396     if (filter.empty() || (base::UTF8ToUTF16(quota_info->host).find(filter) !=
   1397                            base::string16::npos)) {
   1398       CookieTreeHostNode* host_node =
   1399           root->GetOrCreateHostNode(GURL("http://" + quota_info->host));
   1400       host_node->UpdateOrCreateQuotaNode(quota_info);
   1401     }
   1402   }
   1403 }
   1404 
   1405 void CookiesTreeModel::PopulateFlashLSOInfoWithFilter(
   1406     LocalDataContainer* container,
   1407     ScopedBatchUpdateNotifier* notifier,
   1408     const base::string16& filter) {
   1409   CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
   1410 
   1411   if (container->flash_lso_domain_list_.empty())
   1412     return;
   1413 
   1414   std::string filter_utf8 = base::UTF16ToUTF8(filter);
   1415   notifier->StartBatchUpdate();
   1416   for (std::vector<std::string>::iterator it =
   1417            container->flash_lso_domain_list_.begin();
   1418        it != container->flash_lso_domain_list_.end(); ++it) {
   1419     if (filter_utf8.empty() || it->find(filter_utf8) != std::string::npos) {
   1420       // Create a fake origin for GetOrCreateHostNode().
   1421       GURL origin("http://" + *it);
   1422       CookieTreeHostNode* host_node = root->GetOrCreateHostNode(origin);
   1423       host_node->GetOrCreateFlashLSONode(*it);
   1424     }
   1425   }
   1426 }
   1427 
   1428 void CookiesTreeModel::NotifyObserverBeginBatch() {
   1429   // Only notify the model once if we're batching in a nested manner.
   1430   if (batch_update_++ == 0) {
   1431     FOR_EACH_OBSERVER(Observer,
   1432                       cookies_observer_list_,
   1433                       TreeModelBeginBatch(this));
   1434   }
   1435 }
   1436 
   1437 void CookiesTreeModel::NotifyObserverEndBatch() {
   1438   // Only notify the observers if this is the outermost call to EndBatch() if
   1439   // called in a nested manner.
   1440   if (--batch_update_ == 0) {
   1441     FOR_EACH_OBSERVER(Observer,
   1442                       cookies_observer_list_,
   1443                       TreeModelEndBatch(this));
   1444   }
   1445 }
   1446