Roll src/third_party/WebKit f298044:aa8346d (svn 202628:202629)
[chromium-blink-merge.git] / chrome / browser / extensions / extension_special_storage_policy.cc
blob2990f6daba22ebbd7cc532a7d0fa29f35508d4d3
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.
5 #include "chrome/browser/extensions/extension_special_storage_policy.h"
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/logging.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/metrics/histogram.h"
12 #include "base/stl_util.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "chrome/browser/content_settings/cookie_settings_factory.h"
15 #include "chrome/common/chrome_switches.h"
16 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
17 #include "chrome/common/url_constants.h"
18 #include "components/content_settings/core/browser/cookie_settings.h"
19 #include "components/content_settings/core/common/content_settings.h"
20 #include "components/content_settings/core/common/content_settings_types.h"
21 #include "content/public/browser/browser_context.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/storage_partition.h"
24 #include "content/public/common/url_constants.h"
25 #include "extensions/common/constants.h"
26 #include "extensions/common/extension.h"
27 #include "extensions/common/extension_set.h"
28 #include "extensions/common/manifest_handlers/app_isolation_info.h"
29 #include "extensions/common/manifest_handlers/content_capabilities_handler.h"
30 #include "extensions/common/permissions/permissions_data.h"
31 #include "storage/browser/quota/quota_manager.h"
32 #include "storage/common/quota/quota_status_code.h"
33 #include "storage/common/quota/quota_types.h"
35 using content::BrowserThread;
36 using extensions::APIPermission;
37 using extensions::Extension;
38 using storage::SpecialStoragePolicy;
40 namespace {
42 void ReportQuotaUsage(storage::QuotaStatusCode code, int64 usage, int64 quota) {
43 if (code == storage::kQuotaStatusOk) {
44 // We're interested in the amount of space hosted apps are using. Record it
45 // when the extension is granted the unlimited storage permission (once per
46 // extension load, so on average once per run).
47 UMA_HISTOGRAM_MEMORY_KB("Extensions.HostedAppUnlimitedStorageUsage", usage);
51 // Log the usage for a hosted app with unlimited storage.
52 void LogHostedAppUnlimitedStorageUsage(
53 scoped_refptr<const Extension> extension,
54 content::BrowserContext* browser_context) {
55 GURL launch_url =
56 extensions::AppLaunchInfo::GetLaunchWebURL(extension.get()).GetOrigin();
57 content::StoragePartition* partition =
58 browser_context ? // |browser_context| can be NULL in unittests.
59 content::BrowserContext::GetStoragePartitionForSite(browser_context,
60 launch_url) :
61 NULL;
62 if (partition) {
63 // We only have to query for kStorageTypePersistent data usage, because apps
64 // cannot ask for any more temporary storage, according to
65 // https://developers.google.com/chrome/whitepapers/storage.
66 BrowserThread::PostAfterStartupTask(
67 FROM_HERE,
68 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO),
69 base::Bind(&storage::QuotaManager::GetUsageAndQuotaForWebApps,
70 partition->GetQuotaManager(),
71 launch_url,
72 storage::kStorageTypePersistent,
73 base::Bind(&ReportQuotaUsage)));
77 } // namespace
79 ExtensionSpecialStoragePolicy::ExtensionSpecialStoragePolicy(
80 content_settings::CookieSettings* cookie_settings)
81 : cookie_settings_(cookie_settings) {
84 ExtensionSpecialStoragePolicy::~ExtensionSpecialStoragePolicy() {}
86 bool ExtensionSpecialStoragePolicy::IsStorageProtected(const GURL& origin) {
87 if (origin.SchemeIs(extensions::kExtensionScheme))
88 return true;
89 base::AutoLock locker(lock_);
90 return protected_apps_.Contains(origin);
93 bool ExtensionSpecialStoragePolicy::IsStorageUnlimited(const GURL& origin) {
94 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
95 switches::kUnlimitedStorage))
96 return true;
98 if (origin.SchemeIs(content::kChromeDevToolsScheme) &&
99 origin.host() == chrome::kChromeUIDevToolsHost)
100 return true;
102 base::AutoLock locker(lock_);
103 return unlimited_extensions_.Contains(origin) ||
104 content_capabilities_unlimited_extensions_.GrantsCapabilitiesTo(
105 origin);
108 bool ExtensionSpecialStoragePolicy::IsStorageSessionOnly(const GURL& origin) {
109 if (cookie_settings_.get() == NULL)
110 return false;
111 return cookie_settings_->IsCookieSessionOnly(origin);
114 bool ExtensionSpecialStoragePolicy::CanQueryDiskSize(const GURL& origin) {
115 base::AutoLock locker(lock_);
116 return installed_apps_.Contains(origin);
119 bool ExtensionSpecialStoragePolicy::HasSessionOnlyOrigins() {
120 if (cookie_settings_.get() == NULL)
121 return false;
122 if (cookie_settings_->GetDefaultCookieSetting(NULL) ==
123 CONTENT_SETTING_SESSION_ONLY)
124 return true;
125 ContentSettingsForOneType entries;
126 cookie_settings_->GetCookieSettings(&entries);
127 for (size_t i = 0; i < entries.size(); ++i) {
128 if (entries[i].setting == CONTENT_SETTING_SESSION_ONLY)
129 return true;
131 return false;
134 bool ExtensionSpecialStoragePolicy::HasIsolatedStorage(const GURL& origin) {
135 base::AutoLock locker(lock_);
136 return isolated_extensions_.Contains(origin);
139 bool ExtensionSpecialStoragePolicy::IsStorageDurable(const GURL& origin) {
140 return cookie_settings_->IsStorageDurable(origin);
143 bool ExtensionSpecialStoragePolicy::NeedsProtection(
144 const extensions::Extension* extension) {
145 return extension->is_hosted_app() && !extension->from_bookmark();
148 const extensions::ExtensionSet*
149 ExtensionSpecialStoragePolicy::ExtensionsProtectingOrigin(
150 const GURL& origin) {
151 base::AutoLock locker(lock_);
152 return protected_apps_.ExtensionsContaining(origin);
155 void ExtensionSpecialStoragePolicy::GrantRightsForExtension(
156 const extensions::Extension* extension,
157 content::BrowserContext* browser_context) {
158 base::AutoLock locker(lock_);
159 DCHECK(extension);
161 int change_flags = 0;
162 if (extensions::ContentCapabilitiesInfo::Get(extension)
163 .permissions.count(APIPermission::kUnlimitedStorage) > 0) {
164 content_capabilities_unlimited_extensions_.Add(extension);
165 change_flags |= SpecialStoragePolicy::STORAGE_UNLIMITED;
168 if (NeedsProtection(extension) ||
169 extension->permissions_data()->HasAPIPermission(
170 APIPermission::kUnlimitedStorage) ||
171 extension->permissions_data()->HasAPIPermission(
172 APIPermission::kFileBrowserHandler) ||
173 extensions::AppIsolationInfo::HasIsolatedStorage(extension) ||
174 extension->is_app()) {
175 if (NeedsProtection(extension) && protected_apps_.Add(extension))
176 change_flags |= SpecialStoragePolicy::STORAGE_PROTECTED;
177 // FIXME: Does GrantRightsForExtension imply |extension| is installed?
178 if (extension->is_app())
179 installed_apps_.Add(extension);
181 if (extension->permissions_data()->HasAPIPermission(
182 APIPermission::kUnlimitedStorage) &&
183 unlimited_extensions_.Add(extension)) {
184 if (extension->is_hosted_app())
185 LogHostedAppUnlimitedStorageUsage(extension, browser_context);
186 change_flags |= SpecialStoragePolicy::STORAGE_UNLIMITED;
189 if (extension->permissions_data()->HasAPIPermission(
190 APIPermission::kFileBrowserHandler))
191 file_handler_extensions_.Add(extension);
193 if (extensions::AppIsolationInfo::HasIsolatedStorage(extension))
194 isolated_extensions_.Add(extension);
197 if (change_flags) {
198 NotifyGranted(Extension::GetBaseURLFromExtensionId(extension->id()),
199 change_flags);
203 void ExtensionSpecialStoragePolicy::RevokeRightsForExtension(
204 const extensions::Extension* extension) {
205 base::AutoLock locker(lock_);
206 DCHECK(extension);
208 int change_flags = 0;
209 if (extensions::ContentCapabilitiesInfo::Get(extension)
210 .permissions.count(APIPermission::kUnlimitedStorage) > 0) {
211 content_capabilities_unlimited_extensions_.Remove(extension);
212 change_flags |= SpecialStoragePolicy::STORAGE_UNLIMITED;
215 if (NeedsProtection(extension) ||
216 extension->permissions_data()->HasAPIPermission(
217 APIPermission::kUnlimitedStorage) ||
218 extension->permissions_data()->HasAPIPermission(
219 APIPermission::kFileBrowserHandler) ||
220 extensions::AppIsolationInfo::HasIsolatedStorage(extension) ||
221 extension->is_app()) {
222 if (NeedsProtection(extension) && protected_apps_.Remove(extension))
223 change_flags |= SpecialStoragePolicy::STORAGE_PROTECTED;
225 if (extension->is_app())
226 installed_apps_.Remove(extension);
228 if (extension->permissions_data()->HasAPIPermission(
229 APIPermission::kUnlimitedStorage) &&
230 unlimited_extensions_.Remove(extension))
231 change_flags |= SpecialStoragePolicy::STORAGE_UNLIMITED;
233 if (extension->permissions_data()->HasAPIPermission(
234 APIPermission::kFileBrowserHandler))
235 file_handler_extensions_.Remove(extension);
237 if (extensions::AppIsolationInfo::HasIsolatedStorage(extension))
238 isolated_extensions_.Remove(extension);
241 if (change_flags) {
242 NotifyRevoked(Extension::GetBaseURLFromExtensionId(extension->id()),
243 change_flags);
247 void ExtensionSpecialStoragePolicy::RevokeRightsForAllExtensions() {
249 base::AutoLock locker(lock_);
250 protected_apps_.Clear();
251 installed_apps_.Clear();
252 unlimited_extensions_.Clear();
253 file_handler_extensions_.Clear();
254 isolated_extensions_.Clear();
255 content_capabilities_unlimited_extensions_.Clear();
258 NotifyCleared();
261 void ExtensionSpecialStoragePolicy::NotifyGranted(
262 const GURL& origin,
263 int change_flags) {
264 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
265 BrowserThread::PostTask(
266 BrowserThread::IO, FROM_HERE,
267 base::Bind(&ExtensionSpecialStoragePolicy::NotifyGranted, this,
268 origin, change_flags));
269 return;
271 SpecialStoragePolicy::NotifyGranted(origin, change_flags);
274 void ExtensionSpecialStoragePolicy::NotifyRevoked(
275 const GURL& origin,
276 int change_flags) {
277 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
278 BrowserThread::PostTask(
279 BrowserThread::IO, FROM_HERE,
280 base::Bind(&ExtensionSpecialStoragePolicy::NotifyRevoked, this,
281 origin, change_flags));
282 return;
284 SpecialStoragePolicy::NotifyRevoked(origin, change_flags);
287 void ExtensionSpecialStoragePolicy::NotifyCleared() {
288 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
289 BrowserThread::PostTask(
290 BrowserThread::IO, FROM_HERE,
291 base::Bind(&ExtensionSpecialStoragePolicy::NotifyCleared, this));
292 return;
294 SpecialStoragePolicy::NotifyCleared();
297 //-----------------------------------------------------------------------------
298 // SpecialCollection helper class
299 //-----------------------------------------------------------------------------
301 ExtensionSpecialStoragePolicy::SpecialCollection::SpecialCollection() {}
303 ExtensionSpecialStoragePolicy::SpecialCollection::~SpecialCollection() {
304 STLDeleteValues(&cached_results_);
307 bool ExtensionSpecialStoragePolicy::SpecialCollection::Contains(
308 const GURL& origin) {
309 return !ExtensionsContaining(origin)->is_empty();
312 bool ExtensionSpecialStoragePolicy::SpecialCollection::GrantsCapabilitiesTo(
313 const GURL& origin) {
314 for (scoped_refptr<const Extension> extension : extensions_) {
315 if (extensions::ContentCapabilitiesInfo::Get(extension.get())
316 .url_patterns.MatchesURL(origin)) {
317 return true;
320 return false;
323 const extensions::ExtensionSet*
324 ExtensionSpecialStoragePolicy::SpecialCollection::ExtensionsContaining(
325 const GURL& origin) {
326 CachedResults::const_iterator found = cached_results_.find(origin);
327 if (found != cached_results_.end())
328 return found->second;
330 extensions::ExtensionSet* result = new extensions::ExtensionSet();
331 for (extensions::ExtensionSet::const_iterator iter = extensions_.begin();
332 iter != extensions_.end(); ++iter) {
333 if ((*iter)->OverlapsWithOrigin(origin))
334 result->Insert(*iter);
336 cached_results_[origin] = result;
337 return result;
340 bool ExtensionSpecialStoragePolicy::SpecialCollection::ContainsExtension(
341 const std::string& extension_id) {
342 return extensions_.Contains(extension_id);
345 bool ExtensionSpecialStoragePolicy::SpecialCollection::Add(
346 const extensions::Extension* extension) {
347 ClearCache();
348 return extensions_.Insert(extension);
351 bool ExtensionSpecialStoragePolicy::SpecialCollection::Remove(
352 const extensions::Extension* extension) {
353 ClearCache();
354 return extensions_.Remove(extension->id());
357 void ExtensionSpecialStoragePolicy::SpecialCollection::Clear() {
358 ClearCache();
359 extensions_.Clear();
362 void ExtensionSpecialStoragePolicy::SpecialCollection::ClearCache() {
363 STLDeleteValues(&cached_results_);