Bug 1852740: add tests for the `fetchpriority` attribute in Link headers. r=necko...
[gecko.git] / dom / storage / LocalStorage.cpp
blobec75566242017367e54346c8f181e6db925bcb75
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"
26 namespace mozilla {
28 using namespace ipc;
30 namespace dom {
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()),
40 "mManager");
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),
57 mManager(aManager),
58 mCache(aCache),
59 mDocumentURI(aDocumentURI),
60 mIsPrivate(aIsPrivate) {
61 mCache->Preload();
64 LocalStorage::~LocalStorage() = default;
66 int64_t LocalStorage::GetOriginQuotaUsage() const {
67 return mCache->GetOriginQuotaUsage(this);
70 uint32_t LocalStorage::GetLength(nsIPrincipal& aSubjectPrincipal,
71 ErrorResult& aRv) {
72 if (!CanUseStorage(aSubjectPrincipal)) {
73 aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
74 return 0;
77 uint32_t length;
78 aRv = mCache->GetLength(this, &length);
79 return 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);
86 return;
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);
96 return;
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);
106 return;
109 nsString data;
110 bool ok = data.Assign(aData, fallible);
111 if (!ok) {
112 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
113 return;
116 nsString old;
117 aRv = mCache->SetItem(this, aKey, data, old);
118 if (aRv.Failed()) {
119 return;
122 if (!aRv.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION)) {
123 OnChange(aKey, old, aData);
127 void LocalStorage::RemoveItem(const nsAString& aKey,
128 nsIPrincipal& aSubjectPrincipal,
129 ErrorResult& aRv) {
130 if (!CanUseStorage(aSubjectPrincipal)) {
131 aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
132 return;
135 nsAutoString old;
136 aRv = mCache->RemoveItem(this, aKey, old);
137 if (aRv.Failed()) {
138 return;
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);
149 return;
152 aRv = mCache->Clear(this);
153 if (NS_WARN_IF(aRv.Failed())) {
154 return;
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);
172 nsAutoString key;
173 nsAutoString old;
174 nsAutoString value;
176 aStorageEvent->GetKey(key);
177 aStorageEvent->GetNewValue(value);
179 // No key means clearing the full storage.
180 if (key.IsVoid()) {
181 MOZ_ASSERT(value.IsVoid());
182 mCache->Clear(this, LocalStorageCache::E10sPropagated);
183 return;
186 // No new value means removing the key.
187 if (value.IsVoid()) {
188 mCache->RemoveItem(this, key, old, LocalStorageCache::E10sPropagated);
189 return;
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
199 aKeys.Clear();
200 return;
203 mCache->GetKeys(this, aKeys);
206 bool LocalStorage::IsForkOf(const Storage* aOther) const {
207 MOZ_ASSERT(aOther);
208 if (aOther->Type() != eLocalStorage) {
209 return false;
212 return mCache == static_cast<const LocalStorage*>(aOther)->mCache;
215 } // namespace dom
216 } // namespace mozilla