1 // Copyright (c) 2011 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/memory/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
27 static const char kFileOriginNodeName[] = "file://";
28
29 ///////////////////////////////////////////////////////////////////////////////
30 // CookieTreeNode, public:
31
DeleteStoredObjects()32 void CookieTreeNode::DeleteStoredObjects() {
33 std::for_each(children().begin(),
34 children().end(),
35 std::mem_fun(&CookieTreeNode::DeleteStoredObjects));
36 }
37
GetModel() const38 CookiesTreeModel* CookieTreeNode::GetModel() const {
39 if (parent())
40 return parent()->GetModel();
41 else
42 return NULL;
43 }
44
45 ///////////////////////////////////////////////////////////////////////////////
46 // CookieTreeCookieNode, public:
47
CookieTreeCookieNode(net::CookieMonster::CanonicalCookie * cookie)48 CookieTreeCookieNode::CookieTreeCookieNode(
49 net::CookieMonster::CanonicalCookie* cookie)
50 : CookieTreeNode(UTF8ToUTF16(cookie->Name())),
51 cookie_(cookie) {
52 }
53
~CookieTreeCookieNode()54 CookieTreeCookieNode::~CookieTreeCookieNode() {}
55
DeleteStoredObjects()56 void 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
GetDetailedInfo() const67 CookieTreeNode::DetailedInfo CookieTreeCookieNode::GetDetailedInfo() const {
68 return DetailedInfo(parent()->parent()->GetTitle(),
69 DetailedInfo::TYPE_COOKIE,
70 cookie_, NULL, NULL, NULL, NULL, NULL);
71 }
72
73 namespace {
74 // comparison functor, for use in CookieTreeRootNode
75 class OriginNodeComparator {
76 public:
operator ()(const CookieTreeNode * lhs,const CookieTreeNode * rhs)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:
CanonicalizeHost(const string16 & host16)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
CookieTreeAppCacheNode(const appcache::AppCacheInfo * appcache_info)135 CookieTreeAppCacheNode::CookieTreeAppCacheNode(
136 const appcache::AppCacheInfo* appcache_info)
137 : CookieTreeNode(UTF8ToUTF16(appcache_info->manifest_url.spec())),
138 appcache_info_(appcache_info) {
139 }
140
DeleteStoredObjects()141 void CookieTreeAppCacheNode::DeleteStoredObjects() {
142 DCHECK(GetModel()->appcache_helper_);
143 GetModel()->appcache_helper_->DeleteAppCacheGroup(
144 appcache_info_->manifest_url);
145 }
146
GetDetailedInfo() const147 CookieTreeNode::DetailedInfo CookieTreeAppCacheNode::GetDetailedInfo() const {
148 return DetailedInfo(parent()->parent()->GetTitle(),
149 DetailedInfo::TYPE_APPCACHE,
150 NULL, NULL, NULL, NULL, appcache_info_, NULL);
151 }
152
153 ///////////////////////////////////////////////////////////////////////////////
154 // CookieTreeDatabaseNode, public:
155
CookieTreeDatabaseNode(BrowsingDataDatabaseHelper::DatabaseInfo * database_info)156 CookieTreeDatabaseNode::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
~CookieTreeDatabaseNode()164 CookieTreeDatabaseNode::~CookieTreeDatabaseNode() {}
165
DeleteStoredObjects()166 void CookieTreeDatabaseNode::DeleteStoredObjects() {
167 GetModel()->database_helper_->DeleteDatabase(
168 database_info_->origin_identifier, database_info_->database_name);
169 }
170
GetDetailedInfo() const171 CookieTreeNode::DetailedInfo CookieTreeDatabaseNode::GetDetailedInfo() const {
172 return DetailedInfo(parent()->parent()->GetTitle(),
173 DetailedInfo::TYPE_DATABASE,
174 NULL, database_info_, NULL, NULL, NULL, NULL);
175 }
176
177 ///////////////////////////////////////////////////////////////////////////////
178 // CookieTreeLocalStorageNode, public:
179
CookieTreeLocalStorageNode(BrowsingDataLocalStorageHelper::LocalStorageInfo * local_storage_info)180 CookieTreeLocalStorageNode::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
~CookieTreeLocalStorageNode()189 CookieTreeLocalStorageNode::~CookieTreeLocalStorageNode() {}
190
DeleteStoredObjects()191 void CookieTreeLocalStorageNode::DeleteStoredObjects() {
192 GetModel()->local_storage_helper_->DeleteLocalStorageFile(
193 local_storage_info_->file_path);
194 }
195
196 CookieTreeNode::DetailedInfo
GetDetailedInfo() const197 CookieTreeLocalStorageNode::GetDetailedInfo() const {
198 return DetailedInfo(parent()->parent()->GetTitle(),
199 DetailedInfo::TYPE_LOCAL_STORAGE,
200 NULL, NULL, local_storage_info_, NULL, NULL, NULL);
201 }
202
203 ///////////////////////////////////////////////////////////////////////////////
204 // CookieTreeSessionStorageNode, public:
205
CookieTreeSessionStorageNode(BrowsingDataLocalStorageHelper::LocalStorageInfo * session_storage_info)206 CookieTreeSessionStorageNode::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
~CookieTreeSessionStorageNode()215 CookieTreeSessionStorageNode::~CookieTreeSessionStorageNode() {}
216
217 CookieTreeNode::DetailedInfo
GetDetailedInfo() const218 CookieTreeSessionStorageNode::GetDetailedInfo() const {
219 return DetailedInfo(parent()->parent()->GetTitle(),
220 DetailedInfo::TYPE_SESSION_STORAGE,
221 NULL, NULL, NULL, session_storage_info_, NULL, NULL);
222 }
223
224 ///////////////////////////////////////////////////////////////////////////////
225 // CookieTreeIndexedDBNode, public:
226
CookieTreeIndexedDBNode(BrowsingDataIndexedDBHelper::IndexedDBInfo * indexed_db_info)227 CookieTreeIndexedDBNode::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
~CookieTreeIndexedDBNode()236 CookieTreeIndexedDBNode::~CookieTreeIndexedDBNode() {}
237
DeleteStoredObjects()238 void CookieTreeIndexedDBNode::DeleteStoredObjects() {
239 GetModel()->indexed_db_helper_->DeleteIndexedDBFile(
240 indexed_db_info_->file_path);
241 }
242
GetDetailedInfo() const243 CookieTreeNode::DetailedInfo CookieTreeIndexedDBNode::GetDetailedInfo() const {
244 return DetailedInfo(parent()->parent()->GetTitle(),
245 DetailedInfo::TYPE_INDEXED_DB,
246 NULL, NULL, NULL, NULL, NULL, indexed_db_info_);
247 }
248
249 ///////////////////////////////////////////////////////////////////////////////
250 // CookieTreeRootNode, public:
251
CookieTreeRootNode(CookiesTreeModel * model)252 CookieTreeRootNode::CookieTreeRootNode(CookiesTreeModel* model)
253 : model_(model) {
254 }
255
~CookieTreeRootNode()256 CookieTreeRootNode::~CookieTreeRootNode() {}
257
GetOrCreateOriginNode(const GURL & url)258 CookieTreeOriginNode* 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, retval, (origin_node_iterator - children().begin()));
278 return retval;
279 }
280
GetModel() const281 CookiesTreeModel* CookieTreeRootNode::GetModel() const {
282 return model_;
283 }
284
GetDetailedInfo() const285 CookieTreeNode::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
TitleForUrl(const GURL & url)295 std::wstring CookieTreeOriginNode::TitleForUrl(
296 const GURL& url) {
297 return UTF8ToWide(url.SchemeIsFile() ? kFileOriginNodeName : url.host());
298 }
299
CookieTreeOriginNode(const GURL & url)300 CookieTreeOriginNode::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
~CookieTreeOriginNode()310 CookieTreeOriginNode::~CookieTreeOriginNode() {}
311
GetDetailedInfo() const312 CookieTreeNode::DetailedInfo CookieTreeOriginNode::GetDetailedInfo() const {
313 return DetailedInfo(GetTitle(),
314 DetailedInfo::TYPE_ORIGIN,
315 NULL, NULL, NULL, NULL, NULL, NULL);
316 }
317
GetOrCreateCookiesNode()318 CookieTreeCookiesNode* 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
GetOrCreateDatabasesNode()326 CookieTreeDatabasesNode* 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
334 CookieTreeLocalStoragesNode*
GetOrCreateLocalStoragesNode()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
343 CookieTreeSessionStoragesNode*
GetOrCreateSessionStoragesNode()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
GetOrCreateAppCachesNode()352 CookieTreeAppCachesNode* 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
GetOrCreateIndexedDBsNode()360 CookieTreeIndexedDBsNode* 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
CreateContentException(HostContentSettingsMap * content_settings,ContentSetting setting) const368 void 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
CanCreateContentException() const378 bool CookieTreeOriginNode::CanCreateContentException() const {
379 return !url_.SchemeIsFile();
380 }
381
382 ///////////////////////////////////////////////////////////////////////////////
383 // CookieTreeCookiesNode, public:
384
CookieTreeCookiesNode()385 CookieTreeCookiesNode::CookieTreeCookiesNode()
386 : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_COOKIES)) {
387 }
388
~CookieTreeCookiesNode()389 CookieTreeCookiesNode::~CookieTreeCookiesNode() {
390 }
391
GetDetailedInfo() const392 CookieTreeNode::DetailedInfo CookieTreeCookiesNode::GetDetailedInfo() const {
393 return DetailedInfo(parent()->GetTitle(),
394 DetailedInfo::TYPE_COOKIES,
395 NULL, NULL, NULL, NULL, NULL, NULL);
396 }
397
398 ///////////////////////////////////////////////////////////////////////////////
399 // CookieTreeAppCachesNode, public:
400
CookieTreeAppCachesNode()401 CookieTreeAppCachesNode::CookieTreeAppCachesNode()
402 : CookieTreeNode(l10n_util::GetStringUTF16(
403 IDS_COOKIES_APPLICATION_CACHES)) {
404 }
405
~CookieTreeAppCachesNode()406 CookieTreeAppCachesNode::~CookieTreeAppCachesNode() {}
407
GetDetailedInfo() const408 CookieTreeNode::DetailedInfo CookieTreeAppCachesNode::GetDetailedInfo() const {
409 return DetailedInfo(parent()->GetTitle(),
410 DetailedInfo::TYPE_APPCACHES,
411 NULL, NULL, NULL, NULL, NULL, NULL);
412 }
413
414 ///////////////////////////////////////////////////////////////////////////////
415 // CookieTreeDatabasesNode, public:
416
CookieTreeDatabasesNode()417 CookieTreeDatabasesNode::CookieTreeDatabasesNode()
418 : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_WEB_DATABASES)) {
419 }
420
~CookieTreeDatabasesNode()421 CookieTreeDatabasesNode::~CookieTreeDatabasesNode() {}
422
GetDetailedInfo() const423 CookieTreeNode::DetailedInfo CookieTreeDatabasesNode::GetDetailedInfo() const {
424 return DetailedInfo(parent()->GetTitle(),
425 DetailedInfo::TYPE_DATABASES,
426 NULL, NULL, NULL, NULL, NULL, NULL);
427 }
428
429 ///////////////////////////////////////////////////////////////////////////////
430 // CookieTreeLocalStoragesNode, public:
431
CookieTreeLocalStoragesNode()432 CookieTreeLocalStoragesNode::CookieTreeLocalStoragesNode()
433 : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_LOCAL_STORAGE)) {
434 }
435
~CookieTreeLocalStoragesNode()436 CookieTreeLocalStoragesNode::~CookieTreeLocalStoragesNode() {}
437
438 CookieTreeNode::DetailedInfo
GetDetailedInfo() const439 CookieTreeLocalStoragesNode::GetDetailedInfo() const {
440 return DetailedInfo(parent()->GetTitle(),
441 DetailedInfo::TYPE_LOCAL_STORAGES,
442 NULL, NULL, NULL, NULL, NULL, NULL);
443 }
444
445 ///////////////////////////////////////////////////////////////////////////////
446 // CookieTreeSessionStoragesNode, public:
447
CookieTreeSessionStoragesNode()448 CookieTreeSessionStoragesNode::CookieTreeSessionStoragesNode()
449 : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_SESSION_STORAGE)) {
450 }
451
~CookieTreeSessionStoragesNode()452 CookieTreeSessionStoragesNode::~CookieTreeSessionStoragesNode() {}
453
454 CookieTreeNode::DetailedInfo
GetDetailedInfo() const455 CookieTreeSessionStoragesNode::GetDetailedInfo() const {
456 return DetailedInfo(parent()->GetTitle(),
457 DetailedInfo::TYPE_SESSION_STORAGES,
458 NULL, NULL, NULL, NULL, NULL, NULL);
459 }
460
461 ///////////////////////////////////////////////////////////////////////////////
462 // CookieTreeIndexedDBsNode, public:
463
CookieTreeIndexedDBsNode()464 CookieTreeIndexedDBsNode::CookieTreeIndexedDBsNode()
465 : CookieTreeNode(l10n_util::GetStringUTF16(IDS_COOKIES_INDEXED_DBS)) {
466 }
467
~CookieTreeIndexedDBsNode()468 CookieTreeIndexedDBsNode::~CookieTreeIndexedDBsNode() {}
469
470 CookieTreeNode::DetailedInfo
GetDetailedInfo() const471 CookieTreeIndexedDBsNode::GetDetailedInfo() const {
472 return DetailedInfo(parent()->GetTitle(),
473 DetailedInfo::TYPE_INDEXED_DBS,
474 NULL, NULL, NULL, NULL, NULL, NULL);
475 }
476
477 ///////////////////////////////////////////////////////////////////////////////
478 // CookieTreeNode, protected
479
operator ()(const CookieTreeNode * lhs,const CookieTreeNode * rhs)480 bool 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
AddChildSortedByTitle(CookieTreeNode * new_child)489 void 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, new_child, iter - children().begin());
496 }
497
498 ///////////////////////////////////////////////////////////////////////////////
499 // CookiesTreeModel, public:
500
CookiesTreeModel(net::CookieMonster * cookie_monster,BrowsingDataDatabaseHelper * database_helper,BrowsingDataLocalStorageHelper * local_storage_helper,BrowsingDataLocalStorageHelper * session_storage_helper,BrowsingDataAppCacheHelper * appcache_helper,BrowsingDataIndexedDBHelper * indexed_db_helper,bool use_cookie_source)501 CookiesTreeModel::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 bool use_cookie_source)
509 : ALLOW_THIS_IN_INITIALIZER_LIST(ui::TreeNodeModel<CookieTreeNode>(
510 new CookieTreeRootNode(this))),
511 cookie_monster_(cookie_monster),
512 appcache_helper_(appcache_helper),
513 database_helper_(database_helper),
514 local_storage_helper_(local_storage_helper),
515 session_storage_helper_(session_storage_helper),
516 indexed_db_helper_(indexed_db_helper),
517 batch_update_(0),
518 use_cookie_source_(use_cookie_source) {
519 LoadCookies();
520 DCHECK(database_helper_);
521 database_helper_->StartFetching(NewCallback(
522 this, &CookiesTreeModel::OnDatabaseModelInfoLoaded));
523 DCHECK(local_storage_helper_);
524 local_storage_helper_->StartFetching(NewCallback(
525 this, &CookiesTreeModel::OnLocalStorageModelInfoLoaded));
526 if (session_storage_helper_) {
527 session_storage_helper_->StartFetching(NewCallback(
528 this, &CookiesTreeModel::OnSessionStorageModelInfoLoaded));
529 }
530
531 // TODO(michaeln): when all of the ui impls have been updated,
532 // make this a required parameter.
533 if (appcache_helper_) {
534 appcache_helper_->StartFetching(NewCallback(
535 this, &CookiesTreeModel::OnAppCacheModelInfoLoaded));
536 }
537
538 if (indexed_db_helper_) {
539 indexed_db_helper_->StartFetching(NewCallback(
540 this, &CookiesTreeModel::OnIndexedDBModelInfoLoaded));
541 }
542 }
543
~CookiesTreeModel()544 CookiesTreeModel::~CookiesTreeModel() {
545 database_helper_->CancelNotification();
546 local_storage_helper_->CancelNotification();
547 if (session_storage_helper_)
548 session_storage_helper_->CancelNotification();
549 if (appcache_helper_)
550 appcache_helper_->CancelNotification();
551 if (indexed_db_helper_)
552 indexed_db_helper_->CancelNotification();
553 }
554
555 ///////////////////////////////////////////////////////////////////////////////
556 // CookiesTreeModel, TreeModel methods (public):
557
558 // TreeModel methods:
559 // Returns the set of icons for the nodes in the tree. You only need override
560 // this if you don't want to use the default folder icons.
GetIcons(std::vector<SkBitmap> * icons)561 void CookiesTreeModel::GetIcons(std::vector<SkBitmap>* icons) {
562 icons->push_back(*ResourceBundle::GetSharedInstance().GetBitmapNamed(
563 IDR_OMNIBOX_HTTP));
564 icons->push_back(*ResourceBundle::GetSharedInstance().GetBitmapNamed(
565 IDR_COOKIE_ICON));
566 icons->push_back(*ResourceBundle::GetSharedInstance().GetBitmapNamed(
567 IDR_COOKIE_STORAGE_ICON));
568 }
569
570 // Returns the index of the icon to use for |node|. Return -1 to use the
571 // default icon. The index is relative to the list of icons returned from
572 // GetIcons.
GetIconIndex(ui::TreeModelNode * node)573 int CookiesTreeModel::GetIconIndex(ui::TreeModelNode* node) {
574 CookieTreeNode* ct_node = static_cast<CookieTreeNode*>(node);
575 switch (ct_node->GetDetailedInfo().node_type) {
576 case CookieTreeNode::DetailedInfo::TYPE_ORIGIN:
577 return ORIGIN;
578 case CookieTreeNode::DetailedInfo::TYPE_COOKIE:
579 return COOKIE;
580 case CookieTreeNode::DetailedInfo::TYPE_DATABASE:
581 return DATABASE;
582 case CookieTreeNode::DetailedInfo::TYPE_LOCAL_STORAGE:
583 return DATABASE; // close enough
584 case CookieTreeNode::DetailedInfo::TYPE_SESSION_STORAGE:
585 return DATABASE; // ditto
586 case CookieTreeNode::DetailedInfo::TYPE_APPCACHE:
587 return DATABASE; // ditto
588 case CookieTreeNode::DetailedInfo::TYPE_INDEXED_DB:
589 return DATABASE; // ditto
590 default:
591 break;
592 }
593 return -1;
594 }
595
LoadCookies()596 void CookiesTreeModel::LoadCookies() {
597 LoadCookiesWithFilter(std::wstring());
598 }
599
LoadCookiesWithFilter(const std::wstring & filter)600 void CookiesTreeModel::LoadCookiesWithFilter(const std::wstring& filter) {
601 // mmargh mmargh mmargh! delicious!
602
603 all_cookies_ = cookie_monster_->GetAllCookies();
604 CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
605 for (CookieList::iterator it = all_cookies_.begin();
606 it != all_cookies_.end(); ++it) {
607 std::string source_string = it->Source();
608 if (source_string.empty() || !use_cookie_source_) {
609 std::string domain = it->Domain();
610 if (domain.length() > 1 && domain[0] == '.')
611 domain = domain.substr(1);
612
613 // We treat secure cookies just the same as normal ones.
614 source_string = std::string(chrome::kHttpScheme) +
615 chrome::kStandardSchemeSeparator + domain + "/";
616 }
617
618 GURL source(source_string);
619 if (!filter.size() ||
620 (CookieTreeOriginNode::TitleForUrl(source).find(filter) !=
621 std::string::npos)) {
622 CookieTreeOriginNode* origin_node =
623 root->GetOrCreateOriginNode(source);
624 CookieTreeCookiesNode* cookies_node =
625 origin_node->GetOrCreateCookiesNode();
626 CookieTreeCookieNode* new_cookie = new CookieTreeCookieNode(&*it);
627 cookies_node->AddCookieNode(new_cookie);
628 }
629 }
630 }
631
DeleteAllStoredObjects()632 void CookiesTreeModel::DeleteAllStoredObjects() {
633 NotifyObserverBeginBatch();
634 CookieTreeNode* root = GetRoot();
635 root->DeleteStoredObjects();
636 int num_children = root->child_count();
637 for (int i = num_children - 1; i >= 0; --i)
638 delete Remove(root, root->GetChild(i));
639 NotifyObserverTreeNodeChanged(root);
640 NotifyObserverEndBatch();
641 }
642
DeleteCookieNode(CookieTreeNode * cookie_node)643 void CookiesTreeModel::DeleteCookieNode(CookieTreeNode* cookie_node) {
644 if (cookie_node == GetRoot())
645 return;
646 cookie_node->DeleteStoredObjects();
647 CookieTreeNode* parent_node = cookie_node->parent();
648 delete Remove(parent_node, cookie_node);
649 if (parent_node->child_count() == 0)
650 DeleteCookieNode(parent_node);
651 }
652
UpdateSearchResults(const std::wstring & filter)653 void CookiesTreeModel::UpdateSearchResults(const std::wstring& filter) {
654 CookieTreeNode* root = GetRoot();
655 int num_children = root->child_count();
656 NotifyObserverBeginBatch();
657 for (int i = num_children - 1; i >= 0; --i)
658 delete Remove(root, root->GetChild(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
AddCookiesTreeObserver(Observer * observer)669 void 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
RemoveCookiesTreeObserver(Observer * observer)675 void 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
OnAppCacheModelInfoLoaded()681 void CookiesTreeModel::OnAppCacheModelInfoLoaded() {
682 appcache_info_ = appcache_helper_->info_collection();
683 PopulateAppCacheInfoWithFilter(std::wstring());
684 }
685
PopulateAppCacheInfoWithFilter(const std::wstring & filter)686 void 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
OnDatabaseModelInfoLoaded(const DatabaseInfoList & database_info)719 void CookiesTreeModel::OnDatabaseModelInfoLoaded(
720 const DatabaseInfoList& database_info) {
721 database_info_list_ = database_info;
722 PopulateDatabaseInfoWithFilter(std::wstring());
723 }
724
PopulateDatabaseInfoWithFilter(const std::wstring & filter)725 void 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
OnLocalStorageModelInfoLoaded(const LocalStorageInfoList & local_storage_info)751 void CookiesTreeModel::OnLocalStorageModelInfoLoaded(
752 const LocalStorageInfoList& local_storage_info) {
753 local_storage_info_list_ = local_storage_info;
754 PopulateLocalStorageInfoWithFilter(std::wstring());
755 }
756
PopulateLocalStorageInfoWithFilter(const std::wstring & filter)757 void 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
OnSessionStorageModelInfoLoaded(const LocalStorageInfoList & session_storage_info)784 void CookiesTreeModel::OnSessionStorageModelInfoLoaded(
785 const LocalStorageInfoList& session_storage_info) {
786 session_storage_info_list_ = session_storage_info;
787 PopulateSessionStorageInfoWithFilter(std::wstring());
788 }
789
PopulateSessionStorageInfoWithFilter(const std::wstring & filter)790 void 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
OnIndexedDBModelInfoLoaded(const IndexedDBInfoList & indexed_db_info)817 void CookiesTreeModel::OnIndexedDBModelInfoLoaded(
818 const IndexedDBInfoList& indexed_db_info) {
819 indexed_db_info_list_ = indexed_db_info;
820 PopulateIndexedDBInfoWithFilter(std::wstring());
821 }
822
PopulateIndexedDBInfoWithFilter(const std::wstring & filter)823 void 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
NotifyObserverBeginBatch()850 void 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
NotifyObserverEndBatch()859 void 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