1 // Copyright 2017 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/counters/site_data_counting_helper.h"
6 
7 #include "base/bind.h"
8 #include "build/build_config.h"
9 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "components/browsing_data/content/browsing_data_helper.h"
12 #include "components/content_settings/core/browser/host_content_settings_map.h"
13 #include "content/public/browser/browser_task_traits.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "content/public/browser/dom_storage_context.h"
16 #include "content/public/browser/session_storage_usage_info.h"
17 #include "content/public/browser/storage_partition.h"
18 #include "content/public/browser/storage_usage_info.h"
19 #include "media/media_buildflags.h"
20 #include "net/cookies/cookie_util.h"
21 #include "ppapi/buildflags/buildflags.h"
22 #include "services/network/public/mojom/cookie_manager.mojom.h"
23 #include "storage/browser/file_system/file_system_context.h"
24 #include "storage/browser/quota/quota_manager.h"
25 #include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
26 #include "url/gurl.h"
27 #include "url/origin.h"
28 
29 #if defined(OS_ANDROID)
30 #include "components/cdm/browser/media_drm_storage_impl.h"  // nogncheck crbug.com/1125897
31 #endif
32 
33 using content::BrowserThread;
34 
SiteDataCountingHelper(Profile * profile,base::Time begin,base::Time end,base::OnceCallback<void (int)> completion_callback)35 SiteDataCountingHelper::SiteDataCountingHelper(
36     Profile* profile,
37     base::Time begin,
38     base::Time end,
39     base::OnceCallback<void(int)> completion_callback)
40     : profile_(profile),
41       begin_(begin),
42       end_(end),
43       completion_callback_(std::move(completion_callback)),
44       tasks_(0) {}
45 
~SiteDataCountingHelper()46 SiteDataCountingHelper::~SiteDataCountingHelper() {}
47 
CountAndDestroySelfWhenFinished()48 void SiteDataCountingHelper::CountAndDestroySelfWhenFinished() {
49   content::StoragePartition* partition =
50       content::BrowserContext::GetDefaultStoragePartition(profile_);
51 
52   scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy(
53       profile_->GetSpecialStoragePolicy());
54 
55   tasks_ += 1;
56   // Count origins with cookies.
57   network::mojom::CookieManager* cookie_manager =
58       partition->GetCookieManagerForBrowserProcess();
59   cookie_manager->GetAllCookies(base::BindOnce(
60       &SiteDataCountingHelper::GetCookiesCallback, base::Unretained(this)));
61 
62   storage::QuotaManager* quota_manager = partition->GetQuotaManager();
63   if (quota_manager) {
64     // Count origins with filesystem, websql, appcache, indexeddb,
65     // serviceworkers and cachestorage using quota manager.
66     auto origins_callback =
67         base::BindRepeating(&SiteDataCountingHelper::GetQuotaOriginsCallback,
68                             base::Unretained(this));
69     const blink::mojom::StorageType types[] = {
70         blink::mojom::StorageType::kTemporary,
71         blink::mojom::StorageType::kPersistent,
72         blink::mojom::StorageType::kSyncable};
73     for (auto type : types) {
74       tasks_ += 1;
75       content::GetIOThreadTaskRunner({})->PostTask(
76           FROM_HERE,
77           base::BindOnce(&storage::QuotaManager::GetOriginsModifiedBetween,
78                          quota_manager, type, begin_, end_, origins_callback));
79     }
80   }
81 
82   // Count origins with local storage or session storage.
83   content::DOMStorageContext* dom_storage = partition->GetDOMStorageContext();
84   if (dom_storage) {
85     tasks_ += 1;
86     auto local_callback = base::BindOnce(
87         &SiteDataCountingHelper::GetLocalStorageUsageInfoCallback,
88         base::Unretained(this), special_storage_policy);
89     dom_storage->GetLocalStorageUsage(std::move(local_callback));
90     // TODO(772337): Enable session storage counting when deletion is fixed.
91   }
92 
93 #if defined(OS_ANDROID)
94   // Count origins with media licenses on Android.
95   tasks_ += 1;
96   Done(cdm::MediaDrmStorageImpl::GetOriginsModifiedBetween(profile_->GetPrefs(),
97                                                            begin_, end_));
98 #endif  // defined(OS_ANDROID)
99 
100 #if BUILDFLAG(ENABLE_LIBRARY_CDMS)
101   // Count origins with media licenses.
102   storage::FileSystemContext* file_system_context =
103       content::BrowserContext::GetDefaultStoragePartition(profile_)
104           ->GetFileSystemContext();
105   media_license_helper_ =
106       BrowsingDataMediaLicenseHelper::Create(file_system_context);
107   if (media_license_helper_) {
108     tasks_ += 1;
109     media_license_helper_->StartFetching(
110         base::BindOnce(&SiteDataCountingHelper::SitesWithMediaLicensesCallback,
111                        base::Unretained(this)));
112   }
113 #endif
114 
115   // Counting site usage data and durable permissions.
116   auto* hcsm = HostContentSettingsMapFactory::GetForProfile(profile_);
117   const ContentSettingsType content_settings[] = {
118     ContentSettingsType::DURABLE_STORAGE,
119     ContentSettingsType::APP_BANNER,
120 #if !defined(OS_ANDROID)
121     ContentSettingsType::INSTALLED_WEB_APP_METADATA,
122 #endif
123   };
124   for (auto type : content_settings) {
125     tasks_ += 1;
126     GetOriginsFromHostContentSettignsMap(hcsm, type);
127   }
128 }
129 
GetOriginsFromHostContentSettignsMap(HostContentSettingsMap * hcsm,ContentSettingsType type)130 void SiteDataCountingHelper::GetOriginsFromHostContentSettignsMap(
131     HostContentSettingsMap* hcsm,
132     ContentSettingsType type) {
133   std::set<GURL> origins;
134   ContentSettingsForOneType settings;
135   hcsm->GetSettingsForOneType(type, &settings);
136   for (const ContentSettingPatternSource& rule : settings) {
137     GURL url(rule.primary_pattern.ToString());
138     if (!url.is_empty()) {
139       origins.insert(url);
140     }
141   }
142   Done(std::vector<GURL>(origins.begin(), origins.end()));
143 }
144 
GetCookiesCallback(const net::CookieList & cookies)145 void SiteDataCountingHelper::GetCookiesCallback(
146     const net::CookieList& cookies) {
147   std::vector<GURL> origins;
148   for (const net::CanonicalCookie& cookie : cookies) {
149     if (cookie.CreationDate() >= begin_ && cookie.CreationDate() < end_) {
150       GURL url = net::cookie_util::CookieOriginToURL(cookie.Domain(),
151                                                      cookie.IsSecure());
152       origins.push_back(url);
153     }
154   }
155   content::GetUIThreadTaskRunner({})->PostTask(
156       FROM_HERE, base::BindOnce(&SiteDataCountingHelper::Done,
157                                 base::Unretained(this), origins));
158 }
159 
GetQuotaOriginsCallback(const std::set<url::Origin> & origins,blink::mojom::StorageType type)160 void SiteDataCountingHelper::GetQuotaOriginsCallback(
161     const std::set<url::Origin>& origins,
162     blink::mojom::StorageType type) {
163   DCHECK_CURRENTLY_ON(BrowserThread::IO);
164   std::vector<GURL> urls;
165   urls.resize(origins.size());
166   for (const url::Origin& origin : origins)
167     urls.push_back(origin.GetURL());
168   content::GetUIThreadTaskRunner({})->PostTask(
169       FROM_HERE, base::BindOnce(&SiteDataCountingHelper::Done,
170                                 base::Unretained(this), std::move(urls)));
171 }
172 
GetLocalStorageUsageInfoCallback(const scoped_refptr<storage::SpecialStoragePolicy> & policy,const std::vector<content::StorageUsageInfo> & infos)173 void SiteDataCountingHelper::GetLocalStorageUsageInfoCallback(
174     const scoped_refptr<storage::SpecialStoragePolicy>& policy,
175     const std::vector<content::StorageUsageInfo>& infos) {
176   std::vector<GURL> origins;
177   for (const auto& info : infos) {
178     if (info.last_modified >= begin_ && info.last_modified < end_ &&
179         (!policy || !policy->IsStorageProtected(info.origin.GetURL()))) {
180       origins.push_back(info.origin.GetURL());
181     }
182   }
183   Done(origins);
184 }
185 
SitesWithMediaLicensesCallback(const std::list<BrowsingDataMediaLicenseHelper::MediaLicenseInfo> & media_license_info_list)186 void SiteDataCountingHelper::SitesWithMediaLicensesCallback(
187     const std::list<BrowsingDataMediaLicenseHelper::MediaLicenseInfo>&
188         media_license_info_list) {
189   std::vector<GURL> origins;
190   for (const auto& info : media_license_info_list) {
191     if (info.last_modified_time >= begin_ && info.last_modified_time < end_)
192       origins.push_back(info.origin);
193   }
194   Done(origins);
195 }
196 
Done(const std::vector<GURL> & origins)197 void SiteDataCountingHelper::Done(const std::vector<GURL>& origins) {
198   DCHECK_CURRENTLY_ON(BrowserThread::UI);
199   DCHECK(tasks_ > 0);
200   for (const GURL& origin : origins) {
201     if (browsing_data::HasWebScheme(origin))
202       unique_hosts_.insert(origin.host());
203   }
204   if (--tasks_ > 0)
205     return;
206   base::ThreadTaskRunnerHandle::Get()->PostTask(
207       FROM_HERE,
208       base::BindOnce(std::move(completion_callback_), unique_hosts_.size()));
209   base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
210 }
211