1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/src/storage/DOMStorageManager.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,719 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "DOMStorageManager.h" 1.10 +#include "DOMStorage.h" 1.11 +#include "DOMStorageDBThread.h" 1.12 + 1.13 +#include "nsIScriptSecurityManager.h" 1.14 +#include "nsIEffectiveTLDService.h" 1.15 + 1.16 +#include "nsNetUtil.h" 1.17 +#include "nsPrintfCString.h" 1.18 +#include "nsXULAppAPI.h" 1.19 +#include "nsThreadUtils.h" 1.20 +#include "nsIObserverService.h" 1.21 +#include "mozIThirdPartyUtil.h" 1.22 +#include "mozilla/Services.h" 1.23 +#include "mozilla/Preferences.h" 1.24 + 1.25 +// Only allow relatively small amounts of data since performance of 1.26 +// the synchronous IO is very bad. 1.27 +// We are enforcing simple per-origin quota only. 1.28 +#define DEFAULT_QUOTA_LIMIT (5 * 1024) 1.29 + 1.30 +namespace mozilla { 1.31 +namespace dom { 1.32 + 1.33 +namespace { // anon 1.34 + 1.35 +int32_t gQuotaLimit = DEFAULT_QUOTA_LIMIT; 1.36 + 1.37 +} // anon 1.38 + 1.39 +DOMLocalStorageManager* 1.40 +DOMLocalStorageManager::sSelf = nullptr; 1.41 + 1.42 +// static 1.43 +uint32_t 1.44 +DOMStorageManager::GetQuota() 1.45 +{ 1.46 + static bool preferencesInitialized = false; 1.47 + if (!preferencesInitialized) { 1.48 + mozilla::Preferences::AddIntVarCache(&gQuotaLimit, "dom.storage.default_quota", 1.49 + DEFAULT_QUOTA_LIMIT); 1.50 + preferencesInitialized = true; 1.51 + } 1.52 + 1.53 + return gQuotaLimit * 1024; // pref is in kBs 1.54 +} 1.55 + 1.56 +void 1.57 +ReverseString(const nsCSubstring& aSource, nsCSubstring& aResult) 1.58 +{ 1.59 + nsACString::const_iterator sourceBegin, sourceEnd; 1.60 + aSource.BeginReading(sourceBegin); 1.61 + aSource.EndReading(sourceEnd); 1.62 + 1.63 + aResult.SetLength(aSource.Length()); 1.64 + nsACString::iterator destEnd; 1.65 + aResult.EndWriting(destEnd); 1.66 + 1.67 + while (sourceBegin != sourceEnd) { 1.68 + *(--destEnd) = *sourceBegin; 1.69 + ++sourceBegin; 1.70 + } 1.71 +} 1.72 + 1.73 +nsresult 1.74 +CreateReversedDomain(const nsACString& aAsciiDomain, 1.75 + nsACString& aKey) 1.76 +{ 1.77 + if (aAsciiDomain.IsEmpty()) { 1.78 + return NS_ERROR_NOT_AVAILABLE; 1.79 + } 1.80 + 1.81 + ReverseString(aAsciiDomain, aKey); 1.82 + 1.83 + aKey.AppendLiteral("."); 1.84 + return NS_OK; 1.85 +} 1.86 + 1.87 +bool 1.88 +PrincipalsEqual(nsIPrincipal* aObjectPrincipal, nsIPrincipal* aSubjectPrincipal) 1.89 +{ 1.90 + if (!aSubjectPrincipal) { 1.91 + return true; 1.92 + } 1.93 + 1.94 + if (!aObjectPrincipal) { 1.95 + return false; 1.96 + } 1.97 + 1.98 + return aSubjectPrincipal->Equals(aObjectPrincipal); 1.99 +} 1.100 + 1.101 +NS_IMPL_ISUPPORTS(DOMStorageManager, 1.102 + nsIDOMStorageManager) 1.103 + 1.104 +DOMStorageManager::DOMStorageManager(nsPIDOMStorage::StorageType aType) 1.105 + : mCaches(10) 1.106 + , mType(aType) 1.107 + , mLowDiskSpace(false) 1.108 +{ 1.109 + DOMStorageObserver* observer = DOMStorageObserver::Self(); 1.110 + NS_ASSERTION(observer, "No DOMStorageObserver, cannot observe private data delete notifications!"); 1.111 + 1.112 + if (observer) { 1.113 + observer->AddSink(this); 1.114 + } 1.115 +} 1.116 + 1.117 +DOMStorageManager::~DOMStorageManager() 1.118 +{ 1.119 + DOMStorageObserver* observer = DOMStorageObserver::Self(); 1.120 + if (observer) { 1.121 + observer->RemoveSink(this); 1.122 + } 1.123 +} 1.124 + 1.125 +namespace { // anon 1.126 + 1.127 +nsresult 1.128 +AppendFirstPartyToKey(nsIURI* aFirstPartyIsolationURI, nsACString& aKey) 1.129 +{ 1.130 + if (aFirstPartyIsolationURI) { 1.131 + nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil = 1.132 + do_GetService(THIRDPARTYUTIL_CONTRACTID); 1.133 + if (!thirdPartyUtil) 1.134 + return NS_ERROR_FAILURE; 1.135 + 1.136 + nsAutoCString firstPartyHost; 1.137 + nsresult rv = thirdPartyUtil->GetFirstPartyHostForIsolation(aFirstPartyIsolationURI, 1.138 + firstPartyHost); 1.139 + NS_ENSURE_SUCCESS(rv, rv); 1.140 + 1.141 + aKey.AppendLiteral("&"); 1.142 + aKey.Append(firstPartyHost); 1.143 + } 1.144 + 1.145 + return NS_OK; 1.146 +} 1.147 + 1.148 +nsresult 1.149 +CreateScopeKey(nsIURI* aFirstPartyIsolationURI, nsIPrincipal* aPrincipal, 1.150 + nsACString& aKey) 1.151 +{ 1.152 + nsCOMPtr<nsIURI> uri; 1.153 + nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri)); 1.154 + NS_ENSURE_SUCCESS(rv, rv); 1.155 + if (!uri) { 1.156 + return NS_ERROR_UNEXPECTED; 1.157 + } 1.158 + 1.159 + nsAutoCString domainScope; 1.160 + rv = uri->GetAsciiHost(domainScope); 1.161 + NS_ENSURE_SUCCESS(rv, rv); 1.162 + 1.163 + if (domainScope.IsEmpty()) { 1.164 + // For the file:/// protocol use the exact directory as domain. 1.165 + bool isScheme = false; 1.166 + if (NS_SUCCEEDED(uri->SchemeIs("file", &isScheme)) && isScheme) { 1.167 + nsCOMPtr<nsIURL> url = do_QueryInterface(uri, &rv); 1.168 + NS_ENSURE_SUCCESS(rv, rv); 1.169 + rv = url->GetDirectory(domainScope); 1.170 + NS_ENSURE_SUCCESS(rv, rv); 1.171 + } 1.172 + } 1.173 + 1.174 + nsAutoCString key; 1.175 + 1.176 + rv = CreateReversedDomain(domainScope, key); 1.177 + if (NS_FAILED(rv)) { 1.178 + return rv; 1.179 + } 1.180 + 1.181 + nsAutoCString scheme; 1.182 + rv = uri->GetScheme(scheme); 1.183 + NS_ENSURE_SUCCESS(rv, rv); 1.184 + 1.185 + key.Append(NS_LITERAL_CSTRING(":") + scheme); 1.186 + 1.187 + int32_t port = NS_GetRealPort(uri); 1.188 + if (port != -1) { 1.189 + key.Append(nsPrintfCString(":%d", port)); 1.190 + } 1.191 + 1.192 + bool unknownAppId; 1.193 + rv = aPrincipal->GetUnknownAppId(&unknownAppId); 1.194 + NS_ENSURE_SUCCESS(rv, rv); 1.195 + 1.196 + if (!unknownAppId) { 1.197 + uint32_t appId; 1.198 + rv = aPrincipal->GetAppId(&appId); 1.199 + NS_ENSURE_SUCCESS(rv, rv); 1.200 + 1.201 + bool isInBrowserElement; 1.202 + rv = aPrincipal->GetIsInBrowserElement(&isInBrowserElement); 1.203 + NS_ENSURE_SUCCESS(rv, rv); 1.204 + 1.205 + if (appId == nsIScriptSecurityManager::NO_APP_ID && !isInBrowserElement) { 1.206 + aKey.Assign(key); 1.207 + } else { 1.208 + aKey.Truncate(); 1.209 + aKey.AppendInt(appId); 1.210 + aKey.Append(NS_LITERAL_CSTRING(":") + (isInBrowserElement ? 1.211 + NS_LITERAL_CSTRING("t") : NS_LITERAL_CSTRING("f")) + 1.212 + NS_LITERAL_CSTRING(":") + key); 1.213 + } 1.214 + } 1.215 + 1.216 + // Isolate scope keys to the URL bar domain by appending &firstPartyHost 1.217 + // if available. 1.218 + return AppendFirstPartyToKey(aFirstPartyIsolationURI, aKey); 1.219 +} 1.220 + 1.221 +nsresult 1.222 +CreateQuotaDBKey(nsIURI* aFirstPartyIsolationURI, nsIPrincipal* aPrincipal, 1.223 + nsACString& aKey) 1.224 +{ 1.225 + nsresult rv; 1.226 + 1.227 + nsAutoCString subdomainsDBKey; 1.228 + nsCOMPtr<nsIEffectiveTLDService> eTLDService(do_GetService( 1.229 + NS_EFFECTIVETLDSERVICE_CONTRACTID, &rv)); 1.230 + NS_ENSURE_SUCCESS(rv, rv); 1.231 + 1.232 + nsCOMPtr<nsIURI> uri; 1.233 + rv = aPrincipal->GetURI(getter_AddRefs(uri)); 1.234 + NS_ENSURE_SUCCESS(rv, rv); 1.235 + NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED); 1.236 + 1.237 + nsAutoCString eTLDplusOne; 1.238 + rv = eTLDService->GetBaseDomain(uri, 0, eTLDplusOne); 1.239 + if (NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS == rv) { 1.240 + // XXX bug 357323 - what to do for localhost/file exactly? 1.241 + rv = uri->GetAsciiHost(eTLDplusOne); 1.242 + } 1.243 + NS_ENSURE_SUCCESS(rv, rv); 1.244 + 1.245 + CreateReversedDomain(eTLDplusOne, subdomainsDBKey); 1.246 + 1.247 + bool unknownAppId; 1.248 + rv = aPrincipal->GetUnknownAppId(&unknownAppId); 1.249 + NS_ENSURE_SUCCESS(rv, rv); 1.250 + 1.251 + if (!unknownAppId) { 1.252 + uint32_t appId; 1.253 + rv = aPrincipal->GetAppId(&appId); 1.254 + NS_ENSURE_SUCCESS(rv, rv); 1.255 + 1.256 + bool isInBrowserElement; 1.257 + rv = aPrincipal->GetIsInBrowserElement(&isInBrowserElement); 1.258 + NS_ENSURE_SUCCESS(rv, rv); 1.259 + 1.260 + if (appId == nsIScriptSecurityManager::NO_APP_ID && !isInBrowserElement) { 1.261 + aKey.Assign(subdomainsDBKey); 1.262 + } else { 1.263 + aKey.Truncate(); 1.264 + aKey.AppendInt(appId); 1.265 + aKey.Append(NS_LITERAL_CSTRING(":") + (isInBrowserElement ? 1.266 + NS_LITERAL_CSTRING("t") : NS_LITERAL_CSTRING("f")) + 1.267 + NS_LITERAL_CSTRING(":") + subdomainsDBKey); 1.268 + } 1.269 + } 1.270 + 1.271 + // Isolate scope keys to the URL bar domain by appending &firstPartyHost 1.272 + // if available. 1.273 + return AppendFirstPartyToKey(aFirstPartyIsolationURI, aKey); 1.274 +} 1.275 + 1.276 +} // anon 1.277 + 1.278 +DOMStorageCache* 1.279 +DOMStorageManager::GetCache(const nsACString& aScope) const 1.280 +{ 1.281 + DOMStorageCacheHashKey* entry = mCaches.GetEntry(aScope); 1.282 + if (!entry) { 1.283 + return nullptr; 1.284 + } 1.285 + 1.286 + return entry->cache(); 1.287 +} 1.288 + 1.289 +already_AddRefed<DOMStorageUsage> 1.290 +DOMStorageManager::GetScopeUsage(const nsACString& aScope) 1.291 +{ 1.292 + nsRefPtr<DOMStorageUsage> usage; 1.293 + if (mUsages.Get(aScope, &usage)) { 1.294 + return usage.forget(); 1.295 + } 1.296 + 1.297 + usage = new DOMStorageUsage(aScope); 1.298 + 1.299 + if (mType == LocalStorage) { 1.300 + DOMStorageDBBridge* db = DOMStorageCache::StartDatabase(); 1.301 + if (db) { 1.302 + db->AsyncGetUsage(usage); 1.303 + } 1.304 + } 1.305 + 1.306 + mUsages.Put(aScope, usage); 1.307 + 1.308 + return usage.forget(); 1.309 +} 1.310 + 1.311 +already_AddRefed<DOMStorageCache> 1.312 +DOMStorageManager::PutCache(const nsACString& aScope, 1.313 + nsIURI* aFirstPartyIsolationURI, 1.314 + nsIPrincipal* aPrincipal) 1.315 +{ 1.316 + DOMStorageCacheHashKey* entry = mCaches.PutEntry(aScope); 1.317 + nsRefPtr<DOMStorageCache> cache = entry->cache(); 1.318 + 1.319 + nsAutoCString quotaScope; 1.320 + CreateQuotaDBKey(aFirstPartyIsolationURI, aPrincipal, quotaScope); 1.321 + 1.322 + // To avoid ever persisting session storage to disk, initialize LocalStorage 1.323 + // like SessionStorage. 1.324 + switch (mType) { 1.325 + case SessionStorage: 1.326 + case LocalStorage: 1.327 + // Lifetime handled by the manager, don't persist 1.328 + entry->HardRef(); 1.329 + cache->Init(this, false, aFirstPartyIsolationURI, aPrincipal, quotaScope); 1.330 + break; 1.331 + 1.332 + default: 1.333 + MOZ_ASSERT(false); 1.334 + } 1.335 + 1.336 + return cache.forget(); 1.337 +} 1.338 + 1.339 +void 1.340 +DOMStorageManager::DropCache(DOMStorageCache* aCache) 1.341 +{ 1.342 + if (!NS_IsMainThread()) { 1.343 + NS_WARNING("DOMStorageManager::DropCache called on a non-main thread, shutting down?"); 1.344 + } 1.345 + 1.346 + mCaches.RemoveEntry(aCache->Scope()); 1.347 +} 1.348 + 1.349 +nsresult 1.350 +DOMStorageManager::GetStorageInternal(bool aCreate, 1.351 + nsIURI* aFirstPartyIsolationURI, 1.352 + nsIPrincipal* aPrincipal, 1.353 + const nsAString& aDocumentURI, 1.354 + bool aPrivate, 1.355 + nsIDOMStorage** aRetval) 1.356 +{ 1.357 + nsresult rv; 1.358 + 1.359 + nsAutoCString scope; 1.360 + rv = CreateScopeKey(aFirstPartyIsolationURI, aPrincipal, scope); 1.361 + if (NS_FAILED(rv)) { 1.362 + return NS_ERROR_NOT_AVAILABLE; 1.363 + } 1.364 + 1.365 + nsRefPtr<DOMStorageCache> cache = GetCache(scope); 1.366 + 1.367 + // Get or create a cache for the given scope 1.368 + if (!cache) { 1.369 + if (!aCreate) { 1.370 + *aRetval = nullptr; 1.371 + return NS_OK; 1.372 + } 1.373 + 1.374 + if (!aRetval) { 1.375 + // This is demand to just preload the cache, if the scope has 1.376 + // no data stored, bypass creation and preload of the cache. 1.377 + DOMStorageDBBridge* db = DOMStorageCache::GetDatabase(); 1.378 + if (db) { 1.379 + if (!db->ShouldPreloadScope(scope)) { 1.380 + return NS_OK; 1.381 + } 1.382 + } else { 1.383 + if (scope.Equals(NS_LITERAL_CSTRING("knalb.:about"))) { 1.384 + return NS_OK; 1.385 + } 1.386 + } 1.387 + } 1.388 + 1.389 + // There is always a single instance of a cache per scope 1.390 + // in a single instance of a DOM storage manager. 1.391 + cache = PutCache(scope, aFirstPartyIsolationURI, aPrincipal); 1.392 + } else if (mType == SessionStorage) { 1.393 + if (!cache->CheckPrincipal(aPrincipal)) { 1.394 + return NS_ERROR_DOM_SECURITY_ERR; 1.395 + } 1.396 + } 1.397 + 1.398 + if (aRetval) { 1.399 + *aRetval = new DOMStorage(this, cache, aDocumentURI, aPrincipal, aPrivate); 1.400 + NS_ADDREF(*aRetval); 1.401 + } 1.402 + 1.403 + return NS_OK; 1.404 +} 1.405 + 1.406 +NS_IMETHODIMP 1.407 +DOMStorageManager::PrecacheStorage(nsIPrincipal* aPrincipal) 1.408 +{ 1.409 + return GetStorageInternal(true, nullptr, aPrincipal, EmptyString(), 1.410 + false, nullptr); 1.411 +} 1.412 + 1.413 +NS_IMETHODIMP 1.414 +DOMStorageManager::PrecacheStorageForFirstParty(nsIURI* aFirstPartyIsolationURI, 1.415 + nsIPrincipal* aPrincipal) 1.416 +{ 1.417 + return GetStorageInternal(true, aFirstPartyIsolationURI, aPrincipal, EmptyString(), 1.418 + false, nullptr); 1.419 +} 1.420 + 1.421 +NS_IMETHODIMP 1.422 +DOMStorageManager::CreateStorage(nsIPrincipal* aPrincipal, 1.423 + const nsAString& aDocumentURI, 1.424 + bool aPrivate, 1.425 + nsIDOMStorage** aRetval) 1.426 +{ 1.427 + return GetStorageInternal(true, nullptr, aPrincipal, aDocumentURI, 1.428 + aPrivate, aRetval); 1.429 +} 1.430 + 1.431 +NS_IMETHODIMP 1.432 +DOMStorageManager::CreateStorageForFirstParty(nsIURI* aFirstPartyIsolationURI, 1.433 + nsIPrincipal* aPrincipal, 1.434 + const nsAString& aDocumentURI, 1.435 + bool aPrivate, 1.436 + nsIDOMStorage** aRetval) 1.437 +{ 1.438 + return GetStorageInternal(true, aFirstPartyIsolationURI, aPrincipal, aDocumentURI, 1.439 + aPrivate, aRetval); 1.440 +} 1.441 + 1.442 +NS_IMETHODIMP 1.443 +DOMStorageManager::GetStorage(nsIPrincipal* aPrincipal, 1.444 + bool aPrivate, 1.445 + nsIDOMStorage** aRetval) 1.446 +{ 1.447 + return GetStorageInternal(false, nullptr, aPrincipal, EmptyString(), 1.448 + aPrivate, aRetval); 1.449 +} 1.450 + 1.451 +NS_IMETHODIMP 1.452 +DOMStorageManager::GetStorageForFirstParty(nsIURI* aFirstPartyIsolationURI, 1.453 + nsIPrincipal* aPrincipal, 1.454 + bool aPrivate, 1.455 + nsIDOMStorage** aRetval) 1.456 +{ 1.457 + return GetStorageInternal(false, aFirstPartyIsolationURI, aPrincipal, 1.458 + EmptyString(), aPrivate, aRetval); 1.459 +} 1.460 + 1.461 +NS_IMETHODIMP 1.462 +DOMStorageManager::CloneStorage(nsIDOMStorage* aStorage) 1.463 +{ 1.464 + if (mType != SessionStorage) { 1.465 + // Cloning is supported only for sessionStorage 1.466 + return NS_ERROR_NOT_IMPLEMENTED; 1.467 + } 1.468 + 1.469 + nsCOMPtr<nsPIDOMStorage> pstorage = do_QueryInterface(aStorage); 1.470 + if (!pstorage) { 1.471 + return NS_ERROR_UNEXPECTED; 1.472 + } 1.473 + 1.474 + const DOMStorageCache* origCache = pstorage->GetCache(); 1.475 + 1.476 + DOMStorageCache* existingCache = GetCache(origCache->Scope()); 1.477 + if (existingCache) { 1.478 + // Do not replace an existing sessionStorage. 1.479 + return NS_ERROR_NOT_AVAILABLE; 1.480 + } 1.481 + 1.482 + // Since this manager is sessionStorage manager, PutCache hard references 1.483 + // the cache in our hashtable. 1.484 + nsRefPtr<DOMStorageCache> newCache = PutCache(origCache->Scope(), 1.485 + origCache->FirstPartyIsolationURI(), 1.486 + origCache->Principal()); 1.487 + 1.488 + newCache->CloneFrom(origCache); 1.489 + return NS_OK; 1.490 +} 1.491 + 1.492 +NS_IMETHODIMP 1.493 +DOMStorageManager::CheckStorage(nsIPrincipal* aPrincipal, 1.494 + nsIDOMStorage* aStorage, 1.495 + bool* aRetval) 1.496 +{ 1.497 + return CheckStorageForFirstParty(nullptr, aPrincipal, aStorage, aRetval); 1.498 +} 1.499 + 1.500 +NS_IMETHODIMP 1.501 +DOMStorageManager::CheckStorageForFirstParty(nsIURI* aFirstPartyIsolationURI, 1.502 + nsIPrincipal* aPrincipal, 1.503 + nsIDOMStorage* aStorage, 1.504 + bool* aRetval) 1.505 +{ 1.506 + nsCOMPtr<nsPIDOMStorage> pstorage = do_QueryInterface(aStorage); 1.507 + if (!pstorage) { 1.508 + return NS_ERROR_UNEXPECTED; 1.509 + } 1.510 + 1.511 + *aRetval = false; 1.512 + 1.513 + if (!aPrincipal) { 1.514 + return NS_ERROR_NOT_AVAILABLE; 1.515 + } 1.516 + 1.517 + nsAutoCString scope; 1.518 + nsresult rv = CreateScopeKey(aFirstPartyIsolationURI, aPrincipal, scope); 1.519 + if (NS_FAILED(rv)) { 1.520 + return rv; 1.521 + } 1.522 + 1.523 + DOMStorageCache* cache = GetCache(scope); 1.524 + if (cache != pstorage->GetCache()) { 1.525 + return NS_OK; 1.526 + } 1.527 + 1.528 + if (!pstorage->PrincipalEquals(aPrincipal)) { 1.529 + return NS_OK; 1.530 + } 1.531 + 1.532 + *aRetval = true; 1.533 + return NS_OK; 1.534 +} 1.535 + 1.536 +// Obsolete nsIDOMStorageManager methods 1.537 + 1.538 +NS_IMETHODIMP 1.539 +DOMStorageManager::GetLocalStorageForPrincipal(nsIPrincipal* aPrincipal, 1.540 + const nsAString& aDocumentURI, 1.541 + bool aPrivate, 1.542 + nsIDOMStorage** aRetval) 1.543 +{ 1.544 + if (mType != LocalStorage) { 1.545 + return NS_ERROR_UNEXPECTED; 1.546 + } 1.547 + 1.548 + return CreateStorage(aPrincipal, aDocumentURI, aPrivate, aRetval); 1.549 +} 1.550 + 1.551 +namespace { // anon 1.552 + 1.553 +class ClearCacheEnumeratorData 1.554 +{ 1.555 +public: 1.556 + ClearCacheEnumeratorData(uint32_t aFlags) 1.557 + : mUnloadFlags(aFlags) 1.558 + {} 1.559 + 1.560 + uint32_t mUnloadFlags; 1.561 + nsCString mKeyPrefix; 1.562 +}; 1.563 + 1.564 +} // anon 1.565 + 1.566 +PLDHashOperator 1.567 +DOMStorageManager::ClearCacheEnumerator(DOMStorageCacheHashKey* aEntry, void* aClosure) 1.568 +{ 1.569 + DOMStorageCache* cache = aEntry->cache(); 1.570 + nsCString& key = const_cast<nsCString&>(cache->Scope()); 1.571 + 1.572 + ClearCacheEnumeratorData* data = static_cast<ClearCacheEnumeratorData*>(aClosure); 1.573 + 1.574 + if (data->mKeyPrefix.IsEmpty() || StringBeginsWith(key, data->mKeyPrefix)) { 1.575 + cache->UnloadItems(data->mUnloadFlags); 1.576 + } 1.577 + 1.578 + return PL_DHASH_NEXT; 1.579 +} 1.580 + 1.581 +nsresult 1.582 +DOMStorageManager::Observe(const char* aTopic, const nsACString& aScopePrefix) 1.583 +{ 1.584 + // Clear everything, caches + database 1.585 + if (!strcmp(aTopic, "cookie-cleared")) { 1.586 + ClearCacheEnumeratorData data(DOMStorageCache::kUnloadComplete); 1.587 + mCaches.EnumerateEntries(ClearCacheEnumerator, &data); 1.588 + 1.589 + return NS_OK; 1.590 + } 1.591 + 1.592 + // Clear from caches everything that has been stored 1.593 + // while in session-only mode 1.594 + if (!strcmp(aTopic, "session-only-cleared")) { 1.595 + ClearCacheEnumeratorData data(DOMStorageCache::kUnloadSession); 1.596 + data.mKeyPrefix = aScopePrefix; 1.597 + mCaches.EnumerateEntries(ClearCacheEnumerator, &data); 1.598 + 1.599 + return NS_OK; 1.600 + } 1.601 + 1.602 + // Clear everything (including so and pb data) from caches and database 1.603 + // for the gived domain and subdomains. 1.604 + if (!strcmp(aTopic, "domain-data-cleared")) { 1.605 + ClearCacheEnumeratorData data(DOMStorageCache::kUnloadComplete); 1.606 + data.mKeyPrefix = aScopePrefix; 1.607 + mCaches.EnumerateEntries(ClearCacheEnumerator, &data); 1.608 + 1.609 + return NS_OK; 1.610 + } 1.611 + 1.612 + // Clear all private-browsing caches 1.613 + if (!strcmp(aTopic, "private-browsing-data-cleared")) { 1.614 + ClearCacheEnumeratorData data(DOMStorageCache::kUnloadPrivate); 1.615 + mCaches.EnumerateEntries(ClearCacheEnumerator, &data); 1.616 + 1.617 + return NS_OK; 1.618 + } 1.619 + 1.620 + // Clear localStorage data beloging to an app. 1.621 + if (!strcmp(aTopic, "app-data-cleared")) { 1.622 + 1.623 + // sessionStorage is expected to stay 1.624 + if (mType == SessionStorage) { 1.625 + return NS_OK; 1.626 + } 1.627 + 1.628 + ClearCacheEnumeratorData data(DOMStorageCache::kUnloadComplete); 1.629 + data.mKeyPrefix = aScopePrefix; 1.630 + mCaches.EnumerateEntries(ClearCacheEnumerator, &data); 1.631 + 1.632 + return NS_OK; 1.633 + } 1.634 + 1.635 + if (!strcmp(aTopic, "profile-change")) { 1.636 + // For case caches are still referenced - clear them completely 1.637 + ClearCacheEnumeratorData data(DOMStorageCache::kUnloadComplete); 1.638 + mCaches.EnumerateEntries(ClearCacheEnumerator, &data); 1.639 + 1.640 + mCaches.Clear(); 1.641 + return NS_OK; 1.642 + } 1.643 + 1.644 + if (!strcmp(aTopic, "low-disk-space")) { 1.645 + if (mType == LocalStorage) { 1.646 + mLowDiskSpace = true; 1.647 + } 1.648 + 1.649 + return NS_OK; 1.650 + } 1.651 + 1.652 + if (!strcmp(aTopic, "no-low-disk-space")) { 1.653 + if (mType == LocalStorage) { 1.654 + mLowDiskSpace = false; 1.655 + } 1.656 + 1.657 + return NS_OK; 1.658 + } 1.659 + 1.660 +#ifdef DOM_STORAGE_TESTS 1.661 + if (!strcmp(aTopic, "test-reload")) { 1.662 + if (mType != LocalStorage) { 1.663 + return NS_OK; 1.664 + } 1.665 + 1.666 + // This immediately completely reloads all caches from the database. 1.667 + ClearCacheEnumeratorData data(DOMStorageCache::kTestReload); 1.668 + mCaches.EnumerateEntries(ClearCacheEnumerator, &data); 1.669 + return NS_OK; 1.670 + } 1.671 + 1.672 + if (!strcmp(aTopic, "test-flushed")) { 1.673 + if (XRE_GetProcessType() != GeckoProcessType_Default) { 1.674 + nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); 1.675 + if (obs) { 1.676 + obs->NotifyObservers(nullptr, "domstorage-test-flushed", nullptr); 1.677 + } 1.678 + } 1.679 + 1.680 + return NS_OK; 1.681 + } 1.682 +#endif 1.683 + 1.684 + NS_ERROR("Unexpected topic"); 1.685 + return NS_ERROR_UNEXPECTED; 1.686 +} 1.687 + 1.688 +// DOMLocalStorageManager 1.689 + 1.690 +DOMLocalStorageManager::DOMLocalStorageManager() 1.691 + : DOMStorageManager(LocalStorage) 1.692 +{ 1.693 + NS_ASSERTION(!sSelf, "Somebody is trying to do_CreateInstance(\"@mozilla/dom/localStorage-manager;1\""); 1.694 + sSelf = this; 1.695 + 1.696 + if (XRE_GetProcessType() != GeckoProcessType_Default) { 1.697 + // Do this only on the child process. The thread IPC bridge 1.698 + // is also used to communicate chrome observer notifications. 1.699 + // Note: must be called after we set sSelf 1.700 + DOMStorageCache::StartDatabase(); 1.701 + } 1.702 +} 1.703 + 1.704 +DOMLocalStorageManager::~DOMLocalStorageManager() 1.705 +{ 1.706 + sSelf = nullptr; 1.707 +} 1.708 + 1.709 +// DOMSessionStorageManager 1.710 + 1.711 +DOMSessionStorageManager::DOMSessionStorageManager() 1.712 + : DOMStorageManager(SessionStorage) 1.713 +{ 1.714 + if (XRE_GetProcessType() != GeckoProcessType_Default) { 1.715 + // Do this only on the child process. The thread IPC bridge 1.716 + // is also used to communicate chrome observer notifications. 1.717 + DOMStorageCache::StartDatabase(); 1.718 + } 1.719 +} 1.720 + 1.721 +} // ::dom 1.722 +} // ::mozilla