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 "SessionStorageManager.h"
8
9
#include "mozilla/dom/ContentChild.h"
10
#include "mozilla/dom/ContentParent.h"
11
#include "SessionStorage.h"
12
#include "SessionStorageCache.h"
13
#include "SessionStorageObserver.h"
14
#include "SessionStorageService.h"
15
#include "StorageUtils.h"
16
17
namespace mozilla {
18
namespace dom {
19
20
using namespace StorageUtils;
21
22
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SessionStorageManager)
23
NS_INTERFACE_MAP_ENTRY(nsISupports)
24
NS_INTERFACE_MAP_ENTRY(nsIDOMStorageManager)
25
NS_INTERFACE_MAP_ENTRY(nsIDOMSessionStorageManager)
26
NS_INTERFACE_MAP_END
27
28
NS_IMPL_CYCLE_COLLECTION(SessionStorageManager, mBrowsingContext)
29
NS_IMPL_CYCLE_COLLECTING_ADDREF(SessionStorageManager)
30
NS_IMPL_CYCLE_COLLECTING_RELEASE(SessionStorageManager)
31
32
SessionStorageManager::SessionStorageManager(
33
RefPtr<BrowsingContext> aBrowsingContext)
34
: mBrowsingContext(std::move(aBrowsingContext)) {
35
if (const auto service = SessionStorageService::Get()) {
36
service->RegisterSessionStorageManager(this);
37
}
38
39
StorageObserver* observer = StorageObserver::Self();
40
NS_ASSERTION(
41
observer,
42
"No StorageObserver, cannot observe private data delete notifications!");
43
44
if (observer) {
45
observer->AddSink(this);
46
}
47
48
if (!XRE_IsParentProcess() && NextGenLocalStorageEnabled()) {
49
// When LSNG is enabled the thread IPC bridge doesn't exist, so we have to
50
// create own protocol to distribute chrome observer notifications to
51
// content processes.
52
mObserver = SessionStorageObserver::Get();
53
54
if (!mObserver) {
55
ContentChild* contentActor = ContentChild::GetSingleton();
56
MOZ_ASSERT(contentActor);
57
58
RefPtr<SessionStorageObserver> observer = new SessionStorageObserver();
59
60
SessionStorageObserverChild* actor =
61
new SessionStorageObserverChild(observer);
62
63
MOZ_ALWAYS_TRUE(
64
contentActor->SendPSessionStorageObserverConstructor(actor));
65
66
observer->SetActor(actor);
67
68
mObserver = std::move(observer);
69
}
70
}
71
}
72
73
SessionStorageManager::~SessionStorageManager() {
74
StorageObserver* observer = StorageObserver::Self();
75
if (observer) {
76
observer->RemoveSink(this);
77
}
78
79
if (const auto service = SessionStorageService::Get()) {
80
service->UnregisterSessionStorageManager(this);
81
}
82
}
83
84
NS_IMETHODIMP
85
SessionStorageManager::PrecacheStorage(nsIPrincipal* aPrincipal,
86
nsIPrincipal* aStoragePrincipal,
87
Storage** aRetval) {
88
// Nothing to preload.
89
return NS_OK;
90
}
91
92
NS_IMETHODIMP
93
SessionStorageManager::GetSessionStorageCache(
94
nsIPrincipal* aPrincipal, nsIPrincipal* aStoragePrincipal,
95
RefPtr<SessionStorageCache>* aRetVal) {
96
return GetSessionStorageCacheHelper(aStoragePrincipal, true, nullptr,
97
aRetVal);
98
}
99
100
nsresult SessionStorageManager::GetSessionStorageCacheHelper(
101
nsIPrincipal* aPrincipal, bool aMakeIfNeeded,
102
SessionStorageCache* aCloneFrom, RefPtr<SessionStorageCache>* aRetVal) {
103
nsAutoCString originKey;
104
nsAutoCString originAttributes;
105
nsresult rv = aPrincipal->GetStorageOriginKey(originKey);
106
aPrincipal->OriginAttributesRef().CreateSuffix(originAttributes);
107
if (NS_FAILED(rv)) {
108
return NS_ERROR_NOT_AVAILABLE;
109
}
110
111
return GetSessionStorageCacheHelper(originAttributes, originKey,
112
aMakeIfNeeded, aCloneFrom, aRetVal);
113
}
114
115
nsresult SessionStorageManager::GetSessionStorageCacheHelper(
116
const nsACString& aOriginAttrs, const nsACString& aOriginKey,
117
bool aMakeIfNeeded, SessionStorageCache* aCloneFrom,
118
RefPtr<SessionStorageCache>* aRetVal) {
119
if (OriginRecord* const originRecord = GetOriginRecord(
120
aOriginAttrs, aOriginKey, aMakeIfNeeded, aCloneFrom)) {
121
*aRetVal = originRecord->mCache;
122
} else {
123
*aRetVal = nullptr;
124
}
125
return NS_OK;
126
}
127
128
SessionStorageManager::OriginRecord* SessionStorageManager::GetOriginRecord(
129
const nsACString& aOriginAttrs, const nsACString& aOriginKey,
130
const bool aMakeIfNeeded, SessionStorageCache* const aCloneFrom) {
131
OriginKeyHashTable* table;
132
if (!mOATable.Get(aOriginAttrs, &table)) {
133
if (aMakeIfNeeded) {
134
table = new OriginKeyHashTable();
135
mOATable.Put(aOriginAttrs, table);
136
} else {
137
return nullptr;
138
}
139
}
140
141
OriginRecord* originRecord;
142
if (!table->Get(aOriginKey, &originRecord)) {
143
if (aMakeIfNeeded) {
144
originRecord = new OriginRecord();
145
if (aCloneFrom) {
146
originRecord->mCache = aCloneFrom->Clone();
147
} else {
148
originRecord->mCache = new SessionStorageCache();
149
}
150
table->Put(aOriginKey, originRecord);
151
} else {
152
return nullptr;
153
}
154
}
155
156
return originRecord;
157
}
158
159
NS_IMETHODIMP
160
SessionStorageManager::CreateStorage(mozIDOMWindow* aWindow,
161
nsIPrincipal* aPrincipal,
162
nsIPrincipal* aStoragePrincipal,
163
const nsAString& aDocumentURI,
164
bool aPrivate, Storage** aRetval) {
165
RefPtr<SessionStorageCache> cache;
166
nsresult rv = GetSessionStorageCache(aPrincipal, aStoragePrincipal, &cache);
167
if (NS_FAILED(rv)) {
168
return rv;
169
}
170
171
nsCOMPtr<nsPIDOMWindowInner> inner = nsPIDOMWindowInner::From(aWindow);
172
173
// No StoragePrincipal for sessionStorage.
174
RefPtr<SessionStorage> storage = new SessionStorage(
175
inner, aPrincipal, cache, this, aDocumentURI, aPrivate);
176
177
storage.forget(aRetval);
178
return NS_OK;
179
}
180
181
NS_IMETHODIMP
182
SessionStorageManager::GetStorage(mozIDOMWindow* aWindow,
183
nsIPrincipal* aPrincipal,
184
nsIPrincipal* aStoragePrincipal,
185
bool aPrivate, Storage** aRetval) {
186
*aRetval = nullptr;
187
188
RefPtr<SessionStorageCache> cache;
189
nsresult rv =
190
GetSessionStorageCacheHelper(aStoragePrincipal, false, nullptr, &cache);
191
if (NS_FAILED(rv) || !cache) {
192
return rv;
193
}
194
195
nsCOMPtr<nsPIDOMWindowInner> inner = nsPIDOMWindowInner::From(aWindow);
196
197
RefPtr<SessionStorage> storage = new SessionStorage(
198
inner, aStoragePrincipal, cache, this, EmptyString(), aPrivate);
199
200
storage.forget(aRetval);
201
return NS_OK;
202
}
203
204
NS_IMETHODIMP
205
SessionStorageManager::CloneStorage(Storage* aStorage) {
206
if (NS_WARN_IF(!aStorage)) {
207
return NS_ERROR_UNEXPECTED;
208
}
209
210
if (aStorage->Type() != Storage::eSessionStorage) {
211
return NS_ERROR_UNEXPECTED;
212
}
213
214
RefPtr<SessionStorageCache> cache;
215
return GetSessionStorageCacheHelper(
216
aStorage->StoragePrincipal(), true,
217
static_cast<SessionStorage*>(aStorage)->Cache(), &cache);
218
}
219
220
NS_IMETHODIMP
221
SessionStorageManager::CheckStorage(nsIPrincipal* aPrincipal, Storage* aStorage,
222
bool* aRetval) {
223
if (NS_WARN_IF(!aStorage)) {
224
return NS_ERROR_UNEXPECTED;
225
}
226
227
if (!aPrincipal) {
228
return NS_ERROR_NOT_AVAILABLE;
229
}
230
231
*aRetval = false;
232
233
RefPtr<SessionStorageCache> cache;
234
nsresult rv =
235
GetSessionStorageCacheHelper(aPrincipal, false, nullptr, &cache);
236
if (NS_FAILED(rv) || !cache) {
237
return rv;
238
}
239
240
if (aStorage->Type() != Storage::eSessionStorage) {
241
return NS_OK;
242
}
243
244
RefPtr<SessionStorage> sessionStorage =
245
static_cast<SessionStorage*>(aStorage);
246
if (sessionStorage->Cache() != cache) {
247
return NS_OK;
248
}
249
250
if (!StorageUtils::PrincipalsEqual(aStorage->Principal(), aPrincipal)) {
251
return NS_OK;
252
}
253
254
*aRetval = true;
255
return NS_OK;
256
}
257
258
void SessionStorageManager::ClearStorages(
259
ClearStorageType aType, const OriginAttributesPattern& aPattern,
260
const nsACString& aOriginScope) {
261
for (auto iter1 = mOATable.Iter(); !iter1.Done(); iter1.Next()) {
262
OriginAttributes oa;
263
DebugOnly<bool> ok = oa.PopulateFromSuffix(iter1.Key());
264
MOZ_ASSERT(ok);
265
if (!aPattern.Matches(oa)) {
266
// This table doesn't match the given origin attributes pattern
267
continue;
268
}
269
270
OriginKeyHashTable* table = iter1.UserData();
271
for (auto iter2 = table->Iter(); !iter2.Done(); iter2.Next()) {
272
if (aOriginScope.IsEmpty() ||
273
StringBeginsWith(iter2.Key(), aOriginScope)) {
274
const auto cache = iter2.Data()->mCache;
275
if (aType == eAll) {
276
cache->Clear(SessionStorageCache::eDefaultSetType, false);
277
cache->Clear(SessionStorageCache::eSessionSetType, false);
278
} else {
279
MOZ_ASSERT(aType == eSessionOnly);
280
cache->Clear(SessionStorageCache::eSessionSetType, false);
281
}
282
}
283
}
284
}
285
}
286
287
void SessionStorageManager::SendSessionStorageDataToParentProcess() {
288
if (!mBrowsingContext || mBrowsingContext->IsDiscarded()) {
289
return;
290
}
291
292
for (auto oaIter = mOATable.Iter(); !oaIter.Done(); oaIter.Next()) {
293
for (auto originIter = oaIter.Data()->Iter(); !originIter.Done();
294
originIter.Next()) {
295
SendSessionStorageCache(ContentChild::GetSingleton(), oaIter.Key(),
296
originIter.Key(), originIter.Data()->mCache);
297
}
298
}
299
}
300
301
void SessionStorageManager::SendSessionStorageDataToContentProcess(
302
ContentParent* const aActor, nsIPrincipal* const aPrincipal) {
303
nsAutoCString originAttrs;
304
nsAutoCString originKey;
305
nsresult rv = aPrincipal->GetStorageOriginKey(originKey);
306
aPrincipal->OriginAttributesRef().CreateSuffix(originAttrs);
307
if (NS_FAILED(rv)) {
308
return;
309
}
310
311
const auto originRecord =
312
GetOriginRecord(originAttrs, originKey, false, nullptr);
313
if (!originRecord) {
314
return;
315
}
316
317
const auto id = aActor->ChildID();
318
if (!originRecord->mKnownTo.Contains(id)) {
319
originRecord->mKnownTo.PutEntry(id);
320
SendSessionStorageCache(aActor, originAttrs, originKey,
321
originRecord->mCache);
322
}
323
}
324
325
template <typename Actor>
326
void SessionStorageManager::SendSessionStorageCache(
327
Actor* const aActor, const nsACString& aOriginAttrs,
328
const nsACString& aOriginKey, SessionStorageCache* const aCache) {
329
nsTArray<KeyValuePair> defaultData =
330
aCache->SerializeData(SessionStorageCache::eDefaultSetType);
331
nsTArray<KeyValuePair> sessionData =
332
aCache->SerializeData(SessionStorageCache::eSessionSetType);
333
Unused << aActor->SendSessionStorageData(
334
mBrowsingContext->Id(), nsCString{aOriginAttrs}, nsCString{aOriginKey},
335
defaultData, sessionData);
336
}
337
338
void SessionStorageManager::LoadSessionStorageData(
339
ContentParent* const aSource, const nsACString& aOriginAttrs,
340
const nsACString& aOriginKey, const nsTArray<KeyValuePair>& aDefaultData,
341
const nsTArray<KeyValuePair>& aSessionData) {
342
const auto originRecord =
343
GetOriginRecord(aOriginAttrs, aOriginKey, true, nullptr);
344
MOZ_ASSERT(originRecord);
345
346
if (aSource) {
347
originRecord->mKnownTo.RemoveEntry(aSource->ChildID());
348
}
349
350
originRecord->mCache->DeserializeData(SessionStorageCache::eDefaultSetType,
351
aDefaultData);
352
originRecord->mCache->DeserializeData(SessionStorageCache::eSessionSetType,
353
aSessionData);
354
}
355
356
nsresult SessionStorageManager::Observe(
357
const char* aTopic, const nsAString& aOriginAttributesPattern,
358
const nsACString& aOriginScope) {
359
OriginAttributesPattern pattern;
360
if (!pattern.Init(aOriginAttributesPattern)) {
361
NS_ERROR("Cannot parse origin attributes pattern");
362
return NS_ERROR_FAILURE;
363
}
364
365
// Clear everything, caches + database
366
if (!strcmp(aTopic, "cookie-cleared")) {
367
ClearStorages(eAll, pattern, EmptyCString());
368
return NS_OK;
369
}
370
371
// Clear from caches everything that has been stored
372
// while in session-only mode
373
if (!strcmp(aTopic, "session-only-cleared")) {
374
ClearStorages(eSessionOnly, pattern, aOriginScope);
375
return NS_OK;
376
}
377
378
// Clear everything (including so and pb data) from caches and database
379
// for the given domain and subdomains.
380
if (!strcmp(aTopic, "browser:purge-sessionStorage")) {
381
ClearStorages(eAll, pattern, aOriginScope);
382
return NS_OK;
383
}
384
385
if (!strcmp(aTopic, "profile-change")) {
386
// For case caches are still referenced - clear them completely
387
ClearStorages(eAll, pattern, EmptyCString());
388
mOATable.Clear();
389
return NS_OK;
390
}
391
392
return NS_OK;
393
}
394
395
} // namespace dom
396
} // namespace mozilla