dom/src/storage/DOMStorageManager.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "DOMStorageManager.h"
     7 #include "DOMStorage.h"
     8 #include "DOMStorageDBThread.h"
    10 #include "nsIScriptSecurityManager.h"
    11 #include "nsIEffectiveTLDService.h"
    13 #include "nsNetUtil.h"
    14 #include "nsPrintfCString.h"
    15 #include "nsXULAppAPI.h"
    16 #include "nsThreadUtils.h"
    17 #include "nsIObserverService.h"
    18 #include "mozIThirdPartyUtil.h"
    19 #include "mozilla/Services.h"
    20 #include "mozilla/Preferences.h"
    22 // Only allow relatively small amounts of data since performance of
    23 // the synchronous IO is very bad.
    24 // We are enforcing simple per-origin quota only.
    25 #define DEFAULT_QUOTA_LIMIT (5 * 1024)
    27 namespace mozilla {
    28 namespace dom {
    30 namespace { // anon
    32 int32_t gQuotaLimit = DEFAULT_QUOTA_LIMIT;
    34 } // anon
    36 DOMLocalStorageManager*
    37 DOMLocalStorageManager::sSelf = nullptr;
    39 // static
    40 uint32_t
    41 DOMStorageManager::GetQuota()
    42 {
    43   static bool preferencesInitialized = false;
    44   if (!preferencesInitialized) {
    45     mozilla::Preferences::AddIntVarCache(&gQuotaLimit, "dom.storage.default_quota",
    46                                          DEFAULT_QUOTA_LIMIT);
    47     preferencesInitialized = true;
    48   }
    50   return gQuotaLimit * 1024; // pref is in kBs
    51 }
    53 void
    54 ReverseString(const nsCSubstring& aSource, nsCSubstring& aResult)
    55 {
    56   nsACString::const_iterator sourceBegin, sourceEnd;
    57   aSource.BeginReading(sourceBegin);
    58   aSource.EndReading(sourceEnd);
    60   aResult.SetLength(aSource.Length());
    61   nsACString::iterator destEnd;
    62   aResult.EndWriting(destEnd);
    64   while (sourceBegin != sourceEnd) {
    65     *(--destEnd) = *sourceBegin;
    66     ++sourceBegin;
    67   }
    68 }
    70 nsresult
    71 CreateReversedDomain(const nsACString& aAsciiDomain,
    72                      nsACString& aKey)
    73 {
    74   if (aAsciiDomain.IsEmpty()) {
    75     return NS_ERROR_NOT_AVAILABLE;
    76   }
    78   ReverseString(aAsciiDomain, aKey);
    80   aKey.AppendLiteral(".");
    81   return NS_OK;
    82 }
    84 bool
    85 PrincipalsEqual(nsIPrincipal* aObjectPrincipal, nsIPrincipal* aSubjectPrincipal)
    86 {
    87   if (!aSubjectPrincipal) {
    88     return true;
    89   }
    91   if (!aObjectPrincipal) {
    92     return false;
    93   }
    95   return aSubjectPrincipal->Equals(aObjectPrincipal);
    96 }
    98 NS_IMPL_ISUPPORTS(DOMStorageManager,
    99                   nsIDOMStorageManager)
   101 DOMStorageManager::DOMStorageManager(nsPIDOMStorage::StorageType aType)
   102   : mCaches(10)
   103   , mType(aType)
   104   , mLowDiskSpace(false)
   105 {
   106   DOMStorageObserver* observer = DOMStorageObserver::Self();
   107   NS_ASSERTION(observer, "No DOMStorageObserver, cannot observe private data delete notifications!");
   109   if (observer) {
   110     observer->AddSink(this);
   111   }
   112 }
   114 DOMStorageManager::~DOMStorageManager()
   115 {
   116   DOMStorageObserver* observer = DOMStorageObserver::Self();
   117   if (observer) {
   118     observer->RemoveSink(this);
   119   }
   120 }
   122 namespace { // anon
   124 nsresult
   125 AppendFirstPartyToKey(nsIURI* aFirstPartyIsolationURI, nsACString& aKey)
   126 {
   127   if (aFirstPartyIsolationURI) {
   128     nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
   129                             do_GetService(THIRDPARTYUTIL_CONTRACTID);
   130     if (!thirdPartyUtil)
   131       return NS_ERROR_FAILURE;
   133     nsAutoCString firstPartyHost;
   134     nsresult rv = thirdPartyUtil->GetFirstPartyHostForIsolation(aFirstPartyIsolationURI,
   135                                                                 firstPartyHost);
   136     NS_ENSURE_SUCCESS(rv, rv);
   138     aKey.AppendLiteral("&");
   139     aKey.Append(firstPartyHost);
   140   }
   142   return NS_OK;
   143 }
   145 nsresult
   146 CreateScopeKey(nsIURI* aFirstPartyIsolationURI, nsIPrincipal* aPrincipal,
   147                nsACString& aKey)
   148 {
   149   nsCOMPtr<nsIURI> uri;
   150   nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri));
   151   NS_ENSURE_SUCCESS(rv, rv);
   152   if (!uri) {
   153     return NS_ERROR_UNEXPECTED;
   154   }
   156   nsAutoCString domainScope;
   157   rv = uri->GetAsciiHost(domainScope);
   158   NS_ENSURE_SUCCESS(rv, rv);
   160   if (domainScope.IsEmpty()) {
   161     // For the file:/// protocol use the exact directory as domain.
   162     bool isScheme = false;
   163     if (NS_SUCCEEDED(uri->SchemeIs("file", &isScheme)) && isScheme) {
   164       nsCOMPtr<nsIURL> url = do_QueryInterface(uri, &rv);
   165       NS_ENSURE_SUCCESS(rv, rv);
   166       rv = url->GetDirectory(domainScope);
   167       NS_ENSURE_SUCCESS(rv, rv);
   168     }
   169   }
   171   nsAutoCString key;
   173   rv = CreateReversedDomain(domainScope, key);
   174   if (NS_FAILED(rv)) {
   175     return rv;
   176   }
   178   nsAutoCString scheme;
   179   rv = uri->GetScheme(scheme);
   180   NS_ENSURE_SUCCESS(rv, rv);
   182   key.Append(NS_LITERAL_CSTRING(":") + scheme);
   184   int32_t port = NS_GetRealPort(uri);
   185   if (port != -1) {
   186     key.Append(nsPrintfCString(":%d", port));
   187   }
   189   bool unknownAppId;
   190   rv = aPrincipal->GetUnknownAppId(&unknownAppId);
   191   NS_ENSURE_SUCCESS(rv, rv);
   193   if (!unknownAppId) {
   194     uint32_t appId;
   195     rv = aPrincipal->GetAppId(&appId);
   196     NS_ENSURE_SUCCESS(rv, rv);
   198     bool isInBrowserElement;
   199     rv = aPrincipal->GetIsInBrowserElement(&isInBrowserElement);
   200     NS_ENSURE_SUCCESS(rv, rv);
   202     if (appId == nsIScriptSecurityManager::NO_APP_ID && !isInBrowserElement) {
   203       aKey.Assign(key);
   204     } else {
   205       aKey.Truncate();
   206       aKey.AppendInt(appId);
   207       aKey.Append(NS_LITERAL_CSTRING(":") + (isInBrowserElement ?
   208                   NS_LITERAL_CSTRING("t") : NS_LITERAL_CSTRING("f")) +
   209                   NS_LITERAL_CSTRING(":") + key);
   210     }
   211   }
   213   // Isolate scope keys to the URL bar domain by appending &firstPartyHost
   214   // if available.
   215   return AppendFirstPartyToKey(aFirstPartyIsolationURI, aKey);
   216 }
   218 nsresult
   219 CreateQuotaDBKey(nsIURI* aFirstPartyIsolationURI, nsIPrincipal* aPrincipal,
   220                  nsACString& aKey)
   221 {
   222   nsresult rv;
   224   nsAutoCString subdomainsDBKey;
   225   nsCOMPtr<nsIEffectiveTLDService> eTLDService(do_GetService(
   226     NS_EFFECTIVETLDSERVICE_CONTRACTID, &rv));
   227   NS_ENSURE_SUCCESS(rv, rv);
   229   nsCOMPtr<nsIURI> uri;
   230   rv = aPrincipal->GetURI(getter_AddRefs(uri));
   231   NS_ENSURE_SUCCESS(rv, rv);
   232   NS_ENSURE_TRUE(uri, NS_ERROR_UNEXPECTED);
   234   nsAutoCString eTLDplusOne;
   235   rv = eTLDService->GetBaseDomain(uri, 0, eTLDplusOne);
   236   if (NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS == rv) {
   237     // XXX bug 357323 - what to do for localhost/file exactly?
   238     rv = uri->GetAsciiHost(eTLDplusOne);
   239   }
   240   NS_ENSURE_SUCCESS(rv, rv);
   242   CreateReversedDomain(eTLDplusOne, subdomainsDBKey);
   244   bool unknownAppId;
   245   rv = aPrincipal->GetUnknownAppId(&unknownAppId);
   246   NS_ENSURE_SUCCESS(rv, rv);
   248   if (!unknownAppId) {
   249     uint32_t appId;
   250     rv = aPrincipal->GetAppId(&appId);
   251     NS_ENSURE_SUCCESS(rv, rv);
   253     bool isInBrowserElement;
   254     rv = aPrincipal->GetIsInBrowserElement(&isInBrowserElement);
   255     NS_ENSURE_SUCCESS(rv, rv);
   257     if (appId == nsIScriptSecurityManager::NO_APP_ID && !isInBrowserElement) {
   258       aKey.Assign(subdomainsDBKey);
   259     } else {
   260       aKey.Truncate();
   261       aKey.AppendInt(appId);
   262       aKey.Append(NS_LITERAL_CSTRING(":") + (isInBrowserElement ?
   263                   NS_LITERAL_CSTRING("t") : NS_LITERAL_CSTRING("f")) +
   264                   NS_LITERAL_CSTRING(":") + subdomainsDBKey);
   265     }
   266   }
   268   // Isolate scope keys to the URL bar domain by appending &firstPartyHost
   269   // if available.
   270   return AppendFirstPartyToKey(aFirstPartyIsolationURI, aKey);
   271 }
   273 } // anon
   275 DOMStorageCache*
   276 DOMStorageManager::GetCache(const nsACString& aScope) const
   277 {
   278   DOMStorageCacheHashKey* entry = mCaches.GetEntry(aScope);
   279   if (!entry) {
   280     return nullptr;
   281   }
   283   return entry->cache();
   284 }
   286 already_AddRefed<DOMStorageUsage>
   287 DOMStorageManager::GetScopeUsage(const nsACString& aScope)
   288 {
   289   nsRefPtr<DOMStorageUsage> usage;
   290   if (mUsages.Get(aScope, &usage)) {
   291     return usage.forget();
   292   }
   294   usage = new DOMStorageUsage(aScope);
   296   if (mType == LocalStorage) {
   297     DOMStorageDBBridge* db = DOMStorageCache::StartDatabase();
   298     if (db) {
   299       db->AsyncGetUsage(usage);
   300     }
   301   }
   303   mUsages.Put(aScope, usage);
   305   return usage.forget();
   306 }
   308 already_AddRefed<DOMStorageCache>
   309 DOMStorageManager::PutCache(const nsACString& aScope,
   310                             nsIURI* aFirstPartyIsolationURI,
   311                             nsIPrincipal* aPrincipal)
   312 {
   313   DOMStorageCacheHashKey* entry = mCaches.PutEntry(aScope);
   314   nsRefPtr<DOMStorageCache> cache = entry->cache();
   316   nsAutoCString quotaScope;
   317   CreateQuotaDBKey(aFirstPartyIsolationURI, aPrincipal, quotaScope);
   319   // To avoid ever persisting session storage to disk, initialize LocalStorage
   320   // like SessionStorage.
   321   switch (mType) {
   322   case SessionStorage:
   323   case LocalStorage:
   324     // Lifetime handled by the manager, don't persist
   325     entry->HardRef();
   326     cache->Init(this, false, aFirstPartyIsolationURI, aPrincipal, quotaScope);
   327     break;
   329   default:
   330     MOZ_ASSERT(false);
   331   }
   333   return cache.forget();
   334 }
   336 void
   337 DOMStorageManager::DropCache(DOMStorageCache* aCache)
   338 {
   339   if (!NS_IsMainThread()) {
   340     NS_WARNING("DOMStorageManager::DropCache called on a non-main thread, shutting down?");
   341   }
   343   mCaches.RemoveEntry(aCache->Scope());
   344 }
   346 nsresult
   347 DOMStorageManager::GetStorageInternal(bool aCreate,
   348                                       nsIURI* aFirstPartyIsolationURI,
   349                                       nsIPrincipal* aPrincipal,
   350                                       const nsAString& aDocumentURI,
   351                                       bool aPrivate,
   352                                       nsIDOMStorage** aRetval)
   353 {
   354   nsresult rv;
   356   nsAutoCString scope;
   357   rv = CreateScopeKey(aFirstPartyIsolationURI, aPrincipal, scope);
   358   if (NS_FAILED(rv)) {
   359     return NS_ERROR_NOT_AVAILABLE;
   360   }
   362   nsRefPtr<DOMStorageCache> cache = GetCache(scope);
   364   // Get or create a cache for the given scope
   365   if (!cache) {
   366     if (!aCreate) {
   367       *aRetval = nullptr;
   368       return NS_OK;
   369     }
   371     if (!aRetval) {
   372       // This is demand to just preload the cache, if the scope has
   373       // no data stored, bypass creation and preload of the cache.
   374       DOMStorageDBBridge* db = DOMStorageCache::GetDatabase();
   375       if (db) {
   376         if (!db->ShouldPreloadScope(scope)) {
   377           return NS_OK;
   378         }
   379       } else {
   380         if (scope.Equals(NS_LITERAL_CSTRING("knalb.:about"))) {
   381           return NS_OK;
   382         }
   383       }
   384     }
   386     // There is always a single instance of a cache per scope
   387     // in a single instance of a DOM storage manager.
   388     cache = PutCache(scope, aFirstPartyIsolationURI, aPrincipal);
   389   } else if (mType == SessionStorage) {
   390     if (!cache->CheckPrincipal(aPrincipal)) {
   391       return NS_ERROR_DOM_SECURITY_ERR;
   392     }
   393   }
   395   if (aRetval) {
   396     *aRetval = new DOMStorage(this, cache, aDocumentURI, aPrincipal, aPrivate);
   397     NS_ADDREF(*aRetval);
   398   }
   400   return NS_OK;
   401 }
   403 NS_IMETHODIMP
   404 DOMStorageManager::PrecacheStorage(nsIPrincipal* aPrincipal)
   405 {
   406   return GetStorageInternal(true, nullptr, aPrincipal, EmptyString(),
   407                             false, nullptr);
   408 }
   410 NS_IMETHODIMP
   411 DOMStorageManager::PrecacheStorageForFirstParty(nsIURI* aFirstPartyIsolationURI,
   412                                                 nsIPrincipal* aPrincipal)
   413 {
   414   return GetStorageInternal(true, aFirstPartyIsolationURI, aPrincipal, EmptyString(),
   415                             false, nullptr);
   416 }
   418 NS_IMETHODIMP
   419 DOMStorageManager::CreateStorage(nsIPrincipal* aPrincipal,
   420                                  const nsAString& aDocumentURI,
   421                                  bool aPrivate,
   422                                  nsIDOMStorage** aRetval)
   423 {
   424   return GetStorageInternal(true, nullptr, aPrincipal, aDocumentURI,
   425                             aPrivate, aRetval);
   426 }
   428 NS_IMETHODIMP
   429 DOMStorageManager::CreateStorageForFirstParty(nsIURI* aFirstPartyIsolationURI,
   430                                               nsIPrincipal* aPrincipal,
   431                                               const nsAString& aDocumentURI,
   432                                               bool aPrivate,
   433                                               nsIDOMStorage** aRetval)
   434 {
   435   return GetStorageInternal(true, aFirstPartyIsolationURI, aPrincipal, aDocumentURI,
   436                             aPrivate, aRetval);
   437 }
   439 NS_IMETHODIMP
   440 DOMStorageManager::GetStorage(nsIPrincipal* aPrincipal,
   441                               bool aPrivate,
   442                               nsIDOMStorage** aRetval)
   443 {
   444   return GetStorageInternal(false, nullptr, aPrincipal, EmptyString(),
   445                             aPrivate, aRetval);
   446 }
   448 NS_IMETHODIMP
   449 DOMStorageManager::GetStorageForFirstParty(nsIURI* aFirstPartyIsolationURI,
   450                                            nsIPrincipal* aPrincipal,
   451                                            bool aPrivate,
   452                                            nsIDOMStorage** aRetval)
   453 {
   454   return GetStorageInternal(false, aFirstPartyIsolationURI, aPrincipal,
   455                             EmptyString(), aPrivate, aRetval);
   456 }
   458 NS_IMETHODIMP
   459 DOMStorageManager::CloneStorage(nsIDOMStorage* aStorage)
   460 {
   461   if (mType != SessionStorage) {
   462     // Cloning is supported only for sessionStorage
   463     return NS_ERROR_NOT_IMPLEMENTED;
   464   }
   466   nsCOMPtr<nsPIDOMStorage> pstorage = do_QueryInterface(aStorage);
   467   if (!pstorage) {
   468     return NS_ERROR_UNEXPECTED;
   469   }
   471   const DOMStorageCache* origCache = pstorage->GetCache();
   473   DOMStorageCache* existingCache = GetCache(origCache->Scope());
   474   if (existingCache) {
   475     // Do not replace an existing sessionStorage.
   476     return NS_ERROR_NOT_AVAILABLE;
   477   }
   479   // Since this manager is sessionStorage manager, PutCache hard references
   480   // the cache in our hashtable.
   481   nsRefPtr<DOMStorageCache> newCache = PutCache(origCache->Scope(),
   482                                                 origCache->FirstPartyIsolationURI(),
   483                                                 origCache->Principal());
   485   newCache->CloneFrom(origCache);
   486   return NS_OK;
   487 }
   489 NS_IMETHODIMP
   490 DOMStorageManager::CheckStorage(nsIPrincipal* aPrincipal,
   491                                 nsIDOMStorage* aStorage,
   492                                 bool* aRetval)
   493 {
   494   return CheckStorageForFirstParty(nullptr, aPrincipal, aStorage, aRetval);
   495 }
   497 NS_IMETHODIMP
   498 DOMStorageManager::CheckStorageForFirstParty(nsIURI* aFirstPartyIsolationURI,
   499                                              nsIPrincipal* aPrincipal,
   500                                              nsIDOMStorage* aStorage,
   501                                              bool* aRetval)
   502 {
   503   nsCOMPtr<nsPIDOMStorage> pstorage = do_QueryInterface(aStorage);
   504   if (!pstorage) {
   505     return NS_ERROR_UNEXPECTED;
   506   }
   508   *aRetval = false;
   510   if (!aPrincipal) {
   511     return NS_ERROR_NOT_AVAILABLE;
   512   }
   514   nsAutoCString scope;
   515   nsresult rv = CreateScopeKey(aFirstPartyIsolationURI, aPrincipal, scope);
   516   if (NS_FAILED(rv)) {
   517     return rv;
   518   }
   520   DOMStorageCache* cache = GetCache(scope);
   521   if (cache != pstorage->GetCache()) {
   522     return NS_OK;
   523   }
   525   if (!pstorage->PrincipalEquals(aPrincipal)) {
   526     return NS_OK;
   527   }
   529   *aRetval = true;
   530   return NS_OK;
   531 }
   533 // Obsolete nsIDOMStorageManager methods
   535 NS_IMETHODIMP
   536 DOMStorageManager::GetLocalStorageForPrincipal(nsIPrincipal* aPrincipal,
   537                                                const nsAString& aDocumentURI,
   538                                                bool aPrivate,
   539                                                nsIDOMStorage** aRetval)
   540 {
   541   if (mType != LocalStorage) {
   542     return NS_ERROR_UNEXPECTED;
   543   }
   545   return CreateStorage(aPrincipal, aDocumentURI, aPrivate, aRetval);
   546 }
   548 namespace { // anon
   550 class ClearCacheEnumeratorData
   551 {
   552 public:
   553   ClearCacheEnumeratorData(uint32_t aFlags)
   554     : mUnloadFlags(aFlags)
   555   {}
   557   uint32_t mUnloadFlags;
   558   nsCString mKeyPrefix;
   559 };
   561 } // anon
   563 PLDHashOperator
   564 DOMStorageManager::ClearCacheEnumerator(DOMStorageCacheHashKey* aEntry, void* aClosure)
   565 {
   566   DOMStorageCache* cache = aEntry->cache();
   567   nsCString& key = const_cast<nsCString&>(cache->Scope());
   569   ClearCacheEnumeratorData* data = static_cast<ClearCacheEnumeratorData*>(aClosure);
   571   if (data->mKeyPrefix.IsEmpty() || StringBeginsWith(key, data->mKeyPrefix)) {
   572     cache->UnloadItems(data->mUnloadFlags);
   573   }
   575   return PL_DHASH_NEXT;
   576 }
   578 nsresult
   579 DOMStorageManager::Observe(const char* aTopic, const nsACString& aScopePrefix)
   580 {
   581   // Clear everything, caches + database
   582   if (!strcmp(aTopic, "cookie-cleared")) {
   583     ClearCacheEnumeratorData data(DOMStorageCache::kUnloadComplete);
   584     mCaches.EnumerateEntries(ClearCacheEnumerator, &data);
   586     return NS_OK;
   587   }
   589   // Clear from caches everything that has been stored
   590   // while in session-only mode
   591   if (!strcmp(aTopic, "session-only-cleared")) {
   592     ClearCacheEnumeratorData data(DOMStorageCache::kUnloadSession);
   593     data.mKeyPrefix = aScopePrefix;
   594     mCaches.EnumerateEntries(ClearCacheEnumerator, &data);
   596     return NS_OK;
   597   }
   599   // Clear everything (including so and pb data) from caches and database
   600   // for the gived domain and subdomains.
   601   if (!strcmp(aTopic, "domain-data-cleared")) {
   602     ClearCacheEnumeratorData data(DOMStorageCache::kUnloadComplete);
   603     data.mKeyPrefix = aScopePrefix;
   604     mCaches.EnumerateEntries(ClearCacheEnumerator, &data);
   606     return NS_OK;
   607   }
   609   // Clear all private-browsing caches
   610   if (!strcmp(aTopic, "private-browsing-data-cleared")) {
   611     ClearCacheEnumeratorData data(DOMStorageCache::kUnloadPrivate);
   612     mCaches.EnumerateEntries(ClearCacheEnumerator, &data);
   614     return NS_OK;
   615   }
   617   // Clear localStorage data beloging to an app.
   618   if (!strcmp(aTopic, "app-data-cleared")) {
   620     // sessionStorage is expected to stay
   621     if (mType == SessionStorage) {
   622       return NS_OK;
   623     }
   625     ClearCacheEnumeratorData data(DOMStorageCache::kUnloadComplete);
   626     data.mKeyPrefix = aScopePrefix;
   627     mCaches.EnumerateEntries(ClearCacheEnumerator, &data);
   629     return NS_OK;
   630   }
   632   if (!strcmp(aTopic, "profile-change")) {
   633     // For case caches are still referenced - clear them completely
   634     ClearCacheEnumeratorData data(DOMStorageCache::kUnloadComplete);
   635     mCaches.EnumerateEntries(ClearCacheEnumerator, &data);
   637     mCaches.Clear();
   638     return NS_OK;
   639   }
   641   if (!strcmp(aTopic, "low-disk-space")) {
   642     if (mType == LocalStorage) {
   643       mLowDiskSpace = true;
   644     }
   646     return NS_OK;
   647   }
   649   if (!strcmp(aTopic, "no-low-disk-space")) {
   650     if (mType == LocalStorage) {
   651       mLowDiskSpace = false;
   652     }
   654     return NS_OK;
   655   }
   657 #ifdef DOM_STORAGE_TESTS
   658   if (!strcmp(aTopic, "test-reload")) {
   659     if (mType != LocalStorage) {
   660       return NS_OK;
   661     }
   663     // This immediately completely reloads all caches from the database.
   664     ClearCacheEnumeratorData data(DOMStorageCache::kTestReload);
   665     mCaches.EnumerateEntries(ClearCacheEnumerator, &data);
   666     return NS_OK;
   667   }
   669   if (!strcmp(aTopic, "test-flushed")) {
   670     if (XRE_GetProcessType() != GeckoProcessType_Default) {
   671       nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   672       if (obs) {
   673         obs->NotifyObservers(nullptr, "domstorage-test-flushed", nullptr);
   674       }
   675     }
   677     return NS_OK;
   678   }
   679 #endif
   681   NS_ERROR("Unexpected topic");
   682   return NS_ERROR_UNEXPECTED;
   683 }
   685 // DOMLocalStorageManager
   687 DOMLocalStorageManager::DOMLocalStorageManager()
   688   : DOMStorageManager(LocalStorage)
   689 {
   690   NS_ASSERTION(!sSelf, "Somebody is trying to do_CreateInstance(\"@mozilla/dom/localStorage-manager;1\"");
   691   sSelf = this;
   693   if (XRE_GetProcessType() != GeckoProcessType_Default) {
   694     // Do this only on the child process.  The thread IPC bridge
   695     // is also used to communicate chrome observer notifications.
   696     // Note: must be called after we set sSelf
   697     DOMStorageCache::StartDatabase();
   698   }
   699 }
   701 DOMLocalStorageManager::~DOMLocalStorageManager()
   702 {
   703   sSelf = nullptr;
   704 }
   706 // DOMSessionStorageManager
   708 DOMSessionStorageManager::DOMSessionStorageManager()
   709   : DOMStorageManager(SessionStorage)
   710 {
   711   if (XRE_GetProcessType() != GeckoProcessType_Default) {
   712     // Do this only on the child process.  The thread IPC bridge
   713     // is also used to communicate chrome observer notifications.
   714     DOMStorageCache::StartDatabase();
   715   }
   716 }
   718 } // ::dom
   719 } // ::mozilla

mercurial