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