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