Source code

Revision control

Other Tools

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/. */
6
7
#include "LocalStorage.h"
8
#include "LocalStorageCache.h"
9
#include "LocalStorageManager.h"
10
#include "StorageUtils.h"
11
12
#include "nsIPrincipal.h"
13
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"
25
26
namespace mozilla {
27
28
using namespace ipc;
29
30
namespace dom {
31
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
42
43
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(LocalStorage)
44
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
45
NS_INTERFACE_MAP_END_INHERITING(Storage)
46
47
NS_IMPL_ADDREF_INHERITED(LocalStorage, Storage)
48
NS_IMPL_RELEASE_INHERITED(LocalStorage, Storage)
49
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();
62
}
63
64
LocalStorage::~LocalStorage() = default;
65
66
int64_t LocalStorage::GetOriginQuotaUsage() const {
67
return mCache->GetOriginQuotaUsage(this);
68
}
69
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;
75
}
76
77
uint32_t length;
78
aRv = mCache->GetLength(this, &length);
79
return length;
80
}
81
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;
87
}
88
89
aRv = mCache->GetKey(this, aIndex, aResult);
90
}
91
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;
97
}
98
99
aRv = mCache->GetItem(this, aKey, aResult);
100
}
101
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;
107
}
108
109
nsString data;
110
bool ok = data.Assign(aData, fallible);
111
if (!ok) {
112
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
113
return;
114
}
115
116
nsString old;
117
aRv = mCache->SetItem(this, aKey, data, old);
118
if (aRv.Failed()) {
119
return;
120
}
121
122
if (!aRv.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION)) {
123
OnChange(aKey, old, aData);
124
}
125
}
126
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;
133
}
134
135
nsAutoString old;
136
aRv = mCache->RemoveItem(this, aKey, old);
137
if (aRv.Failed()) {
138
return;
139
}
140
141
if (!aRv.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION)) {
142
OnChange(aKey, old, VoidString());
143
}
144
}
145
146
void LocalStorage::Clear(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) {
147
if (!CanUseStorage(aSubjectPrincipal)) {
148
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
149
return;
150
}
151
152
aRv = mCache->Clear(this);
153
if (NS_WARN_IF(aRv.Failed())) {
154
return;
155
}
156
157
if (!aRv.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION)) {
158
OnChange(VoidString(), VoidString(), VoidString());
159
}
160
}
161
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);
167
}
168
169
void LocalStorage::ApplyEvent(StorageEvent* aStorageEvent) {
170
MOZ_ASSERT(aStorageEvent);
171
172
nsAutoString key;
173
nsAutoString old;
174
nsAutoString value;
175
176
aStorageEvent->GetKey(key);
177
aStorageEvent->GetNewValue(value);
178
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;
184
}
185
186
// No new value means removing the key.
187
if (value.IsVoid()) {
188
mCache->RemoveItem(this, key, old, LocalStorageCache::E10sPropagated);
189
return;
190
}
191
192
// Otherwise, we set the new value.
193
mCache->SetItem(this, key, value, old, LocalStorageCache::E10sPropagated);
194
}
195
196
void LocalStorage::GetSupportedNames(nsTArray<nsString>& aKeys) {
197
if (!CanUseStorage(*nsContentUtils::SubjectPrincipal())) {
198
// return just an empty array
199
aKeys.Clear();
200
return;
201
}
202
203
mCache->GetKeys(this, aKeys);
204
}
205
206
bool LocalStorage::IsForkOf(const Storage* aOther) const {
207
MOZ_ASSERT(aOther);
208
if (aOther->Type() != eLocalStorage) {
209
return false;
210
}
211
212
return mCache == static_cast<const LocalStorage*>(aOther)->mCache;
213
}
214
215
} // namespace dom
216
} // namespace mozilla