Merge backout.
[mozilla-central.git] / dom / src / storage / nsDOMStorage.cpp
blob77a2c48ef754190fc1e73669590e13c177bbe748
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Mozilla Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 2006
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Neil Deakin <enndeakin@sympatico.ca>
24 * Johnny Stenback <jst@mozilla.com>
25 * Ehsan Akhgari <ehsan.akhgari@gmail.com>
26 * Honza Bambas <honzab@firemni.cz>
28 * Alternatively, the contents of this file may be used under the terms of
29 * either of the GNU General Public License Version 2 or later (the "GPL"),
30 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 * in which case the provisions of the GPL or the LGPL are applicable instead
32 * of those above. If you wish to allow use of your version of this file only
33 * under the terms of either the GPL or the LGPL, and not to allow others to
34 * use your version of this file under the terms of the MPL, indicate your
35 * decision by deleting the provisions above and replace them with the notice
36 * and other provisions required by the GPL or the LGPL. If you do not delete
37 * the provisions above, a recipient may use your version of this file under
38 * the terms of any one of the MPL, the GPL or the LGPL.
40 * ***** END LICENSE BLOCK ***** */
42 #include "prnetdb.h"
43 #include "nsCOMPtr.h"
44 #include "nsDOMError.h"
45 #include "nsDOMClassInfo.h"
46 #include "nsUnicharUtils.h"
47 #include "nsIDocument.h"
48 #include "nsDOMStorage.h"
49 #include "nsEscape.h"
50 #include "nsContentUtils.h"
51 #include "nsIScriptSecurityManager.h"
52 #include "nsIPrincipal.h"
53 #include "nsIURI.h"
54 #include "nsReadableUtils.h"
55 #include "nsIObserverService.h"
56 #include "nsNetUtil.h"
57 #include "nsIPrefBranch.h"
58 #include "nsICookiePermission.h"
59 #include "nsIPermission.h"
60 #include "nsIPermissionManager.h"
61 #include "nsCycleCollectionParticipant.h"
62 #include "nsIOfflineCacheUpdate.h"
63 #include "nsIJSContextStack.h"
64 #include "nsIPrivateBrowsingService.h"
65 #include "nsDOMString.h"
66 #include "nsNetCID.h"
67 #include "nsIProxyObjectManager.h"
69 static const PRUint32 ASK_BEFORE_ACCEPT = 1;
70 static const PRUint32 ACCEPT_SESSION = 2;
71 static const PRUint32 BEHAVIOR_REJECT = 2;
73 static const PRUint32 DEFAULT_QUOTA = 5 * 1024;
74 // Be generous with offline apps by default...
75 static const PRUint32 DEFAULT_OFFLINE_APP_QUOTA = 200 * 1024;
76 // ... but warn if it goes over this amount
77 static const PRUint32 DEFAULT_OFFLINE_WARN_QUOTA = 50 * 1024;
79 static const char kPermissionType[] = "cookie";
80 static const char kStorageEnabled[] = "dom.storage.enabled";
81 static const char kDefaultQuota[] = "dom.storage.default_quota";
82 static const char kCookiesBehavior[] = "network.cookie.cookieBehavior";
83 static const char kCookiesLifetimePolicy[] = "network.cookie.lifetimePolicy";
84 static const char kOfflineAppWarnQuota[] = "offline-apps.quota.warn";
85 static const char kOfflineAppQuota[] = "offline-apps.quota.max";
87 // The URI returned is the innermost URI that should be used for
88 // security-check-like stuff. aHost is its hostname, correctly canonicalized.
89 static nsresult
90 GetPrincipalURIAndHost(nsIPrincipal* aPrincipal, nsIURI** aURI, nsCString& aHost)
92 nsresult rv = aPrincipal->GetDomain(aURI);
93 NS_ENSURE_SUCCESS(rv, rv);
95 if (!*aURI) {
96 rv = aPrincipal->GetURI(aURI);
97 NS_ENSURE_SUCCESS(rv, rv);
100 if (!*aURI) {
101 return NS_OK;
104 nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(*aURI);
105 if (!innerURI) {
106 return NS_ERROR_UNEXPECTED;
109 rv = innerURI->GetAsciiHost(aHost);
110 if (NS_FAILED(rv)) {
111 return NS_ERROR_DOM_SECURITY_ERR;
114 innerURI.swap(*aURI);
116 return NS_OK;
120 // Helper that tells us whether the caller is secure or not.
123 static PRBool
124 IsCallerSecure()
126 nsCOMPtr<nsIPrincipal> subjectPrincipal;
127 nsContentUtils::GetSecurityManager()->
128 GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
130 if (!subjectPrincipal) {
131 // No subject principal means no code is running. Default to not
132 // being secure in that case.
134 return PR_FALSE;
137 nsCOMPtr<nsIURI> codebase;
138 subjectPrincipal->GetURI(getter_AddRefs(codebase));
140 if (!codebase) {
141 return PR_FALSE;
144 nsCOMPtr<nsIURI> innerUri = NS_GetInnermostURI(codebase);
146 if (!innerUri) {
147 return PR_FALSE;
150 PRBool isHttps = PR_FALSE;
151 nsresult rv = innerUri->SchemeIs("https", &isHttps);
153 return NS_SUCCEEDED(rv) && isHttps;
156 PRUint32
157 GetOfflinePermission(const nsACString &aDomain)
159 // Fake a URI for the permission manager
160 nsCOMPtr<nsIURI> uri;
161 NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("http://") + aDomain);
163 PRUint32 perm;
164 if (uri) {
165 nsCOMPtr<nsIPermissionManager> permissionManager =
166 do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
168 if (permissionManager &&
169 NS_SUCCEEDED(permissionManager->TestPermission(uri, "offline-app", &perm)))
170 return perm;
173 return nsIPermissionManager::UNKNOWN_ACTION;
176 PRBool
177 IsOfflineAllowed(const nsACString &aDomain)
179 PRInt32 perm = GetOfflinePermission(aDomain);
180 return IS_PERMISSION_ALLOWED(perm);
183 // Returns two quotas - A hard limit for which adding data will be an error,
184 // and a limit after which a warning event will be sent to the observer
185 // service. The warn limit may be -1, in which case there will be no warning.
186 // If aOverrideQuota is set, the larger offline apps quota is used and no
187 // warning is sent.
188 static PRUint32
189 GetQuota(const nsACString &aDomain, PRInt32 *aQuota, PRInt32 *aWarnQuota,
190 bool aOverrideQuota)
192 PRUint32 perm = GetOfflinePermission(aDomain);
193 if (IS_PERMISSION_ALLOWED(perm) || aOverrideQuota) {
194 // This is an offline app, give more space by default.
195 *aQuota = ((PRInt32)nsContentUtils::GetIntPref(kOfflineAppQuota,
196 DEFAULT_OFFLINE_APP_QUOTA) * 1024);
198 if (perm == nsIOfflineCacheUpdateService::ALLOW_NO_WARN ||
199 aOverrideQuota) {
200 *aWarnQuota = -1;
201 } else {
202 *aWarnQuota = ((PRInt32)nsContentUtils::GetIntPref(kOfflineAppWarnQuota,
203 DEFAULT_OFFLINE_WARN_QUOTA) * 1024);
205 return perm;
208 // FIXME: per-domain quotas?
209 *aQuota = ((PRInt32)nsContentUtils::GetIntPref(kDefaultQuota,
210 DEFAULT_QUOTA) * 1024);
211 *aWarnQuota = -1;
213 return perm;
216 nsSessionStorageEntry::nsSessionStorageEntry(KeyTypePointer aStr)
217 : nsStringHashKey(aStr), mItem(nsnull)
221 nsSessionStorageEntry::nsSessionStorageEntry(const nsSessionStorageEntry& aToCopy)
222 : nsStringHashKey(aToCopy), mItem(nsnull)
224 NS_ERROR("We're horked.");
227 nsSessionStorageEntry::~nsSessionStorageEntry()
232 // nsDOMStorageManager
235 nsDOMStorageManager* nsDOMStorageManager::gStorageManager;
237 nsDOMStorageManager::nsDOMStorageManager()
238 : mInPrivateBrowsing(PR_FALSE)
242 NS_IMPL_ISUPPORTS2(nsDOMStorageManager,
243 nsIDOMStorageManager,
244 nsIObserver)
246 //static
247 nsresult
248 nsDOMStorageManager::Initialize()
250 gStorageManager = new nsDOMStorageManager();
251 if (!gStorageManager)
252 return NS_ERROR_OUT_OF_MEMORY;
254 if (!gStorageManager->mStorages.Init()) {
255 delete gStorageManager;
256 gStorageManager = nsnull;
257 return NS_ERROR_OUT_OF_MEMORY;
260 NS_ADDREF(gStorageManager);
262 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
263 if (!os)
264 return NS_OK;
266 os->AddObserver(gStorageManager, "cookie-changed", PR_FALSE);
267 os->AddObserver(gStorageManager, "offline-app-removed", PR_FALSE);
268 os->AddObserver(gStorageManager, NS_PRIVATE_BROWSING_SWITCH_TOPIC, PR_FALSE);
269 os->AddObserver(gStorageManager, "profile-after-change", PR_FALSE);
270 os->AddObserver(gStorageManager, "perm-changed", PR_FALSE);
272 return NS_OK;
275 //static
276 nsDOMStorageManager*
277 nsDOMStorageManager::GetInstance()
279 NS_ASSERTION(gStorageManager,
280 "nsDOMStorageManager::GetInstance() called before Initialize()");
281 NS_IF_ADDREF(gStorageManager);
282 return gStorageManager;
285 //static
286 void
287 nsDOMStorageManager::Shutdown()
289 NS_IF_RELEASE(gStorageManager);
290 gStorageManager = nsnull;
292 #ifdef MOZ_STORAGE
293 delete nsDOMStorage::gStorageDB;
294 nsDOMStorage::gStorageDB = nsnull;
295 #endif
298 static PLDHashOperator
299 ClearStorage(nsDOMStorageEntry* aEntry, void* userArg)
301 aEntry->mStorage->ClearAll();
302 return PL_DHASH_REMOVE;
305 static nsresult
306 GetOfflineDomains(nsTArray<nsString>& aDomains)
308 nsCOMPtr<nsIPermissionManager> permissionManager =
309 do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
310 if (permissionManager) {
311 nsCOMPtr<nsISimpleEnumerator> enumerator;
312 nsresult rv = permissionManager->GetEnumerator(getter_AddRefs(enumerator));
313 NS_ENSURE_SUCCESS(rv, rv);
315 PRBool hasMore;
316 while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMore)) && hasMore) {
317 nsCOMPtr<nsISupports> supp;
318 rv = enumerator->GetNext(getter_AddRefs(supp));
319 NS_ENSURE_SUCCESS(rv, rv);
321 nsCOMPtr<nsIPermission> perm(do_QueryInterface(supp, &rv));
322 NS_ENSURE_SUCCESS(rv, rv);
324 PRUint32 capability;
325 rv = perm->GetCapability(&capability);
326 NS_ENSURE_SUCCESS(rv, rv);
327 if (capability != nsIPermissionManager::DENY_ACTION) {
328 nsCAutoString type;
329 rv = perm->GetType(type);
330 NS_ENSURE_SUCCESS(rv, rv);
332 if (type.EqualsLiteral("offline-app")) {
333 nsCAutoString host;
334 rv = perm->GetHost(host);
335 NS_ENSURE_SUCCESS(rv, rv);
337 aDomains.AppendElement(NS_ConvertUTF8toUTF16(host));
343 return NS_OK;
346 nsresult
347 nsDOMStorageManager::Observe(nsISupports *aSubject,
348 const char *aTopic,
349 const PRUnichar *aData)
351 if (!strcmp(aTopic, "profile-after-change")) {
352 nsCOMPtr<nsIPrivateBrowsingService> pbs =
353 do_GetService(NS_PRIVATE_BROWSING_SERVICE_CONTRACTID);
354 if (pbs)
355 pbs->GetPrivateBrowsingEnabled(&gStorageManager->mInPrivateBrowsing);
357 else if (!strcmp(aTopic, "offline-app-removed")) {
358 #ifdef MOZ_STORAGE
359 nsresult rv = nsDOMStorage::InitDB();
360 NS_ENSURE_SUCCESS(rv, rv);
361 return nsDOMStorage::gStorageDB->RemoveOwner(NS_ConvertUTF16toUTF8(aData),
362 PR_TRUE);
363 #endif
364 } else if (!strcmp(aTopic, "cookie-changed") &&
365 !nsCRT::strcmp(aData, NS_LITERAL_STRING("cleared").get())) {
366 mStorages.EnumerateEntries(ClearStorage, nsnull);
368 #ifdef MOZ_STORAGE
369 nsresult rv = nsDOMStorage::InitDB();
370 NS_ENSURE_SUCCESS(rv, rv);
372 // Remove global storage for domains that aren't marked for offline use.
373 nsTArray<nsString> domains;
374 rv = GetOfflineDomains(domains);
375 NS_ENSURE_SUCCESS(rv, rv);
376 return nsDOMStorage::gStorageDB->RemoveOwners(domains, PR_TRUE, PR_FALSE);
377 #endif
378 } else if (!strcmp(aTopic, NS_PRIVATE_BROWSING_SWITCH_TOPIC)) {
379 mStorages.EnumerateEntries(ClearStorage, nsnull);
380 if (!nsCRT::strcmp(aData, NS_LITERAL_STRING(NS_PRIVATE_BROWSING_ENTER).get()))
381 mInPrivateBrowsing = PR_TRUE;
382 else if (!nsCRT::strcmp(aData, NS_LITERAL_STRING(NS_PRIVATE_BROWSING_LEAVE).get()))
383 mInPrivateBrowsing = PR_FALSE;
384 #ifdef MOZ_STORAGE
385 nsresult rv = nsDOMStorage::InitDB();
386 NS_ENSURE_SUCCESS(rv, rv);
388 return nsDOMStorage::gStorageDB->DropPrivateBrowsingStorages();
389 #endif
390 } else if (!strcmp(aTopic, "perm-changed")) {
391 // Check for cookie permission change
392 nsCOMPtr<nsIPermission> perm(do_QueryInterface(aSubject));
393 if (perm) {
394 nsCAutoString type;
395 perm->GetType(type);
396 if (type != NS_LITERAL_CSTRING("cookie"))
397 return NS_OK;
399 PRUint32 cap = 0;
400 perm->GetCapability(&cap);
401 if (!(cap & nsICookiePermission::ACCESS_SESSION) ||
402 nsDependentString(aData) != NS_LITERAL_STRING("deleted"))
403 return NS_OK;
405 nsCAutoString host;
406 perm->GetHost(host);
407 if (host.IsEmpty())
408 return NS_OK;
410 #ifdef MOZ_STORAGE
411 nsresult rv = nsDOMStorage::InitDB();
412 NS_ENSURE_SUCCESS(rv, rv);
414 return nsDOMStorage::gStorageDB->DropSessionOnlyStoragesForHost(host);
415 #endif
419 return NS_OK;
422 NS_IMETHODIMP
423 nsDOMStorageManager::GetUsage(const nsAString& aDomain,
424 PRInt32 *aUsage)
426 nsresult rv = nsDOMStorage::InitDB();
427 NS_ENSURE_SUCCESS(rv, rv);
429 return nsDOMStorage::gStorageDB->GetUsage(NS_ConvertUTF16toUTF8(aDomain),
430 PR_FALSE, aUsage);
433 NS_IMETHODIMP
434 nsDOMStorageManager::ClearOfflineApps()
436 nsresult rv = nsDOMStorage::InitDB();
437 NS_ENSURE_SUCCESS(rv, rv);
439 nsTArray<nsString> domains;
440 rv = GetOfflineDomains(domains);
441 NS_ENSURE_SUCCESS(rv, rv);
442 return nsDOMStorage::gStorageDB->RemoveOwners(domains, PR_TRUE, PR_TRUE);
445 NS_IMETHODIMP
446 nsDOMStorageManager::GetLocalStorageForPrincipal(nsIPrincipal *aPrincipal,
447 const nsSubstring &aDocumentURI,
448 nsIDOMStorage **aResult)
450 NS_ENSURE_ARG_POINTER(aPrincipal);
451 *aResult = nsnull;
453 nsresult rv;
455 nsRefPtr<nsDOMStorage2> storage = new nsDOMStorage2();
456 if (!storage)
457 return NS_ERROR_OUT_OF_MEMORY;
459 rv = storage->InitAsLocalStorage(aPrincipal, aDocumentURI);
460 if (NS_FAILED(rv))
461 return rv;
463 *aResult = storage.get();
464 storage.forget();
466 return NS_OK;
469 void
470 nsDOMStorageManager::AddToStoragesHash(nsDOMStorage* aStorage)
472 nsDOMStorageEntry* entry = mStorages.PutEntry(aStorage);
473 if (entry)
474 entry->mStorage = aStorage;
477 void
478 nsDOMStorageManager::RemoveFromStoragesHash(nsDOMStorage* aStorage)
480 nsDOMStorageEntry* entry = mStorages.GetEntry(aStorage);
481 if (entry)
482 mStorages.RemoveEntry(aStorage);
486 // nsDOMStorage
489 #ifdef MOZ_STORAGE
490 nsDOMStorageDBWrapper* nsDOMStorage::gStorageDB = nsnull;
491 #endif
493 nsDOMStorageEntry::nsDOMStorageEntry(KeyTypePointer aStr)
494 : nsVoidPtrHashKey(aStr), mStorage(nsnull)
498 nsDOMStorageEntry::nsDOMStorageEntry(const nsDOMStorageEntry& aToCopy)
499 : nsVoidPtrHashKey(aToCopy), mStorage(nsnull)
501 NS_ERROR("DOMStorage horked.");
504 nsDOMStorageEntry::~nsDOMStorageEntry()
508 PLDHashOperator
509 SessionStorageTraverser(nsSessionStorageEntry* aEntry, void* userArg) {
510 nsCycleCollectionTraversalCallback *cb =
511 static_cast<nsCycleCollectionTraversalCallback*>(userArg);
513 cb->NoteXPCOMChild((nsIDOMStorageItem *) aEntry->mItem);
515 return PL_DHASH_NEXT;
518 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMStorage)
519 NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsDOMStorage)
520 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMStorage)
522 if (tmp->mItems.IsInitialized()) {
523 tmp->mItems.EnumerateEntries(SessionStorageTraverser, &cb);
526 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
528 DOMCI_DATA(StorageObsolete, nsDOMStorage)
530 NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsDOMStorage, nsIDOMStorageObsolete)
531 NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsDOMStorage, nsIDOMStorageObsolete)
532 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMStorage)
533 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMStorageObsolete)
534 NS_INTERFACE_MAP_ENTRY(nsIDOMStorageObsolete)
535 NS_INTERFACE_MAP_ENTRY(nsPIDOMStorage)
536 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(StorageObsolete)
537 NS_INTERFACE_MAP_END
539 nsresult
540 NS_NewDOMStorage(nsISupports* aOuter, REFNSIID aIID, void** aResult)
542 nsDOMStorage* storage = new nsDOMStorage();
543 if (!storage)
544 return NS_ERROR_OUT_OF_MEMORY;
546 return storage->QueryInterface(aIID, aResult);
549 nsresult
550 NS_NewDOMStorage2(nsISupports* aOuter, REFNSIID aIID, void** aResult)
552 nsDOMStorage2* storage = new nsDOMStorage2();
553 if (!storage)
554 return NS_ERROR_OUT_OF_MEMORY;
556 return storage->QueryInterface(aIID, aResult);
559 nsDOMStorage::nsDOMStorage()
560 : mUseDB(PR_FALSE)
561 , mSessionOnly(PR_TRUE)
562 , mStorageType(nsPIDOMStorage::Unknown)
563 , mItemsCached(PR_FALSE)
564 , mEventBroadcaster(nsnull)
565 , mCanUseChromePersist(false)
567 mSecurityChecker = this;
568 mItems.Init(8);
569 if (nsDOMStorageManager::gStorageManager)
570 nsDOMStorageManager::gStorageManager->AddToStoragesHash(this);
573 nsDOMStorage::nsDOMStorage(nsDOMStorage& aThat)
574 : mUseDB(PR_FALSE) // Any clone is not using the database
575 , mDomain(aThat.mDomain)
576 , mSessionOnly(PR_TRUE)
577 , mStorageType(aThat.mStorageType)
578 , mItemsCached(PR_FALSE)
579 #ifdef MOZ_STORAGE
580 , mScopeDBKey(aThat.mScopeDBKey)
581 #endif
582 , mEventBroadcaster(nsnull)
583 , mCanUseChromePersist(aThat.mCanUseChromePersist)
585 mSecurityChecker = this;
586 mItems.Init(8);
588 if (nsDOMStorageManager::gStorageManager)
589 nsDOMStorageManager::gStorageManager->AddToStoragesHash(this);
592 nsDOMStorage::~nsDOMStorage()
594 if (nsDOMStorageManager::gStorageManager)
595 nsDOMStorageManager::gStorageManager->RemoveFromStoragesHash(this);
598 static
599 nsresult
600 GetDomainURI(nsIPrincipal *aPrincipal, PRBool aIncludeDomain, nsIURI **_domain)
602 nsCOMPtr<nsIURI> uri;
604 if (aIncludeDomain) {
605 nsresult rv = aPrincipal->GetDomain(getter_AddRefs(uri));
606 NS_ENSURE_SUCCESS(rv, rv);
609 if (!uri) {
610 nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri));
611 NS_ENSURE_SUCCESS(rv, rv);
614 // Check if we really got any URI. System principal doesn't return a URI
615 // instance and we would crash in NS_GetInnermostURI below.
616 if (!uri)
617 return NS_ERROR_NOT_AVAILABLE;
619 nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(uri);
620 if (!innerURI)
621 return NS_ERROR_UNEXPECTED;
622 innerURI.forget(_domain);
624 return NS_OK;
627 nsresult
628 nsDOMStorage::InitAsSessionStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI)
630 nsCOMPtr<nsIURI> domainURI;
631 nsresult rv = GetDomainURI(aPrincipal, PR_TRUE, getter_AddRefs(domainURI));
632 NS_ENSURE_SUCCESS(rv, rv);
634 // No need to check for a return value. If this would fail we would not get
635 // here as we call GetPrincipalURIAndHost (nsDOMStorage.cpp:88) from
636 // nsDOMStorage::CanUseStorage before we query the storage manager for a new
637 // sessionStorage. It calls GetAsciiHost on innermost URI. If it fails, we
638 // won't get to InitAsSessionStorage.
639 domainURI->GetAsciiHost(mDomain);
641 mDocumentURI = aDocumentURI;
643 #ifdef MOZ_STORAGE
644 mUseDB = PR_FALSE;
645 mScopeDBKey.Truncate();
646 mQuotaDomainDBKey.Truncate();
647 #endif
649 mStorageType = SessionStorage;
650 return NS_OK;
653 nsresult
654 nsDOMStorage::InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI)
656 nsCOMPtr<nsIURI> domainURI;
657 nsresult rv = GetDomainURI(aPrincipal, PR_FALSE, getter_AddRefs(domainURI));
658 NS_ENSURE_SUCCESS(rv, rv);
660 // No need to check for a return value. If this would fail we would not get
661 // here as we call GetPrincipalURIAndHost (nsDOMStorage.cpp:88) from
662 // nsDOMStorage::CanUseStorage before we query the storage manager for a new
663 // localStorage. It calls GetAsciiHost on innermost URI. If it fails, we won't
664 // get to InitAsLocalStorage. Actually, mDomain will get replaced with
665 // mPrincipal in bug 455070. It is not even used for localStorage.
666 domainURI->GetAsciiHost(mDomain);
668 mDocumentURI = aDocumentURI;
670 #ifdef MOZ_STORAGE
671 nsDOMStorageDBWrapper::CreateOriginScopeDBKey(domainURI, mScopeDBKey);
673 // XXX Bug 357323, we have to solve the issue how to define
674 // origin for file URLs. In that case CreateOriginScopeDBKey
675 // fails (the result is empty) and we must avoid database use
676 // in that case because it produces broken entries w/o owner.
677 mUseDB = !mScopeDBKey.IsEmpty();
679 nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(mDomain,
680 PR_TRUE, PR_FALSE, mQuotaDomainDBKey);
681 nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(mDomain,
682 PR_TRUE, PR_TRUE, mQuotaETLDplus1DomainDBKey);
683 #endif
685 mStorageType = LocalStorage;
687 nsCOMPtr<nsIURI> URI;
688 if (NS_SUCCEEDED(aPrincipal->GetURI(getter_AddRefs(URI))) && URI) {
689 mCanUseChromePersist = URICanUseChromePersist(URI);
692 return NS_OK;
695 nsresult
696 nsDOMStorage::InitAsGlobalStorage(const nsACString &aDomainDemanded)
698 mDomain = aDomainDemanded;
699 #ifdef MOZ_STORAGE
700 nsDOMStorageDBWrapper::CreateDomainScopeDBKey(aDomainDemanded, mScopeDBKey);
702 // XXX Bug 357323, we have to solve the issue how to define
703 // origin for file URLs. In that case CreateOriginScopeDBKey
704 // fails (the result is empty) and we must avoid database use
705 // in that case because it produces broken entries w/o owner.
706 if (!(mUseDB = !mScopeDBKey.IsEmpty()))
707 mScopeDBKey.AppendLiteral(":");
709 nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(aDomainDemanded,
710 PR_TRUE, PR_FALSE, mQuotaDomainDBKey);
711 nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(aDomainDemanded,
712 PR_TRUE, PR_TRUE, mQuotaETLDplus1DomainDBKey);
713 #endif
715 mStorageType = GlobalStorage;
716 mEventBroadcaster = this;
717 return NS_OK;
720 static PLDHashOperator
721 CopyStorageItems(nsSessionStorageEntry* aEntry, void* userArg)
723 nsDOMStorage* newstorage = static_cast<nsDOMStorage*>(userArg);
725 newstorage->SetItem(aEntry->GetKey(), aEntry->mItem->GetValueInternal());
727 if (aEntry->mItem->IsSecure()) {
728 newstorage->SetSecure(aEntry->GetKey(), PR_TRUE);
731 return PL_DHASH_NEXT;
734 nsresult
735 nsDOMStorage::CloneFrom(nsDOMStorage* aThat)
737 aThat->mItems.EnumerateEntries(CopyStorageItems, this);
738 return NS_OK;
741 //static
742 PRBool
743 nsDOMStorage::CanUseStorage(PRPackedBool* aSessionOnly)
745 // check if the calling domain can use storage. Downgrade to session
746 // only if only session storage may be used.
747 NS_ASSERTION(aSessionOnly, "null session flag");
748 *aSessionOnly = PR_FALSE;
750 if (!nsContentUtils::GetBoolPref(kStorageEnabled))
751 return PR_FALSE;
753 // chrome can always use storage regardless of permission preferences
754 if (nsContentUtils::IsCallerChrome())
755 return PR_TRUE;
757 nsCOMPtr<nsIPrincipal> subjectPrincipal;
758 nsContentUtils::GetSecurityManager()->
759 GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
761 // if subjectPrincipal were null we'd have returned after
762 // IsCallerChrome().
764 nsCOMPtr<nsIURI> subjectURI;
765 nsCAutoString unused;
766 if (NS_FAILED(GetPrincipalURIAndHost(subjectPrincipal,
767 getter_AddRefs(subjectURI),
768 unused))) {
769 return PR_FALSE;
772 nsCOMPtr<nsIPermissionManager> permissionManager =
773 do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
774 if (!permissionManager)
775 return PR_FALSE;
777 PRUint32 perm;
778 permissionManager->TestPermission(subjectURI, kPermissionType, &perm);
780 if (perm == nsIPermissionManager::DENY_ACTION)
781 return PR_FALSE;
783 // In private browsing mode we ougth to behave as in session-only cookies
784 // mode to prevent detection of being in private browsing mode and ensuring
785 // that there will be no traces left.
786 if (perm == nsICookiePermission::ACCESS_SESSION ||
787 nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode()) {
788 *aSessionOnly = PR_TRUE;
790 else if (perm != nsIPermissionManager::ALLOW_ACTION) {
791 PRUint32 cookieBehavior = nsContentUtils::GetIntPref(kCookiesBehavior);
792 PRUint32 lifetimePolicy = nsContentUtils::GetIntPref(kCookiesLifetimePolicy);
794 // Treat "ask every time" as "reject always".
795 // Chrome persistent pages can bypass this check.
796 if ((cookieBehavior == BEHAVIOR_REJECT || lifetimePolicy == ASK_BEFORE_ACCEPT) &&
797 !URICanUseChromePersist(subjectURI))
798 return PR_FALSE;
800 if (lifetimePolicy == ACCEPT_SESSION)
801 *aSessionOnly = PR_TRUE;
804 return PR_TRUE;
807 PRBool
808 nsDOMStorage::CacheStoragePermissions()
810 // Bug 488446, disallowing storage use when in session only mode.
811 // This is temporary fix before we find complete solution for storage
812 // behavior in private browsing mode or session-only cookies mode.
813 if (!CanUseStorage(&mSessionOnly))
814 return PR_FALSE;
816 nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
817 if (!ssm)
818 return PR_FALSE;
820 nsCOMPtr<nsIPrincipal> subjectPrincipal;
821 ssm->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
823 NS_ASSERTION(mSecurityChecker, "Has non-null mSecurityChecker");
824 return mSecurityChecker->CanAccess(subjectPrincipal);
827 // static
828 PRBool
829 nsDOMStorage::URICanUseChromePersist(nsIURI* aURI) {
830 PRBool isAbout;
831 return
832 (NS_SUCCEEDED(aURI->SchemeIs("moz-safe-about", &isAbout)) && isAbout) ||
833 (NS_SUCCEEDED(aURI->SchemeIs("about", &isAbout)) && isAbout);
836 bool
837 nsDOMStorage::CanUseChromePersist()
839 return mCanUseChromePersist;
842 class ItemCounterState
844 public:
845 ItemCounterState(PRBool aIsCallerSecure)
846 : mIsCallerSecure(aIsCallerSecure), mCount(0)
850 PRBool mIsCallerSecure;
851 PRBool mCount;
852 private:
853 ItemCounterState(); // Not to be implemented
856 static PLDHashOperator
857 ItemCounter(nsSessionStorageEntry* aEntry, void* userArg)
859 ItemCounterState *state = (ItemCounterState *)userArg;
861 if (state->mIsCallerSecure || !aEntry->mItem->IsSecure()) {
862 ++state->mCount;
865 return PL_DHASH_NEXT;
868 NS_IMETHODIMP
869 nsDOMStorage::GetLength(PRUint32 *aLength)
871 if (!CacheStoragePermissions())
872 return NS_ERROR_DOM_SECURITY_ERR;
874 // Force reload of items from database. This ensures sync localStorages for
875 // same origins among different windows.
876 mItemsCached = PR_FALSE;
877 if (UseDB())
878 CacheKeysFromDB();
880 ItemCounterState state(IsCallerSecure());
882 mItems.EnumerateEntries(ItemCounter, &state);
884 *aLength = state.mCount;
886 return NS_OK;
889 class IndexFinderData
891 public:
892 IndexFinderData(PRBool aIsCallerSecure, PRUint32 aWantedIndex)
893 : mIsCallerSecure(aIsCallerSecure), mIndex(0), mWantedIndex(aWantedIndex),
894 mItem(nsnull)
898 PRBool mIsCallerSecure;
899 PRUint32 mIndex;
900 PRUint32 mWantedIndex;
901 nsSessionStorageEntry *mItem;
903 private:
904 IndexFinderData(); // Not to be implemented
907 static PLDHashOperator
908 IndexFinder(nsSessionStorageEntry* aEntry, void* userArg)
910 IndexFinderData *data = (IndexFinderData *)userArg;
912 if (data->mIndex == data->mWantedIndex &&
913 (data->mIsCallerSecure || !aEntry->mItem->IsSecure())) {
914 data->mItem = aEntry;
916 return PL_DHASH_STOP;
919 ++data->mIndex;
921 return PL_DHASH_NEXT;
924 NS_IMETHODIMP
925 nsDOMStorage::Key(PRUint32 aIndex, nsAString& aKey)
927 // XXXjst: This is as retarded as the DOM spec is, takes an unsigned
928 // int, but the spec talks about what to do if a negative value is
929 // passed in.
931 // XXX: This does a linear search for the key at index, which would
932 // suck if there's a large numer of indexes. Do we care? If so,
933 // maybe we need to have a lazily populated key array here or
934 // something?
936 if (!CacheStoragePermissions())
937 return NS_ERROR_DOM_SECURITY_ERR;
939 if (UseDB())
940 CacheKeysFromDB();
942 IndexFinderData data(IsCallerSecure(), aIndex);
943 mItems.EnumerateEntries(IndexFinder, &data);
945 if (!data.mItem) {
946 // aIndex was larger than the number of accessible keys. Throw.
947 return NS_ERROR_DOM_INDEX_SIZE_ERR;
950 aKey = data.mItem->GetKey();
952 return NS_OK;
955 nsIDOMStorageItem*
956 nsDOMStorage::GetNamedItem(const nsAString& aKey, nsresult* aResult)
958 if (!CacheStoragePermissions()) {
959 *aResult = NS_ERROR_DOM_SECURITY_ERR;
960 return nsnull;
963 *aResult = NS_OK;
964 if (aKey.IsEmpty())
965 return nsnull;
967 nsSessionStorageEntry *entry = mItems.GetEntry(aKey);
968 nsIDOMStorageItem* item = nsnull;
969 if (entry) {
970 if (IsCallerSecure() || !entry->mItem->IsSecure()) {
971 item = entry->mItem;
974 else if (UseDB()) {
975 PRBool secure;
976 nsAutoString value;
977 nsresult rv = GetDBValue(aKey, value, &secure);
978 // return null if access isn't allowed or the key wasn't found
979 if (rv == NS_ERROR_DOM_SECURITY_ERR || rv == NS_ERROR_DOM_NOT_FOUND_ERR)
980 return nsnull;
982 *aResult = rv;
983 NS_ENSURE_SUCCESS(rv, nsnull);
985 nsRefPtr<nsDOMStorageItem> newitem =
986 new nsDOMStorageItem(this, aKey, value, secure);
987 if (newitem && (entry = mItems.PutEntry(aKey))) {
988 item = entry->mItem = newitem;
990 else {
991 *aResult = NS_ERROR_OUT_OF_MEMORY;
995 return item;
998 nsresult
999 nsDOMStorage::GetItem(const nsAString& aKey, nsAString &aData)
1001 nsresult rv;
1003 // IMPORTANT:
1004 // CacheStoragePermissions() is called inside of
1005 // GetItem(nsAString, nsIDOMStorageItem)
1006 // To call it particularly in this method would just duplicate
1007 // the call. If the code changes, make sure that call to
1008 // CacheStoragePermissions() is put here!
1010 nsCOMPtr<nsIDOMStorageItem> item;
1011 rv = GetItem(aKey, getter_AddRefs(item));
1012 if (NS_FAILED(rv))
1013 return rv;
1015 if (item) {
1016 rv = item->GetValue(aData);
1017 NS_ENSURE_SUCCESS(rv, rv);
1019 else
1020 SetDOMStringToNull(aData);
1022 return NS_OK;
1025 NS_IMETHODIMP
1026 nsDOMStorage::GetItem(const nsAString& aKey, nsIDOMStorageItem **aItem)
1028 nsresult rv;
1030 NS_IF_ADDREF(*aItem = GetNamedItem(aKey, &rv));
1032 return rv;
1035 NS_IMETHODIMP
1036 nsDOMStorage::SetItem(const nsAString& aKey, const nsAString& aData)
1038 if (!CacheStoragePermissions())
1039 return NS_ERROR_DOM_SECURITY_ERR;
1041 if (aKey.IsEmpty())
1042 return NS_OK;
1044 nsString oldValue;
1045 SetDOMStringToNull(oldValue);
1047 nsresult rv;
1048 nsRefPtr<nsDOMStorageItem> newitem = nsnull;
1049 nsSessionStorageEntry *entry = mItems.GetEntry(aKey);
1050 if (entry) {
1051 if (entry->mItem->IsSecure() && !IsCallerSecure()) {
1052 return NS_ERROR_DOM_SECURITY_ERR;
1054 oldValue = entry->mItem->GetValueInternal();
1055 entry->mItem->SetValueInternal(aData);
1057 else {
1058 newitem = new nsDOMStorageItem(this, aKey, aData, IsCallerSecure());
1059 if (!newitem)
1060 return NS_ERROR_OUT_OF_MEMORY;
1063 if (UseDB()) {
1064 rv = SetDBValue(aKey, aData, IsCallerSecure());
1065 NS_ENSURE_SUCCESS(rv, rv);
1068 if (newitem) {
1069 entry = mItems.PutEntry(aKey);
1070 NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
1071 entry->mItem = newitem;
1074 if ((oldValue != aData || mStorageType == GlobalStorage) && mEventBroadcaster)
1075 mEventBroadcaster->BroadcastChangeNotification(aKey, oldValue, aData);
1077 return NS_OK;
1080 NS_IMETHODIMP nsDOMStorage::RemoveItem(const nsAString& aKey)
1082 if (!CacheStoragePermissions())
1083 return NS_ERROR_DOM_SECURITY_ERR;
1085 if (aKey.IsEmpty())
1086 return NS_OK;
1088 nsString oldValue;
1089 nsSessionStorageEntry *entry = mItems.GetEntry(aKey);
1091 if (entry && entry->mItem->IsSecure() && !IsCallerSecure()) {
1092 return NS_ERROR_DOM_SECURITY_ERR;
1095 if (UseDB()) {
1096 #ifdef MOZ_STORAGE
1097 nsresult rv = InitDB();
1098 NS_ENSURE_SUCCESS(rv, rv);
1100 nsAutoString value;
1101 PRBool secureItem;
1102 rv = GetDBValue(aKey, value, &secureItem);
1103 if (rv == NS_ERROR_DOM_NOT_FOUND_ERR)
1104 return NS_OK;
1105 NS_ENSURE_SUCCESS(rv, rv);
1107 oldValue = value;
1109 rv = gStorageDB->RemoveKey(this, aKey, !IsOfflineAllowed(mDomain),
1110 aKey.Length() + value.Length());
1111 NS_ENSURE_SUCCESS(rv, rv);
1113 mItemsCached = PR_FALSE;
1114 #endif
1116 else if (entry) {
1117 // clear string as StorageItems may be referencing this item
1118 oldValue = entry->mItem->GetValueInternal();
1119 entry->mItem->ClearValue();
1122 if (entry) {
1123 mItems.RawRemoveEntry(entry);
1126 if ((!oldValue.IsEmpty() && mStorageType != GlobalStorage) && mEventBroadcaster) {
1127 nsAutoString nullString;
1128 SetDOMStringToNull(nullString);
1129 mEventBroadcaster->BroadcastChangeNotification(aKey, oldValue, nullString);
1132 return NS_OK;
1135 PR_STATIC_CALLBACK(PLDHashOperator)
1136 CheckSecure(nsSessionStorageEntry* aEntry, void* userArg)
1138 PRBool* secure = (PRBool*)userArg;
1139 if (aEntry->mItem->IsSecure()) {
1140 *secure = PR_TRUE;
1141 return PL_DHASH_STOP;
1144 return PL_DHASH_NEXT;
1147 nsresult
1148 nsDOMStorage::Clear()
1150 if (!CacheStoragePermissions())
1151 return NS_ERROR_DOM_SECURITY_ERR;
1153 if (UseDB())
1154 CacheKeysFromDB();
1156 PRInt32 oldCount = mItems.Count();
1158 PRBool foundSecureItem = PR_FALSE;
1159 mItems.EnumerateEntries(CheckSecure, &foundSecureItem);
1161 if (foundSecureItem && !IsCallerSecure()) {
1162 return NS_ERROR_DOM_SECURITY_ERR;
1165 #ifdef MOZ_STORAGE
1166 if (UseDB()) {
1167 nsresult rv = InitDB();
1168 NS_ENSURE_SUCCESS(rv, rv);
1170 rv = gStorageDB->ClearStorage(this);
1171 NS_ENSURE_SUCCESS(rv, rv);
1173 #endif
1175 mItems.Clear();
1177 if (oldCount && mEventBroadcaster) {
1178 nsAutoString nullString;
1179 SetDOMStringToNull(nullString);
1180 mEventBroadcaster->BroadcastChangeNotification(nullString, nullString, nullString);
1183 return NS_OK;
1186 nsresult
1187 nsDOMStorage::InitDB()
1189 #ifdef MOZ_STORAGE
1190 if (!gStorageDB) {
1191 gStorageDB = new nsDOMStorageDBWrapper();
1192 if (!gStorageDB)
1193 return NS_ERROR_OUT_OF_MEMORY;
1195 nsresult rv = gStorageDB->Init();
1196 if (NS_FAILED(rv)) {
1197 // Failed to initialize the DB, delete it and null out the
1198 // pointer so we don't end up attempting to use an
1199 // un-initialized DB later on.
1201 delete gStorageDB;
1202 gStorageDB = nsnull;
1204 return rv;
1207 #endif
1209 return NS_OK;
1212 nsresult
1213 nsDOMStorage::CacheKeysFromDB()
1215 #ifdef MOZ_STORAGE
1216 // cache all the keys in the hash. This is used by the Length and Key methods
1217 // use this cache for better performance. The disadvantage is that the
1218 // order may break if someone changes the keys in the database directly.
1219 if (!mItemsCached) {
1220 nsresult rv = InitDB();
1221 NS_ENSURE_SUCCESS(rv, rv);
1223 mItems.Clear();
1225 rv = gStorageDB->GetAllKeys(this, &mItems);
1226 NS_ENSURE_SUCCESS(rv, rv);
1228 mItemsCached = PR_TRUE;
1230 #endif
1232 return NS_OK;
1235 nsresult
1236 nsDOMStorage::GetDBValue(const nsAString& aKey, nsAString& aValue,
1237 PRBool* aSecure)
1239 aValue.Truncate();
1241 #ifdef MOZ_STORAGE
1242 if (!UseDB())
1243 return NS_OK;
1245 nsresult rv = InitDB();
1246 NS_ENSURE_SUCCESS(rv, rv);
1248 nsAutoString value;
1249 rv = gStorageDB->GetKeyValue(this, aKey, value, aSecure);
1251 if (rv == NS_ERROR_DOM_NOT_FOUND_ERR && mStorageType != GlobalStorage) {
1252 SetDOMStringToNull(aValue);
1255 if (NS_FAILED(rv))
1256 return rv;
1258 if (!IsCallerSecure() && *aSecure) {
1259 return NS_ERROR_DOM_SECURITY_ERR;
1262 aValue.Assign(value);
1263 #endif
1265 return NS_OK;
1268 nsresult
1269 nsDOMStorage::SetDBValue(const nsAString& aKey,
1270 const nsAString& aValue,
1271 PRBool aSecure)
1273 #ifdef MOZ_STORAGE
1274 if (!UseDB())
1275 return NS_OK;
1277 nsresult rv = InitDB();
1278 NS_ENSURE_SUCCESS(rv, rv);
1280 PRInt32 offlineAppPermission;
1281 PRInt32 quota;
1282 PRInt32 warnQuota;
1283 offlineAppPermission = GetQuota(mDomain, &quota, &warnQuota,
1284 CanUseChromePersist());
1286 PRInt32 usage;
1287 rv = gStorageDB->SetKey(this, aKey, aValue, aSecure, quota,
1288 !IS_PERMISSION_ALLOWED(offlineAppPermission),
1289 &usage);
1290 NS_ENSURE_SUCCESS(rv, rv);
1292 mItemsCached = PR_FALSE;
1294 if (warnQuota >= 0 && usage > warnQuota) {
1295 // try to include the window that exceeded the warn quota
1296 nsCOMPtr<nsIDOMWindow> window;
1297 JSContext *cx;
1298 nsCOMPtr<nsIJSContextStack> stack =
1299 do_GetService("@mozilla.org/js/xpc/ContextStack;1");
1300 if (stack && NS_SUCCEEDED(stack->Peek(&cx)) && cx) {
1301 nsCOMPtr<nsIScriptContext> scriptContext;
1302 scriptContext = GetScriptContextFromJSContext(cx);
1303 if (scriptContext) {
1304 window = do_QueryInterface(scriptContext->GetGlobalObject());
1308 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
1309 os->NotifyObservers(window, "dom-storage-warn-quota-exceeded",
1310 NS_ConvertUTF8toUTF16(mDomain).get());
1313 #endif
1315 return NS_OK;
1318 nsresult
1319 nsDOMStorage::SetSecure(const nsAString& aKey, PRBool aSecure)
1321 #ifdef MOZ_STORAGE
1322 if (UseDB()) {
1323 nsresult rv = InitDB();
1324 NS_ENSURE_SUCCESS(rv, rv);
1326 return gStorageDB->SetSecure(this, aKey, aSecure);
1328 #else
1329 return NS_ERROR_NOT_IMPLEMENTED;
1330 #endif
1332 nsSessionStorageEntry *entry = mItems.GetEntry(aKey);
1333 NS_ASSERTION(entry, "Don't use SetSecure() with nonexistent keys!");
1335 if (entry) {
1336 entry->mItem->SetSecureInternal(aSecure);
1339 return NS_OK;
1342 static PLDHashOperator
1343 ClearStorageItem(nsSessionStorageEntry* aEntry, void* userArg)
1345 aEntry->mItem->SetValueInternal(EmptyString());
1346 return PL_DHASH_NEXT;
1349 void
1350 nsDOMStorage::ClearAll()
1352 mItems.EnumerateEntries(ClearStorageItem, nsnull);
1353 mItemsCached = PR_FALSE;
1356 already_AddRefed<nsIDOMStorage>
1357 nsDOMStorage::Clone()
1359 NS_ASSERTION(PR_FALSE, "Old DOMStorage doesn't implement cloning");
1360 return nsnull;
1363 already_AddRefed<nsIDOMStorage>
1364 nsDOMStorage::Fork(const nsSubstring &aDocumentURI)
1366 NS_ASSERTION(PR_FALSE, "Old DOMStorage doesn't implement forking");
1367 return nsnull;
1370 PRBool nsDOMStorage::IsForkOf(nsIDOMStorage* aThat)
1372 NS_ASSERTION(PR_FALSE, "Old DOMStorage doesn't implement forking");
1373 return PR_FALSE;
1376 struct KeysArrayBuilderStruct
1378 PRBool callerIsSecure;
1379 nsTArray<nsString> *keys;
1382 static PLDHashOperator
1383 KeysArrayBuilder(nsSessionStorageEntry* aEntry, void* userArg)
1385 KeysArrayBuilderStruct *keystruct = (KeysArrayBuilderStruct *)userArg;
1387 if (keystruct->callerIsSecure || !aEntry->mItem->IsSecure())
1388 keystruct->keys->AppendElement(aEntry->GetKey());
1390 return PL_DHASH_NEXT;
1393 nsTArray<nsString> *
1394 nsDOMStorage::GetKeys()
1396 if (UseDB())
1397 CacheKeysFromDB();
1399 KeysArrayBuilderStruct keystruct;
1400 keystruct.callerIsSecure = IsCallerSecure();
1401 keystruct.keys = new nsTArray<nsString>();
1402 if (keystruct.keys)
1403 mItems.EnumerateEntries(KeysArrayBuilder, &keystruct);
1405 return keystruct.keys;
1408 nsIPrincipal*
1409 nsDOMStorage::Principal()
1411 return nsnull;
1414 PRBool
1415 nsDOMStorage::CanAccessSystem(nsIPrincipal *aPrincipal)
1417 if (!aPrincipal)
1418 return PR_TRUE;
1420 nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
1421 if (!ssm)
1422 return PR_FALSE;
1424 PRBool isSystem;
1425 nsresult rv = ssm->IsSystemPrincipal(aPrincipal, &isSystem);
1427 return NS_SUCCEEDED(rv) && isSystem;
1430 PRBool
1431 nsDOMStorage::CanAccess(nsIPrincipal *aPrincipal)
1433 // Allow C++/system callers to access the storage
1434 if (CanAccessSystem(aPrincipal))
1435 return PR_TRUE;
1437 nsCAutoString domain;
1438 nsCOMPtr<nsIURI> unused;
1439 nsresult rv = GetPrincipalURIAndHost(aPrincipal,
1440 getter_AddRefs(unused), domain);
1441 NS_ENSURE_SUCCESS(rv, PR_FALSE);
1443 return domain.Equals(mDomain);
1446 nsPIDOMStorage::nsDOMStorageType
1447 nsDOMStorage::StorageType()
1449 return mStorageType;
1452 void
1453 nsDOMStorage::BroadcastChangeNotification(const nsSubstring &aKey,
1454 const nsSubstring &aOldValue,
1455 const nsSubstring &aNewValue)
1457 nsCOMPtr<nsIObserverService> observerService =
1458 mozilla::services::GetObserverService();
1459 if (!observerService) {
1460 return;
1463 // Fire off a notification that a storage object changed. If the
1464 // storage object is a session storage object, we don't pass a
1465 // domain, but if it's a global storage object we do.
1466 observerService->NotifyObservers((nsIDOMStorageObsolete *)this,
1467 "dom-storage-changed",
1468 NS_ConvertUTF8toUTF16(mDomain).get());
1472 // nsDOMStorage2
1475 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMStorage2)
1476 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMStorage2)
1477 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mStorage)
1478 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1479 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMStorage2)
1480 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mStorage, nsIDOMStorageObsolete)
1481 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1483 DOMCI_DATA(Storage, nsDOMStorage2)
1485 NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsDOMStorage2, nsIDOMStorage)
1486 NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsDOMStorage2, nsIDOMStorage)
1487 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMStorage2)
1488 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMStorage)
1489 NS_INTERFACE_MAP_ENTRY(nsIDOMStorage)
1490 NS_INTERFACE_MAP_ENTRY(nsPIDOMStorage)
1491 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Storage)
1492 NS_INTERFACE_MAP_END
1494 nsDOMStorage2::nsDOMStorage2()
1498 nsDOMStorage2::nsDOMStorage2(nsDOMStorage2& aThat)
1500 mStorage = new nsDOMStorage(*aThat.mStorage.get());
1501 mStorage->mSecurityChecker = mStorage;
1502 mPrincipal = aThat.mPrincipal;
1505 nsresult
1506 nsDOMStorage2::InitAsSessionStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI)
1508 mStorage = new nsDOMStorage();
1509 if (!mStorage)
1510 return NS_ERROR_OUT_OF_MEMORY;
1512 // Leave security checks only for domain (nsDOMStorage implementation)
1513 mStorage->mSecurityChecker = mStorage;
1514 mPrincipal = aPrincipal;
1515 mDocumentURI = aDocumentURI;
1517 return mStorage->InitAsSessionStorage(aPrincipal, aDocumentURI);
1520 nsresult
1521 nsDOMStorage2::InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI)
1523 mStorage = new nsDOMStorage();
1524 if (!mStorage)
1525 return NS_ERROR_OUT_OF_MEMORY;
1527 mStorage->mSecurityChecker = this;
1528 mPrincipal = aPrincipal;
1529 mDocumentURI = aDocumentURI;
1531 return mStorage->InitAsLocalStorage(aPrincipal, aDocumentURI);
1534 nsresult
1535 nsDOMStorage2::InitAsGlobalStorage(const nsACString &aDomainDemanded)
1537 NS_ASSERTION(PR_FALSE, "Should not initialize nsDOMStorage2 as global storage.");
1538 return NS_ERROR_NOT_IMPLEMENTED;
1541 already_AddRefed<nsIDOMStorage>
1542 nsDOMStorage2::Clone()
1544 nsDOMStorage2* storage = new nsDOMStorage2(*this);
1545 if (!storage)
1546 return nsnull;
1548 storage->mStorage->CloneFrom(mStorage);
1549 NS_ADDREF(storage);
1551 return storage;
1554 already_AddRefed<nsIDOMStorage>
1555 nsDOMStorage2::Fork(const nsSubstring &aDocumentURI)
1557 nsRefPtr<nsDOMStorage2> storage = new nsDOMStorage2();
1558 if (!storage)
1559 return nsnull;
1561 nsresult rv = storage->InitAsSessionStorageFork(mPrincipal, aDocumentURI, mStorage);
1562 if (NS_FAILED(rv))
1563 return nsnull;
1565 nsIDOMStorage* result = static_cast<nsIDOMStorage*>(storage.get());
1566 storage.forget();
1567 return result;
1570 PRBool nsDOMStorage2::IsForkOf(nsIDOMStorage* aThat)
1572 if (!aThat)
1573 return PR_FALSE;
1575 nsDOMStorage2* storage = static_cast<nsDOMStorage2*>(aThat);
1576 return mStorage == storage->mStorage;
1579 nsresult
1580 nsDOMStorage2::InitAsSessionStorageFork(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI, nsIDOMStorageObsolete* aStorage)
1582 mPrincipal = aPrincipal;
1583 mDocumentURI = aDocumentURI;
1584 mStorage = static_cast<nsDOMStorage*>(aStorage);
1586 return NS_OK;
1589 nsTArray<nsString> *
1590 nsDOMStorage2::GetKeys()
1592 return mStorage->GetKeys();
1595 nsIPrincipal*
1596 nsDOMStorage2::Principal()
1598 return mPrincipal;
1601 PRBool
1602 nsDOMStorage2::CanAccess(nsIPrincipal *aPrincipal)
1604 if (mStorage->mSecurityChecker != this)
1605 return mStorage->mSecurityChecker->CanAccess(aPrincipal);
1607 // Allow C++ callers to access the storage
1608 if (!aPrincipal)
1609 return PR_TRUE;
1611 // Allow more powerful principals (e.g. system) to access the storage
1612 PRBool subsumes;
1613 nsresult rv = aPrincipal->Subsumes(mPrincipal, &subsumes);
1614 if (NS_FAILED(rv))
1615 return PR_FALSE;
1617 return subsumes;
1620 nsPIDOMStorage::nsDOMStorageType
1621 nsDOMStorage2::StorageType()
1623 if (mStorage)
1624 return mStorage->StorageType();
1626 return nsPIDOMStorage::Unknown;
1629 void
1630 nsDOMStorage2::BroadcastChangeNotification(const nsSubstring &aKey,
1631 const nsSubstring &aOldValue,
1632 const nsSubstring &aNewValue)
1634 nsresult rv;
1635 nsCOMPtr<nsIDOMStorageEvent> event = new nsDOMStorageEvent();
1636 rv = event->InitStorageEvent(NS_LITERAL_STRING("storage"),
1637 PR_FALSE,
1638 PR_FALSE,
1639 aKey,
1640 aOldValue,
1641 aNewValue,
1642 mDocumentURI,
1643 static_cast<nsIDOMStorage*>(this));
1644 if (NS_FAILED(rv)) {
1645 return;
1648 nsCOMPtr<nsIObserverService> observerService =
1649 mozilla::services::GetObserverService();
1650 if (!observerService) {
1651 return;
1654 nsCOMPtr<nsIObserverService> observerServiceProxy;
1655 rv = NS_GetProxyForObject(NS_PROXY_TO_MAIN_THREAD,
1656 NS_GET_IID(nsIObserverService),
1657 observerService,
1658 NS_PROXY_ASYNC | NS_PROXY_ALWAYS,
1659 getter_AddRefs(observerServiceProxy));
1660 if (NS_FAILED(rv)) {
1661 return;
1664 // Fire off a notification that a storage object changed.
1665 observerServiceProxy->NotifyObservers(event,
1666 "dom-storage2-changed",
1667 nsnull);
1670 NS_IMETHODIMP
1671 nsDOMStorage2::GetLength(PRUint32 *aLength)
1673 return mStorage->GetLength(aLength);
1676 NS_IMETHODIMP
1677 nsDOMStorage2::Key(PRUint32 aIndex, nsAString& aKey)
1679 return mStorage->Key(aIndex, aKey);
1682 NS_IMETHODIMP
1683 nsDOMStorage2::GetItem(const nsAString& aKey, nsAString &aData)
1685 return mStorage->GetItem(aKey, aData);
1688 NS_IMETHODIMP
1689 nsDOMStorage2::SetItem(const nsAString& aKey, const nsAString& aData)
1691 mStorage->mEventBroadcaster = this;
1692 return mStorage->SetItem(aKey, aData);
1695 NS_IMETHODIMP
1696 nsDOMStorage2::RemoveItem(const nsAString& aKey)
1698 mStorage->mEventBroadcaster = this;
1699 return mStorage->RemoveItem(aKey);
1702 NS_IMETHODIMP
1703 nsDOMStorage2::Clear()
1705 mStorage->mEventBroadcaster = this;
1706 return mStorage->Clear();
1710 // nsDOMStorageList
1713 DOMCI_DATA(StorageList, nsDOMStorageList)
1715 NS_INTERFACE_MAP_BEGIN(nsDOMStorageList)
1716 NS_INTERFACE_MAP_ENTRY(nsISupports)
1717 NS_INTERFACE_MAP_ENTRY(nsIDOMStorageList)
1718 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(StorageList)
1719 NS_INTERFACE_MAP_END
1721 NS_IMPL_ADDREF(nsDOMStorageList)
1722 NS_IMPL_RELEASE(nsDOMStorageList)
1724 nsIDOMStorageObsolete*
1725 nsDOMStorageList::GetNamedItem(const nsAString& aDomain, nsresult* aResult)
1727 nsCAutoString requestedDomain;
1729 // Normalize the requested domain
1730 nsCOMPtr<nsIIDNService> idn = do_GetService(NS_IDNSERVICE_CONTRACTID);
1731 if (idn) {
1732 *aResult = idn->ConvertUTF8toACE(NS_ConvertUTF16toUTF8(aDomain),
1733 requestedDomain);
1734 NS_ENSURE_SUCCESS(*aResult, nsnull);
1735 } else {
1736 // Don't have the IDN service, best we can do is URL escape.
1737 NS_EscapeURL(NS_ConvertUTF16toUTF8(aDomain),
1738 esc_OnlyNonASCII | esc_AlwaysCopy,
1739 requestedDomain);
1741 ToLowerCase(requestedDomain);
1743 nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
1744 if (!ssm) {
1745 *aResult = NS_ERROR_FAILURE;
1746 return nsnull;
1749 nsCOMPtr<nsIPrincipal> subjectPrincipal;
1750 *aResult = ssm->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
1751 NS_ENSURE_SUCCESS(*aResult, nsnull);
1753 nsCAutoString currentDomain;
1754 if (subjectPrincipal) {
1755 nsCOMPtr<nsIURI> unused;
1756 *aResult = GetPrincipalURIAndHost(subjectPrincipal, getter_AddRefs(unused),
1757 currentDomain);
1758 NS_ENSURE_SUCCESS(*aResult, nsnull);
1760 PRPackedBool sessionOnly;
1761 if (!nsDOMStorage::CanUseStorage(&sessionOnly)) {
1762 *aResult = NS_ERROR_DOM_SECURITY_ERR;
1763 return nsnull;
1767 PRBool isSystem = nsContentUtils::IsCallerTrustedForRead();
1768 if (currentDomain.IsEmpty() && !isSystem) {
1769 *aResult = NS_ERROR_DOM_SECURITY_ERR;
1770 return nsnull;
1773 return GetStorageForDomain(requestedDomain,
1774 currentDomain, isSystem, aResult);
1777 NS_IMETHODIMP
1778 nsDOMStorageList::NamedItem(const nsAString& aDomain,
1779 nsIDOMStorageObsolete** aStorage)
1781 nsresult rv;
1782 NS_IF_ADDREF(*aStorage = GetNamedItem(aDomain, &rv));
1783 return rv;
1786 // static
1787 PRBool
1788 nsDOMStorageList::CanAccessDomain(const nsACString& aRequestedDomain,
1789 const nsACString& aCurrentDomain)
1791 return aRequestedDomain.Equals(aCurrentDomain);
1794 nsIDOMStorageObsolete*
1795 nsDOMStorageList::GetStorageForDomain(const nsACString& aRequestedDomain,
1796 const nsACString& aCurrentDomain,
1797 PRBool aNoCurrentDomainCheck,
1798 nsresult* aResult)
1800 nsTArray<nsCString> requestedDomainArray;
1801 if ((!aNoCurrentDomainCheck &&
1802 !CanAccessDomain(aRequestedDomain, aCurrentDomain)) ||
1803 !ConvertDomainToArray(aRequestedDomain, &requestedDomainArray)) {
1804 *aResult = NS_ERROR_DOM_SECURITY_ERR;
1806 return nsnull;
1809 // now rebuild a string for the domain.
1810 nsCAutoString usedDomain;
1811 PRUint32 requestedPos = 0;
1812 for (requestedPos = 0; requestedPos < requestedDomainArray.Length();
1813 requestedPos++) {
1814 if (!usedDomain.IsEmpty())
1815 usedDomain.Append('.');
1816 usedDomain.Append(requestedDomainArray[requestedPos]);
1819 *aResult = NS_OK;
1821 // now have a valid domain, so look it up in the storage table
1822 nsIDOMStorageObsolete* storage = mStorages.GetWeak(usedDomain);
1823 if (!storage) {
1824 nsRefPtr<nsDOMStorage> newstorage;
1825 newstorage = new nsDOMStorage();
1826 if (newstorage && mStorages.Put(usedDomain, newstorage)) {
1827 *aResult = newstorage->InitAsGlobalStorage(usedDomain);
1828 if (NS_FAILED(*aResult)) {
1829 mStorages.Remove(usedDomain);
1830 return nsnull;
1832 storage = newstorage;
1834 else {
1835 *aResult = NS_ERROR_OUT_OF_MEMORY;
1839 return storage;
1842 // static
1843 PRBool
1844 nsDOMStorageList::ConvertDomainToArray(const nsACString& aDomain,
1845 nsTArray<nsCString> *aArray)
1847 PRInt32 length = aDomain.Length();
1848 PRInt32 n = 0;
1849 while (n < length) {
1850 PRInt32 dotpos = aDomain.FindChar('.', n);
1851 nsCAutoString domain;
1853 if (dotpos == -1) // no more dots
1854 domain.Assign(Substring(aDomain, n));
1855 else if (dotpos - n == 0) // no point continuing in this case
1856 return false;
1857 else if (dotpos >= 0)
1858 domain.Assign(Substring(aDomain, n, dotpos - n));
1860 ToLowerCase(domain);
1861 aArray->AppendElement(domain);
1863 if (dotpos == -1)
1864 break;
1866 n = dotpos + 1;
1869 // if n equals the length, there is a dot at the end, so treat it as invalid
1870 return (n != length);
1873 nsresult
1874 NS_NewDOMStorageList(nsIDOMStorageList** aResult)
1876 *aResult = new nsDOMStorageList();
1877 if (!*aResult)
1878 return NS_ERROR_OUT_OF_MEMORY;
1880 NS_ADDREF(*aResult);
1881 return NS_OK;
1885 // nsDOMStorageItem
1888 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMStorageItem)
1889 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMStorageItem)
1891 tmp->mStorage = nsnull;
1893 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1894 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMStorageItem)
1896 cb.NoteXPCOMChild((nsIDOMStorageObsolete*) tmp->mStorage);
1898 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1900 NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsDOMStorageItem, nsIDOMStorageItem)
1901 NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsDOMStorageItem, nsIDOMStorageItem)
1903 DOMCI_DATA(StorageItem, nsDOMStorageItem)
1905 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMStorageItem)
1906 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMStorageItem)
1907 NS_INTERFACE_MAP_ENTRY(nsIDOMStorageItem)
1908 NS_INTERFACE_MAP_ENTRY(nsIDOMToString)
1909 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(StorageItem)
1910 NS_INTERFACE_MAP_END
1912 nsDOMStorageItem::nsDOMStorageItem(nsDOMStorage* aStorage,
1913 const nsAString& aKey,
1914 const nsAString& aValue,
1915 PRBool aSecure)
1916 : mSecure(aSecure),
1917 mKey(aKey),
1918 mValue(aValue),
1919 mStorage(aStorage)
1923 nsDOMStorageItem::~nsDOMStorageItem()
1927 NS_IMETHODIMP
1928 nsDOMStorageItem::GetSecure(PRBool* aSecure)
1930 if (!mStorage->CacheStoragePermissions() || !IsCallerSecure()) {
1931 return NS_ERROR_DOM_INVALID_ACCESS_ERR;
1934 if (mStorage->UseDB()) {
1935 nsAutoString value;
1936 return mStorage->GetDBValue(mKey, value, aSecure);
1939 *aSecure = IsSecure();
1940 return NS_OK;
1943 NS_IMETHODIMP
1944 nsDOMStorageItem::SetSecure(PRBool aSecure)
1946 if (!mStorage->CacheStoragePermissions() || !IsCallerSecure()) {
1947 return NS_ERROR_DOM_INVALID_ACCESS_ERR;
1950 if (mStorage->UseDB()) {
1951 nsresult rv = mStorage->SetSecure(mKey, aSecure);
1952 NS_ENSURE_SUCCESS(rv, rv);
1955 mSecure = aSecure;
1956 return NS_OK;
1959 NS_IMETHODIMP
1960 nsDOMStorageItem::GetValue(nsAString& aValue)
1962 if (!mStorage->CacheStoragePermissions())
1963 return NS_ERROR_DOM_INVALID_ACCESS_ERR;
1965 if (mStorage->UseDB()) {
1966 // GetDBValue checks the secure state so no need to do it here
1967 PRBool secure;
1968 nsresult rv = mStorage->GetDBValue(mKey, aValue, &secure);
1969 if (rv == NS_ERROR_DOM_NOT_FOUND_ERR)
1970 return NS_OK;
1971 return rv;
1974 if (IsSecure() && !IsCallerSecure()) {
1975 return NS_ERROR_DOM_SECURITY_ERR;
1978 aValue = mValue;
1979 return NS_OK;
1982 NS_IMETHODIMP
1983 nsDOMStorageItem::SetValue(const nsAString& aValue)
1985 if (!mStorage->CacheStoragePermissions())
1986 return NS_ERROR_DOM_INVALID_ACCESS_ERR;
1988 PRBool secureCaller = IsCallerSecure();
1990 if (mStorage->UseDB()) {
1991 // SetDBValue() does the security checks for us.
1992 return mStorage->SetDBValue(mKey, aValue, secureCaller);
1995 PRBool secureItem = IsSecure();
1997 if (!secureCaller && secureItem) {
1998 // The item is secure, but the caller isn't. Throw.
1999 return NS_ERROR_DOM_SECURITY_ERR;
2002 mValue = aValue;
2003 mSecure = secureCaller;
2004 return NS_OK;
2007 NS_IMETHODIMP
2008 nsDOMStorageItem::ToString(nsAString& aStr)
2010 return GetValue(aStr);
2013 // Cycle collection implementation for nsDOMStorageEvent
2014 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMStorageEvent)
2016 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMStorageEvent, nsDOMEvent)
2017 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mStorageArea)
2018 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
2020 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMStorageEvent, nsDOMEvent)
2021 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mStorageArea)
2022 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
2024 NS_IMPL_ADDREF_INHERITED(nsDOMStorageEvent, nsDOMEvent)
2025 NS_IMPL_RELEASE_INHERITED(nsDOMStorageEvent, nsDOMEvent)
2027 DOMCI_DATA(StorageEvent, nsDOMStorageEvent)
2029 // QueryInterface implementation for nsDOMStorageEvent
2030 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMStorageEvent)
2031 NS_INTERFACE_MAP_ENTRY(nsIDOMStorageEvent)
2032 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(StorageEvent)
2033 NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
2036 /* readonly attribute DOMString key; */
2037 NS_IMETHODIMP nsDOMStorageEvent::GetKey(nsAString & aKey)
2039 aKey = mKey;
2040 return NS_OK;
2043 /* readonly attribute DOMString oldValue; */
2044 NS_IMETHODIMP nsDOMStorageEvent::GetOldValue(nsAString & aOldValue)
2046 aOldValue = mOldValue;
2047 return NS_OK;
2050 /* readonly attribute DOMString newValue; */
2051 NS_IMETHODIMP nsDOMStorageEvent::GetNewValue(nsAString & aNewValue)
2053 aNewValue = mNewValue;
2054 return NS_OK;
2057 /* readonly attribute DOMString url; */
2058 NS_IMETHODIMP nsDOMStorageEvent::GetUrl(nsAString & aUrl)
2060 aUrl = mUrl;
2061 return NS_OK;
2064 /* readonly attribute nsIDOMStorage storageArea; */
2065 NS_IMETHODIMP nsDOMStorageEvent::GetStorageArea(nsIDOMStorage * *aStorageArea)
2067 NS_ENSURE_ARG_POINTER(aStorageArea);
2069 NS_ADDREF(*aStorageArea = mStorageArea);
2070 return NS_OK;
2073 /* void initStorageEvent (in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString keyArg, in DOMString oldValueArg, in DOMString newValueArg, in DOMString urlArg, in nsIDOMStorage storageAreaArg); */
2074 NS_IMETHODIMP nsDOMStorageEvent::InitStorageEvent(const nsAString & typeArg,
2075 PRBool canBubbleArg,
2076 PRBool cancelableArg,
2077 const nsAString & keyArg,
2078 const nsAString & oldValueArg,
2079 const nsAString & newValueArg,
2080 const nsAString & urlArg,
2081 nsIDOMStorage *storageAreaArg)
2083 nsresult rv;
2085 rv = InitEvent(typeArg, canBubbleArg, cancelableArg);
2086 NS_ENSURE_SUCCESS(rv, rv);
2088 mKey = keyArg;
2089 mOldValue = oldValueArg;
2090 mNewValue = newValueArg;
2091 mUrl = urlArg;
2092 mStorageArea = storageAreaArg;
2094 return NS_OK;
2097 // Obsolete globalStorage event
2099 DOMCI_DATA(StorageEventObsolete, nsDOMStorageEventObsolete)
2101 // QueryInterface implementation for nsDOMStorageEventObsolete
2102 NS_INTERFACE_MAP_BEGIN(nsDOMStorageEventObsolete)
2103 NS_INTERFACE_MAP_ENTRY(nsIDOMStorageEventObsolete)
2104 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(StorageEventObsolete)
2105 NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
2107 NS_IMPL_ADDREF_INHERITED(nsDOMStorageEventObsolete, nsDOMEvent)
2108 NS_IMPL_RELEASE_INHERITED(nsDOMStorageEventObsolete, nsDOMEvent)
2111 NS_IMETHODIMP
2112 nsDOMStorageEventObsolete::GetDomain(nsAString& aDomain)
2114 // mDomain will be #session for session storage for events that fire
2115 // due to a change in a session storage object.
2116 aDomain = mDomain;
2118 return NS_OK;
2121 NS_IMETHODIMP
2122 nsDOMStorageEventObsolete::InitStorageEvent(const nsAString& aTypeArg,
2123 PRBool aCanBubbleArg,
2124 PRBool aCancelableArg,
2125 const nsAString& aDomainArg)
2127 nsresult rv = InitEvent(aTypeArg, aCanBubbleArg, aCancelableArg);
2128 NS_ENSURE_SUCCESS(rv, rv);
2130 mDomain = aDomainArg;
2132 return NS_OK;