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.

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

mercurial