cookies_tree_model.cc revision dc0f95d653279beabeb9817299e2902918ba123e
1// Copyright (c) 2010 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/cookies_tree_model.h"
6
7#include <algorithm>
8#include <functional>
9#include <vector>
10
11#include "base/callback.h"
12#include "base/linked_ptr.h"
13#include "base/string_util.h"
14#include "base/utf_string_conversions.h"
15#include "chrome/browser/extensions/extension_service.h"
16#include "content/browser/in_process_webkit/webkit_context.h"
17#include "grit/app_resources.h"
18#include "grit/generated_resources.h"
19#include "grit/theme_resources.h"
20#include "net/base/cookie_monster.h"
21#include "net/base/registry_controlled_domain.h"
22#include "net/url_request/url_request_context.h"
23#include "third_party/skia/include/core/SkBitmap.h"
24#include "ui/base/l10n/l10n_util.h"
25#include "ui/base/resource/resource_bundle.h"
26
27static const char kFileOriginNodeName[] = "file://";
28
29///////////////////////////////////////////////////////////////////////////////
30// CookieTreeNode, public:
31
32void CookieTreeNode::DeleteStoredObjects() {
33  std::for_each(children().begin(),
34                children().end(),
35                std::mem_fun(&CookieTreeNode::DeleteStoredObjects));
36}
37
38CookiesTreeModel* CookieTreeNode::GetModel() const {
39  if (GetParent())
40    return GetParent()->GetModel();
41  else
42    return NULL;
43}
44
45///////////////////////////////////////////////////////////////////////////////
46// CookieTreeCookieNode, public:
47
48CookieTreeCookieNode::CookieTreeCookieNode(
49    net::CookieMonster::CanonicalCookie* cookie)
50    : CookieTreeNode(UTF8ToUTF16(cookie->Name())),
51      cookie_(cookie) {
52}
53
54CookieTreeCookieNode::~CookieTreeCookieNode() {}
55
56void CookieTreeCookieNode::DeleteStoredObjects() {
57  // notify CookieMonster that we should delete this cookie
58  // We have stored a copy of all the cookies in the model, and our model is
59  // never re-calculated. Thus, we just need to delete the nodes from our
60  // model, and tell CookieMonster to delete the cookies. We can keep the
61  // vector storing the cookies in-tact and not delete from there (that would
62  // invalidate our pointers), and the fact that it contains semi out-of-date
63  // data is not problematic as we don't re-build the model based on that.
64  GetModel()->cookie_monster_->DeleteCanonicalCookie(*cookie_);
65}
66
67CookieTreeNode::DetailedInfo CookieTreeCookieNode::GetDetailedInfo() const {
68  return DetailedInfo(GetParent()->GetParent()->GetTitle(),
69                      DetailedInfo::TYPE_COOKIE,
70                      cookie_, NULL, NULL, NULL, NULL, NULL);
71}
72
73namespace {
74// comparison functor, for use in CookieTreeRootNode
75class OriginNodeComparator {
76 public:
77  bool operator() (const CookieTreeNode* lhs,
78                   const CookieTreeNode* rhs) {
79    // We want to order by registry controlled domain, so we would get
80    // google.com, ad.google.com, www.google.com,
81    // microsoft.com, ad.microsoft.com. CanonicalizeHost transforms the origins
82    // into a form like google.com.www so that string comparisons work.
83    return (CanonicalizeHost(lhs->GetTitle()) <
84            CanonicalizeHost(rhs->GetTitle()));
85  }
86
87 private:
88  static std::string CanonicalizeHost(const string16& host16) {
89    // The canonicalized representation makes the registry controlled domain
90    // come first, and then adds subdomains in reverse order, e.g.
91    // 1.mail.google.com would become google.com.mail.1, and then a standard
92    // string comparison works to order hosts by registry controlled domain
93    // first. Leading dots are ignored, ".google.com" is the same as
94    // "google.com".
95
96    std::string host = UTF16ToUTF8(host16);
97    std::string retval = net::RegistryControlledDomainService::
98        GetDomainAndRegistry(host);
99    if (!retval.length())  // Is an IP address or other special origin.
100      return host;
101
102    std::string::size_type position = host.rfind(retval);
103
104    // The host may be the registry controlled domain, in which case fail fast.
105    if (position == 0 || position == std::string::npos)
106      return host;
107
108    // If host is www.google.com, retval will contain google.com at this point.
109    // Start operating to the left of the registry controlled domain, e.g. in
110    // the www.google.com example, start at index 3.
111    --position;
112
113    // If position == 0, that means it's a dot; this will be ignored to treat
114    // ".google.com" the same as "google.com".
115    while (position > 0) {
116      retval += std::string(".");
117      // Copy up to the next dot. host[position] is a dot so start after it.
118      std::string::size_type next_dot = host.rfind(".", position - 1);
119      if (next_dot == std::string::npos) {
120        retval += host.substr(0, position);
121        break;
122      }
123      retval += host.substr(next_dot + 1, position - (next_dot + 1));
124      position = next_dot;
125    }
126    return retval;
127  }
128};
129
130}  // namespace
131
132///////////////////////////////////////////////////////////////////////////////
133// CookieTreeAppCacheNode, public:
134
135CookieTreeAppCacheNode::CookieTreeAppCacheNode(
136    const appcache::AppCacheInfo* appcache_info)
137    : CookieTreeNode(UTF8ToUTF16(appcache_info->manifest_url.spec())),
138      appcache_info_(appcache_info) {
139}
140
141void CookieTreeAppCacheNode::DeleteStoredObjects() {
142  DCHECK(GetModel()->appcache_helper_);
143  GetModel()->appcache_helper_->DeleteAppCacheGroup(
144      appcache_info_->manifest_url);
145}
146
147CookieTreeNode::DetailedInfo CookieTreeAppCacheNode::GetDetailedInfo() const {
148  return DetailedInfo(GetParent()->GetParent()->GetTitle(),
149                      DetailedInfo::TYPE_APPCACHE,
150                      NULL, NULL, NULL, NULL, appcache_info_, NULL);
151}
152
153///////////////////////////////////////////////////////////////////////////////
154// CookieTreeDatabaseNode, public:
155
156CookieTreeDatabaseNode::CookieTreeDatabaseNode(
157    BrowsingDataDatabaseHelper::DatabaseInfo* database_info)
158    : CookieTreeNode(database_info->database_name.empty() ?
159          l10n_util::GetStringUTF16(IDS_COOKIES_WEB_DATABASE_UNNAMED_NAME) :
160          UTF8ToUTF16(database_info->database_name)),
161      database_info_(database_info) {
162}
163
164CookieTreeDatabaseNode::~CookieTreeDatabaseNode() {}
165
166void CookieTreeDatabaseNode::DeleteStoredObjects() {
167  GetModel()->database_helper_->DeleteDatabase(
168      database_info_->origin_identifier, database_info_->database_name);
169}
170
171CookieTreeNode::DetailedInfo CookieTreeDatabaseNode::GetDetailedInfo() const {
172  return DetailedInfo(GetParent()->GetParent()->GetTitle(),
173                      DetailedInfo::TYPE_DATABASE,
174                      NULL, database_info_, NULL, NULL, NULL, NULL);
175}
176
177///////////////////////////////////////////////////////////////////////////////
178// CookieTreeLocalStorageNode, public:
179
180CookieTreeLocalStorageNode::CookieTreeLocalStorageNode(
181    BrowsingDataLocalStorageHelper::LocalStorageInfo* local_storage_info)
182    : CookieTreeNode(UTF8ToUTF16(
183          local_storage_info->origin.empty() ?
184              local_storage_info->database_identifier :
185              local_storage_info->origin)),
186      local_storage_info_(local_storage_info) {
187}
188
189CookieTreeLocalStorageNode::~CookieTreeLocalStorageNode() {}
190
191void CookieTreeLocalStorageNode::DeleteStoredObjects() {
192  GetModel()->local_storage_helper_->DeleteLocalStorageFile(
193      local_storage_info_->file_path);
194}
195
196CookieTreeNode::DetailedInfo
197CookieTreeLocalStorageNode::GetDetailedInfo() const {
198  return DetailedInfo(GetParent()->GetParent()->GetTitle(),
199                      DetailedInfo::TYPE_LOCAL_STORAGE,
200                      NULL, NULL, local_storage_info_, NULL, NULL, NULL);
201}
202
203///////////////////////////////////////////////////////////////////////////////
204// CookieTreeSessionStorageNode, public:
205
206CookieTreeSessionStorageNode::CookieTreeSessionStorageNode(
207    BrowsingDataLocalStorageHelper::LocalStorageInfo* session_storage_info)
208    : CookieTreeNode(UTF8ToUTF16(
209          session_storage_info->origin.empty() ?
210              session_storage_info->database_identifier :
211              session_storage_info->origin)),
212      session_storage_info_(session_storage_info) {
213}
214
215CookieTreeSessionStorageNode::~CookieTreeSessionStorageNode() {}
216
217CookieTreeNode::DetailedInfo
218CookieTreeSessionStorageNode::GetDetailedInfo() const {
219  return DetailedInfo(GetParent()->GetParent()->GetTitle(),
220                      DetailedInfo::TYPE_SESSION_STORAGE,
221                      NULL, NULL, NULL, session_storage_info_, NULL, NULL);
222}
223
224///////////////////////////////////////////////////////////////////////////////
225// CookieTreeIndexedDBNode, public:
226
227CookieTreeIndexedDBNode::CookieTreeIndexedDBNode(
228    BrowsingDataIndexedDBHelper::IndexedDBInfo* indexed_db_info)
229    : CookieTreeNode(UTF8ToUTF16(
230          indexed_db_info->origin.empty() ?
231              indexed_db_info->database_identifier :
232              indexed_db_info->origin)),
233      indexed_db_info_(indexed_db_info) {
234}
235
236CookieTreeIndexedDBNode::~CookieTreeIndexedDBNode() {}
237
238void CookieTreeIndexedDBNode::DeleteStoredObjects() {
239  GetModel()->indexed_db_helper_->DeleteIndexedDBFile(
240      indexed_db_info_->file_path);
241}
242
243CookieTreeNode::DetailedInfo CookieTreeIndexedDBNode::GetDetailedInfo() const {
244  return DetailedInfo(GetParent()->GetParent()->GetTitle(),
245                      DetailedInfo::TYPE_INDEXED_DB,
246                      NULL, NULL, NULL, NULL, NULL, indexed_db_info_);
247}
248
249///////////////////////////////////////////////////////////////////////////////
250// CookieTreeRootNode, public:
251
252CookieTreeRootNode::CookieTreeRootNode(CookiesTreeModel* model)
253    : model_(model) {
254}
255
256CookieTreeRootNode::~CookieTreeRootNode() {}
257
258CookieTreeOriginNode* CookieTreeRootNode::GetOrCreateOriginNode(
259    const GURL& url) {
260  CookieTreeOriginNode origin_node(url);
261
262  // First see if there is an existing match.
263  std::vector<CookieTreeNode*>::iterator origin_node_iterator =
264      lower_bound(children().begin(),
265                  children().end(),
266                  &origin_node,
267                  OriginNodeComparator());
268
269  if (origin_node_iterator != children().end() &&
270      WideToUTF16Hack(CookieTreeOriginNode::TitleForUrl(url)) ==
271      (*origin_node_iterator)->GetTitle())
272    return static_cast<CookieTreeOriginNode*>(*origin_node_iterator);
273  // Node doesn't exist, create a new one and insert it into the (ordered)
274  // children.
275  CookieTreeOriginNode* retval = new CookieTreeOriginNode(url);
276  DCHECK(model_);
277  model_->Add(this, (origin_node_iterator - children().begin()), retval);
278  return retval;
279}
280
281CookiesTreeModel* CookieTreeRootNode::GetModel() const {
282  return model_;
283}
284
285CookieTreeNode::DetailedInfo CookieTreeRootNode::GetDetailedInfo() const {
286  return DetailedInfo(string16(),
287                      DetailedInfo::TYPE_ROOT,
288                      NULL, NULL, NULL, NULL, NULL, NULL);
289}
290
291///////////////////////////////////////////////////////////////////////////////
292// CookieTreeOriginNode, public:
293
294// static
295std::wstring CookieTreeOriginNode::TitleForUrl(
296    const GURL& url) {
297  return UTF8ToWide(url.SchemeIsFile() ? kFileOriginNodeName : url.host());
298}
299
300CookieTreeOriginNode::CookieTreeOriginNode(const GURL& url)
301    : CookieTreeNode(WideToUTF16Hack(TitleForUrl(url))),
302      cookies_child_(NULL),
303      databases_child_(NULL),
304      local_storages_child_(NULL),
305      session_storages_child_(NULL),
306      appcaches_child_(NULL),
307      indexed_dbs_child_(NULL),
308      url_(url) {}
309
310CookieTreeOriginNode::~CookieTreeOriginNode() {}
311
312CookieTreeNode::DetailedInfo CookieTreeOriginNode::GetDetailedInfo() const {
313  return DetailedInfo(GetTitle(),
314                      DetailedInfo::TYPE_ORIGIN,
315                      NULL, NULL, NULL, NULL, NULL, NULL);
316}
317
318CookieTreeCookiesNode* CookieTreeOriginNode::GetOrCreateCookiesNode() {
319  if (cookies_child_)
320    return cookies_child_;
321  cookies_child_ = new CookieTreeCookiesNode;
322  AddChildSortedByTitle(cookies_child_);
323  return cookies_child_;
324}
325
326CookieTreeDatabasesNode* CookieTreeOriginNode::GetOrCreateDatabasesNode() {
327  if (databases_child_)
328    return databases_child_;
329  databases_child_ = new CookieTreeDatabasesNode;
330  AddChildSortedByTitle(databases_child_);
331  return databases_child_;
332}
333
334CookieTreeLocalStoragesNode*
335    CookieTreeOriginNode::GetOrCreateLocalStoragesNode() {
336  if (local_storages_child_)
337    return local_storages_child_;
338  local_storages_child_ = new CookieTreeLocalStoragesNode;
339  AddChildSortedByTitle(local_storages_child_);
340  return local_storages_child_;
341}
342
343CookieTreeSessionStoragesNode*
344    CookieTreeOriginNode::GetOrCreateSessionStoragesNode() {
345  if (session_storages_child_)
346    return session_storages_child_;
347  session_storages_child_ = new CookieTreeSessionStoragesNode;
348  AddChildSortedByTitle(session_storages_child_);
349  return session_storages_child_;
350}
351
352CookieTreeAppCachesNode* CookieTreeOriginNode::GetOrCreateAppCachesNode() {
353  if (appcaches_child_)
354    return appcaches_child_;
355  appcaches_child_ = new CookieTreeAppCachesNode;
356  AddChildSortedByTitle(appcaches_child_);
357  return appcaches_child_;
358}
359
360CookieTreeIndexedDBsNode* CookieTreeOriginNode::GetOrCreateIndexedDBsNode() {
361  if (indexed_dbs_child_)
362    return indexed_dbs_child_;
363  indexed_dbs_child_ = new CookieTreeIndexedDBsNode;
364  AddChildSortedByTitle(indexed_dbs_child_);
365  return indexed_dbs_child_;
366}
367
368void CookieTreeOriginNode::CreateContentException(
369    HostContentSettingsMap* content_settings, ContentSetting setting) const {
370  if (CanCreateContentException()) {
371    content_settings->AddExceptionForURL(url_,
372                                         CONTENT_SETTINGS_TYPE_COOKIES,
373                                         "",
374                                         setting);
375  }
376}
377
378bool CookieTreeOriginNode::CanCreateContentException() const {
379  return !url_.SchemeIsFile();
380}
381
382///////////////////////////////////////////////////////////////////////////////
383// CookieTreeCookiesNode, public:
384
385CookieTreeCookiesNode::CookieTreeCookiesNode()
386    : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_COOKIES)) {
387}
388
389CookieTreeCookiesNode::~CookieTreeCookiesNode() {
390}
391
392CookieTreeNode::DetailedInfo CookieTreeCookiesNode::GetDetailedInfo() const {
393  return DetailedInfo(GetParent()->GetTitle(),
394                      DetailedInfo::TYPE_COOKIES,
395                      NULL, NULL, NULL, NULL, NULL, NULL);
396}
397
398///////////////////////////////////////////////////////////////////////////////
399// CookieTreeAppCachesNode, public:
400
401CookieTreeAppCachesNode::CookieTreeAppCachesNode()
402    : CookieTreeNode(l10n_util::GetStringUTF16(
403                         IDS_COOKIES_APPLICATION_CACHES)) {
404}
405
406CookieTreeAppCachesNode::~CookieTreeAppCachesNode() {}
407
408CookieTreeNode::DetailedInfo CookieTreeAppCachesNode::GetDetailedInfo() const {
409  return DetailedInfo(GetParent()->GetTitle(),
410                      DetailedInfo::TYPE_APPCACHES,
411                      NULL, NULL, NULL, NULL, NULL, NULL);
412}
413
414///////////////////////////////////////////////////////////////////////////////
415// CookieTreeDatabasesNode, public:
416
417CookieTreeDatabasesNode::CookieTreeDatabasesNode()
418    : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_WEB_DATABASES)) {
419}
420
421CookieTreeDatabasesNode::~CookieTreeDatabasesNode() {}
422
423CookieTreeNode::DetailedInfo CookieTreeDatabasesNode::GetDetailedInfo() const {
424  return DetailedInfo(GetParent()->GetTitle(),
425                      DetailedInfo::TYPE_DATABASES,
426                      NULL, NULL, NULL, NULL, NULL, NULL);
427}
428
429///////////////////////////////////////////////////////////////////////////////
430// CookieTreeLocalStoragesNode, public:
431
432CookieTreeLocalStoragesNode::CookieTreeLocalStoragesNode()
433    : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_LOCAL_STORAGE)) {
434}
435
436CookieTreeLocalStoragesNode::~CookieTreeLocalStoragesNode() {}
437
438CookieTreeNode::DetailedInfo
439CookieTreeLocalStoragesNode::GetDetailedInfo() const {
440  return DetailedInfo(GetParent()->GetTitle(),
441                      DetailedInfo::TYPE_LOCAL_STORAGES,
442                      NULL, NULL, NULL, NULL, NULL, NULL);
443}
444
445///////////////////////////////////////////////////////////////////////////////
446// CookieTreeSessionStoragesNode, public:
447
448CookieTreeSessionStoragesNode::CookieTreeSessionStoragesNode()
449    : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_SESSION_STORAGE)) {
450}
451
452CookieTreeSessionStoragesNode::~CookieTreeSessionStoragesNode() {}
453
454CookieTreeNode::DetailedInfo
455CookieTreeSessionStoragesNode::GetDetailedInfo() const {
456  return DetailedInfo(GetParent()->GetTitle(),
457                      DetailedInfo::TYPE_SESSION_STORAGES,
458                      NULL, NULL, NULL, NULL, NULL, NULL);
459}
460
461///////////////////////////////////////////////////////////////////////////////
462// CookieTreeIndexedDBsNode, public:
463
464CookieTreeIndexedDBsNode::CookieTreeIndexedDBsNode()
465    : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_INDEXED_DBS)) {
466}
467
468CookieTreeIndexedDBsNode::~CookieTreeIndexedDBsNode() {}
469
470CookieTreeNode::DetailedInfo
471CookieTreeIndexedDBsNode::GetDetailedInfo() const {
472  return DetailedInfo(GetParent()->GetTitle(),
473                      DetailedInfo::TYPE_INDEXED_DBS,
474                      NULL, NULL, NULL, NULL, NULL, NULL);
475}
476
477///////////////////////////////////////////////////////////////////////////////
478// CookieTreeNode, protected
479
480bool CookieTreeNode::NodeTitleComparator::operator() (
481    const CookieTreeNode* lhs, const CookieTreeNode* rhs) {
482  const CookieTreeNode* left =
483      static_cast<const CookieTreeNode*>(lhs);
484  const CookieTreeNode* right =
485      static_cast<const CookieTreeNode*>(rhs);
486  return (left->GetTitle() < right->GetTitle());
487}
488
489void CookieTreeNode::AddChildSortedByTitle(CookieTreeNode* new_child) {
490  std::vector<CookieTreeNode*>::iterator iter =
491      lower_bound(children().begin(),
492                  children().end(),
493                  new_child,
494                  NodeTitleComparator());
495  GetModel()->Add(this, iter - children().begin(), new_child);
496}
497
498///////////////////////////////////////////////////////////////////////////////
499// CookiesTreeModel, public:
500
501CookiesTreeModel::CookiesTreeModel(
502    net::CookieMonster* cookie_monster,
503    BrowsingDataDatabaseHelper* database_helper,
504    BrowsingDataLocalStorageHelper* local_storage_helper,
505    BrowsingDataLocalStorageHelper* session_storage_helper,
506    BrowsingDataAppCacheHelper* appcache_helper,
507    BrowsingDataIndexedDBHelper* indexed_db_helper)
508    : ALLOW_THIS_IN_INITIALIZER_LIST(ui::TreeNodeModel<CookieTreeNode>(
509          new CookieTreeRootNode(this))),
510      cookie_monster_(cookie_monster),
511      appcache_helper_(appcache_helper),
512      database_helper_(database_helper),
513      local_storage_helper_(local_storage_helper),
514      session_storage_helper_(session_storage_helper),
515      indexed_db_helper_(indexed_db_helper),
516      batch_update_(0) {
517  LoadCookies();
518  DCHECK(database_helper_);
519  database_helper_->StartFetching(NewCallback(
520      this, &CookiesTreeModel::OnDatabaseModelInfoLoaded));
521  DCHECK(local_storage_helper_);
522  local_storage_helper_->StartFetching(NewCallback(
523      this, &CookiesTreeModel::OnLocalStorageModelInfoLoaded));
524  if (session_storage_helper_) {
525    session_storage_helper_->StartFetching(NewCallback(
526        this, &CookiesTreeModel::OnSessionStorageModelInfoLoaded));
527  }
528
529  // TODO(michaeln): when all of the ui impls have been updated,
530  // make this a required parameter.
531  if (appcache_helper_) {
532    appcache_helper_->StartFetching(NewCallback(
533        this, &CookiesTreeModel::OnAppCacheModelInfoLoaded));
534  }
535
536  if (indexed_db_helper_) {
537    indexed_db_helper_->StartFetching(NewCallback(
538        this, &CookiesTreeModel::OnIndexedDBModelInfoLoaded));
539  }
540}
541
542CookiesTreeModel::~CookiesTreeModel() {
543  database_helper_->CancelNotification();
544  local_storage_helper_->CancelNotification();
545  if (session_storage_helper_)
546    session_storage_helper_->CancelNotification();
547  if (appcache_helper_)
548    appcache_helper_->CancelNotification();
549  if (indexed_db_helper_)
550    indexed_db_helper_->CancelNotification();
551}
552
553///////////////////////////////////////////////////////////////////////////////
554// CookiesTreeModel, TreeModel methods (public):
555
556// TreeModel methods:
557// Returns the set of icons for the nodes in the tree. You only need override
558// this if you don't want to use the default folder icons.
559void CookiesTreeModel::GetIcons(std::vector<SkBitmap>* icons) {
560  icons->push_back(*ResourceBundle::GetSharedInstance().GetBitmapNamed(
561      IDR_DEFAULT_FAVICON));
562  icons->push_back(*ResourceBundle::GetSharedInstance().GetBitmapNamed(
563      IDR_COOKIE_ICON));
564  icons->push_back(*ResourceBundle::GetSharedInstance().GetBitmapNamed(
565      IDR_COOKIE_STORAGE_ICON));
566}
567
568// Returns the index of the icon to use for |node|. Return -1 to use the
569// default icon. The index is relative to the list of icons returned from
570// GetIcons.
571int CookiesTreeModel::GetIconIndex(ui::TreeModelNode* node) {
572  CookieTreeNode* ct_node = static_cast<CookieTreeNode*>(node);
573  switch (ct_node->GetDetailedInfo().node_type) {
574    case CookieTreeNode::DetailedInfo::TYPE_ORIGIN:
575      return ORIGIN;
576    case CookieTreeNode::DetailedInfo::TYPE_COOKIE:
577      return COOKIE;
578    case CookieTreeNode::DetailedInfo::TYPE_DATABASE:
579      return DATABASE;
580    case CookieTreeNode::DetailedInfo::TYPE_LOCAL_STORAGE:
581      return DATABASE;  // close enough
582    case CookieTreeNode::DetailedInfo::TYPE_SESSION_STORAGE:
583      return DATABASE;  // ditto
584    case CookieTreeNode::DetailedInfo::TYPE_APPCACHE:
585      return DATABASE;  // ditto
586    case CookieTreeNode::DetailedInfo::TYPE_INDEXED_DB:
587      return DATABASE;  // ditto
588    default:
589      break;
590  }
591  return -1;
592}
593
594void CookiesTreeModel::LoadCookies() {
595  LoadCookiesWithFilter(std::wstring());
596}
597
598void CookiesTreeModel::LoadCookiesWithFilter(const std::wstring& filter) {
599  // mmargh mmargh mmargh! delicious!
600
601  all_cookies_ = cookie_monster_->GetAllCookies();
602  CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
603  for (CookieList::iterator it = all_cookies_.begin();
604       it != all_cookies_.end(); ++it) {
605    std::string source_string = it->Source();
606    if (source_string.empty()) {
607      std::string domain = it->Domain();
608      if (domain.length() > 1 && domain[0] == '.')
609        domain = domain.substr(1);
610
611      // We treat secure cookies just the same as normal ones.
612      source_string = std::string(chrome::kHttpScheme) +
613          chrome::kStandardSchemeSeparator + domain + "/";
614    }
615
616    GURL source(source_string);
617    if (!filter.size() ||
618        (CookieTreeOriginNode::TitleForUrl(source).find(filter) !=
619         std::string::npos)) {
620      CookieTreeOriginNode* origin_node =
621          root->GetOrCreateOriginNode(source);
622      CookieTreeCookiesNode* cookies_node =
623          origin_node->GetOrCreateCookiesNode();
624      CookieTreeCookieNode* new_cookie = new CookieTreeCookieNode(&*it);
625      cookies_node->AddCookieNode(new_cookie);
626    }
627  }
628}
629
630void CookiesTreeModel::DeleteAllStoredObjects() {
631  NotifyObserverBeginBatch();
632  CookieTreeNode* root = GetRoot();
633  root->DeleteStoredObjects();
634  int num_children = root->GetChildCount();
635  for (int i = num_children - 1; i >= 0; --i)
636    delete Remove(root, i);
637  NotifyObserverTreeNodeChanged(root);
638  NotifyObserverEndBatch();
639}
640
641void CookiesTreeModel::DeleteCookieNode(CookieTreeNode* cookie_node) {
642  if (cookie_node == GetRoot())
643    return;
644  cookie_node->DeleteStoredObjects();
645  // find the parent and index
646  CookieTreeNode* parent_node = cookie_node->GetParent();
647  int cookie_node_index = parent_node->IndexOfChild(cookie_node);
648  delete Remove(parent_node, cookie_node_index);
649  if (parent_node->GetChildCount() == 0)
650    DeleteCookieNode(parent_node);
651}
652
653void CookiesTreeModel::UpdateSearchResults(const std::wstring& filter) {
654  CookieTreeNode* root = GetRoot();
655  int num_children = root->GetChildCount();
656  NotifyObserverBeginBatch();
657  for (int i = num_children - 1; i >= 0; --i)
658    delete Remove(root, i);
659  LoadCookiesWithFilter(filter);
660  PopulateDatabaseInfoWithFilter(filter);
661  PopulateLocalStorageInfoWithFilter(filter);
662  PopulateSessionStorageInfoWithFilter(filter);
663  PopulateAppCacheInfoWithFilter(filter);
664  PopulateIndexedDBInfoWithFilter(filter);
665  NotifyObserverTreeNodeChanged(root);
666  NotifyObserverEndBatch();
667}
668
669void CookiesTreeModel::AddCookiesTreeObserver(Observer* observer) {
670  cookies_observer_list_.AddObserver(observer);
671  // Call super so that TreeNodeModel can notify, too.
672  ui::TreeNodeModel<CookieTreeNode>::AddObserver(observer);
673}
674
675void CookiesTreeModel::RemoveCookiesTreeObserver(Observer* observer) {
676  cookies_observer_list_.RemoveObserver(observer);
677  // Call super so that TreeNodeModel doesn't have dead pointers.
678  ui::TreeNodeModel<CookieTreeNode>::RemoveObserver(observer);
679}
680
681void CookiesTreeModel::OnAppCacheModelInfoLoaded() {
682  appcache_info_ = appcache_helper_->info_collection();
683  PopulateAppCacheInfoWithFilter(std::wstring());
684}
685
686void CookiesTreeModel::PopulateAppCacheInfoWithFilter(
687    const std::wstring& filter) {
688  using appcache::AppCacheInfo;
689  using appcache::AppCacheInfoVector;
690  typedef std::map<GURL, AppCacheInfoVector> InfoByOrigin;
691
692  if (!appcache_info_ || appcache_info_->infos_by_origin.empty())
693    return;
694
695  CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
696  NotifyObserverBeginBatch();
697  for (InfoByOrigin::const_iterator origin =
698           appcache_info_->infos_by_origin.begin();
699       origin != appcache_info_->infos_by_origin.end(); ++origin) {
700    std::wstring origin_node_name = UTF8ToWide(origin->first.host());
701    if (filter.empty() ||
702        (origin_node_name.find(filter) != std::wstring::npos)) {
703      CookieTreeOriginNode* origin_node =
704          root->GetOrCreateOriginNode(origin->first);
705      CookieTreeAppCachesNode* appcaches_node =
706          origin_node->GetOrCreateAppCachesNode();
707
708      for (AppCacheInfoVector::const_iterator info = origin->second.begin();
709           info != origin->second.end(); ++info) {
710        appcaches_node->AddAppCacheNode(
711            new CookieTreeAppCacheNode(&(*info)));
712      }
713    }
714  }
715  NotifyObserverTreeNodeChanged(root);
716  NotifyObserverEndBatch();
717}
718
719void CookiesTreeModel::OnDatabaseModelInfoLoaded(
720    const DatabaseInfoList& database_info) {
721  database_info_list_ = database_info;
722  PopulateDatabaseInfoWithFilter(std::wstring());
723}
724
725void CookiesTreeModel::PopulateDatabaseInfoWithFilter(
726    const std::wstring& filter) {
727  if (database_info_list_.empty())
728    return;
729  CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
730  NotifyObserverBeginBatch();
731  for (DatabaseInfoList::iterator database_info = database_info_list_.begin();
732       database_info != database_info_list_.end();
733       ++database_info) {
734    GURL origin(database_info->origin);
735
736    if (!filter.size() ||
737        (CookieTreeOriginNode::TitleForUrl(origin).find(filter) !=
738         std::wstring::npos)) {
739      CookieTreeOriginNode* origin_node =
740          root->GetOrCreateOriginNode(origin);
741      CookieTreeDatabasesNode* databases_node =
742          origin_node->GetOrCreateDatabasesNode();
743      databases_node->AddDatabaseNode(
744          new CookieTreeDatabaseNode(&(*database_info)));
745    }
746  }
747  NotifyObserverTreeNodeChanged(root);
748  NotifyObserverEndBatch();
749}
750
751void CookiesTreeModel::OnLocalStorageModelInfoLoaded(
752    const LocalStorageInfoList& local_storage_info) {
753  local_storage_info_list_ = local_storage_info;
754  PopulateLocalStorageInfoWithFilter(std::wstring());
755}
756
757void CookiesTreeModel::PopulateLocalStorageInfoWithFilter(
758    const std::wstring& filter) {
759  if (local_storage_info_list_.empty())
760    return;
761  CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
762  NotifyObserverBeginBatch();
763  for (LocalStorageInfoList::iterator local_storage_info =
764       local_storage_info_list_.begin();
765       local_storage_info != local_storage_info_list_.end();
766       ++local_storage_info) {
767    GURL origin(local_storage_info->origin);
768
769    if (!filter.size() ||
770        (CookieTreeOriginNode::TitleForUrl(origin).find(filter) !=
771         std::wstring::npos)) {
772      CookieTreeOriginNode* origin_node =
773          root->GetOrCreateOriginNode(origin);
774      CookieTreeLocalStoragesNode* local_storages_node =
775          origin_node->GetOrCreateLocalStoragesNode();
776      local_storages_node->AddLocalStorageNode(
777          new CookieTreeLocalStorageNode(&(*local_storage_info)));
778    }
779  }
780  NotifyObserverTreeNodeChanged(root);
781  NotifyObserverEndBatch();
782}
783
784void CookiesTreeModel::OnSessionStorageModelInfoLoaded(
785    const LocalStorageInfoList& session_storage_info) {
786  session_storage_info_list_ = session_storage_info;
787  PopulateSessionStorageInfoWithFilter(std::wstring());
788}
789
790void CookiesTreeModel::PopulateSessionStorageInfoWithFilter(
791    const std::wstring& filter) {
792  if (session_storage_info_list_.empty())
793    return;
794  CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
795  NotifyObserverBeginBatch();
796  for (LocalStorageInfoList::iterator session_storage_info =
797       session_storage_info_list_.begin();
798       session_storage_info != session_storage_info_list_.end();
799       ++session_storage_info) {
800    GURL origin(session_storage_info->origin);
801
802    if (!filter.size() ||
803        (CookieTreeOriginNode::TitleForUrl(origin).find(filter) !=
804         std::wstring::npos)) {
805      CookieTreeOriginNode* origin_node =
806          root->GetOrCreateOriginNode(origin);
807      CookieTreeSessionStoragesNode* session_storages_node =
808          origin_node->GetOrCreateSessionStoragesNode();
809      session_storages_node->AddSessionStorageNode(
810          new CookieTreeSessionStorageNode(&(*session_storage_info)));
811    }
812  }
813  NotifyObserverTreeNodeChanged(root);
814  NotifyObserverEndBatch();
815}
816
817void CookiesTreeModel::OnIndexedDBModelInfoLoaded(
818    const IndexedDBInfoList& indexed_db_info) {
819  indexed_db_info_list_ = indexed_db_info;
820  PopulateIndexedDBInfoWithFilter(std::wstring());
821}
822
823void CookiesTreeModel::PopulateIndexedDBInfoWithFilter(
824    const std::wstring& filter) {
825  if (indexed_db_info_list_.empty())
826    return;
827  CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
828  NotifyObserverBeginBatch();
829  for (IndexedDBInfoList::iterator indexed_db_info =
830       indexed_db_info_list_.begin();
831       indexed_db_info != indexed_db_info_list_.end();
832       ++indexed_db_info) {
833    GURL origin(indexed_db_info->origin);
834
835    if (!filter.size() ||
836        (CookieTreeOriginNode::TitleForUrl(origin).find(filter) !=
837         std::wstring::npos)) {
838      CookieTreeOriginNode* origin_node =
839          root->GetOrCreateOriginNode(origin);
840      CookieTreeIndexedDBsNode* indexed_dbs_node =
841          origin_node->GetOrCreateIndexedDBsNode();
842      indexed_dbs_node->AddIndexedDBNode(
843          new CookieTreeIndexedDBNode(&(*indexed_db_info)));
844    }
845  }
846  NotifyObserverTreeNodeChanged(root);
847  NotifyObserverEndBatch();
848}
849
850void CookiesTreeModel::NotifyObserverBeginBatch() {
851  // Only notify the model once if we're batching in a nested manner.
852  if (batch_update_++ == 0) {
853    FOR_EACH_OBSERVER(Observer,
854                      cookies_observer_list_,
855                      TreeModelBeginBatch(this));
856  }
857}
858
859void CookiesTreeModel::NotifyObserverEndBatch() {
860  // Only notify the observers if this is the outermost call to EndBatch() if
861  // called in a nested manner.
862  if (--batch_update_ == 0) {
863    FOR_EACH_OBSERVER(Observer,
864                      cookies_observer_list_,
865                      TreeModelEndBatch(this));
866  }
867}
868