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
32namespace {
33
34struct 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.
41struct 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
65std::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
113bool 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
145LocalDataContainer* 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
155CookieTreeNode::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
167CookieTreeNode::DetailedInfo::~DetailedInfo() {}
168
169CookieTreeNode::DetailedInfo& CookieTreeNode::DetailedInfo::Init(
170    NodeType type) {
171  DCHECK_EQ(TYPE_NONE, node_type);
172  node_type = type;
173  return *this;
174}
175
176CookieTreeNode::DetailedInfo& CookieTreeNode::DetailedInfo::InitHost() {
177  Init(TYPE_HOST);
178  return *this;
179}
180
181CookieTreeNode::DetailedInfo& CookieTreeNode::DetailedInfo::InitCookie(
182    const net::CanonicalCookie* cookie) {
183  Init(TYPE_COOKIE);
184  this->cookie = cookie;
185  return *this;
186}
187
188CookieTreeNode::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
196CookieTreeNode::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
205CookieTreeNode::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
214CookieTreeNode::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
223CookieTreeNode::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
231CookieTreeNode::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
239CookieTreeNode::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
246CookieTreeNode::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
253CookieTreeNode::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
263void CookieTreeNode::DeleteStoredObjects() {
264  std::for_each(children().begin(),
265                children().end(),
266                std::mem_fun(&CookieTreeNode::DeleteStoredObjects));
267}
268
269CookiesTreeModel* CookieTreeNode::GetModel() const {
270  if (parent())
271    return parent()->GetModel();
272  else
273    return NULL;
274}
275
276///////////////////////////////////////////////////////////////////////////////
277// CookieTreeCookieNode, public:
278
279CookieTreeCookieNode::CookieTreeCookieNode(
280    std::list<net::CanonicalCookie>::iterator cookie)
281    : CookieTreeNode(UTF8ToUTF16(cookie->Name())),
282      cookie_(cookie) {
283}
284
285CookieTreeCookieNode::~CookieTreeCookieNode() {}
286
287void CookieTreeCookieNode::DeleteStoredObjects() {
288  LocalDataContainer* container = GetLocalDataContainerForNode(this);
289  CHECK(container);
290  container->cookie_helper_->DeleteCookie(*cookie_);
291  container->cookie_list_.erase(cookie_);
292}
293
294CookieTreeNode::DetailedInfo CookieTreeCookieNode::GetDetailedInfo() const {
295  return DetailedInfo().InitCookie(&*cookie_);
296}
297
298///////////////////////////////////////////////////////////////////////////////
299// CookieTreeAppCacheNode, public:
300
301CookieTreeAppCacheNode::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
309CookieTreeAppCacheNode::~CookieTreeAppCacheNode() {
310}
311
312void 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
323CookieTreeNode::DetailedInfo CookieTreeAppCacheNode::GetDetailedInfo() const {
324  return DetailedInfo().InitAppCache(origin_url_, &*appcache_info_);
325}
326
327///////////////////////////////////////////////////////////////////////////////
328// CookieTreeDatabaseNode, public:
329
330CookieTreeDatabaseNode::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
338CookieTreeDatabaseNode::~CookieTreeDatabaseNode() {}
339
340void 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
350CookieTreeNode::DetailedInfo CookieTreeDatabaseNode::GetDetailedInfo() const {
351  return DetailedInfo().InitDatabase(&*database_info_);
352}
353
354///////////////////////////////////////////////////////////////////////////////
355// CookieTreeLocalStorageNode, public:
356
357CookieTreeLocalStorageNode::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
364CookieTreeLocalStorageNode::~CookieTreeLocalStorageNode() {}
365
366void 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
376CookieTreeNode::DetailedInfo
377CookieTreeLocalStorageNode::GetDetailedInfo() const {
378  return DetailedInfo().InitLocalStorage(
379      &*local_storage_info_);
380}
381
382///////////////////////////////////////////////////////////////////////////////
383// CookieTreeSessionStorageNode, public:
384
385CookieTreeSessionStorageNode::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
392CookieTreeSessionStorageNode::~CookieTreeSessionStorageNode() {}
393
394void CookieTreeSessionStorageNode::DeleteStoredObjects() {
395  LocalDataContainer* container = GetLocalDataContainerForNode(this);
396
397  if (container) {
398    container->session_storage_info_list_.erase(session_storage_info_);
399  }
400}
401
402CookieTreeNode::DetailedInfo
403CookieTreeSessionStorageNode::GetDetailedInfo() const {
404  return DetailedInfo().InitSessionStorage(&*session_storage_info_);
405}
406
407///////////////////////////////////////////////////////////////////////////////
408// CookieTreeIndexedDBNode, public:
409
410CookieTreeIndexedDBNode::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
418CookieTreeIndexedDBNode::~CookieTreeIndexedDBNode() {}
419
420void 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
430CookieTreeNode::DetailedInfo CookieTreeIndexedDBNode::GetDetailedInfo() const {
431  return DetailedInfo().InitIndexedDB(&*indexed_db_info_);
432}
433
434///////////////////////////////////////////////////////////////////////////////
435// CookieTreeFileSystemNode, public:
436
437CookieTreeFileSystemNode::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
445CookieTreeFileSystemNode::~CookieTreeFileSystemNode() {}
446
447void 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
457CookieTreeNode::DetailedInfo CookieTreeFileSystemNode::GetDetailedInfo() const {
458  return DetailedInfo().InitFileSystem(&*file_system_info_);
459}
460
461///////////////////////////////////////////////////////////////////////////////
462// CookieTreeQuotaNode, public:
463
464CookieTreeQuotaNode::CookieTreeQuotaNode(
465    std::list<BrowsingDataQuotaHelper::QuotaInfo>::iterator quota_info)
466    : CookieTreeNode(UTF8ToUTF16(quota_info->host)),
467      quota_info_(quota_info) {
468}
469
470CookieTreeQuotaNode::~CookieTreeQuotaNode() {}
471
472void 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
483CookieTreeNode::DetailedInfo CookieTreeQuotaNode::GetDetailedInfo() const {
484  return DetailedInfo().InitQuota(&*quota_info_);
485}
486
487///////////////////////////////////////////////////////////////////////////////
488// CookieTreeServerBoundCertNode, public:
489
490CookieTreeServerBoundCertNode::CookieTreeServerBoundCertNode(
491      net::ServerBoundCertStore::ServerBoundCertList::iterator cert)
492    : CookieTreeNode(ASCIIToUTF16(cert->server_identifier())),
493      server_bound_cert_(cert) {
494}
495
496CookieTreeServerBoundCertNode::~CookieTreeServerBoundCertNode() {}
497
498void 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
508CookieTreeNode::DetailedInfo
509CookieTreeServerBoundCertNode::GetDetailedInfo() const {
510  return DetailedInfo().InitServerBoundCert(&*server_bound_cert_);
511}
512
513///////////////////////////////////////////////////////////////////////////////
514// CookieTreeRootNode, public:
515
516CookieTreeRootNode::CookieTreeRootNode(CookiesTreeModel* model)
517    : model_(model) {
518}
519
520CookieTreeRootNode::~CookieTreeRootNode() {}
521
522CookieTreeHostNode* 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
542CookiesTreeModel* CookieTreeRootNode::GetModel() const {
543  return model_;
544}
545
546CookieTreeNode::DetailedInfo CookieTreeRootNode::GetDetailedInfo() const {
547  return DetailedInfo().Init(DetailedInfo::TYPE_ROOT);
548}
549
550///////////////////////////////////////////////////////////////////////////////
551// CookieTreeHostNode, public:
552
553// static
554string16 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
561CookieTreeHostNode::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
576CookieTreeHostNode::~CookieTreeHostNode() {}
577
578const 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
584CookieTreeNode::DetailedInfo CookieTreeHostNode::GetDetailedInfo() const {
585  return DetailedInfo().InitHost();
586}
587
588CookieTreeCookiesNode* 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
596CookieTreeDatabasesNode* 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
604CookieTreeLocalStoragesNode*
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
613CookieTreeSessionStoragesNode*
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
622CookieTreeAppCachesNode* 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
630CookieTreeIndexedDBsNode* 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
638CookieTreeFileSystemsNode* 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
646CookieTreeQuotaNode* 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
655CookieTreeServerBoundCertsNode*
656CookieTreeHostNode::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
664CookieTreeFlashLSONode* 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
674void 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
689bool CookieTreeHostNode::CanCreateContentException() const {
690  return !url_.SchemeIsFile();
691}
692
693///////////////////////////////////////////////////////////////////////////////
694// CookieTreeCookiesNode, public:
695
696CookieTreeCookiesNode::CookieTreeCookiesNode()
697    : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_COOKIES)) {
698}
699
700CookieTreeCookiesNode::~CookieTreeCookiesNode() {
701}
702
703CookieTreeNode::DetailedInfo CookieTreeCookiesNode::GetDetailedInfo() const {
704  return DetailedInfo().Init(DetailedInfo::TYPE_COOKIES);
705}
706
707///////////////////////////////////////////////////////////////////////////////
708// CookieTreeAppCachesNode, public:
709
710CookieTreeAppCachesNode::CookieTreeAppCachesNode()
711    : CookieTreeNode(l10n_util::GetStringUTF16(
712                         IDS_COOKIES_APPLICATION_CACHES)) {
713}
714
715CookieTreeAppCachesNode::~CookieTreeAppCachesNode() {}
716
717CookieTreeNode::DetailedInfo CookieTreeAppCachesNode::GetDetailedInfo() const {
718  return DetailedInfo().Init(DetailedInfo::TYPE_APPCACHES);
719}
720
721///////////////////////////////////////////////////////////////////////////////
722// CookieTreeDatabasesNode, public:
723
724CookieTreeDatabasesNode::CookieTreeDatabasesNode()
725    : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_WEB_DATABASES)) {
726}
727
728CookieTreeDatabasesNode::~CookieTreeDatabasesNode() {}
729
730CookieTreeNode::DetailedInfo CookieTreeDatabasesNode::GetDetailedInfo() const {
731  return DetailedInfo().Init(DetailedInfo::TYPE_DATABASES);
732}
733
734///////////////////////////////////////////////////////////////////////////////
735// CookieTreeLocalStoragesNode, public:
736
737CookieTreeLocalStoragesNode::CookieTreeLocalStoragesNode()
738    : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_LOCAL_STORAGE)) {
739}
740
741CookieTreeLocalStoragesNode::~CookieTreeLocalStoragesNode() {}
742
743CookieTreeNode::DetailedInfo
744CookieTreeLocalStoragesNode::GetDetailedInfo() const {
745  return DetailedInfo().Init(DetailedInfo::TYPE_LOCAL_STORAGES);
746}
747
748///////////////////////////////////////////////////////////////////////////////
749// CookieTreeSessionStoragesNode, public:
750
751CookieTreeSessionStoragesNode::CookieTreeSessionStoragesNode()
752    : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_SESSION_STORAGE)) {
753}
754
755CookieTreeSessionStoragesNode::~CookieTreeSessionStoragesNode() {}
756
757CookieTreeNode::DetailedInfo
758CookieTreeSessionStoragesNode::GetDetailedInfo() const {
759  return DetailedInfo().Init(DetailedInfo::TYPE_SESSION_STORAGES);
760}
761
762///////////////////////////////////////////////////////////////////////////////
763// CookieTreeIndexedDBsNode, public:
764
765CookieTreeIndexedDBsNode::CookieTreeIndexedDBsNode()
766    : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_INDEXED_DBS)) {
767}
768
769CookieTreeIndexedDBsNode::~CookieTreeIndexedDBsNode() {}
770
771CookieTreeNode::DetailedInfo
772CookieTreeIndexedDBsNode::GetDetailedInfo() const {
773  return DetailedInfo().Init(DetailedInfo::TYPE_INDEXED_DBS);
774}
775
776///////////////////////////////////////////////////////////////////////////////
777// CookieTreeFileSystemsNode, public:
778
779CookieTreeFileSystemsNode::CookieTreeFileSystemsNode()
780    : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_FILE_SYSTEMS)) {
781}
782
783CookieTreeFileSystemsNode::~CookieTreeFileSystemsNode() {}
784
785CookieTreeNode::DetailedInfo
786CookieTreeFileSystemsNode::GetDetailedInfo() const {
787  return DetailedInfo().Init(DetailedInfo::TYPE_FILE_SYSTEMS);
788}
789
790///////////////////////////////////////////////////////////////////////////////
791// CookieTreeServerBoundCertsNode, public:
792
793CookieTreeServerBoundCertsNode::CookieTreeServerBoundCertsNode()
794    : CookieTreeNode(
795        l10n_util::GetStringUTF16(IDS_COOKIES_SERVER_BOUND_CERTS)) {
796}
797
798CookieTreeServerBoundCertsNode::~CookieTreeServerBoundCertsNode() {}
799
800CookieTreeNode::DetailedInfo
801CookieTreeServerBoundCertsNode::GetDetailedInfo() const {
802  return DetailedInfo().Init(DetailedInfo::TYPE_SERVER_BOUND_CERTS);
803}
804
805void 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
815CookieTreeFlashLSONode::CookieTreeFlashLSONode(
816    const std::string& domain)
817    : domain_(domain) {}
818CookieTreeFlashLSONode::~CookieTreeFlashLSONode() {}
819
820void 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
831CookieTreeNode::DetailedInfo CookieTreeFlashLSONode::GetDetailedInfo() const {
832  return DetailedInfo().InitFlashLSO(domain_);
833}
834
835///////////////////////////////////////////////////////////////////////////////
836// ScopedBatchUpdateNotifier
837CookiesTreeModel::ScopedBatchUpdateNotifier::ScopedBatchUpdateNotifier(
838  CookiesTreeModel* model, CookieTreeNode* node)
839      : model_(model), node_(node), batch_in_progress_(false) {
840}
841
842CookiesTreeModel::ScopedBatchUpdateNotifier::~ScopedBatchUpdateNotifier() {
843  if (batch_in_progress_) {
844    model_->NotifyObserverTreeNodeChanged(node_);
845    model_->NotifyObserverEndBatch();
846  }
847}
848
849void CookiesTreeModel::ScopedBatchUpdateNotifier::StartBatchUpdate() {
850  if (!batch_in_progress_) {
851    model_->NotifyObserverBeginBatch();
852    batch_in_progress_ = true;
853  }
854}
855
856///////////////////////////////////////////////////////////////////////////////
857// CookiesTreeModel, public:
858CookiesTreeModel::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
870CookiesTreeModel::~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.
879void 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.
891int 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
920void 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
931void 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
941void 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
960const 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
974void 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
980void 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
986void CookiesTreeModel::PopulateAppCacheInfo(LocalDataContainer* container) {
987  ScopedBatchUpdateNotifier notifier(this, GetRoot());
988  PopulateAppCacheInfoWithFilter(container, &notifier, string16());
989}
990
991void CookiesTreeModel::PopulateCookieInfo(LocalDataContainer* container) {
992  ScopedBatchUpdateNotifier notifier(this, GetRoot());
993  PopulateCookieInfoWithFilter(container, &notifier, string16());
994}
995
996void CookiesTreeModel::PopulateDatabaseInfo(LocalDataContainer* container) {
997  ScopedBatchUpdateNotifier notifier(this, GetRoot());
998  PopulateDatabaseInfoWithFilter(container, &notifier, string16());
999}
1000
1001void CookiesTreeModel::PopulateLocalStorageInfo(LocalDataContainer* container) {
1002  ScopedBatchUpdateNotifier notifier(this, GetRoot());
1003  PopulateLocalStorageInfoWithFilter(container, &notifier, string16());
1004}
1005
1006void CookiesTreeModel::PopulateSessionStorageInfo(
1007      LocalDataContainer* container) {
1008  ScopedBatchUpdateNotifier notifier(this, GetRoot());
1009  PopulateSessionStorageInfoWithFilter(container, &notifier, string16());
1010}
1011
1012void CookiesTreeModel::PopulateIndexedDBInfo(LocalDataContainer* container){
1013  ScopedBatchUpdateNotifier notifier(this, GetRoot());
1014  PopulateIndexedDBInfoWithFilter(container, &notifier, string16());
1015}
1016
1017void CookiesTreeModel::PopulateFileSystemInfo(LocalDataContainer* container) {
1018  ScopedBatchUpdateNotifier notifier(this, GetRoot());
1019  PopulateFileSystemInfoWithFilter(container, &notifier, string16());
1020}
1021
1022void CookiesTreeModel::PopulateQuotaInfo(LocalDataContainer* container) {
1023  ScopedBatchUpdateNotifier notifier(this, GetRoot());
1024  PopulateQuotaInfoWithFilter(container, &notifier, string16());
1025}
1026
1027void CookiesTreeModel::PopulateServerBoundCertInfo(
1028      LocalDataContainer* container) {
1029  ScopedBatchUpdateNotifier notifier(this, GetRoot());
1030  PopulateServerBoundCertInfoWithFilter(container, &notifier, string16());
1031}
1032
1033void CookiesTreeModel::PopulateFlashLSOInfo(
1034      LocalDataContainer* container) {
1035  ScopedBatchUpdateNotifier notifier(this, GetRoot());
1036  PopulateFlashLSOInfoWithFilter(container, &notifier, string16());
1037}
1038
1039void 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
1069void 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
1102void 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
1130void 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
1158void 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
1186void 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
1214void 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
1247void 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
1275void 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
1297void 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
1320void 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
1329void 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