dom/src/storage/DOMStorageObserver.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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 "DOMStorageObserver.h"
     8 #include "DOMStorageDBThread.h"
     9 #include "DOMStorageCache.h"
    11 #include "nsIObserverService.h"
    12 #include "nsIURI.h"
    13 #include "nsIURL.h"
    14 #include "nsIScriptSecurityManager.h"
    15 #include "nsIPermission.h"
    16 #include "nsIIDNService.h"
    17 #include "mozIApplicationClearPrivateDataParams.h"
    18 #include "nsICookiePermission.h"
    20 #include "nsPrintfCString.h"
    21 #include "nsXULAppAPI.h"
    22 #include "nsEscape.h"
    23 #include "nsNetCID.h"
    24 #include "mozilla/Services.h"
    25 #include "nsServiceManagerUtils.h"
    27 namespace mozilla {
    28 namespace dom {
    30 static const char kStartupTopic[] = "sessionstore-windows-restored";
    31 static const uint32_t kStartupDelay = 0;
    33 NS_IMPL_ISUPPORTS(DOMStorageObserver,
    34                   nsIObserver,
    35                   nsISupportsWeakReference)
    37 DOMStorageObserver* DOMStorageObserver::sSelf = nullptr;
    39 extern nsresult
    40 CreateReversedDomain(const nsACString& aAsciiDomain, nsACString& aKey);
    42 // static
    43 nsresult
    44 DOMStorageObserver::Init()
    45 {
    46   if (sSelf) {
    47     return NS_OK;
    48   }
    50   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
    51   if (!obs) {
    52     return NS_ERROR_UNEXPECTED;
    53   }
    55   sSelf = new DOMStorageObserver();
    56   NS_ADDREF(sSelf);
    58   // Chrome clear operations.
    59   obs->AddObserver(sSelf, kStartupTopic, true);
    60   obs->AddObserver(sSelf, "cookie-changed", true);
    61   obs->AddObserver(sSelf, "perm-changed", true);
    62   obs->AddObserver(sSelf, "browser:purge-domain-data", true);
    63   obs->AddObserver(sSelf, "last-pb-context-exited", true);
    64   obs->AddObserver(sSelf, "webapps-clear-data", true);
    66   // Shutdown
    67   obs->AddObserver(sSelf, "profile-after-change", true);
    68   obs->AddObserver(sSelf, "profile-before-change", true);
    69   obs->AddObserver(sSelf, "xpcom-shutdown", true);
    71   // Observe low device storage notifications.
    72   obs->AddObserver(sSelf, "disk-space-watcher", true);
    74 #ifdef DOM_STORAGE_TESTS
    75   // Testing
    76   obs->AddObserver(sSelf, "domstorage-test-flush-force", true);
    77   if (XRE_GetProcessType() == GeckoProcessType_Default) {
    78     // Only to forward to child process.
    79     obs->AddObserver(sSelf, "domstorage-test-flushed", true);
    80   }
    82   obs->AddObserver(sSelf, "domstorage-test-reload", true);
    83 #endif
    85   return NS_OK;
    86 }
    88 // static
    89 nsresult
    90 DOMStorageObserver::Shutdown()
    91 {
    92   if (!sSelf) {
    93     return NS_ERROR_NOT_INITIALIZED;
    94   }
    96   NS_RELEASE(sSelf);
    97   return NS_OK;
    98 }
   100 void
   101 DOMStorageObserver::AddSink(DOMStorageObserverSink* aObs)
   102 {
   103   mSinks.AppendElement(aObs);
   104 }
   106 void
   107 DOMStorageObserver::RemoveSink(DOMStorageObserverSink* aObs)
   108 {
   109   mSinks.RemoveElement(aObs);
   110 }
   112 void
   113 DOMStorageObserver::Notify(const char* aTopic, const nsACString& aData)
   114 {
   115   for (uint32_t i = 0; i < mSinks.Length(); ++i) {
   116     DOMStorageObserverSink* sink = mSinks[i];
   117     sink->Observe(aTopic, aData);
   118   }
   119 }
   121 NS_IMETHODIMP
   122 DOMStorageObserver::Observe(nsISupports* aSubject,
   123                             const char* aTopic,
   124                             const char16_t* aData)
   125 {
   126   nsresult rv;
   128   // Start the thread that opens the database.
   129   if (!strcmp(aTopic, kStartupTopic)) {
   130     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   131     obs->RemoveObserver(this, kStartupTopic);
   133     mDBThreadStartDelayTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
   134     if (!mDBThreadStartDelayTimer) {
   135       return NS_ERROR_UNEXPECTED;
   136     }
   138     mDBThreadStartDelayTimer->Init(this, nsITimer::TYPE_ONE_SHOT, kStartupDelay);
   140     return NS_OK;
   141   }
   143   // Timer callback used to start the database a short timer after startup
   144   if (!strcmp(aTopic, NS_TIMER_CALLBACK_TOPIC)) {
   145     nsCOMPtr<nsITimer> timer = do_QueryInterface(aSubject);
   146     if (!timer) {
   147       return NS_ERROR_UNEXPECTED;
   148     }
   150     if (timer == mDBThreadStartDelayTimer) {
   151       mDBThreadStartDelayTimer = nullptr;
   153       DOMStorageDBBridge* db = DOMStorageCache::StartDatabase();
   154       NS_ENSURE_TRUE(db, NS_ERROR_FAILURE);
   155     }
   157     return NS_OK;
   158   }
   160   // Clear everything, caches + database
   161   if (!strcmp(aTopic, "cookie-changed")) {
   162     if (!NS_LITERAL_STRING("cleared").Equals(aData)) {
   163       return NS_OK;
   164     }
   166     DOMStorageDBBridge* db = DOMStorageCache::StartDatabase();
   167     NS_ENSURE_TRUE(db, NS_ERROR_FAILURE);
   169     db->AsyncClearAll();
   171     Notify("cookie-cleared");
   173     return NS_OK;
   174   }
   176   // Clear from caches everything that has been stored
   177   // while in session-only mode
   178   if (!strcmp(aTopic, "perm-changed")) {
   179     // Check for cookie permission change
   180     nsCOMPtr<nsIPermission> perm(do_QueryInterface(aSubject));
   181     if (!perm) {
   182       return NS_OK;
   183     }
   185     nsAutoCString type;
   186     perm->GetType(type);
   187     if (type != NS_LITERAL_CSTRING("cookie")) {
   188       return NS_OK;
   189     }
   191     uint32_t cap = 0;
   192     perm->GetCapability(&cap);
   193     if (!(cap & nsICookiePermission::ACCESS_SESSION) ||
   194         !NS_LITERAL_STRING("deleted").Equals(nsDependentString(aData))) {
   195       return NS_OK;
   196     }
   198     nsAutoCString host;
   199     perm->GetHost(host);
   200     if (host.IsEmpty()) {
   201       return NS_OK;
   202     }
   204     nsAutoCString scope;
   205     rv = CreateReversedDomain(host, scope);
   206     NS_ENSURE_SUCCESS(rv, rv);
   208     Notify("session-only-cleared", scope);
   210     return NS_OK;
   211   }
   213   // Clear everything (including so and pb data) from caches and database
   214   // for the gived domain and subdomains.
   215   if (!strcmp(aTopic, "browser:purge-domain-data")) {
   216     // Convert the domain name to the ACE format
   217     nsAutoCString aceDomain;
   218     nsCOMPtr<nsIIDNService> converter = do_GetService(NS_IDNSERVICE_CONTRACTID);
   219     if (converter) {
   220       rv = converter->ConvertUTF8toACE(NS_ConvertUTF16toUTF8(aData), aceDomain);
   221       NS_ENSURE_SUCCESS(rv, rv);
   222     } else {
   223       // In case the IDN service is not available, this is the best we can come up with!
   224       NS_EscapeURL(NS_ConvertUTF16toUTF8(aData),
   225                    esc_OnlyNonASCII | esc_AlwaysCopy,
   226                    aceDomain);
   227     }
   229     nsAutoCString scopePrefix;
   230     rv = CreateReversedDomain(aceDomain, scopePrefix);
   231     NS_ENSURE_SUCCESS(rv, rv);
   233     DOMStorageDBBridge* db = DOMStorageCache::StartDatabase();
   234     NS_ENSURE_TRUE(db, NS_ERROR_FAILURE);
   236     db->AsyncClearMatchingScope(scopePrefix);
   238     Notify("domain-data-cleared", scopePrefix);
   240     return NS_OK;
   241   }
   243   // Clear all private-browsing caches
   244   if (!strcmp(aTopic, "last-pb-context-exited")) {
   245     Notify("private-browsing-data-cleared");
   247     return NS_OK;
   248   }
   250   // Clear data beloging to an app.
   251   if (!strcmp(aTopic, "webapps-clear-data")) {
   252     nsCOMPtr<mozIApplicationClearPrivateDataParams> params =
   253       do_QueryInterface(aSubject);
   254     if (!params) {
   255       NS_ERROR("'webapps-clear-data' notification's subject should be a mozIApplicationClearPrivateDataParams");
   256       return NS_ERROR_UNEXPECTED;
   257     }
   259     uint32_t appId;
   260     bool browserOnly;
   262     rv = params->GetAppId(&appId);
   263     NS_ENSURE_SUCCESS(rv, rv);
   265     rv = params->GetBrowserOnly(&browserOnly);
   266     NS_ENSURE_SUCCESS(rv, rv);
   268     MOZ_ASSERT(appId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
   270     DOMStorageDBBridge* db = DOMStorageCache::StartDatabase();
   271     NS_ENSURE_TRUE(db, NS_ERROR_FAILURE);
   273     nsAutoCString scope;
   274     scope.AppendInt(appId);
   275     scope.Append(NS_LITERAL_CSTRING(":t:"));
   276     db->AsyncClearMatchingScope(scope);
   277     Notify("app-data-cleared", scope);
   279     if (!browserOnly) {
   280       scope.Truncate();
   281       scope.AppendInt(appId);
   282       scope.Append(NS_LITERAL_CSTRING(":f:"));
   283       db->AsyncClearMatchingScope(scope);
   284       Notify("app-data-cleared", scope);
   285     }
   287     return NS_OK;
   288   }
   290   if (!strcmp(aTopic, "profile-after-change")) {
   291     Notify("profile-change");
   293     return NS_OK;
   294   }
   296   if (!strcmp(aTopic, "profile-before-change") ||
   297       !strcmp(aTopic, "xpcom-shutdown")) {
   298     rv = DOMStorageCache::StopDatabase();
   299     if (NS_FAILED(rv)) {
   300       NS_WARNING("Error while stopping DOMStorage DB background thread");
   301     }
   303     return NS_OK;
   304   }
   306   if (!strcmp(aTopic, "disk-space-watcher")) {
   307     if (NS_LITERAL_STRING("full").Equals(aData)) {
   308       Notify("low-disk-space");
   309     } else if (NS_LITERAL_STRING("free").Equals(aData)) {
   310       Notify("no-low-disk-space");
   311     }
   313     return NS_OK;
   314   }
   316 #ifdef DOM_STORAGE_TESTS
   317   if (!strcmp(aTopic, "domstorage-test-flush-force")) {
   318     DOMStorageDBBridge* db = DOMStorageCache::GetDatabase();
   319     if (db) {
   320       db->AsyncFlush();
   321     }
   323     return NS_OK;
   324   }
   326   if (!strcmp(aTopic, "domstorage-test-flushed")) {
   327     // Only used to propagate to IPC children
   328     Notify("test-flushed");
   330     return NS_OK;
   331   }
   333   if (!strcmp(aTopic, "domstorage-test-reload")) {
   334     Notify("test-reload");
   336     return NS_OK;
   337   }
   338 #endif
   340   NS_ERROR("Unexpected topic");
   341   return NS_ERROR_UNEXPECTED;
   342 }
   344 } // ::dom
   345 } // ::mozilla

mercurial