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