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 "StorageIPC.h"
8
9
#include "LocalStorageManager.h"
10
11
#include "mozilla/ipc/BackgroundChild.h"
12
#include "mozilla/ipc/BackgroundParent.h"
13
#include "mozilla/ipc/PBackgroundChild.h"
14
#include "mozilla/ipc/PBackgroundParent.h"
15
#include "mozilla/dom/ContentParent.h"
16
#include "mozilla/Unused.h"
17
#include "nsThreadUtils.h"
18
19
namespace mozilla {
20
namespace dom {
21
22
namespace {
23
24
typedef nsClassHashtable<nsCStringHashKey, nsTArray<LocalStorageCacheParent*>>
25
LocalStorageCacheParentHashtable;
26
27
StaticAutoPtr<LocalStorageCacheParentHashtable> gLocalStorageCacheParents;
28
29
StorageDBChild* sStorageChild = nullptr;
30
31
// False until we shut the storage child down.
32
bool sStorageChildDown = false;
33
34
} // namespace
35
36
LocalStorageCacheChild::LocalStorageCacheChild(LocalStorageCache* aCache)
37
: mCache(aCache) {
38
AssertIsOnOwningThread();
39
MOZ_ASSERT(aCache);
40
aCache->AssertIsOnOwningThread();
41
42
MOZ_COUNT_CTOR(LocalStorageCacheChild);
43
}
44
45
LocalStorageCacheChild::~LocalStorageCacheChild() {
46
AssertIsOnOwningThread();
47
48
MOZ_COUNT_DTOR(LocalStorageCacheChild);
49
}
50
51
void LocalStorageCacheChild::SendDeleteMeInternal() {
52
AssertIsOnOwningThread();
53
54
if (mCache) {
55
mCache->ClearActor();
56
mCache = nullptr;
57
58
MOZ_ALWAYS_TRUE(PBackgroundLocalStorageCacheChild::SendDeleteMe());
59
}
60
}
61
62
void LocalStorageCacheChild::ActorDestroy(ActorDestroyReason aWhy) {
63
AssertIsOnOwningThread();
64
65
if (mCache) {
66
mCache->ClearActor();
67
mCache = nullptr;
68
}
69
}
70
71
mozilla::ipc::IPCResult LocalStorageCacheChild::RecvObserve(
72
const PrincipalInfo& aPrincipalInfo,
73
const PrincipalInfo& aCachePrincipalInfo,
74
const uint32_t& aPrivateBrowsingId, const nsString& aDocumentURI,
75
const nsString& aKey, const nsString& aOldValue,
76
const nsString& aNewValue) {
77
AssertIsOnOwningThread();
78
79
nsresult rv;
80
nsCOMPtr<nsIPrincipal> principal =
81
PrincipalInfoToPrincipal(aPrincipalInfo, &rv);
82
if (NS_WARN_IF(NS_FAILED(rv))) {
83
return IPC_FAIL_NO_REASON(this);
84
}
85
86
nsCOMPtr<nsIPrincipal> cachePrincipal =
87
PrincipalInfoToPrincipal(aCachePrincipalInfo, &rv);
88
if (NS_WARN_IF(NS_FAILED(rv))) {
89
return IPC_FAIL_NO_REASON(this);
90
}
91
92
if (StorageUtils::PrincipalsEqual(principal, cachePrincipal)) {
93
Storage::NotifyChange(/* aStorage */ nullptr, principal, aKey, aOldValue,
94
aNewValue,
95
/* aStorageType */ u"localStorage", aDocumentURI,
96
/* aIsPrivate */ !!aPrivateBrowsingId,
97
/* aImmediateDispatch */ true);
98
}
99
100
return IPC_OK();
101
}
102
103
// ----------------------------------------------------------------------------
104
// Child
105
// ----------------------------------------------------------------------------
106
107
class StorageDBChild::ShutdownObserver final : public nsIObserver {
108
public:
109
ShutdownObserver() { MOZ_ASSERT(NS_IsMainThread()); }
110
111
NS_DECL_ISUPPORTS
112
NS_DECL_NSIOBSERVER
113
114
private:
115
~ShutdownObserver() { MOZ_ASSERT(NS_IsMainThread()); }
116
};
117
118
void StorageDBChild::AddIPDLReference() {
119
MOZ_ASSERT(!mIPCOpen, "Attempting to retain multiple IPDL references");
120
mIPCOpen = true;
121
AddRef();
122
}
123
124
void StorageDBChild::ReleaseIPDLReference() {
125
MOZ_ASSERT(mIPCOpen, "Attempting to release non-existent IPDL reference");
126
mIPCOpen = false;
127
Release();
128
}
129
130
StorageDBChild::StorageDBChild(LocalStorageManager* aManager)
131
: mManager(aManager), mStatus(NS_OK), mIPCOpen(false) {
132
MOZ_ASSERT(!NextGenLocalStorageEnabled());
133
}
134
135
StorageDBChild::~StorageDBChild() {}
136
137
// static
138
StorageDBChild* StorageDBChild::Get() {
139
MOZ_ASSERT(NS_IsMainThread());
140
MOZ_ASSERT(!NextGenLocalStorageEnabled());
141
142
return sStorageChild;
143
}
144
145
// static
146
StorageDBChild* StorageDBChild::GetOrCreate() {
147
MOZ_ASSERT(NS_IsMainThread());
148
MOZ_ASSERT(!NextGenLocalStorageEnabled());
149
150
if (sStorageChild || sStorageChildDown) {
151
// When sStorageChildDown is at true, sStorageChild is null.
152
// Checking sStorageChildDown flag here prevents reinitialization of
153
// the storage child after shutdown.
154
return sStorageChild;
155
}
156
157
// Use LocalStorageManager::Ensure in case we're called from
158
// DOMSessionStorageManager's initializer and we haven't yet initialized the
159
// local storage manager.
160
RefPtr<StorageDBChild> storageChild =
161
new StorageDBChild(LocalStorageManager::Ensure());
162
163
nsresult rv = storageChild->Init();
164
if (NS_WARN_IF(NS_FAILED(rv))) {
165
return nullptr;
166
}
167
168
storageChild.forget(&sStorageChild);
169
170
return sStorageChild;
171
}
172
173
nsTHashtable<nsCStringHashKey>& StorageDBChild::OriginsHavingData() {
174
if (!mOriginsHavingData) {
175
mOriginsHavingData = new nsTHashtable<nsCStringHashKey>;
176
}
177
178
return *mOriginsHavingData;
179
}
180
181
nsresult StorageDBChild::Init() {
182
MOZ_ASSERT(NS_IsMainThread());
183
184
PBackgroundChild* actor = BackgroundChild::GetOrCreateForCurrentThread();
185
if (NS_WARN_IF(!actor)) {
186
return NS_ERROR_FAILURE;
187
}
188
189
nsString profilePath;
190
if (XRE_IsParentProcess()) {
191
nsresult rv = StorageDBThread::GetProfilePath(profilePath);
192
if (NS_WARN_IF(NS_FAILED(rv))) {
193
return rv;
194
}
195
}
196
197
AddIPDLReference();
198
199
actor->SendPBackgroundStorageConstructor(this, profilePath);
200
201
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
202
MOZ_ASSERT(observerService);
203
204
nsCOMPtr<nsIObserver> observer = new ShutdownObserver();
205
206
MOZ_ALWAYS_SUCCEEDS(
207
observerService->AddObserver(observer, "xpcom-shutdown", false));
208
209
return NS_OK;
210
}
211
212
nsresult StorageDBChild::Shutdown() {
213
// There is nothing to do here, IPC will release automatically and
214
// the actual thread running on the parent process will also stop
215
// automatically in profile-before-change topic observer.
216
return NS_OK;
217
}
218
219
void StorageDBChild::AsyncPreload(LocalStorageCacheBridge* aCache,
220
bool aPriority) {
221
if (mIPCOpen) {
222
// Adding ref to cache for the time of preload. This ensures a reference to
223
// to the cache and that all keys will load into this cache object.
224
mLoadingCaches.PutEntry(aCache);
225
SendAsyncPreload(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
226
aPriority);
227
} else {
228
// No IPC, no love. But the LoadDone call is expected.
229
aCache->LoadDone(NS_ERROR_UNEXPECTED);
230
}
231
}
232
233
void StorageDBChild::AsyncGetUsage(StorageUsageBridge* aUsage) {
234
if (mIPCOpen) {
235
SendAsyncGetUsage(aUsage->OriginScope());
236
}
237
}
238
239
void StorageDBChild::SyncPreload(LocalStorageCacheBridge* aCache,
240
bool aForceSync) {
241
if (NS_FAILED(mStatus)) {
242
aCache->LoadDone(mStatus);
243
return;
244
}
245
246
if (!mIPCOpen) {
247
aCache->LoadDone(NS_ERROR_UNEXPECTED);
248
return;
249
}
250
251
// There is no way to put the child process to a wait state to receive all
252
// incoming async responses from the parent, hence we have to do a sync
253
// preload instead. We are smart though, we only demand keys that are left to
254
// load in case the async preload has already loaded some keys.
255
nsTArray<nsString> keys, values;
256
nsresult rv;
257
SendPreload(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
258
aCache->LoadedCount(), &keys, &values, &rv);
259
260
for (uint32_t i = 0; i < keys.Length(); ++i) {
261
aCache->LoadItem(keys[i], values[i]);
262
}
263
264
aCache->LoadDone(rv);
265
}
266
267
nsresult StorageDBChild::AsyncAddItem(LocalStorageCacheBridge* aCache,
268
const nsAString& aKey,
269
const nsAString& aValue) {
270
if (NS_FAILED(mStatus) || !mIPCOpen) {
271
return mStatus;
272
}
273
274
SendAsyncAddItem(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
275
nsString(aKey), nsString(aValue));
276
OriginsHavingData().PutEntry(aCache->Origin());
277
return NS_OK;
278
}
279
280
nsresult StorageDBChild::AsyncUpdateItem(LocalStorageCacheBridge* aCache,
281
const nsAString& aKey,
282
const nsAString& aValue) {
283
if (NS_FAILED(mStatus) || !mIPCOpen) {
284
return mStatus;
285
}
286
287
SendAsyncUpdateItem(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
288
nsString(aKey), nsString(aValue));
289
OriginsHavingData().PutEntry(aCache->Origin());
290
return NS_OK;
291
}
292
293
nsresult StorageDBChild::AsyncRemoveItem(LocalStorageCacheBridge* aCache,
294
const nsAString& aKey) {
295
if (NS_FAILED(mStatus) || !mIPCOpen) {
296
return mStatus;
297
}
298
299
SendAsyncRemoveItem(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
300
nsString(aKey));
301
return NS_OK;
302
}
303
304
nsresult StorageDBChild::AsyncClear(LocalStorageCacheBridge* aCache) {
305
if (NS_FAILED(mStatus) || !mIPCOpen) {
306
return mStatus;
307
}
308
309
SendAsyncClear(aCache->OriginSuffix(), aCache->OriginNoSuffix());
310
OriginsHavingData().RemoveEntry(aCache->Origin());
311
return NS_OK;
312
}
313
314
bool StorageDBChild::ShouldPreloadOrigin(const nsACString& aOrigin) {
315
// Return true if we didn't receive the origins list yet.
316
// I tend to rather preserve a bit of early-after-start performance
317
// than a bit of memory here.
318
return !mOriginsHavingData || mOriginsHavingData->Contains(aOrigin);
319
}
320
321
mozilla::ipc::IPCResult StorageDBChild::RecvObserve(
322
const nsCString& aTopic, const nsString& aOriginAttributesPattern,
323
const nsCString& aOriginScope) {
324
MOZ_ASSERT(!XRE_IsParentProcess());
325
326
StorageObserver::Self()->Notify(aTopic.get(), aOriginAttributesPattern,
327
aOriginScope);
328
return IPC_OK();
329
}
330
331
mozilla::ipc::IPCResult StorageDBChild::RecvOriginsHavingData(
332
nsTArray<nsCString>&& aOrigins) {
333
// Force population of mOriginsHavingData even if there are no origins so that
334
// ShouldPreloadOrigin does not generate false positives for all origins.
335
if (!aOrigins.Length()) {
336
Unused << OriginsHavingData();
337
}
338
339
for (uint32_t i = 0; i < aOrigins.Length(); ++i) {
340
OriginsHavingData().PutEntry(aOrigins[i]);
341
}
342
343
return IPC_OK();
344
}
345
346
mozilla::ipc::IPCResult StorageDBChild::RecvLoadItem(
347
const nsCString& aOriginSuffix, const nsCString& aOriginNoSuffix,
348
const nsString& aKey, const nsString& aValue) {
349
LocalStorageCache* aCache =
350
mManager->GetCache(aOriginSuffix, aOriginNoSuffix);
351
if (aCache) {
352
aCache->LoadItem(aKey, aValue);
353
}
354
355
return IPC_OK();
356
}
357
358
mozilla::ipc::IPCResult StorageDBChild::RecvLoadDone(
359
const nsCString& aOriginSuffix, const nsCString& aOriginNoSuffix,
360
const nsresult& aRv) {
361
LocalStorageCache* aCache =
362
mManager->GetCache(aOriginSuffix, aOriginNoSuffix);
363
if (aCache) {
364
aCache->LoadDone(aRv);
365
366
// Just drop reference to this cache now since the load is done.
367
mLoadingCaches.RemoveEntry(static_cast<LocalStorageCacheBridge*>(aCache));
368
}
369
370
return IPC_OK();
371
}
372
373
mozilla::ipc::IPCResult StorageDBChild::RecvLoadUsage(
374
const nsCString& aOriginNoSuffix, const int64_t& aUsage) {
375
RefPtr<StorageUsageBridge> scopeUsage =
376
mManager->GetOriginUsage(aOriginNoSuffix);
377
scopeUsage->LoadUsage(aUsage);
378
return IPC_OK();
379
}
380
381
mozilla::ipc::IPCResult StorageDBChild::RecvError(const nsresult& aRv) {
382
mStatus = aRv;
383
return IPC_OK();
384
}
385
386
NS_IMPL_ISUPPORTS(StorageDBChild::ShutdownObserver, nsIObserver)
387
388
NS_IMETHODIMP
389
StorageDBChild::ShutdownObserver::Observe(nsISupports* aSubject,
390
const char* aTopic,
391
const char16_t* aData) {
392
MOZ_ASSERT(NS_IsMainThread());
393
MOZ_ASSERT(!strcmp(aTopic, "xpcom-shutdown"));
394
395
nsCOMPtr<nsIObserverService> observerService =
396
mozilla::services::GetObserverService();
397
if (NS_WARN_IF(!observerService)) {
398
return NS_ERROR_FAILURE;
399
}
400
401
Unused << observerService->RemoveObserver(this, "xpcom-shutdown");
402
403
if (sStorageChild) {
404
sStorageChildDown = true;
405
406
MOZ_ALWAYS_TRUE(sStorageChild->PBackgroundStorageChild::SendDeleteMe());
407
408
NS_RELEASE(sStorageChild);
409
sStorageChild = nullptr;
410
}
411
412
return NS_OK;
413
}
414
415
SessionStorageObserverChild::SessionStorageObserverChild(
416
SessionStorageObserver* aObserver)
417
: mObserver(aObserver) {
418
AssertIsOnOwningThread();
419
MOZ_ASSERT(NextGenLocalStorageEnabled());
420
MOZ_ASSERT(aObserver);
421
aObserver->AssertIsOnOwningThread();
422
423
MOZ_COUNT_CTOR(SessionStorageObserverChild);
424
}
425
426
SessionStorageObserverChild::~SessionStorageObserverChild() {
427
AssertIsOnOwningThread();
428
429
MOZ_COUNT_DTOR(SessionStorageObserverChild);
430
}
431
432
void SessionStorageObserverChild::SendDeleteMeInternal() {
433
AssertIsOnOwningThread();
434
435
if (mObserver) {
436
mObserver->ClearActor();
437
mObserver = nullptr;
438
439
// Don't check result here since IPC may no longer be available due to
440
// SessionStorageManager (which holds a strong reference to
441
// SessionStorageObserver) being destroyed very late in the game.
442
PSessionStorageObserverChild::SendDeleteMe();
443
}
444
}
445
446
void SessionStorageObserverChild::ActorDestroy(ActorDestroyReason aWhy) {
447
AssertIsOnOwningThread();
448
449
if (mObserver) {
450
mObserver->ClearActor();
451
mObserver = nullptr;
452
}
453
}
454
455
mozilla::ipc::IPCResult SessionStorageObserverChild::RecvObserve(
456
const nsCString& aTopic, const nsString& aOriginAttributesPattern,
457
const nsCString& aOriginScope) {
458
AssertIsOnOwningThread();
459
460
StorageObserver::Self()->Notify(aTopic.get(), aOriginAttributesPattern,
461
aOriginScope);
462
return IPC_OK();
463
}
464
465
LocalStorageCacheParent::LocalStorageCacheParent(
466
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
467
const nsACString& aOriginKey, uint32_t aPrivateBrowsingId)
468
: mPrincipalInfo(aPrincipalInfo),
469
mOriginKey(aOriginKey),
470
mPrivateBrowsingId(aPrivateBrowsingId),
471
mActorDestroyed(false) {
472
AssertIsOnBackgroundThread();
473
}
474
475
LocalStorageCacheParent::~LocalStorageCacheParent() {
476
MOZ_ASSERT(mActorDestroyed);
477
}
478
479
void LocalStorageCacheParent::ActorDestroy(ActorDestroyReason aWhy) {
480
AssertIsOnBackgroundThread();
481
MOZ_ASSERT(!mActorDestroyed);
482
483
mActorDestroyed = true;
484
485
MOZ_ASSERT(gLocalStorageCacheParents);
486
487
nsTArray<LocalStorageCacheParent*>* array;
488
gLocalStorageCacheParents->Get(mOriginKey, &array);
489
MOZ_ASSERT(array);
490
491
array->RemoveElement(this);
492
493
if (array->IsEmpty()) {
494
gLocalStorageCacheParents->Remove(mOriginKey);
495
}
496
497
if (!gLocalStorageCacheParents->Count()) {
498
gLocalStorageCacheParents = nullptr;
499
}
500
}
501
502
mozilla::ipc::IPCResult LocalStorageCacheParent::RecvDeleteMe() {
503
AssertIsOnBackgroundThread();
504
MOZ_ASSERT(!mActorDestroyed);
505
506
IProtocol* mgr = Manager();
507
if (!PBackgroundLocalStorageCacheParent::Send__delete__(this)) {
508
return IPC_FAIL_NO_REASON(mgr);
509
}
510
return IPC_OK();
511
}
512
513
mozilla::ipc::IPCResult LocalStorageCacheParent::RecvNotify(
514
const nsString& aDocumentURI, const nsString& aKey,
515
const nsString& aOldValue, const nsString& aNewValue) {
516
AssertIsOnBackgroundThread();
517
MOZ_ASSERT(gLocalStorageCacheParents);
518
519
nsTArray<LocalStorageCacheParent*>* array;
520
gLocalStorageCacheParents->Get(mOriginKey, &array);
521
MOZ_ASSERT(array);
522
523
for (LocalStorageCacheParent* localStorageCacheParent : *array) {
524
if (localStorageCacheParent != this) {
525
// When bug 1443925 is fixed, we can compare mPrincipalInfo against
526
// localStorageCacheParent->PrincipalInfo() here on the background thread
527
// instead of posting it to the main thread. The advantage of doing so is
528
// that it would save an IPC message in the case where the principals do
529
// not match.
530
Unused << localStorageCacheParent->SendObserve(
531
mPrincipalInfo, localStorageCacheParent->PrincipalInfo(),
532
mPrivateBrowsingId, aDocumentURI, aKey, aOldValue, aNewValue);
533
}
534
}
535
536
return IPC_OK();
537
}
538
539
// ----------------------------------------------------------------------------
540
// Parent
541
// ----------------------------------------------------------------------------
542
543
class StorageDBParent::ObserverSink : public StorageObserverSink {
544
nsCOMPtr<nsIEventTarget> mOwningEventTarget;
545
546
// Only touched on the PBackground thread.
547
StorageDBParent* MOZ_NON_OWNING_REF mActor;
548
549
public:
550
explicit ObserverSink(StorageDBParent* aActor)
551
: mOwningEventTarget(GetCurrentThreadEventTarget()), mActor(aActor) {
552
AssertIsOnBackgroundThread();
553
MOZ_ASSERT(aActor);
554
}
555
556
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(StorageDBParent::ObserverSink);
557
558
void Start();
559
560
void Stop();
561
562
private:
563
~ObserverSink() = default;
564
565
void AddSink();
566
567
void RemoveSink();
568
569
void Notify(const nsCString& aTopic, const nsString& aOriginAttributesPattern,
570
const nsCString& aOriginScope);
571
572
// StorageObserverSink
573
nsresult Observe(const char* aTopic, const nsAString& aOriginAttrPattern,
574
const nsACString& aOriginScope) override;
575
};
576
577
NS_IMPL_ADDREF(StorageDBParent)
578
NS_IMPL_RELEASE(StorageDBParent)
579
580
void StorageDBParent::AddIPDLReference() {
581
MOZ_ASSERT(!mIPCOpen, "Attempting to retain multiple IPDL references");
582
mIPCOpen = true;
583
AddRef();
584
}
585
586
void StorageDBParent::ReleaseIPDLReference() {
587
MOZ_ASSERT(mIPCOpen, "Attempting to release non-existent IPDL reference");
588
mIPCOpen = false;
589
Release();
590
}
591
592
namespace {} // namespace
593
594
StorageDBParent::StorageDBParent(const nsString& aProfilePath)
595
: mProfilePath(aProfilePath), mIPCOpen(false) {
596
AssertIsOnBackgroundThread();
597
598
// We are always open by IPC only
599
AddIPDLReference();
600
}
601
602
StorageDBParent::~StorageDBParent() {
603
AssertIsOnBackgroundThread();
604
605
if (mObserverSink) {
606
mObserverSink->Stop();
607
mObserverSink = nullptr;
608
}
609
}
610
611
void StorageDBParent::Init() {
612
AssertIsOnBackgroundThread();
613
614
PBackgroundParent* actor = Manager();
615
MOZ_ASSERT(actor);
616
617
if (BackgroundParent::IsOtherProcessActor(actor)) {
618
mObserverSink = new ObserverSink(this);
619
mObserverSink->Start();
620
}
621
622
StorageDBThread* storageThread = StorageDBThread::Get();
623
if (storageThread) {
624
nsTArray<nsCString> scopes;
625
storageThread->GetOriginsHavingData(&scopes);
626
mozilla::Unused << SendOriginsHavingData(scopes);
627
}
628
}
629
630
StorageDBParent::CacheParentBridge* StorageDBParent::NewCache(
631
const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix) {
632
return new CacheParentBridge(this, aOriginSuffix, aOriginNoSuffix);
633
}
634
635
void StorageDBParent::ActorDestroy(ActorDestroyReason aWhy) {
636
// Implement me! Bug 1005169
637
}
638
639
mozilla::ipc::IPCResult StorageDBParent::RecvDeleteMe() {
640
AssertIsOnBackgroundThread();
641
642
IProtocol* mgr = Manager();
643
if (!PBackgroundStorageParent::Send__delete__(this)) {
644
return IPC_FAIL_NO_REASON(mgr);
645
}
646
return IPC_OK();
647
}
648
649
mozilla::ipc::IPCResult StorageDBParent::RecvAsyncPreload(
650
const nsCString& aOriginSuffix, const nsCString& aOriginNoSuffix,
651
const bool& aPriority) {
652
StorageDBThread* storageThread = StorageDBThread::GetOrCreate(mProfilePath);
653
if (!storageThread) {
654
return IPC_FAIL_NO_REASON(this);
655
}
656
657
storageThread->AsyncPreload(NewCache(aOriginSuffix, aOriginNoSuffix),
658
aPriority);
659
660
return IPC_OK();
661
}
662
663
mozilla::ipc::IPCResult StorageDBParent::RecvAsyncGetUsage(
664
const nsCString& aOriginNoSuffix) {
665
StorageDBThread* storageThread = StorageDBThread::GetOrCreate(mProfilePath);
666
if (!storageThread) {
667
return IPC_FAIL_NO_REASON(this);
668
}
669
670
// The object releases it self in LoadUsage method
671
RefPtr<UsageParentBridge> usage =
672
new UsageParentBridge(this, aOriginNoSuffix);
673
674
storageThread->AsyncGetUsage(usage);
675
676
return IPC_OK();
677
}
678
679
namespace {
680
681
// We need another implementation of LocalStorageCacheBridge to do
682
// synchronous IPC preload. This class just receives Load* notifications
683
// and fills the returning arguments of RecvPreload with the database
684
// values for us.
685
class SyncLoadCacheHelper : public LocalStorageCacheBridge {
686
public:
687
SyncLoadCacheHelper(const nsCString& aOriginSuffix,
688
const nsCString& aOriginNoSuffix,
689
uint32_t aAlreadyLoadedCount, nsTArray<nsString>* aKeys,
690
nsTArray<nsString>* aValues, nsresult* rv)
691
: mMonitor("DOM Storage SyncLoad IPC"),
692
mSuffix(aOriginSuffix),
693
mOrigin(aOriginNoSuffix),
694
mKeys(aKeys),
695
mValues(aValues),
696
mRv(rv),
697
mLoaded(false),
698
mLoadedCount(aAlreadyLoadedCount) {
699
// Precaution
700
*mRv = NS_ERROR_UNEXPECTED;
701
}
702
703
virtual const nsCString Origin() const override {
704
return LocalStorageManager::CreateOrigin(mSuffix, mOrigin);
705
}
706
virtual const nsCString& OriginNoSuffix() const override { return mOrigin; }
707
virtual const nsCString& OriginSuffix() const override { return mSuffix; }
708
virtual bool Loaded() override { return mLoaded; }
709
virtual uint32_t LoadedCount() override { return mLoadedCount; }
710
virtual bool LoadItem(const nsAString& aKey,
711
const nsString& aValue) override {
712
// Called on the aCache background thread
713
MOZ_ASSERT(!mLoaded);
714
if (mLoaded) {
715
return false;
716
}
717
718
++mLoadedCount;
719
mKeys->AppendElement(aKey);
720
mValues->AppendElement(aValue);
721
return true;
722
}
723
724
virtual void LoadDone(nsresult aRv) override {
725
// Called on the aCache background thread
726
MonitorAutoLock monitor(mMonitor);
727
MOZ_ASSERT(!mLoaded && mRv);
728
mLoaded = true;
729
if (mRv) {
730
*mRv = aRv;
731
mRv = nullptr;
732
}
733
monitor.Notify();
734
}
735
736
virtual void LoadWait() override {
737
// Called on the main thread, exits after LoadDone() call
738
MonitorAutoLock monitor(mMonitor);
739
while (!mLoaded) {
740
monitor.Wait();
741
}
742
}
743
744
private:
745
Monitor mMonitor;
746
nsCString mSuffix, mOrigin;
747
nsTArray<nsString>* mKeys;
748
nsTArray<nsString>* mValues;
749
nsresult* mRv;
750
bool mLoaded;
751
uint32_t mLoadedCount;
752
};
753
754
} // namespace
755
756
mozilla::ipc::IPCResult StorageDBParent::RecvPreload(
757
const nsCString& aOriginSuffix, const nsCString& aOriginNoSuffix,
758
const uint32_t& aAlreadyLoadedCount, nsTArray<nsString>* aKeys,
759
nsTArray<nsString>* aValues, nsresult* aRv) {
760
StorageDBThread* storageThread = StorageDBThread::GetOrCreate(mProfilePath);
761
if (!storageThread) {
762
return IPC_FAIL_NO_REASON(this);
763
}
764
765
RefPtr<SyncLoadCacheHelper> cache(
766
new SyncLoadCacheHelper(aOriginSuffix, aOriginNoSuffix,
767
aAlreadyLoadedCount, aKeys, aValues, aRv));
768
769
storageThread->SyncPreload(cache, true);
770
771
return IPC_OK();
772
}
773
774
mozilla::ipc::IPCResult StorageDBParent::RecvAsyncAddItem(
775
const nsCString& aOriginSuffix, const nsCString& aOriginNoSuffix,
776
const nsString& aKey, const nsString& aValue) {
777
StorageDBThread* storageThread = StorageDBThread::GetOrCreate(mProfilePath);
778
if (!storageThread) {
779
return IPC_FAIL_NO_REASON(this);
780
}
781
782
nsresult rv = storageThread->AsyncAddItem(
783
NewCache(aOriginSuffix, aOriginNoSuffix), aKey, aValue);
784
if (NS_FAILED(rv) && mIPCOpen) {
785
mozilla::Unused << SendError(rv);
786
}
787
788
return IPC_OK();
789
}
790
791
mozilla::ipc::IPCResult StorageDBParent::RecvAsyncUpdateItem(
792
const nsCString& aOriginSuffix, const nsCString& aOriginNoSuffix,
793
const nsString& aKey, const nsString& aValue) {
794
StorageDBThread* storageThread = StorageDBThread::GetOrCreate(mProfilePath);
795
if (!storageThread) {
796
return IPC_FAIL_NO_REASON(this);
797
}
798
799
nsresult rv = storageThread->AsyncUpdateItem(
800
NewCache(aOriginSuffix, aOriginNoSuffix), aKey, aValue);
801
if (NS_FAILED(rv) && mIPCOpen) {
802
mozilla::Unused << SendError(rv);
803
}
804
805
return IPC_OK();
806
}
807
808
mozilla::ipc::IPCResult StorageDBParent::RecvAsyncRemoveItem(
809
const nsCString& aOriginSuffix, const nsCString& aOriginNoSuffix,
810
const nsString& aKey) {
811
StorageDBThread* storageThread = StorageDBThread::GetOrCreate(mProfilePath);
812
if (!storageThread) {
813
return IPC_FAIL_NO_REASON(this);
814
}
815
816
nsresult rv = storageThread->AsyncRemoveItem(
817
NewCache(aOriginSuffix, aOriginNoSuffix), aKey);
818
if (NS_FAILED(rv) && mIPCOpen) {
819
mozilla::Unused << SendError(rv);
820
}
821
822
return IPC_OK();
823
}
824
825
mozilla::ipc::IPCResult StorageDBParent::RecvAsyncClear(
826
const nsCString& aOriginSuffix, const nsCString& aOriginNoSuffix) {
827
StorageDBThread* storageThread = StorageDBThread::GetOrCreate(mProfilePath);
828
if (!storageThread) {
829
return IPC_FAIL_NO_REASON(this);
830
}
831
832
nsresult rv =
833
storageThread->AsyncClear(NewCache(aOriginSuffix, aOriginNoSuffix));
834
if (NS_FAILED(rv) && mIPCOpen) {
835
mozilla::Unused << SendError(rv);
836
}
837
838
return IPC_OK();
839
}
840
841
mozilla::ipc::IPCResult StorageDBParent::RecvAsyncFlush() {
842
StorageDBThread* storageThread = StorageDBThread::Get();
843
if (!storageThread) {
844
return IPC_FAIL_NO_REASON(this);
845
}
846
847
storageThread->AsyncFlush();
848
849
return IPC_OK();
850
}
851
852
mozilla::ipc::IPCResult StorageDBParent::RecvStartup() {
853
StorageDBThread* storageThread = StorageDBThread::GetOrCreate(mProfilePath);
854
if (!storageThread) {
855
return IPC_FAIL_NO_REASON(this);
856
}
857
858
return IPC_OK();
859
}
860
861
mozilla::ipc::IPCResult StorageDBParent::RecvClearAll() {
862
StorageDBThread* storageThread = StorageDBThread::GetOrCreate(mProfilePath);
863
if (!storageThread) {
864
return IPC_FAIL_NO_REASON(this);
865
}
866
867
storageThread->AsyncClearAll();
868
869
return IPC_OK();
870
}
871
872
mozilla::ipc::IPCResult StorageDBParent::RecvClearMatchingOrigin(
873
const nsCString& aOriginNoSuffix) {
874
StorageDBThread* storageThread = StorageDBThread::GetOrCreate(mProfilePath);
875
if (!storageThread) {
876
return IPC_FAIL_NO_REASON(this);
877
}
878
879
storageThread->AsyncClearMatchingOrigin(aOriginNoSuffix);
880
881
return IPC_OK();
882
}
883
884
mozilla::ipc::IPCResult StorageDBParent::RecvClearMatchingOriginAttributes(
885
const OriginAttributesPattern& aPattern) {
886
StorageDBThread* storageThread = StorageDBThread::GetOrCreate(mProfilePath);
887
if (!storageThread) {
888
return IPC_FAIL_NO_REASON(this);
889
}
890
891
storageThread->AsyncClearMatchingOriginAttributes(aPattern);
892
893
return IPC_OK();
894
}
895
896
void StorageDBParent::Observe(const nsCString& aTopic,
897
const nsString& aOriginAttributesPattern,
898
const nsCString& aOriginScope) {
899
if (mIPCOpen) {
900
mozilla::Unused << SendObserve(aTopic, aOriginAttributesPattern,
901
aOriginScope);
902
}
903
}
904
905
namespace {
906
907
// Results must be sent back on the main thread
908
class LoadRunnable : public Runnable {
909
public:
910
enum TaskType { loadItem, loadDone };
911
912
LoadRunnable(StorageDBParent* aParent, TaskType aType,
913
const nsACString& aOriginSuffix,
914
const nsACString& aOriginNoSuffix,
915
const nsAString& aKey = EmptyString(),
916
const nsAString& aValue = EmptyString())
917
: Runnable("dom::LoadRunnable"),
918
mParent(aParent),
919
mType(aType),
920
mSuffix(aOriginSuffix),
921
mOrigin(aOriginNoSuffix),
922
mKey(aKey),
923
mValue(aValue),
924
mRv(NS_ERROR_NOT_INITIALIZED) {}
925
926
LoadRunnable(StorageDBParent* aParent, TaskType aType,
927
const nsACString& aOriginSuffix,
928
const nsACString& aOriginNoSuffix, nsresult aRv)
929
: Runnable("dom::LoadRunnable"),
930
mParent(aParent),
931
mType(aType),
932
mSuffix(aOriginSuffix),
933
mOrigin(aOriginNoSuffix),
934
mRv(aRv) {}
935
936
private:
937
RefPtr<StorageDBParent> mParent;
938
TaskType mType;
939
nsCString mSuffix, mOrigin;
940
nsString mKey;
941
nsString mValue;
942
nsresult mRv;
943
944
NS_IMETHOD Run() override {
945
if (!mParent->IPCOpen()) {
946
return NS_OK;
947
}
948
949
switch (mType) {
950
case loadItem:
951
mozilla::Unused << mParent->SendLoadItem(mSuffix, mOrigin, mKey,
952
mValue);
953
break;
954
case loadDone:
955
mozilla::Unused << mParent->SendLoadDone(mSuffix, mOrigin, mRv);
956
break;
957
}
958
959
mParent = nullptr;
960
961
return NS_OK;
962
}
963
};
964
965
} // namespace
966
967
// StorageDBParent::CacheParentBridge
968
969
const nsCString StorageDBParent::CacheParentBridge::Origin() const {
970
return LocalStorageManager::CreateOrigin(mOriginSuffix, mOriginNoSuffix);
971
}
972
973
bool StorageDBParent::CacheParentBridge::LoadItem(const nsAString& aKey,
974
const nsString& aValue) {
975
if (mLoaded) {
976
return false;
977
}
978
979
++mLoadedCount;
980
981
RefPtr<LoadRunnable> r =
982
new LoadRunnable(mParent, LoadRunnable::loadItem, mOriginSuffix,
983
mOriginNoSuffix, aKey, aValue);
984
985
MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(r, NS_DISPATCH_NORMAL));
986
987
return true;
988
}
989
990
void StorageDBParent::CacheParentBridge::LoadDone(nsresult aRv) {
991
// Prevent send of duplicate LoadDone.
992
if (mLoaded) {
993
return;
994
}
995
996
mLoaded = true;
997
998
RefPtr<LoadRunnable> r = new LoadRunnable(
999
mParent, LoadRunnable::loadDone, mOriginSuffix, mOriginNoSuffix, aRv);
1000
1001
MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(r, NS_DISPATCH_NORMAL));
1002
}
1003
1004
void StorageDBParent::CacheParentBridge::LoadWait() {
1005
// Should never be called on this implementation
1006
MOZ_ASSERT(false);
1007
}
1008
1009
// XXX Fix me!
1010
// This should be just:
1011
// NS_IMPL_RELEASE_WITH_DESTROY(StorageDBParent::CacheParentBridge, Destroy)
1012
// But due to different strings used for refcount logging and different return
1013
// types, this is done manually for now.
1014
NS_IMETHODIMP_(void)
1015
StorageDBParent::CacheParentBridge::Release(void) {
1016
MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");
1017
nsrefcnt count = --mRefCnt;
1018
NS_LOG_RELEASE(this, count, "LocalStorageCacheBridge");
1019
if (0 == count) {
1020
mRefCnt = 1; /* stabilize */
1021
/* enable this to find non-threadsafe destructors: */
1022
/* NS_ASSERT_OWNINGTHREAD(_class); */
1023
Destroy();
1024
}
1025
}
1026
1027
void StorageDBParent::CacheParentBridge::Destroy() {
1028
if (mOwningEventTarget->IsOnCurrentThread()) {
1029
delete this;
1030
return;
1031
}
1032
1033
RefPtr<Runnable> destroyRunnable = NewNonOwningRunnableMethod(
1034
"CacheParentBridge::Destroy", this, &CacheParentBridge::Destroy);
1035
1036
MOZ_ALWAYS_SUCCEEDS(
1037
mOwningEventTarget->Dispatch(destroyRunnable, NS_DISPATCH_NORMAL));
1038
}
1039
1040
// StorageDBParent::UsageParentBridge
1041
1042
namespace {
1043
1044
class UsageRunnable : public Runnable {
1045
public:
1046
UsageRunnable(StorageDBParent* aParent, const nsACString& aOriginScope,
1047
const int64_t& aUsage)
1048
: Runnable("dom::UsageRunnable"),
1049
mParent(aParent),
1050
mOriginScope(aOriginScope),
1051
mUsage(aUsage) {}
1052
1053
private:
1054
NS_IMETHOD Run() override {
1055
if (!mParent->IPCOpen()) {
1056
return NS_OK;
1057
}
1058
1059
mozilla::Unused << mParent->SendLoadUsage(mOriginScope, mUsage);
1060
1061
mParent = nullptr;
1062
1063
return NS_OK;
1064
}
1065
1066
RefPtr<StorageDBParent> mParent;
1067
nsCString mOriginScope;
1068
int64_t mUsage;
1069
};
1070
1071
} // namespace
1072
1073
void StorageDBParent::UsageParentBridge::LoadUsage(const int64_t aUsage) {
1074
RefPtr<UsageRunnable> r = new UsageRunnable(mParent, mOriginScope, aUsage);
1075
1076
MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(r, NS_DISPATCH_NORMAL));
1077
}
1078
1079
// XXX Fix me!
1080
// This should be just:
1081
// NS_IMPL_RELEASE_WITH_DESTROY(StorageDBParent::UsageParentBridge, Destroy)
1082
// But due to different strings used for refcount logging, this is done manually
1083
// for now.
1084
NS_IMETHODIMP_(MozExternalRefCountType)
1085
StorageDBParent::UsageParentBridge::Release(void) {
1086
MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");
1087
nsrefcnt count = --mRefCnt;
1088
NS_LOG_RELEASE(this, count, "StorageUsageBridge");
1089
if (count == 0) {
1090
Destroy();
1091
return 0;
1092
}
1093
return count;
1094
}
1095
1096
void StorageDBParent::UsageParentBridge::Destroy() {
1097
if (mOwningEventTarget->IsOnCurrentThread()) {
1098
delete this;
1099
return;
1100
}
1101
1102
RefPtr<Runnable> destroyRunnable = NewNonOwningRunnableMethod(
1103
"UsageParentBridge::Destroy", this, &UsageParentBridge::Destroy);
1104
1105
MOZ_ALWAYS_SUCCEEDS(
1106
mOwningEventTarget->Dispatch(destroyRunnable, NS_DISPATCH_NORMAL));
1107
}
1108
1109
void StorageDBParent::ObserverSink::Start() {
1110
AssertIsOnBackgroundThread();
1111
1112
RefPtr<Runnable> runnable =
1113
NewRunnableMethod("StorageDBParent::ObserverSink::AddSink", this,
1114
&StorageDBParent::ObserverSink::AddSink);
1115
1116
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
1117
}
1118
1119
void StorageDBParent::ObserverSink::Stop() {
1120
AssertIsOnBackgroundThread();
1121
1122
mActor = nullptr;
1123
1124
RefPtr<Runnable> runnable =
1125
NewRunnableMethod("StorageDBParent::ObserverSink::RemoveSink", this,
1126
&StorageDBParent::ObserverSink::RemoveSink);
1127
1128
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
1129
}
1130
1131
void StorageDBParent::ObserverSink::AddSink() {
1132
MOZ_ASSERT(NS_IsMainThread());
1133
1134
StorageObserver* observer = StorageObserver::Self();
1135
if (observer) {
1136
observer->AddSink(this);
1137
}
1138
}
1139
1140
void StorageDBParent::ObserverSink::RemoveSink() {
1141
MOZ_ASSERT(NS_IsMainThread());
1142
1143
StorageObserver* observer = StorageObserver::Self();
1144
if (observer) {
1145
observer->RemoveSink(this);
1146
}
1147
}
1148
1149
void StorageDBParent::ObserverSink::Notify(
1150
const nsCString& aTopic, const nsString& aOriginAttributesPattern,
1151
const nsCString& aOriginScope) {
1152
AssertIsOnBackgroundThread();
1153
1154
if (mActor) {
1155
mActor->Observe(aTopic, aOriginAttributesPattern, aOriginScope);
1156
}
1157
}
1158
1159
nsresult StorageDBParent::ObserverSink::Observe(
1160
const char* aTopic, const nsAString& aOriginAttributesPattern,
1161
const nsACString& aOriginScope) {
1162
MOZ_ASSERT(NS_IsMainThread());
1163
1164
RefPtr<Runnable> runnable = NewRunnableMethod<nsCString, nsString, nsCString>(
1165
"StorageDBParent::ObserverSink::Observe2", this,
1166
&StorageDBParent::ObserverSink::Notify, aTopic, aOriginAttributesPattern,
1167
aOriginScope);
1168
1169
MOZ_ALWAYS_SUCCEEDS(
1170
mOwningEventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL));
1171
1172
return NS_OK;
1173
}
1174
1175
SessionStorageObserverParent::SessionStorageObserverParent()
1176
: mActorDestroyed(false) {
1177
MOZ_ASSERT(NS_IsMainThread());
1178
1179
StorageObserver* observer = StorageObserver::Self();
1180
if (observer) {
1181
observer->AddSink(this);
1182
}
1183
}
1184
1185
SessionStorageObserverParent::~SessionStorageObserverParent() {
1186
MOZ_ASSERT(mActorDestroyed);
1187
1188
StorageObserver* observer = StorageObserver::Self();
1189
if (observer) {
1190
observer->RemoveSink(this);
1191
}
1192
}
1193
1194
void SessionStorageObserverParent::ActorDestroy(ActorDestroyReason aWhy) {
1195
MOZ_ASSERT(NS_IsMainThread());
1196
MOZ_ASSERT(!mActorDestroyed);
1197
1198
mActorDestroyed = true;
1199
}
1200
1201
mozilla::ipc::IPCResult SessionStorageObserverParent::RecvDeleteMe() {
1202
MOZ_ASSERT(NS_IsMainThread());
1203
MOZ_ASSERT(!mActorDestroyed);
1204
1205
IProtocol* mgr = Manager();
1206
if (!PSessionStorageObserverParent::Send__delete__(this)) {
1207
return IPC_FAIL_NO_REASON(mgr);
1208
}
1209
return IPC_OK();
1210
}
1211
1212
nsresult SessionStorageObserverParent::Observe(
1213
const char* aTopic, const nsAString& aOriginAttributesPattern,
1214
const nsACString& aOriginScope) {
1215
MOZ_ASSERT(NS_IsMainThread());
1216
1217
if (!mActorDestroyed) {
1218
mozilla::Unused << SendObserve(nsCString(aTopic),
1219
nsString(aOriginAttributesPattern),
1220
nsCString(aOriginScope));
1221
}
1222
return NS_OK;
1223
}
1224
1225
/*******************************************************************************
1226
* Exported functions
1227
******************************************************************************/
1228
1229
PBackgroundLocalStorageCacheParent* AllocPBackgroundLocalStorageCacheParent(
1230
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
1231
const nsCString& aOriginKey, const uint32_t& aPrivateBrowsingId) {
1232
AssertIsOnBackgroundThread();
1233
1234
RefPtr<LocalStorageCacheParent> actor = new LocalStorageCacheParent(
1235
aPrincipalInfo, aOriginKey, aPrivateBrowsingId);
1236
1237
// Transfer ownership to IPDL.
1238
return actor.forget().take();
1239
}
1240
1241
mozilla::ipc::IPCResult RecvPBackgroundLocalStorageCacheConstructor(
1242
mozilla::ipc::PBackgroundParent* aBackgroundActor,
1243
PBackgroundLocalStorageCacheParent* aActor,
1244
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
1245
const nsCString& aOriginKey, const uint32_t& aPrivateBrowsingId) {
1246
AssertIsOnBackgroundThread();
1247
MOZ_ASSERT(aActor);
1248
1249
auto* actor = static_cast<LocalStorageCacheParent*>(aActor);
1250
1251
if (!gLocalStorageCacheParents) {
1252
gLocalStorageCacheParents = new LocalStorageCacheParentHashtable();
1253
}
1254
1255
nsTArray<LocalStorageCacheParent*>* array;
1256
if (!gLocalStorageCacheParents->Get(aOriginKey, &array)) {
1257
array = new nsTArray<LocalStorageCacheParent*>();
1258
gLocalStorageCacheParents->Put(aOriginKey, array);
1259
}
1260
array->AppendElement(actor);
1261
1262
// We are currently trusting the content process not to lie to us. It is
1263
// future work to consult the ClientManager to determine whether this is a
1264
// legitimate origin for the content process.
1265
1266
return IPC_OK();
1267
}
1268
1269
bool DeallocPBackgroundLocalStorageCacheParent(
1270
PBackgroundLocalStorageCacheParent* aActor) {
1271
AssertIsOnBackgroundThread();
1272
MOZ_ASSERT(aActor);
1273
1274
// Transfer ownership back from IPDL.
1275
RefPtr<LocalStorageCacheParent> actor =
1276
dont_AddRef(static_cast<LocalStorageCacheParent*>(aActor));
1277
1278
return true;
1279
}
1280
1281
PBackgroundStorageParent* AllocPBackgroundStorageParent(
1282
const nsString& aProfilePath) {
1283
AssertIsOnBackgroundThread();
1284
1285
return new StorageDBParent(aProfilePath);
1286
}
1287
1288
mozilla::ipc::IPCResult RecvPBackgroundStorageConstructor(
1289
PBackgroundStorageParent* aActor, const nsString& aProfilePath) {
1290
AssertIsOnBackgroundThread();
1291
MOZ_ASSERT(aActor);
1292
1293
auto* actor = static_cast<StorageDBParent*>(aActor);
1294
actor->Init();
1295
return IPC_OK();
1296
}
1297
1298
bool DeallocPBackgroundStorageParent(PBackgroundStorageParent* aActor) {
1299
AssertIsOnBackgroundThread();
1300
MOZ_ASSERT(aActor);
1301
1302
StorageDBParent* actor = static_cast<StorageDBParent*>(aActor);
1303
actor->ReleaseIPDLReference();
1304
return true;
1305
}
1306
1307
PSessionStorageObserverParent* AllocPSessionStorageObserverParent() {
1308
MOZ_ASSERT(NS_IsMainThread());
1309
1310
RefPtr<SessionStorageObserverParent> actor =
1311
new SessionStorageObserverParent();
1312
1313
// Transfer ownership to IPDL.
1314
return actor.forget().take();
1315
}
1316
1317
bool RecvPSessionStorageObserverConstructor(
1318
PSessionStorageObserverParent* aActor) {
1319
MOZ_ASSERT(NS_IsMainThread());
1320
MOZ_ASSERT(aActor);
1321
1322
return true;
1323
}
1324
1325
bool DeallocPSessionStorageObserverParent(
1326
PSessionStorageObserverParent* aActor) {
1327
MOZ_ASSERT(NS_IsMainThread());
1328
MOZ_ASSERT(aActor);
1329
1330
// Transfer ownership back from IPDL.
1331
RefPtr<SessionStorageObserverParent> actor =
1332
dont_AddRef(static_cast<SessionStorageObserverParent*>(aActor));
1333
1334
return true;
1335
}
1336
1337
} // namespace dom
1338
} // namespace mozilla