Line data Source code
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 "nsIObserverService.h"
13 : #include "nsIScriptSecurityManager.h"
14 : #include "nsIPermissionManager.h"
15 : #include "nsIPrincipal.h"
16 : #include "nsICookiePermission.h"
17 :
18 : #include "mozilla/dom/ContentChild.h"
19 : #include "mozilla/dom/ContentParent.h"
20 : #include "mozilla/dom/PermissionMessageUtils.h"
21 : #include "mozilla/dom/StorageBinding.h"
22 : #include "mozilla/dom/StorageEvent.h"
23 : #include "mozilla/dom/StorageEventBinding.h"
24 : #include "mozilla/Services.h"
25 : #include "mozilla/Preferences.h"
26 : #include "mozilla/EnumSet.h"
27 : #include "nsThreadUtils.h"
28 : #include "nsContentUtils.h"
29 : #include "nsServiceManagerUtils.h"
30 :
31 : namespace mozilla {
32 :
33 : using namespace ipc;
34 :
35 : namespace dom {
36 :
37 0 : NS_IMPL_CYCLE_COLLECTION_INHERITED(LocalStorage, Storage, mManager);
38 :
39 3 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(LocalStorage)
40 2 : NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
41 2 : NS_INTERFACE_MAP_END_INHERITING(Storage)
42 :
43 4 : NS_IMPL_ADDREF_INHERITED(LocalStorage, Storage)
44 3 : NS_IMPL_RELEASE_INHERITED(LocalStorage, Storage)
45 :
46 1 : LocalStorage::LocalStorage(nsPIDOMWindowInner* aWindow,
47 : LocalStorageManager* aManager,
48 : LocalStorageCache* aCache,
49 : const nsAString& aDocumentURI,
50 : nsIPrincipal* aPrincipal,
51 1 : bool aIsPrivate)
52 : : Storage(aWindow, aPrincipal)
53 : , mManager(aManager)
54 : , mCache(aCache)
55 : , mDocumentURI(aDocumentURI)
56 1 : , mIsPrivate(aIsPrivate)
57 : {
58 1 : mCache->Preload();
59 1 : }
60 :
61 0 : LocalStorage::~LocalStorage()
62 : {
63 0 : }
64 :
65 : int64_t
66 0 : LocalStorage::GetOriginQuotaUsage() const
67 : {
68 0 : return mCache->GetOriginQuotaUsage(this);
69 : }
70 :
71 : uint32_t
72 0 : LocalStorage::GetLength(nsIPrincipal& aSubjectPrincipal,
73 : ErrorResult& aRv)
74 : {
75 0 : if (!CanUseStorage(aSubjectPrincipal)) {
76 0 : aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
77 0 : return 0;
78 : }
79 :
80 : uint32_t length;
81 0 : aRv = mCache->GetLength(this, &length);
82 0 : return length;
83 : }
84 :
85 : void
86 0 : LocalStorage::Key(uint32_t aIndex, nsAString& aResult,
87 : nsIPrincipal& aSubjectPrincipal,
88 : ErrorResult& aRv)
89 : {
90 0 : if (!CanUseStorage(aSubjectPrincipal)) {
91 0 : aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
92 0 : return;
93 : }
94 :
95 0 : aRv = mCache->GetKey(this, aIndex, aResult);
96 : }
97 :
98 : void
99 0 : LocalStorage::GetItem(const nsAString& aKey, nsAString& aResult,
100 : nsIPrincipal& aSubjectPrincipal,
101 : ErrorResult& aRv)
102 : {
103 0 : if (!CanUseStorage(aSubjectPrincipal)) {
104 0 : aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
105 0 : return;
106 : }
107 :
108 0 : aRv = mCache->GetItem(this, aKey, aResult);
109 : }
110 :
111 : void
112 0 : LocalStorage::SetItem(const nsAString& aKey, const nsAString& aData,
113 : nsIPrincipal& aSubjectPrincipal,
114 : ErrorResult& aRv)
115 : {
116 0 : if (!CanUseStorage(aSubjectPrincipal)) {
117 0 : aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
118 0 : return;
119 : }
120 :
121 0 : nsString data;
122 0 : bool ok = data.Assign(aData, fallible);
123 0 : if (!ok) {
124 0 : aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
125 0 : return;
126 : }
127 :
128 0 : nsString old;
129 0 : aRv = mCache->SetItem(this, aKey, data, old);
130 0 : if (aRv.Failed()) {
131 0 : return;
132 : }
133 :
134 0 : if (!aRv.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION)) {
135 0 : BroadcastChangeNotification(aKey, old, aData);
136 : }
137 : }
138 :
139 : void
140 0 : LocalStorage::RemoveItem(const nsAString& aKey, nsIPrincipal& aSubjectPrincipal,
141 : ErrorResult& aRv)
142 : {
143 0 : if (!CanUseStorage(aSubjectPrincipal)) {
144 0 : aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
145 0 : return;
146 : }
147 :
148 0 : nsAutoString old;
149 0 : aRv = mCache->RemoveItem(this, aKey, old);
150 0 : if (aRv.Failed()) {
151 0 : return;
152 : }
153 :
154 0 : if (!aRv.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION)) {
155 0 : BroadcastChangeNotification(aKey, old, NullString());
156 : }
157 : }
158 :
159 : void
160 0 : LocalStorage::Clear(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv)
161 : {
162 0 : if (!CanUseStorage(aSubjectPrincipal)) {
163 0 : aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
164 0 : return;
165 : }
166 :
167 0 : aRv = mCache->Clear(this);
168 0 : if (NS_WARN_IF(aRv.Failed())) {
169 0 : return;
170 : }
171 :
172 0 : if (!aRv.ErrorCodeIs(NS_SUCCESS_DOM_NO_OPERATION)) {
173 0 : BroadcastChangeNotification(NullString(), NullString(), NullString());
174 : }
175 : }
176 :
177 : void
178 0 : LocalStorage::BroadcastChangeNotification(const nsAString& aKey,
179 : const nsAString& aOldValue,
180 : const nsAString& aNewValue)
181 : {
182 0 : if (!XRE_IsParentProcess() && Principal()) {
183 : // If we are in a child process, we want to send a message to the parent in
184 : // order to broadcast the StorageEvent correctly to any child process.
185 0 : dom::ContentChild* cc = dom::ContentChild::GetSingleton();
186 0 : Unused << NS_WARN_IF(!cc->SendBroadcastLocalStorageChange(
187 : mDocumentURI, nsString(aKey), nsString(aOldValue), nsString(aNewValue),
188 : IPC::Principal(Principal()), mIsPrivate));
189 : }
190 :
191 0 : DispatchStorageEvent(mDocumentURI, aKey, aOldValue, aNewValue,
192 0 : Principal(), mIsPrivate, this, false);
193 0 : }
194 :
195 : /* static */ void
196 0 : LocalStorage::DispatchStorageEvent(const nsAString& aDocumentURI,
197 : const nsAString& aKey,
198 : const nsAString& aOldValue,
199 : const nsAString& aNewValue,
200 : nsIPrincipal* aPrincipal,
201 : bool aIsPrivate,
202 : Storage* aStorage,
203 : bool aImmediateDispatch)
204 : {
205 0 : NotifyChange(aStorage, aPrincipal, aKey, aOldValue, aNewValue,
206 0 : u"localStorage", aDocumentURI, aIsPrivate, aImmediateDispatch);
207 :
208 : // If we are in the parent process and we have the principal, we want to
209 : // broadcast this event to every other process.
210 0 : if (XRE_IsParentProcess() && aPrincipal) {
211 0 : for (auto* cp : ContentParent::AllProcesses(ContentParent::eLive)) {
212 0 : Unused << cp->SendDispatchLocalStorageChange(
213 0 : nsString(aDocumentURI), nsString(aKey), nsString(aOldValue),
214 0 : nsString(aNewValue), IPC::Principal(aPrincipal), aIsPrivate);
215 : }
216 : }
217 0 : }
218 :
219 : void
220 0 : LocalStorage::ApplyEvent(StorageEvent* aStorageEvent)
221 : {
222 0 : MOZ_ASSERT(aStorageEvent);
223 :
224 0 : nsAutoString key;
225 0 : nsAutoString old;
226 0 : nsAutoString value;
227 :
228 0 : aStorageEvent->GetKey(key);
229 0 : aStorageEvent->GetNewValue(value);
230 :
231 : // No key means clearing the full storage.
232 0 : if (key.IsVoid()) {
233 0 : MOZ_ASSERT(value.IsVoid());
234 0 : mCache->Clear(this, LocalStorageCache::E10sPropagated);
235 0 : return;
236 : }
237 :
238 : // No new value means removing the key.
239 0 : if (value.IsVoid()) {
240 0 : mCache->RemoveItem(this, key, old, LocalStorageCache::E10sPropagated);
241 0 : return;
242 : }
243 :
244 : // Otherwise, we set the new value.
245 0 : mCache->SetItem(this, key, value, old, LocalStorageCache::E10sPropagated);
246 : }
247 :
248 : static const char kPermissionType[] = "cookie";
249 : static const char kStorageEnabled[] = "dom.storage.enabled";
250 :
251 : bool
252 0 : LocalStorage::PrincipalEquals(nsIPrincipal* aPrincipal)
253 : {
254 0 : return StorageUtils::PrincipalsEqual(mPrincipal, aPrincipal);
255 : }
256 :
257 : void
258 0 : LocalStorage::GetSupportedNames(nsTArray<nsString>& aKeys)
259 : {
260 0 : if (!CanUseStorage(*nsContentUtils::SubjectPrincipal())) {
261 : // return just an empty array
262 0 : aKeys.Clear();
263 0 : return;
264 : }
265 :
266 0 : mCache->GetKeys(this, aKeys);
267 : }
268 :
269 : bool
270 0 : LocalStorage::IsForkOf(const Storage* aOther) const
271 : {
272 0 : MOZ_ASSERT(aOther);
273 0 : if (aOther->Type() != eLocalStorage) {
274 0 : return false;
275 : }
276 :
277 0 : return mCache == static_cast<const LocalStorage*>(aOther)->mCache;
278 : }
279 :
280 : } // namespace dom
281 : } // namespace mozilla
|