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