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