1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "LocalStorage.h"
8 #include "LocalStorageCache.h"
9 #include "LocalStorageManager.h"
10 #include "StorageUtils.h"
12 #include "nsIPrincipal.h"
14 #include "mozilla/dom/PermissionMessageUtils.h"
15 #include "mozilla/dom/StorageBinding.h"
16 #include "mozilla/dom/StorageEvent.h"
17 #include "mozilla/dom/StorageEventBinding.h"
18 #include "mozilla/ipc/BackgroundChild.h"
19 #include "mozilla/ipc/PBackgroundChild.h"
20 #include "mozilla/Preferences.h"
21 #include "mozilla/EnumSet.h"
22 #include "nsThreadUtils.h"
23 #include "nsContentUtils.h"
24 #include "nsServiceManagerUtils.h"
32 NS_IMPL_CYCLE_COLLECTION_CLASS(LocalStorage
)
33 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(LocalStorage
, Storage
)
34 NS_IMPL_CYCLE_COLLECTION_UNLINK(mManager
)
35 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
36 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(LocalStorage
, Storage
)
37 CycleCollectionNoteChild(
38 cb
, NS_ISUPPORTS_CAST(nsIDOMStorageManager
*, tmp
->mManager
.get()),
40 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
42 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(LocalStorage
)
43 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
44 NS_INTERFACE_MAP_END_INHERITING(Storage
)
46 NS_IMPL_ADDREF_INHERITED(LocalStorage
, Storage
)
47 NS_IMPL_RELEASE_INHERITED(LocalStorage
, Storage
)
49 LocalStorage::LocalStorage(nsPIDOMWindowInner
* aWindow
,
50 LocalStorageManager
* aManager
,
51 LocalStorageCache
* aCache
,
52 const nsAString
& aDocumentURI
,
53 nsIPrincipal
* aPrincipal
,
54 nsIPrincipal
* aStoragePrincipal
, bool aIsPrivate
)
55 : Storage(aWindow
, aPrincipal
, aStoragePrincipal
),
58 mDocumentURI(aDocumentURI
),
59 mIsPrivate(aIsPrivate
) {
63 LocalStorage::~LocalStorage() {}
65 int64_t LocalStorage::GetOriginQuotaUsage() const {
66 return mCache
->GetOriginQuotaUsage(this);
69 uint32_t LocalStorage::GetLength(nsIPrincipal
& aSubjectPrincipal
,
71 if (!CanUseStorage(aSubjectPrincipal
)) {
72 aRv
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
77 aRv
= mCache
->GetLength(this, &length
);
81 void LocalStorage::Key(uint32_t aIndex
, nsAString
& aResult
,
82 nsIPrincipal
& aSubjectPrincipal
, ErrorResult
& aRv
) {
83 if (!CanUseStorage(aSubjectPrincipal
)) {
84 aRv
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
88 aRv
= mCache
->GetKey(this, aIndex
, aResult
);
91 void LocalStorage::GetItem(const nsAString
& aKey
, nsAString
& aResult
,
92 nsIPrincipal
& aSubjectPrincipal
, ErrorResult
& aRv
) {
93 if (!CanUseStorage(aSubjectPrincipal
)) {
94 aRv
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
98 aRv
= mCache
->GetItem(this, aKey
, aResult
);
101 void LocalStorage::SetItem(const nsAString
& aKey
, const nsAString
& aData
,
102 nsIPrincipal
& aSubjectPrincipal
, ErrorResult
& aRv
) {
103 if (!CanUseStorage(aSubjectPrincipal
)) {
104 aRv
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
109 bool ok
= data
.Assign(aData
, fallible
);
111 aRv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
116 aRv
= mCache
->SetItem(this, aKey
, data
, old
);
121 if (!aRv
.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION
)) {
122 OnChange(aKey
, old
, aData
);
126 void LocalStorage::RemoveItem(const nsAString
& aKey
,
127 nsIPrincipal
& aSubjectPrincipal
,
129 if (!CanUseStorage(aSubjectPrincipal
)) {
130 aRv
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
135 aRv
= mCache
->RemoveItem(this, aKey
, old
);
140 if (!aRv
.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION
)) {
141 OnChange(aKey
, old
, VoidString());
145 void LocalStorage::Clear(nsIPrincipal
& aSubjectPrincipal
, ErrorResult
& aRv
) {
146 if (!CanUseStorage(aSubjectPrincipal
)) {
147 aRv
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
151 aRv
= mCache
->Clear(this);
152 if (NS_WARN_IF(aRv
.Failed())) {
156 if (!aRv
.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION
)) {
157 OnChange(VoidString(), VoidString(), VoidString());
161 void LocalStorage::OnChange(const nsAString
& aKey
, const nsAString
& aOldValue
,
162 const nsAString
& aNewValue
) {
163 NotifyChange(/* aStorage */ this, StoragePrincipal(), aKey
, aOldValue
,
164 aNewValue
, /* aStorageType */ u
"localStorage", mDocumentURI
,
165 mIsPrivate
, /* aImmediateDispatch */ false);
168 void LocalStorage::ApplyEvent(StorageEvent
* aStorageEvent
) {
169 MOZ_ASSERT(aStorageEvent
);
175 aStorageEvent
->GetKey(key
);
176 aStorageEvent
->GetNewValue(value
);
178 // No key means clearing the full storage.
180 MOZ_ASSERT(value
.IsVoid());
181 mCache
->Clear(this, LocalStorageCache::E10sPropagated
);
185 // No new value means removing the key.
186 if (value
.IsVoid()) {
187 mCache
->RemoveItem(this, key
, old
, LocalStorageCache::E10sPropagated
);
191 // Otherwise, we set the new value.
192 mCache
->SetItem(this, key
, value
, old
, LocalStorageCache::E10sPropagated
);
195 void LocalStorage::GetSupportedNames(nsTArray
<nsString
>& aKeys
) {
196 if (!CanUseStorage(*nsContentUtils::SubjectPrincipal())) {
197 // return just an empty array
202 mCache
->GetKeys(this, aKeys
);
205 bool LocalStorage::IsForkOf(const Storage
* aOther
) const {
207 if (aOther
->Type() != eLocalStorage
) {
211 return mCache
== static_cast<const LocalStorage
*>(aOther
)->mCache
;
215 } // namespace mozilla