Upstream version 9.38.198.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 <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 "content/public/common/url_constants.h"
21 #include "grit/generated_resources.h"
22 #include "grit/theme_resources.h"
23 #include "grit/ui_resources.h"
24 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
25 #include "net/cookies/canonical_cookie.h"
26 #include "net/url_request/url_request_context.h"
27 #include "ui/base/l10n/l10n_util.h"
28 #include "ui/base/resource/resource_bundle.h"
29 #include "ui/gfx/image/image_skia.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
36 namespace {
37
38 struct 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.
45 struct 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
69 std::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)
118 bool 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
153 LocalDataContainer* 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
163 CookieTreeNode::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
177 CookieTreeNode::DetailedInfo::~DetailedInfo() {}
178
179 CookieTreeNode::DetailedInfo& CookieTreeNode::DetailedInfo::Init(
180     NodeType type) {
181   DCHECK_EQ(TYPE_NONE, node_type);
182   node_type = type;
183   return *this;
184 }
185
186 CookieTreeNode::DetailedInfo& CookieTreeNode::DetailedInfo::InitHost() {
187   Init(TYPE_HOST);
188   return *this;
189 }
190
191 CookieTreeNode::DetailedInfo& CookieTreeNode::DetailedInfo::InitCookie(
192     const net::CanonicalCookie* cookie) {
193   Init(TYPE_COOKIE);
194   this->cookie = cookie;
195   return *this;
196 }
197
198 CookieTreeNode::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
206 CookieTreeNode::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
215 CookieTreeNode::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
224 CookieTreeNode::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
233 CookieTreeNode::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
241 CookieTreeNode::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
249 CookieTreeNode::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
256 CookieTreeNode::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
263 CookieTreeNode::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
271 CookieTreeNode::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
281 void CookieTreeNode::DeleteStoredObjects() {
282   std::for_each(children().begin(),
283                 children().end(),
284                 std::mem_fun(&CookieTreeNode::DeleteStoredObjects));
285 }
286
287 CookiesTreeModel* CookieTreeNode::GetModel() const {
288   if (parent())
289     return parent()->GetModel();
290   else
291     return NULL;
292 }
293
294 ///////////////////////////////////////////////////////////////////////////////
295 // CookieTreeCookieNode, public:
296
297 CookieTreeCookieNode::CookieTreeCookieNode(
298     std::list<net::CanonicalCookie>::iterator cookie)
299     : CookieTreeNode(base::UTF8ToUTF16(cookie->Name())),
300       cookie_(cookie) {
301 }
302
303 CookieTreeCookieNode::~CookieTreeCookieNode() {}
304
305 void CookieTreeCookieNode::DeleteStoredObjects() {
306   LocalDataContainer* container = GetLocalDataContainerForNode(this);
307   container->cookie_helper_->DeleteCookie(*cookie_);
308   container->cookie_list_.erase(cookie_);
309 }
310
311 CookieTreeNode::DetailedInfo CookieTreeCookieNode::GetDetailedInfo() const {
312   return DetailedInfo().InitCookie(&*cookie_);
313 }
314
315 ///////////////////////////////////////////////////////////////////////////////
316 // CookieTreeAppCacheNode, public:
317
318 CookieTreeAppCacheNode::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
326 CookieTreeAppCacheNode::~CookieTreeAppCacheNode() {
327 }
328
329 void 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
340 CookieTreeNode::DetailedInfo CookieTreeAppCacheNode::GetDetailedInfo() const {
341   return DetailedInfo().InitAppCache(origin_url_, &*appcache_info_);
342 }
343
344 ///////////////////////////////////////////////////////////////////////////////
345 // CookieTreeDatabaseNode, public:
346
347 CookieTreeDatabaseNode::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
355 CookieTreeDatabaseNode::~CookieTreeDatabaseNode() {}
356
357 void 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
367 CookieTreeNode::DetailedInfo CookieTreeDatabaseNode::GetDetailedInfo() const {
368   return DetailedInfo().InitDatabase(&*database_info_);
369 }
370
371 ///////////////////////////////////////////////////////////////////////////////
372 // CookieTreeLocalStorageNode, public:
373
374 CookieTreeLocalStorageNode::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
381 CookieTreeLocalStorageNode::~CookieTreeLocalStorageNode() {}
382
383 void 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
393 CookieTreeNode::DetailedInfo
394 CookieTreeLocalStorageNode::GetDetailedInfo() const {
395   return DetailedInfo().InitLocalStorage(
396       &*local_storage_info_);
397 }
398
399 ///////////////////////////////////////////////////////////////////////////////
400 // CookieTreeSessionStorageNode, public:
401
402 CookieTreeSessionStorageNode::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
410 CookieTreeSessionStorageNode::~CookieTreeSessionStorageNode() {}
411
412 void 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
424 CookieTreeNode::DetailedInfo
425 CookieTreeSessionStorageNode::GetDetailedInfo() const {
426   return DetailedInfo().InitSessionStorage(&*session_storage_info_);
427 }
428
429 ///////////////////////////////////////////////////////////////////////////////
430 // CookieTreeIndexedDBNode, public:
431
432 CookieTreeIndexedDBNode::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
440 CookieTreeIndexedDBNode::~CookieTreeIndexedDBNode() {}
441
442 void 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
452 CookieTreeNode::DetailedInfo CookieTreeIndexedDBNode::GetDetailedInfo() const {
453   return DetailedInfo().InitIndexedDB(&*indexed_db_info_);
454 }
455
456 ///////////////////////////////////////////////////////////////////////////////
457 // CookieTreeFileSystemNode, public:
458
459 CookieTreeFileSystemNode::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
467 CookieTreeFileSystemNode::~CookieTreeFileSystemNode() {}
468
469 void 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
479 CookieTreeNode::DetailedInfo CookieTreeFileSystemNode::GetDetailedInfo() const {
480   return DetailedInfo().InitFileSystem(&*file_system_info_);
481 }
482
483 ///////////////////////////////////////////////////////////////////////////////
484 // CookieTreeQuotaNode, public:
485
486 CookieTreeQuotaNode::CookieTreeQuotaNode(
487     std::list<BrowsingDataQuotaHelper::QuotaInfo>::iterator quota_info)
488     : CookieTreeNode(base::UTF8ToUTF16(quota_info->host)),
489       quota_info_(quota_info) {
490 }
491
492 CookieTreeQuotaNode::~CookieTreeQuotaNode() {}
493
494 void 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
505 CookieTreeNode::DetailedInfo CookieTreeQuotaNode::GetDetailedInfo() const {
506   return DetailedInfo().InitQuota(&*quota_info_);
507 }
508
509 ///////////////////////////////////////////////////////////////////////////////
510 // CookieTreeChannelIDNode, public:
511
512 CookieTreeChannelIDNode::CookieTreeChannelIDNode(
513       net::ChannelIDStore::ChannelIDList::iterator channel_id)
514     : CookieTreeNode(base::ASCIIToUTF16(channel_id->server_identifier())),
515       channel_id_(channel_id) {
516 }
517
518 CookieTreeChannelIDNode::~CookieTreeChannelIDNode() {}
519
520 void 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
530 CookieTreeNode::DetailedInfo
531 CookieTreeChannelIDNode::GetDetailedInfo() const {
532   return DetailedInfo().InitChannelID(&*channel_id_);
533 }
534
535 ///////////////////////////////////////////////////////////////////////////////
536 // CookieTreeServiceWorkerNode, public:
537
538 CookieTreeServiceWorkerNode::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
544 CookieTreeServiceWorkerNode::~CookieTreeServiceWorkerNode() {
545 }
546
547 void 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
557 CookieTreeNode::DetailedInfo CookieTreeServiceWorkerNode::GetDetailedInfo()
558     const {
559   return DetailedInfo().InitServiceWorker(&*service_worker_info_);
560 }
561
562 ///////////////////////////////////////////////////////////////////////////////
563 // CookieTreeRootNode, public:
564
565 CookieTreeRootNode::CookieTreeRootNode(CookiesTreeModel* model)
566     : model_(model) {
567 }
568
569 CookieTreeRootNode::~CookieTreeRootNode() {}
570
571 CookieTreeHostNode* 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
591 CookiesTreeModel* CookieTreeRootNode::GetModel() const {
592   return model_;
593 }
594
595 CookieTreeNode::DetailedInfo CookieTreeRootNode::GetDetailedInfo() const {
596   return DetailedInfo().Init(DetailedInfo::TYPE_ROOT);
597 }
598
599 ///////////////////////////////////////////////////////////////////////////////
600 // CookieTreeHostNode, public:
601
602 // static
603 base::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
610 CookieTreeHostNode::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
627 CookieTreeHostNode::~CookieTreeHostNode() {}
628
629 const 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
635 CookieTreeNode::DetailedInfo CookieTreeHostNode::GetDetailedInfo() const {
636   return DetailedInfo().InitHost();
637 }
638
639 CookieTreeCookiesNode* 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
647 CookieTreeDatabasesNode* 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
655 CookieTreeLocalStoragesNode*
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
664 CookieTreeSessionStoragesNode*
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
673 CookieTreeAppCachesNode* 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
681 CookieTreeIndexedDBsNode* 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
689 CookieTreeFileSystemsNode* 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
697 CookieTreeQuotaNode* 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
706 CookieTreeChannelIDsNode*
707 CookieTreeHostNode::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
715 CookieTreeServiceWorkersNode*
716 CookieTreeHostNode::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
724 CookieTreeFlashLSONode* 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
734 void 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
749 bool CookieTreeHostNode::CanCreateContentException() const {
750   return !url_.SchemeIsFile();
751 }
752
753 ///////////////////////////////////////////////////////////////////////////////
754 // CookieTreeCookiesNode, public:
755
756 CookieTreeCookiesNode::CookieTreeCookiesNode()
757     : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_COOKIES)) {
758 }
759
760 CookieTreeCookiesNode::~CookieTreeCookiesNode() {
761 }
762
763 CookieTreeNode::DetailedInfo CookieTreeCookiesNode::GetDetailedInfo() const {
764   return DetailedInfo().Init(DetailedInfo::TYPE_COOKIES);
765 }
766
767 ///////////////////////////////////////////////////////////////////////////////
768 // CookieTreeAppCachesNode, public:
769
770 CookieTreeAppCachesNode::CookieTreeAppCachesNode()
771     : CookieTreeNode(l10n_util::GetStringUTF16(
772                          IDS_COOKIES_APPLICATION_CACHES)) {
773 }
774
775 CookieTreeAppCachesNode::~CookieTreeAppCachesNode() {}
776
777 CookieTreeNode::DetailedInfo CookieTreeAppCachesNode::GetDetailedInfo() const {
778   return DetailedInfo().Init(DetailedInfo::TYPE_APPCACHES);
779 }
780
781 ///////////////////////////////////////////////////////////////////////////////
782 // CookieTreeDatabasesNode, public:
783
784 CookieTreeDatabasesNode::CookieTreeDatabasesNode()
785     : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_WEB_DATABASES)) {
786 }
787
788 CookieTreeDatabasesNode::~CookieTreeDatabasesNode() {}
789
790 CookieTreeNode::DetailedInfo CookieTreeDatabasesNode::GetDetailedInfo() const {
791   return DetailedInfo().Init(DetailedInfo::TYPE_DATABASES);
792 }
793
794 ///////////////////////////////////////////////////////////////////////////////
795 // CookieTreeLocalStoragesNode, public:
796
797 CookieTreeLocalStoragesNode::CookieTreeLocalStoragesNode()
798     : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_LOCAL_STORAGE)) {
799 }
800
801 CookieTreeLocalStoragesNode::~CookieTreeLocalStoragesNode() {}
802
803 CookieTreeNode::DetailedInfo
804 CookieTreeLocalStoragesNode::GetDetailedInfo() const {
805   return DetailedInfo().Init(DetailedInfo::TYPE_LOCAL_STORAGES);
806 }
807
808 ///////////////////////////////////////////////////////////////////////////////
809 // CookieTreeSessionStoragesNode, public:
810
811 CookieTreeSessionStoragesNode::CookieTreeSessionStoragesNode()
812     : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_SESSION_STORAGE)) {
813 }
814
815 CookieTreeSessionStoragesNode::~CookieTreeSessionStoragesNode() {}
816
817 CookieTreeNode::DetailedInfo
818 CookieTreeSessionStoragesNode::GetDetailedInfo() const {
819   return DetailedInfo().Init(DetailedInfo::TYPE_SESSION_STORAGES);
820 }
821
822 ///////////////////////////////////////////////////////////////////////////////
823 // CookieTreeIndexedDBsNode, public:
824
825 CookieTreeIndexedDBsNode::CookieTreeIndexedDBsNode()
826     : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_INDEXED_DBS)) {
827 }
828
829 CookieTreeIndexedDBsNode::~CookieTreeIndexedDBsNode() {}
830
831 CookieTreeNode::DetailedInfo
832 CookieTreeIndexedDBsNode::GetDetailedInfo() const {
833   return DetailedInfo().Init(DetailedInfo::TYPE_INDEXED_DBS);
834 }
835
836 ///////////////////////////////////////////////////////////////////////////////
837 // CookieTreeFileSystemsNode, public:
838
839 CookieTreeFileSystemsNode::CookieTreeFileSystemsNode()
840     : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_FILE_SYSTEMS)) {
841 }
842
843 CookieTreeFileSystemsNode::~CookieTreeFileSystemsNode() {}
844
845 CookieTreeNode::DetailedInfo
846 CookieTreeFileSystemsNode::GetDetailedInfo() const {
847   return DetailedInfo().Init(DetailedInfo::TYPE_FILE_SYSTEMS);
848 }
849
850 ///////////////////////////////////////////////////////////////////////////////
851 // CookieTreeChannelIDsNode, public:
852
853 CookieTreeChannelIDsNode::CookieTreeChannelIDsNode()
854     : CookieTreeNode(
855         l10n_util::GetStringUTF16(IDS_COOKIES_CHANNEL_IDS)) {
856 }
857
858 CookieTreeChannelIDsNode::~CookieTreeChannelIDsNode() {}
859
860 CookieTreeNode::DetailedInfo
861 CookieTreeChannelIDsNode::GetDetailedInfo() const {
862   return DetailedInfo().Init(DetailedInfo::TYPE_CHANNEL_IDS);
863 }
864
865 void 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
876 CookieTreeServiceWorkersNode::CookieTreeServiceWorkersNode()
877     : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_SERVICE_WORKERS)) {
878 }
879
880 CookieTreeServiceWorkersNode::~CookieTreeServiceWorkersNode() {
881 }
882
883 CookieTreeNode::DetailedInfo CookieTreeServiceWorkersNode::GetDetailedInfo()
884     const {
885   return DetailedInfo().Init(DetailedInfo::TYPE_SERVICE_WORKERS);
886 }
887
888 ///////////////////////////////////////////////////////////////////////////////
889 // CookieTreeFlashLSONode
890 CookieTreeFlashLSONode::CookieTreeFlashLSONode(
891     const std::string& domain)
892     : domain_(domain) {}
893 CookieTreeFlashLSONode::~CookieTreeFlashLSONode() {}
894
895 void 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
904 CookieTreeNode::DetailedInfo CookieTreeFlashLSONode::GetDetailedInfo() const {
905   return DetailedInfo().InitFlashLSO(domain_);
906 }
907
908 ///////////////////////////////////////////////////////////////////////////////
909 // ScopedBatchUpdateNotifier
910 CookiesTreeModel::ScopedBatchUpdateNotifier::ScopedBatchUpdateNotifier(
911   CookiesTreeModel* model, CookieTreeNode* node)
912       : model_(model), node_(node), batch_in_progress_(false) {
913 }
914
915 CookiesTreeModel::ScopedBatchUpdateNotifier::~ScopedBatchUpdateNotifier() {
916   if (batch_in_progress_) {
917     model_->NotifyObserverTreeNodeChanged(node_);
918     model_->NotifyObserverEndBatch();
919   }
920 }
921
922 void CookiesTreeModel::ScopedBatchUpdateNotifier::StartBatchUpdate() {
923   if (!batch_in_progress_) {
924     model_->NotifyObserverBeginBatch();
925     batch_in_progress_ = true;
926   }
927 }
928
929 ///////////////////////////////////////////////////////////////////////////////
930 // CookiesTreeModel, public:
931 CookiesTreeModel::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
945 CookiesTreeModel::~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.
954 void 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.
966 int 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
997 void 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
1008 void 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
1018 void 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)
1039 const extensions::ExtensionSet* CookiesTreeModel::ExtensionsProtectingNode(
1040     const CookieTreeNode& cookie_node) {
1041   if (!special_storage_policy_)
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
1054 void 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
1060 void 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
1066 void CookiesTreeModel::PopulateAppCacheInfo(LocalDataContainer* container) {
1067   ScopedBatchUpdateNotifier notifier(this, GetRoot());
1068   PopulateAppCacheInfoWithFilter(container, &notifier, base::string16());
1069 }
1070
1071 void CookiesTreeModel::PopulateCookieInfo(LocalDataContainer* container) {
1072   ScopedBatchUpdateNotifier notifier(this, GetRoot());
1073   PopulateCookieInfoWithFilter(container, &notifier, base::string16());
1074 }
1075
1076 void CookiesTreeModel::PopulateDatabaseInfo(LocalDataContainer* container) {
1077   ScopedBatchUpdateNotifier notifier(this, GetRoot());
1078   PopulateDatabaseInfoWithFilter(container, &notifier, base::string16());
1079 }
1080
1081 void CookiesTreeModel::PopulateLocalStorageInfo(LocalDataContainer* container) {
1082   ScopedBatchUpdateNotifier notifier(this, GetRoot());
1083   PopulateLocalStorageInfoWithFilter(container, &notifier, base::string16());
1084 }
1085
1086 void CookiesTreeModel::PopulateSessionStorageInfo(
1087       LocalDataContainer* container) {
1088   ScopedBatchUpdateNotifier notifier(this, GetRoot());
1089   PopulateSessionStorageInfoWithFilter(container, &notifier, base::string16());
1090 }
1091
1092 void CookiesTreeModel::PopulateIndexedDBInfo(LocalDataContainer* container) {
1093   ScopedBatchUpdateNotifier notifier(this, GetRoot());
1094   PopulateIndexedDBInfoWithFilter(container, &notifier, base::string16());
1095 }
1096
1097 void CookiesTreeModel::PopulateFileSystemInfo(LocalDataContainer* container) {
1098   ScopedBatchUpdateNotifier notifier(this, GetRoot());
1099   PopulateFileSystemInfoWithFilter(container, &notifier, base::string16());
1100 }
1101
1102 void CookiesTreeModel::PopulateQuotaInfo(LocalDataContainer* container) {
1103   ScopedBatchUpdateNotifier notifier(this, GetRoot());
1104   PopulateQuotaInfoWithFilter(container, &notifier, base::string16());
1105 }
1106
1107 void CookiesTreeModel::PopulateChannelIDInfo(
1108       LocalDataContainer* container) {
1109   ScopedBatchUpdateNotifier notifier(this, GetRoot());
1110   PopulateChannelIDInfoWithFilter(container, &notifier, base::string16());
1111 }
1112
1113 void CookiesTreeModel::PopulateServiceWorkerUsageInfo(
1114     LocalDataContainer* container) {
1115   ScopedBatchUpdateNotifier notifier(this, GetRoot());
1116   PopulateServiceWorkerUsageInfoWithFilter(
1117       container, &notifier, base::string16());
1118 }
1119
1120 void CookiesTreeModel::PopulateFlashLSOInfo(
1121       LocalDataContainer* container) {
1122   ScopedBatchUpdateNotifier notifier(this, GetRoot());
1123   PopulateFlashLSOInfoWithFilter(container, &notifier, base::string16());
1124 }
1125
1126 void 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
1156 void 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
1188 void 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
1215 void 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
1242 void 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
1269 void 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
1296 void 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
1329 void 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
1356 void 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
1383 void 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
1405 void 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
1428 void 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
1437 void 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 }