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_WEAK_REFERENCE
36 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
37 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(LocalStorage
, Storage
)
38 CycleCollectionNoteChild(
39 cb
, NS_ISUPPORTS_CAST(nsIDOMStorageManager
*, tmp
->mManager
.get()),
41 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
43 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(LocalStorage
)
44 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
45 NS_INTERFACE_MAP_END_INHERITING(Storage
)
47 NS_IMPL_ADDREF_INHERITED(LocalStorage
, Storage
)
48 NS_IMPL_RELEASE_INHERITED(LocalStorage
, Storage
)
50 LocalStorage::LocalStorage(nsPIDOMWindowInner
* aWindow
,
51 LocalStorageManager
* aManager
,
52 LocalStorageCache
* aCache
,
53 const nsAString
& aDocumentURI
,
54 nsIPrincipal
* aPrincipal
,
55 nsIPrincipal
* aStoragePrincipal
, bool aIsPrivate
)
56 : Storage(aWindow
, aPrincipal
, aStoragePrincipal
),
59 mDocumentURI(aDocumentURI
),
60 mIsPrivate(aIsPrivate
) {
64 LocalStorage::~LocalStorage() = default;
66 int64_t LocalStorage::GetOriginQuotaUsage() const {
67 return mCache
->GetOriginQuotaUsage(this);
70 uint32_t LocalStorage::GetLength(nsIPrincipal
& aSubjectPrincipal
,
72 if (!CanUseStorage(aSubjectPrincipal
)) {
73 aRv
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
78 aRv
= mCache
->GetLength(this, &length
);
82 void LocalStorage::Key(uint32_t aIndex
, nsAString
& aResult
,
83 nsIPrincipal
& aSubjectPrincipal
, ErrorResult
& aRv
) {
84 if (!CanUseStorage(aSubjectPrincipal
)) {
85 aRv
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
89 aRv
= mCache
->GetKey(this, aIndex
, aResult
);
92 void LocalStorage::GetItem(const nsAString
& aKey
, nsAString
& aResult
,
93 nsIPrincipal
& aSubjectPrincipal
, ErrorResult
& aRv
) {
94 if (!CanUseStorage(aSubjectPrincipal
)) {
95 aRv
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
99 aRv
= mCache
->GetItem(this, aKey
, aResult
);
102 void LocalStorage::SetItem(const nsAString
& aKey
, const nsAString
& aData
,
103 nsIPrincipal
& aSubjectPrincipal
, ErrorResult
& aRv
) {
104 if (!CanUseStorage(aSubjectPrincipal
)) {
105 aRv
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
110 bool ok
= data
.Assign(aData
, fallible
);
112 aRv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
117 aRv
= mCache
->SetItem(this, aKey
, data
, old
);
122 if (!aRv
.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION
)) {
123 OnChange(aKey
, old
, aData
);
127 void LocalStorage::RemoveItem(const nsAString
& aKey
,
128 nsIPrincipal
& aSubjectPrincipal
,
130 if (!CanUseStorage(aSubjectPrincipal
)) {
131 aRv
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
136 aRv
= mCache
->RemoveItem(this, aKey
, old
);
141 if (!aRv
.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION
)) {
142 OnChange(aKey
, old
, VoidString());
146 void LocalStorage::Clear(nsIPrincipal
& aSubjectPrincipal
, ErrorResult
& aRv
) {
147 if (!CanUseStorage(aSubjectPrincipal
)) {
148 aRv
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
152 aRv
= mCache
->Clear(this);
153 if (NS_WARN_IF(aRv
.Failed())) {
157 if (!aRv
.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION
)) {
158 OnChange(VoidString(), VoidString(), VoidString());
162 void LocalStorage::OnChange(const nsAString
& aKey
, const nsAString
& aOldValue
,
163 const nsAString
& aNewValue
) {
164 NotifyChange(/* aStorage */ this, StoragePrincipal(), aKey
, aOldValue
,
165 aNewValue
, /* aStorageType */ u
"localStorage", mDocumentURI
,
166 mIsPrivate
, /* aImmediateDispatch */ false);
169 void LocalStorage::ApplyEvent(StorageEvent
* aStorageEvent
) {
170 MOZ_ASSERT(aStorageEvent
);
176 aStorageEvent
->GetKey(key
);
177 aStorageEvent
->GetNewValue(value
);
179 // No key means clearing the full storage.
181 MOZ_ASSERT(value
.IsVoid());
182 mCache
->Clear(this, LocalStorageCache::E10sPropagated
);
186 // No new value means removing the key.
187 if (value
.IsVoid()) {
188 mCache
->RemoveItem(this, key
, old
, LocalStorageCache::E10sPropagated
);
192 // Otherwise, we set the new value.
193 mCache
->SetItem(this, key
, value
, old
, LocalStorageCache::E10sPropagated
);
196 void LocalStorage::GetSupportedNames(nsTArray
<nsString
>& aKeys
) {
197 if (!CanUseStorage(*nsContentUtils::SubjectPrincipal())) {
198 // return just an empty array
203 mCache
->GetKeys(this, aKeys
);
206 bool LocalStorage::IsForkOf(const Storage
* aOther
) const {
208 if (aOther
->Type() != eLocalStorage
) {
212 return mCache
== static_cast<const LocalStorage
*>(aOther
)->mCache
;
216 } // namespace mozilla