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 string16 CookieTreeHostNode::TitleForUrl(
    555     const GURL& url) {
    556   const std::string file_origin_node_name(
    557       std::string(chrome::kFileScheme) + content::kStandardSchemeSeparator);
    558   return UTF8ToUTF16(url.SchemeIsFile() ? file_origin_node_name : url.host());
    559 }
    560 
    561 CookieTreeHostNode::CookieTreeHostNode(const GURL& url)
    562     : CookieTreeNode(TitleForUrl(url)),
    563       cookies_child_(NULL),
    564       databases_child_(NULL),
    565       local_storages_child_(NULL),
    566       session_storages_child_(NULL),
    567       appcaches_child_(NULL),
    568       indexed_dbs_child_(NULL),
    569       file_systems_child_(NULL),
    570       quota_child_(NULL),
    571       server_bound_certs_child_(NULL),
    572       flash_lso_child_(NULL),
    573       url_(url),
    574       canonicalized_host_(CanonicalizeHost(url)) {}
    575 
    576 CookieTreeHostNode::~CookieTreeHostNode() {}
    577 
    578 const std::string CookieTreeHostNode::GetHost() const {
    579   const std::string file_origin_node_name(
    580       std::string(chrome::kFileScheme) + content::kStandardSchemeSeparator);
    581   return url_.SchemeIsFile() ? file_origin_node_name : url_.host();
    582 }
    583 
    584 CookieTreeNode::DetailedInfo CookieTreeHostNode::GetDetailedInfo() const {
    585   return DetailedInfo().InitHost();
    586 }
    587 
    588 CookieTreeCookiesNode* CookieTreeHostNode::GetOrCreateCookiesNode() {
    589   if (cookies_child_)
    590     return cookies_child_;
    591   cookies_child_ = new CookieTreeCookiesNode;
    592   AddChildSortedByTitle(cookies_child_);
    593   return cookies_child_;
    594 }
    595 
    596 CookieTreeDatabasesNode* CookieTreeHostNode::GetOrCreateDatabasesNode() {
    597   if (databases_child_)
    598     return databases_child_;
    599   databases_child_ = new CookieTreeDatabasesNode;
    600   AddChildSortedByTitle(databases_child_);
    601   return databases_child_;
    602 }
    603 
    604 CookieTreeLocalStoragesNode*
    605     CookieTreeHostNode::GetOrCreateLocalStoragesNode() {
    606   if (local_storages_child_)
    607     return local_storages_child_;
    608   local_storages_child_ = new CookieTreeLocalStoragesNode;
    609   AddChildSortedByTitle(local_storages_child_);
    610   return local_storages_child_;
    611 }
    612 
    613 CookieTreeSessionStoragesNode*
    614     CookieTreeHostNode::GetOrCreateSessionStoragesNode() {
    615   if (session_storages_child_)
    616     return session_storages_child_;
    617   session_storages_child_ = new CookieTreeSessionStoragesNode;
    618   AddChildSortedByTitle(session_storages_child_);
    619   return session_storages_child_;
    620 }
    621 
    622 CookieTreeAppCachesNode* CookieTreeHostNode::GetOrCreateAppCachesNode() {
    623   if (appcaches_child_)
    624     return appcaches_child_;
    625   appcaches_child_ = new CookieTreeAppCachesNode;
    626   AddChildSortedByTitle(appcaches_child_);
    627   return appcaches_child_;
    628 }
    629 
    630 CookieTreeIndexedDBsNode* CookieTreeHostNode::GetOrCreateIndexedDBsNode() {
    631   if (indexed_dbs_child_)
    632     return indexed_dbs_child_;
    633   indexed_dbs_child_ = new CookieTreeIndexedDBsNode;
    634   AddChildSortedByTitle(indexed_dbs_child_);
    635   return indexed_dbs_child_;
    636 }
    637 
    638 CookieTreeFileSystemsNode* CookieTreeHostNode::GetOrCreateFileSystemsNode() {
    639   if (file_systems_child_)
    640     return file_systems_child_;
    641   file_systems_child_ = new CookieTreeFileSystemsNode;
    642   AddChildSortedByTitle(file_systems_child_);
    643   return file_systems_child_;
    644 }
    645 
    646 CookieTreeQuotaNode* CookieTreeHostNode::UpdateOrCreateQuotaNode(
    647     std::list<BrowsingDataQuotaHelper::QuotaInfo>::iterator quota_info) {
    648   if (quota_child_)
    649     return quota_child_;
    650   quota_child_ = new CookieTreeQuotaNode(quota_info);
    651   AddChildSortedByTitle(quota_child_);
    652   return quota_child_;
    653 }
    654 
    655 CookieTreeServerBoundCertsNode*
    656 CookieTreeHostNode::GetOrCreateServerBoundCertsNode() {
    657   if (server_bound_certs_child_)
    658     return server_bound_certs_child_;
    659   server_bound_certs_child_ = new CookieTreeServerBoundCertsNode;
    660   AddChildSortedByTitle(server_bound_certs_child_);
    661   return server_bound_certs_child_;
    662 }
    663 
    664 CookieTreeFlashLSONode* CookieTreeHostNode::GetOrCreateFlashLSONode(
    665     const std::string& domain) {
    666   DCHECK_EQ(GetHost(), domain);
    667   if (flash_lso_child_)
    668     return flash_lso_child_;
    669   flash_lso_child_ = new CookieTreeFlashLSONode(domain);
    670   AddChildSortedByTitle(flash_lso_child_);
    671   return flash_lso_child_;
    672 }
    673 
    674 void CookieTreeHostNode::CreateContentException(
    675     CookieSettings* cookie_settings, ContentSetting setting) const {
    676   DCHECK(setting == CONTENT_SETTING_ALLOW ||
    677          setting == CONTENT_SETTING_BLOCK ||
    678          setting == CONTENT_SETTING_SESSION_ONLY);
    679   if (CanCreateContentException()) {
    680     cookie_settings->ResetCookieSetting(
    681         ContentSettingsPattern::FromURLNoWildcard(url_),
    682         ContentSettingsPattern::Wildcard());
    683     cookie_settings->SetCookieSetting(
    684         ContentSettingsPattern::FromURL(url_),
    685         ContentSettingsPattern::Wildcard(), setting);
    686   }
    687 }
    688 
    689 bool CookieTreeHostNode::CanCreateContentException() const {
    690   return !url_.SchemeIsFile();
    691 }
    692 
    693 ///////////////////////////////////////////////////////////////////////////////
    694 // CookieTreeCookiesNode, public:
    695 
    696 CookieTreeCookiesNode::CookieTreeCookiesNode()
    697     : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_COOKIES)) {
    698 }
    699 
    700 CookieTreeCookiesNode::~CookieTreeCookiesNode() {
    701 }
    702 
    703 CookieTreeNode::DetailedInfo CookieTreeCookiesNode::GetDetailedInfo() const {
    704   return DetailedInfo().Init(DetailedInfo::TYPE_COOKIES);
    705 }
    706 
    707 ///////////////////////////////////////////////////////////////////////////////
    708 // CookieTreeAppCachesNode, public:
    709 
    710 CookieTreeAppCachesNode::CookieTreeAppCachesNode()
    711     : CookieTreeNode(l10n_util::GetStringUTF16(
    712                          IDS_COOKIES_APPLICATION_CACHES)) {
    713 }
    714 
    715 CookieTreeAppCachesNode::~CookieTreeAppCachesNode() {}
    716 
    717 CookieTreeNode::DetailedInfo CookieTreeAppCachesNode::GetDetailedInfo() const {
    718   return DetailedInfo().Init(DetailedInfo::TYPE_APPCACHES);
    719 }
    720 
    721 ///////////////////////////////////////////////////////////////////////////////
    722 // CookieTreeDatabasesNode, public:
    723 
    724 CookieTreeDatabasesNode::CookieTreeDatabasesNode()
    725     : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_WEB_DATABASES)) {
    726 }
    727 
    728 CookieTreeDatabasesNode::~CookieTreeDatabasesNode() {}
    729 
    730 CookieTreeNode::DetailedInfo CookieTreeDatabasesNode::GetDetailedInfo() const {
    731   return DetailedInfo().Init(DetailedInfo::TYPE_DATABASES);
    732 }
    733 
    734 ///////////////////////////////////////////////////////////////////////////////
    735 // CookieTreeLocalStoragesNode, public:
    736 
    737 CookieTreeLocalStoragesNode::CookieTreeLocalStoragesNode()
    738     : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_LOCAL_STORAGE)) {
    739 }
    740 
    741 CookieTreeLocalStoragesNode::~CookieTreeLocalStoragesNode() {}
    742 
    743 CookieTreeNode::DetailedInfo
    744 CookieTreeLocalStoragesNode::GetDetailedInfo() const {
    745   return DetailedInfo().Init(DetailedInfo::TYPE_LOCAL_STORAGES);
    746 }
    747 
    748 ///////////////////////////////////////////////////////////////////////////////
    749 // CookieTreeSessionStoragesNode, public:
    750 
    751 CookieTreeSessionStoragesNode::CookieTreeSessionStoragesNode()
    752     : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_SESSION_STORAGE)) {
    753 }
    754 
    755 CookieTreeSessionStoragesNode::~CookieTreeSessionStoragesNode() {}
    756 
    757 CookieTreeNode::DetailedInfo
    758 CookieTreeSessionStoragesNode::GetDetailedInfo() const {
    759   return DetailedInfo().Init(DetailedInfo::TYPE_SESSION_STORAGES);
    760 }
    761 
    762 ///////////////////////////////////////////////////////////////////////////////
    763 // CookieTreeIndexedDBsNode, public:
    764 
    765 CookieTreeIndexedDBsNode::CookieTreeIndexedDBsNode()
    766     : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_INDEXED_DBS)) {
    767 }
    768 
    769 CookieTreeIndexedDBsNode::~CookieTreeIndexedDBsNode() {}
    770 
    771 CookieTreeNode::DetailedInfo
    772 CookieTreeIndexedDBsNode::GetDetailedInfo() const {
    773   return DetailedInfo().Init(DetailedInfo::TYPE_INDEXED_DBS);
    774 }
    775 
    776 ///////////////////////////////////////////////////////////////////////////////
    777 // CookieTreeFileSystemsNode, public:
    778 
    779 CookieTreeFileSystemsNode::CookieTreeFileSystemsNode()
    780     : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_FILE_SYSTEMS)) {
    781 }
    782 
    783 CookieTreeFileSystemsNode::~CookieTreeFileSystemsNode() {}
    784 
    785 CookieTreeNode::DetailedInfo
    786 CookieTreeFileSystemsNode::GetDetailedInfo() const {
    787   return DetailedInfo().Init(DetailedInfo::TYPE_FILE_SYSTEMS);
    788 }
    789 
    790 ///////////////////////////////////////////////////////////////////////////////
    791 // CookieTreeServerBoundCertsNode, public:
    792 
    793 CookieTreeServerBoundCertsNode::CookieTreeServerBoundCertsNode()
    794     : CookieTreeNode(
    795         l10n_util::GetStringUTF16(IDS_COOKIES_SERVER_BOUND_CERTS)) {
    796 }
    797 
    798 CookieTreeServerBoundCertsNode::~CookieTreeServerBoundCertsNode() {}
    799 
    800 CookieTreeNode::DetailedInfo
    801 CookieTreeServerBoundCertsNode::GetDetailedInfo() const {
    802   return DetailedInfo().Init(DetailedInfo::TYPE_SERVER_BOUND_CERTS);
    803 }
    804 
    805 void CookieTreeNode::AddChildSortedByTitle(CookieTreeNode* new_child) {
    806   DCHECK(new_child);
    807   std::vector<CookieTreeNode*>::iterator iter =
    808       std::lower_bound(children().begin(), children().end(), new_child,
    809                        NodeTitleComparator());
    810   GetModel()->Add(this, new_child, iter - children().begin());
    811 }
    812 
    813 ///////////////////////////////////////////////////////////////////////////////
    814 // CookieTreeFlashLSONode
    815 CookieTreeFlashLSONode::CookieTreeFlashLSONode(
    816     const std::string& domain)
    817     : domain_(domain) {}
    818 CookieTreeFlashLSONode::~CookieTreeFlashLSONode() {}
    819 
    820 void CookieTreeFlashLSONode::DeleteStoredObjects() {
    821   // We are one level below the host node.
    822   CookieTreeHostNode* host = static_cast<CookieTreeHostNode*>(parent());
    823   CHECK_EQ(host->GetDetailedInfo().node_type,
    824            CookieTreeNode::DetailedInfo::TYPE_HOST);
    825   LocalDataContainer* container = GetModel()->data_container();
    826   CHECK(container);
    827 
    828   container->flash_lso_helper_->DeleteFlashLSOsForSite(domain_);
    829 }
    830 
    831 CookieTreeNode::DetailedInfo CookieTreeFlashLSONode::GetDetailedInfo() const {
    832   return DetailedInfo().InitFlashLSO(domain_);
    833 }
    834 
    835 ///////////////////////////////////////////////////////////////////////////////
    836 // ScopedBatchUpdateNotifier
    837 CookiesTreeModel::ScopedBatchUpdateNotifier::ScopedBatchUpdateNotifier(
    838   CookiesTreeModel* model, CookieTreeNode* node)
    839       : model_(model), node_(node), batch_in_progress_(false) {
    840 }
    841 
    842 CookiesTreeModel::ScopedBatchUpdateNotifier::~ScopedBatchUpdateNotifier() {
    843   if (batch_in_progress_) {
    844     model_->NotifyObserverTreeNodeChanged(node_);
    845     model_->NotifyObserverEndBatch();
    846   }
    847 }
    848 
    849 void CookiesTreeModel::ScopedBatchUpdateNotifier::StartBatchUpdate() {
    850   if (!batch_in_progress_) {
    851     model_->NotifyObserverBeginBatch();
    852     batch_in_progress_ = true;
    853   }
    854 }
    855 
    856 ///////////////////////////////////////////////////////////////////////////////
    857 // CookiesTreeModel, public:
    858 CookiesTreeModel::CookiesTreeModel(
    859     LocalDataContainer* data_container,
    860     ExtensionSpecialStoragePolicy* special_storage_policy,
    861     bool group_by_cookie_source)
    862     : ui::TreeNodeModel<CookieTreeNode>(new CookieTreeRootNode(this)),
    863       data_container_(data_container),
    864       special_storage_policy_(special_storage_policy),
    865       group_by_cookie_source_(group_by_cookie_source),
    866       batch_update_(0) {
    867   data_container_->Init(this);
    868 }
    869 
    870 CookiesTreeModel::~CookiesTreeModel() {
    871 }
    872 
    873 ///////////////////////////////////////////////////////////////////////////////
    874 // CookiesTreeModel, TreeModel methods (public):
    875 
    876 // TreeModel methods:
    877 // Returns the set of icons for the nodes in the tree. You only need override
    878 // this if you don't want to use the default folder icons.
    879 void CookiesTreeModel::GetIcons(std::vector<gfx::ImageSkia>* icons) {
    880   icons->push_back(*ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
    881       IDR_DEFAULT_FAVICON));
    882   icons->push_back(*ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
    883       IDR_COOKIE_ICON));
    884   icons->push_back(*ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
    885       IDR_COOKIE_STORAGE_ICON));
    886 }
    887 
    888 // Returns the index of the icon to use for |node|. Return -1 to use the
    889 // default icon. The index is relative to the list of icons returned from
    890 // GetIcons.
    891 int CookiesTreeModel::GetIconIndex(ui::TreeModelNode* node) {
    892   CookieTreeNode* ct_node = static_cast<CookieTreeNode*>(node);
    893   switch (ct_node->GetDetailedInfo().node_type) {
    894     case CookieTreeNode::DetailedInfo::TYPE_HOST:
    895       return ORIGIN;
    896     case CookieTreeNode::DetailedInfo::TYPE_COOKIE:
    897       return COOKIE;
    898     case CookieTreeNode::DetailedInfo::TYPE_DATABASE:
    899       return DATABASE;
    900     case CookieTreeNode::DetailedInfo::TYPE_LOCAL_STORAGE:
    901       return DATABASE;  // close enough
    902     case CookieTreeNode::DetailedInfo::TYPE_SESSION_STORAGE:
    903       return DATABASE;  // ditto
    904     case CookieTreeNode::DetailedInfo::TYPE_APPCACHE:
    905       return DATABASE;  // ditto
    906     case CookieTreeNode::DetailedInfo::TYPE_INDEXED_DB:
    907       return DATABASE;  // ditto
    908     case CookieTreeNode::DetailedInfo::TYPE_FILE_SYSTEM:
    909       return DATABASE;  // ditto
    910     case CookieTreeNode::DetailedInfo::TYPE_QUOTA:
    911       return -1;
    912     case CookieTreeNode::DetailedInfo::TYPE_SERVER_BOUND_CERT:
    913       return COOKIE;  // It's kinda like a cookie?
    914     default:
    915       break;
    916   }
    917   return -1;
    918 }
    919 
    920 void CookiesTreeModel::DeleteAllStoredObjects() {
    921   NotifyObserverBeginBatch();
    922   CookieTreeNode* root = GetRoot();
    923   root->DeleteStoredObjects();
    924   int num_children = root->child_count();
    925   for (int i = num_children - 1; i >= 0; --i)
    926     delete Remove(root, root->GetChild(i));
    927   NotifyObserverTreeNodeChanged(root);
    928   NotifyObserverEndBatch();
    929 }
    930 
    931 void CookiesTreeModel::DeleteCookieNode(CookieTreeNode* cookie_node) {
    932   if (cookie_node == GetRoot())
    933     return;
    934   cookie_node->DeleteStoredObjects();
    935   CookieTreeNode* parent_node = cookie_node->parent();
    936   delete Remove(parent_node, cookie_node);
    937   if (parent_node->empty())
    938     DeleteCookieNode(parent_node);
    939 }
    940 
    941 void CookiesTreeModel::UpdateSearchResults(const string16& filter) {
    942   CookieTreeNode* root = GetRoot();
    943   ScopedBatchUpdateNotifier notifier(this, root);
    944   int num_children = root->child_count();
    945   notifier.StartBatchUpdate();
    946   for (int i = num_children - 1; i >= 0; --i)
    947     delete Remove(root, root->GetChild(i));
    948 
    949   PopulateCookieInfoWithFilter(data_container(), &notifier, filter);
    950   PopulateDatabaseInfoWithFilter(data_container(), &notifier, filter);
    951   PopulateLocalStorageInfoWithFilter(data_container(), &notifier, filter);
    952   PopulateSessionStorageInfoWithFilter(data_container(), &notifier, filter);
    953   PopulateAppCacheInfoWithFilter(data_container(), &notifier, filter);
    954   PopulateIndexedDBInfoWithFilter(data_container(), &notifier, filter);
    955   PopulateFileSystemInfoWithFilter(data_container(), &notifier, filter);
    956   PopulateQuotaInfoWithFilter(data_container(), &notifier, filter);
    957   PopulateServerBoundCertInfoWithFilter(data_container(), &notifier, filter);
    958 }
    959 
    960 const ExtensionSet* CookiesTreeModel::ExtensionsProtectingNode(
    961     const CookieTreeNode& cookie_node) {
    962   if (!special_storage_policy_.get())
    963     return NULL;
    964 
    965   CookieTreeNode::DetailedInfo info = cookie_node.GetDetailedInfo();
    966 
    967   if (!TypeIsProtected(info.node_type))
    968     return NULL;
    969 
    970   DCHECK(!info.origin.is_empty());
    971   return special_storage_policy_->ExtensionsProtectingOrigin(info.origin);
    972 }
    973 
    974 void CookiesTreeModel::AddCookiesTreeObserver(Observer* observer) {
    975   cookies_observer_list_.AddObserver(observer);
    976   // Call super so that TreeNodeModel can notify, too.
    977   ui::TreeNodeModel<CookieTreeNode>::AddObserver(observer);
    978 }
    979 
    980 void CookiesTreeModel::RemoveCookiesTreeObserver(Observer* observer) {
    981   cookies_observer_list_.RemoveObserver(observer);
    982   // Call super so that TreeNodeModel doesn't have dead pointers.
    983   ui::TreeNodeModel<CookieTreeNode>::RemoveObserver(observer);
    984 }
    985 
    986 void CookiesTreeModel::PopulateAppCacheInfo(LocalDataContainer* container) {
    987   ScopedBatchUpdateNotifier notifier(this, GetRoot());
    988   PopulateAppCacheInfoWithFilter(container, &notifier, string16());
    989 }
    990 
    991 void CookiesTreeModel::PopulateCookieInfo(LocalDataContainer* container) {
    992   ScopedBatchUpdateNotifier notifier(this, GetRoot());
    993   PopulateCookieInfoWithFilter(container, &notifier, string16());
    994 }
    995 
    996 void CookiesTreeModel::PopulateDatabaseInfo(LocalDataContainer* container) {
    997   ScopedBatchUpdateNotifier notifier(this, GetRoot());
    998   PopulateDatabaseInfoWithFilter(container, &notifier, string16());
    999 }
   1000 
   1001 void CookiesTreeModel::PopulateLocalStorageInfo(LocalDataContainer* container) {
   1002   ScopedBatchUpdateNotifier notifier(this, GetRoot());
   1003   PopulateLocalStorageInfoWithFilter(container, &notifier, string16());
   1004 }
   1005 
   1006 void CookiesTreeModel::PopulateSessionStorageInfo(
   1007       LocalDataContainer* container) {
   1008   ScopedBatchUpdateNotifier notifier(this, GetRoot());
   1009   PopulateSessionStorageInfoWithFilter(container, &notifier, string16());
   1010 }
   1011 
   1012 void CookiesTreeModel::PopulateIndexedDBInfo(LocalDataContainer* container){
   1013   ScopedBatchUpdateNotifier notifier(this, GetRoot());
   1014   PopulateIndexedDBInfoWithFilter(container, &notifier, string16());
   1015 }
   1016 
   1017 void CookiesTreeModel::PopulateFileSystemInfo(LocalDataContainer* container) {
   1018   ScopedBatchUpdateNotifier notifier(this, GetRoot());
   1019   PopulateFileSystemInfoWithFilter(container, &notifier, string16());
   1020 }
   1021 
   1022 void CookiesTreeModel::PopulateQuotaInfo(LocalDataContainer* container) {
   1023   ScopedBatchUpdateNotifier notifier(this, GetRoot());
   1024   PopulateQuotaInfoWithFilter(container, &notifier, string16());
   1025 }
   1026 
   1027 void CookiesTreeModel::PopulateServerBoundCertInfo(
   1028       LocalDataContainer* container) {
   1029   ScopedBatchUpdateNotifier notifier(this, GetRoot());
   1030   PopulateServerBoundCertInfoWithFilter(container, &notifier, string16());
   1031 }
   1032 
   1033 void CookiesTreeModel::PopulateFlashLSOInfo(
   1034       LocalDataContainer* container) {
   1035   ScopedBatchUpdateNotifier notifier(this, GetRoot());
   1036   PopulateFlashLSOInfoWithFilter(container, &notifier, string16());
   1037 }
   1038 
   1039 void CookiesTreeModel::PopulateAppCacheInfoWithFilter(
   1040     LocalDataContainer* container,
   1041     ScopedBatchUpdateNotifier* notifier,
   1042     const string16& filter) {
   1043   using appcache::AppCacheInfo;
   1044   typedef std::map<GURL, std::list<AppCacheInfo> > InfoByOrigin;
   1045   CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
   1046 
   1047   if (container->appcache_info_.empty())
   1048     return;
   1049 
   1050   notifier->StartBatchUpdate();
   1051   for (InfoByOrigin::iterator origin = container->appcache_info_.begin();
   1052        origin != container->appcache_info_.end(); ++origin) {
   1053     string16 host_node_name = UTF8ToUTF16(origin->first.host());
   1054     if (filter.empty() ||
   1055         (host_node_name.find(filter) != string16::npos)) {
   1056       CookieTreeHostNode* host_node = root->GetOrCreateHostNode(origin->first);
   1057       CookieTreeAppCachesNode* appcaches_node =
   1058           host_node->GetOrCreateAppCachesNode();
   1059 
   1060       for (std::list<AppCacheInfo>::iterator info = origin->second.begin();
   1061            info != origin->second.end(); ++info) {
   1062         appcaches_node->AddAppCacheNode(
   1063             new CookieTreeAppCacheNode(origin->first, info));
   1064       }
   1065     }
   1066   }
   1067 }
   1068 
   1069 void CookiesTreeModel::PopulateCookieInfoWithFilter(
   1070     LocalDataContainer* container,
   1071     ScopedBatchUpdateNotifier* notifier,
   1072     const string16& filter) {
   1073   CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
   1074 
   1075   notifier->StartBatchUpdate();
   1076   for (CookieList::iterator it = container->cookie_list_.begin();
   1077        it != container->cookie_list_.end(); ++it) {
   1078     std::string source_string = it->Source();
   1079     if (source_string.empty() || !group_by_cookie_source_) {
   1080       std::string domain = it->Domain();
   1081       if (domain.length() > 1 && domain[0] == '.')
   1082         domain = domain.substr(1);
   1083 
   1084       // We treat secure cookies just the same as normal ones.
   1085       source_string = std::string(chrome::kHttpScheme) +
   1086           content::kStandardSchemeSeparator + domain + "/";
   1087     }
   1088 
   1089     GURL source(source_string);
   1090     if (!filter.size() ||
   1091         (CookieTreeHostNode::TitleForUrl(source).find(filter) !=
   1092         string16::npos)) {
   1093       CookieTreeHostNode* host_node = root->GetOrCreateHostNode(source);
   1094       CookieTreeCookiesNode* cookies_node =
   1095           host_node->GetOrCreateCookiesNode();
   1096       CookieTreeCookieNode* new_cookie = new CookieTreeCookieNode(it);
   1097       cookies_node->AddCookieNode(new_cookie);
   1098     }
   1099   }
   1100 }
   1101 
   1102 void CookiesTreeModel::PopulateDatabaseInfoWithFilter(
   1103     LocalDataContainer* container,
   1104     ScopedBatchUpdateNotifier* notifier,
   1105     const string16& filter) {
   1106   CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
   1107 
   1108   if (container->database_info_list_.empty())
   1109     return;
   1110 
   1111   notifier->StartBatchUpdate();
   1112   for (DatabaseInfoList::iterator database_info =
   1113            container->database_info_list_.begin();
   1114        database_info != container->database_info_list_.end();
   1115        ++database_info) {
   1116     GURL origin(database_info->identifier.ToOrigin());
   1117 
   1118     if (!filter.size() ||
   1119         (CookieTreeHostNode::TitleForUrl(origin).find(filter) !=
   1120         string16::npos)) {
   1121       CookieTreeHostNode* host_node = root->GetOrCreateHostNode(origin);
   1122       CookieTreeDatabasesNode* databases_node =
   1123           host_node->GetOrCreateDatabasesNode();
   1124       databases_node->AddDatabaseNode(
   1125           new CookieTreeDatabaseNode(database_info));
   1126     }
   1127   }
   1128 }
   1129 
   1130 void CookiesTreeModel::PopulateLocalStorageInfoWithFilter(
   1131     LocalDataContainer* container,
   1132     ScopedBatchUpdateNotifier* notifier,
   1133     const string16& filter) {
   1134   CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
   1135 
   1136   if (container->local_storage_info_list_.empty())
   1137     return;
   1138 
   1139   notifier->StartBatchUpdate();
   1140   for (LocalStorageInfoList::iterator local_storage_info =
   1141            container->local_storage_info_list_.begin();
   1142        local_storage_info != container->local_storage_info_list_.end();
   1143        ++local_storage_info) {
   1144     const GURL& origin(local_storage_info->origin_url);
   1145 
   1146     if (!filter.size() ||
   1147         (CookieTreeHostNode::TitleForUrl(origin).find(filter) !=
   1148         std::string::npos)) {
   1149       CookieTreeHostNode* host_node = root->GetOrCreateHostNode(origin);
   1150       CookieTreeLocalStoragesNode* local_storages_node =
   1151           host_node->GetOrCreateLocalStoragesNode();
   1152       local_storages_node->AddLocalStorageNode(
   1153           new CookieTreeLocalStorageNode(local_storage_info));
   1154     }
   1155   }
   1156 }
   1157 
   1158 void CookiesTreeModel::PopulateSessionStorageInfoWithFilter(
   1159     LocalDataContainer* container,
   1160     ScopedBatchUpdateNotifier* notifier,
   1161     const string16& filter) {
   1162   CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
   1163 
   1164   if (container->session_storage_info_list_.empty())
   1165     return;
   1166 
   1167   notifier->StartBatchUpdate();
   1168   for (LocalStorageInfoList::iterator session_storage_info =
   1169            container->session_storage_info_list_.begin();
   1170        session_storage_info != container->session_storage_info_list_.end();
   1171        ++session_storage_info) {
   1172     const GURL& origin = session_storage_info->origin_url;
   1173 
   1174     if (!filter.size() ||
   1175         (CookieTreeHostNode::TitleForUrl(origin).find(filter) !=
   1176         string16::npos)) {
   1177       CookieTreeHostNode* host_node = root->GetOrCreateHostNode(origin);
   1178       CookieTreeSessionStoragesNode* session_storages_node =
   1179           host_node->GetOrCreateSessionStoragesNode();
   1180       session_storages_node->AddSessionStorageNode(
   1181           new CookieTreeSessionStorageNode(session_storage_info));
   1182     }
   1183   }
   1184 }
   1185 
   1186 void CookiesTreeModel::PopulateIndexedDBInfoWithFilter(
   1187     LocalDataContainer* container,
   1188     ScopedBatchUpdateNotifier* notifier,
   1189     const string16& filter) {
   1190   CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
   1191 
   1192   if (container->indexed_db_info_list_.empty())
   1193     return;
   1194 
   1195   notifier->StartBatchUpdate();
   1196   for (IndexedDBInfoList::iterator indexed_db_info =
   1197            container->indexed_db_info_list_.begin();
   1198        indexed_db_info != container->indexed_db_info_list_.end();
   1199        ++indexed_db_info) {
   1200     const GURL& origin = indexed_db_info->origin_;
   1201 
   1202     if (!filter.size() ||
   1203         (CookieTreeHostNode::TitleForUrl(origin).find(filter) !=
   1204         string16::npos)) {
   1205       CookieTreeHostNode* host_node = root->GetOrCreateHostNode(origin);
   1206       CookieTreeIndexedDBsNode* indexed_dbs_node =
   1207           host_node->GetOrCreateIndexedDBsNode();
   1208       indexed_dbs_node->AddIndexedDBNode(
   1209           new CookieTreeIndexedDBNode(indexed_db_info));
   1210     }
   1211   }
   1212 }
   1213 
   1214 void CookiesTreeModel::PopulateServerBoundCertInfoWithFilter(
   1215     LocalDataContainer* container,
   1216     ScopedBatchUpdateNotifier* notifier,
   1217     const string16& filter) {
   1218   CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
   1219 
   1220   if (container->server_bound_cert_list_.empty())
   1221     return;
   1222 
   1223   notifier->StartBatchUpdate();
   1224   for (ServerBoundCertList::iterator cert_info =
   1225            container->server_bound_cert_list_.begin();
   1226        cert_info != container->server_bound_cert_list_.end();
   1227        ++cert_info) {
   1228     GURL origin(cert_info->server_identifier());
   1229     if (!origin.is_valid()) {
   1230       // Domain Bound Cert.  Make a valid URL to satisfy the
   1231       // CookieTreeRootNode::GetOrCreateHostNode interface.
   1232       origin = GURL(std::string(chrome::kHttpsScheme) +
   1233           content::kStandardSchemeSeparator +
   1234           cert_info->server_identifier() + "/");
   1235     }
   1236     string16 title = CookieTreeHostNode::TitleForUrl(origin);
   1237     if (!filter.size() || title.find(filter) != string16::npos) {
   1238       CookieTreeHostNode* host_node = root->GetOrCreateHostNode(origin);
   1239       CookieTreeServerBoundCertsNode* server_bound_certs_node =
   1240           host_node->GetOrCreateServerBoundCertsNode();
   1241       server_bound_certs_node->AddServerBoundCertNode(
   1242           new CookieTreeServerBoundCertNode(cert_info));
   1243     }
   1244   }
   1245 }
   1246 
   1247 void CookiesTreeModel::PopulateFileSystemInfoWithFilter(
   1248     LocalDataContainer* container,
   1249     ScopedBatchUpdateNotifier* notifier,
   1250     const string16& filter) {
   1251   CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
   1252 
   1253   if (container->file_system_info_list_.empty())
   1254     return;
   1255 
   1256   notifier->StartBatchUpdate();
   1257   for (FileSystemInfoList::iterator file_system_info =
   1258            container->file_system_info_list_.begin();
   1259        file_system_info != container->file_system_info_list_.end();
   1260        ++file_system_info) {
   1261     GURL origin(file_system_info->origin);
   1262 
   1263     if (!filter.size() ||
   1264         (CookieTreeHostNode::TitleForUrl(origin).find(filter) !=
   1265         string16::npos)) {
   1266       CookieTreeHostNode* host_node = root->GetOrCreateHostNode(origin);
   1267       CookieTreeFileSystemsNode* file_systems_node =
   1268           host_node->GetOrCreateFileSystemsNode();
   1269       file_systems_node->AddFileSystemNode(
   1270           new CookieTreeFileSystemNode(file_system_info));
   1271     }
   1272   }
   1273 }
   1274 
   1275 void CookiesTreeModel::PopulateQuotaInfoWithFilter(
   1276     LocalDataContainer* container,
   1277     ScopedBatchUpdateNotifier* notifier,
   1278     const string16& filter) {
   1279   CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
   1280 
   1281   if (container->quota_info_list_.empty())
   1282     return;
   1283 
   1284   notifier->StartBatchUpdate();
   1285   for (QuotaInfoList::iterator quota_info = container->quota_info_list_.begin();
   1286        quota_info != container->quota_info_list_.end();
   1287        ++quota_info) {
   1288     if (!filter.size() ||
   1289         (UTF8ToUTF16(quota_info->host).find(filter) != string16::npos)) {
   1290       CookieTreeHostNode* host_node =
   1291           root->GetOrCreateHostNode(GURL("http://" + quota_info->host));
   1292       host_node->UpdateOrCreateQuotaNode(quota_info);
   1293     }
   1294   }
   1295 }
   1296 
   1297 void CookiesTreeModel::PopulateFlashLSOInfoWithFilter(
   1298     LocalDataContainer* container,
   1299     ScopedBatchUpdateNotifier* notifier,
   1300     const string16& filter) {
   1301   CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
   1302 
   1303   if (container->flash_lso_domain_list_.empty())
   1304     return;
   1305 
   1306   std::string filter_utf8 = UTF16ToUTF8(filter);
   1307   notifier->StartBatchUpdate();
   1308   for (std::vector<std::string>::iterator it =
   1309            container->flash_lso_domain_list_.begin();
   1310        it != container->flash_lso_domain_list_.end(); ++it) {
   1311     if (!filter_utf8.size() || it->find(filter_utf8) != std::string::npos) {
   1312       // Create a fake origin for GetOrCreateHostNode().
   1313       GURL origin("http://" + *it);
   1314       CookieTreeHostNode* host_node = root->GetOrCreateHostNode(origin);
   1315       host_node->GetOrCreateFlashLSONode(*it);
   1316     }
   1317   }
   1318 }
   1319 
   1320 void CookiesTreeModel::NotifyObserverBeginBatch() {
   1321   // Only notify the model once if we're batching in a nested manner.
   1322   if (batch_update_++ == 0) {
   1323     FOR_EACH_OBSERVER(Observer,
   1324                       cookies_observer_list_,
   1325                       TreeModelBeginBatch(this));
   1326   }
   1327 }
   1328 
   1329 void CookiesTreeModel::NotifyObserverEndBatch() {
   1330   // Only notify the observers if this is the outermost call to EndBatch() if
   1331   // called in a nested manner.
   1332   if (--batch_update_ == 0) {
   1333     FOR_EACH_OBSERVER(Observer,
   1334                       cookies_observer_list_,
   1335                       TreeModelEndBatch(this));
   1336   }
   1337 }
   1338