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 "DOMStorageIPC.h"
8
9 #include "DOMStorageManager.h"
10
11 #include "mozilla/dom/ContentChild.h"
12 #include "mozilla/dom/ContentParent.h"
13 #include "mozilla/Unused.h"
14 #include "nsIDiskSpaceWatcher.h"
15 #include "nsThreadUtils.h"
16
17 namespace mozilla {
18 namespace dom {
19
20 // ----------------------------------------------------------------------------
21 // Child
22 // ----------------------------------------------------------------------------
23
24 NS_IMPL_ADDREF(DOMStorageDBChild)
25
NS_IMETHODIMP_(MozExternalRefCountType)26 NS_IMETHODIMP_(MozExternalRefCountType) DOMStorageDBChild::Release(void)
27 {
28 NS_PRECONDITION(0 != mRefCnt, "dup release");
29 nsrefcnt count = --mRefCnt;
30 NS_LOG_RELEASE(this, count, "DOMStorageDBChild");
31 if (count == 1 && mIPCOpen) {
32 Send__delete__(this);
33 return 0;
34 }
35 if (count == 0) {
36 mRefCnt = 1;
37 delete this;
38 return 0;
39 }
40 return count;
41 }
42
43 void
AddIPDLReference()44 DOMStorageDBChild::AddIPDLReference()
45 {
46 MOZ_ASSERT(!mIPCOpen, "Attempting to retain multiple IPDL references");
47 mIPCOpen = true;
48 AddRef();
49 }
50
51 void
ReleaseIPDLReference()52 DOMStorageDBChild::ReleaseIPDLReference()
53 {
54 MOZ_ASSERT(mIPCOpen, "Attempting to release non-existent IPDL reference");
55 mIPCOpen = false;
56 Release();
57 }
58
DOMStorageDBChild(DOMLocalStorageManager * aManager)59 DOMStorageDBChild::DOMStorageDBChild(DOMLocalStorageManager* aManager)
60 : mManager(aManager)
61 , mStatus(NS_OK)
62 , mIPCOpen(false)
63 {
64 }
65
~DOMStorageDBChild()66 DOMStorageDBChild::~DOMStorageDBChild()
67 {
68 }
69
70 nsTHashtable<nsCStringHashKey>&
OriginsHavingData()71 DOMStorageDBChild::OriginsHavingData()
72 {
73 if (!mOriginsHavingData) {
74 mOriginsHavingData = new nsTHashtable<nsCStringHashKey>;
75 }
76
77 return *mOriginsHavingData;
78 }
79
80 nsresult
Init()81 DOMStorageDBChild::Init()
82 {
83 ContentChild* child = ContentChild::GetSingleton();
84 AddIPDLReference();
85 child->SendPStorageConstructor(this);
86 return NS_OK;
87 }
88
89 nsresult
Shutdown()90 DOMStorageDBChild::Shutdown()
91 {
92 // There is nothing to do here, IPC will release automatically and
93 // the actual thread running on the parent process will also stop
94 // automatically in profile-before-change topic observer.
95 return NS_OK;
96 }
97
98 void
AsyncPreload(DOMStorageCacheBridge * aCache,bool aPriority)99 DOMStorageDBChild::AsyncPreload(DOMStorageCacheBridge* aCache, bool aPriority)
100 {
101 if (mIPCOpen) {
102 // Adding ref to cache for the time of preload. This ensures a reference to
103 // to the cache and that all keys will load into this cache object.
104 mLoadingCaches.PutEntry(aCache);
105 SendAsyncPreload(aCache->OriginSuffix(), aCache->OriginNoSuffix(), aPriority);
106 } else {
107 // No IPC, no love. But the LoadDone call is expected.
108 aCache->LoadDone(NS_ERROR_UNEXPECTED);
109 }
110 }
111
112 void
AsyncGetUsage(DOMStorageUsageBridge * aUsage)113 DOMStorageDBChild::AsyncGetUsage(DOMStorageUsageBridge* aUsage)
114 {
115 if (mIPCOpen) {
116 SendAsyncGetUsage(aUsage->OriginScope());
117 }
118 }
119
120 void
SyncPreload(DOMStorageCacheBridge * aCache,bool aForceSync)121 DOMStorageDBChild::SyncPreload(DOMStorageCacheBridge* aCache, bool aForceSync)
122 {
123 if (NS_FAILED(mStatus)) {
124 aCache->LoadDone(mStatus);
125 return;
126 }
127
128 if (!mIPCOpen) {
129 aCache->LoadDone(NS_ERROR_UNEXPECTED);
130 return;
131 }
132
133 // There is no way to put the child process to a wait state to receive all
134 // incoming async responses from the parent, hence we have to do a sync preload
135 // instead. We are smart though, we only demand keys that are left to load in
136 // case the async preload has already loaded some keys.
137 InfallibleTArray<nsString> keys, values;
138 nsresult rv;
139 SendPreload(aCache->OriginSuffix(), aCache->OriginNoSuffix(), aCache->LoadedCount(),
140 &keys, &values, &rv);
141
142 for (uint32_t i = 0; i < keys.Length(); ++i) {
143 aCache->LoadItem(keys[i], values[i]);
144 }
145
146 aCache->LoadDone(rv);
147 }
148
149 nsresult
AsyncAddItem(DOMStorageCacheBridge * aCache,const nsAString & aKey,const nsAString & aValue)150 DOMStorageDBChild::AsyncAddItem(DOMStorageCacheBridge* aCache,
151 const nsAString& aKey,
152 const nsAString& aValue)
153 {
154 if (NS_FAILED(mStatus) || !mIPCOpen) {
155 return mStatus;
156 }
157
158 SendAsyncAddItem(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
159 nsString(aKey), nsString(aValue));
160 OriginsHavingData().PutEntry(aCache->Origin());
161 return NS_OK;
162 }
163
164 nsresult
AsyncUpdateItem(DOMStorageCacheBridge * aCache,const nsAString & aKey,const nsAString & aValue)165 DOMStorageDBChild::AsyncUpdateItem(DOMStorageCacheBridge* aCache,
166 const nsAString& aKey,
167 const nsAString& aValue)
168 {
169 if (NS_FAILED(mStatus) || !mIPCOpen) {
170 return mStatus;
171 }
172
173 SendAsyncUpdateItem(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
174 nsString(aKey), nsString(aValue));
175 OriginsHavingData().PutEntry(aCache->Origin());
176 return NS_OK;
177 }
178
179 nsresult
AsyncRemoveItem(DOMStorageCacheBridge * aCache,const nsAString & aKey)180 DOMStorageDBChild::AsyncRemoveItem(DOMStorageCacheBridge* aCache,
181 const nsAString& aKey)
182 {
183 if (NS_FAILED(mStatus) || !mIPCOpen) {
184 return mStatus;
185 }
186
187 SendAsyncRemoveItem(aCache->OriginSuffix(), aCache->OriginNoSuffix(),
188 nsString(aKey));
189 return NS_OK;
190 }
191
192 nsresult
AsyncClear(DOMStorageCacheBridge * aCache)193 DOMStorageDBChild::AsyncClear(DOMStorageCacheBridge* aCache)
194 {
195 if (NS_FAILED(mStatus) || !mIPCOpen) {
196 return mStatus;
197 }
198
199 SendAsyncClear(aCache->OriginSuffix(), aCache->OriginNoSuffix());
200 OriginsHavingData().RemoveEntry(aCache->Origin());
201 return NS_OK;
202 }
203
204 bool
ShouldPreloadOrigin(const nsACString & aOrigin)205 DOMStorageDBChild::ShouldPreloadOrigin(const nsACString& aOrigin)
206 {
207 // Return true if we didn't receive the origins list yet.
208 // I tend to rather preserve a bit of early-after-start performance
209 // than a bit of memory here.
210 return !mOriginsHavingData || mOriginsHavingData->Contains(aOrigin);
211 }
212
213 bool
RecvObserve(const nsCString & aTopic,const nsString & aOriginAttributesPattern,const nsCString & aOriginScope)214 DOMStorageDBChild::RecvObserve(const nsCString& aTopic,
215 const nsString& aOriginAttributesPattern,
216 const nsCString& aOriginScope)
217 {
218 DOMStorageObserver::Self()->Notify(
219 aTopic.get(), aOriginAttributesPattern, aOriginScope);
220 return true;
221 }
222
223 bool
RecvOriginsHavingData(nsTArray<nsCString> && aOrigins)224 DOMStorageDBChild::RecvOriginsHavingData(nsTArray<nsCString>&& aOrigins)
225 {
226 for (uint32_t i = 0; i < aOrigins.Length(); ++i) {
227 OriginsHavingData().PutEntry(aOrigins[i]);
228 }
229
230 return true;
231 }
232
233 bool
RecvLoadItem(const nsCString & aOriginSuffix,const nsCString & aOriginNoSuffix,const nsString & aKey,const nsString & aValue)234 DOMStorageDBChild::RecvLoadItem(const nsCString& aOriginSuffix,
235 const nsCString& aOriginNoSuffix,
236 const nsString& aKey,
237 const nsString& aValue)
238 {
239 DOMStorageCache* aCache = mManager->GetCache(aOriginSuffix, aOriginNoSuffix);
240 if (aCache) {
241 aCache->LoadItem(aKey, aValue);
242 }
243
244 return true;
245 }
246
247 bool
RecvLoadDone(const nsCString & aOriginSuffix,const nsCString & aOriginNoSuffix,const nsresult & aRv)248 DOMStorageDBChild::RecvLoadDone(const nsCString& aOriginSuffix,
249 const nsCString& aOriginNoSuffix,
250 const nsresult& aRv)
251 {
252 DOMStorageCache* aCache = mManager->GetCache(aOriginSuffix, aOriginNoSuffix);
253 if (aCache) {
254 aCache->LoadDone(aRv);
255
256 // Just drop reference to this cache now since the load is done.
257 mLoadingCaches.RemoveEntry(static_cast<DOMStorageCacheBridge*>(aCache));
258 }
259
260 return true;
261 }
262
263 bool
RecvLoadUsage(const nsCString & aOriginNoSuffix,const int64_t & aUsage)264 DOMStorageDBChild::RecvLoadUsage(const nsCString& aOriginNoSuffix, const int64_t& aUsage)
265 {
266 RefPtr<DOMStorageUsageBridge> scopeUsage = mManager->GetOriginUsage(aOriginNoSuffix);
267 scopeUsage->LoadUsage(aUsage);
268 return true;
269 }
270
271 bool
RecvError(const nsresult & aRv)272 DOMStorageDBChild::RecvError(const nsresult& aRv)
273 {
274 mStatus = aRv;
275 return true;
276 }
277
278 // ----------------------------------------------------------------------------
279 // Parent
280 // ----------------------------------------------------------------------------
281
282 NS_IMPL_ADDREF(DOMStorageDBParent)
NS_IMPL_RELEASE(DOMStorageDBParent)283 NS_IMPL_RELEASE(DOMStorageDBParent)
284
285 void
286 DOMStorageDBParent::AddIPDLReference()
287 {
288 MOZ_ASSERT(!mIPCOpen, "Attempting to retain multiple IPDL references");
289 mIPCOpen = true;
290 AddRef();
291 }
292
293 void
ReleaseIPDLReference()294 DOMStorageDBParent::ReleaseIPDLReference()
295 {
296 MOZ_ASSERT(mIPCOpen, "Attempting to release non-existent IPDL reference");
297 mIPCOpen = false;
298 Release();
299 }
300
301 namespace {
302
303 class SendInitialChildDataRunnable : public Runnable
304 {
305 public:
SendInitialChildDataRunnable(DOMStorageDBParent * aParent)306 explicit SendInitialChildDataRunnable(DOMStorageDBParent* aParent)
307 : mParent(aParent)
308 {}
309
310 private:
Run()311 NS_IMETHOD Run() override
312 {
313 if (!mParent->IPCOpen()) {
314 return NS_OK;
315 }
316
317 DOMStorageDBBridge* db = DOMStorageCache::GetDatabase();
318 if (db) {
319 InfallibleTArray<nsCString> scopes;
320 db->GetOriginsHavingData(&scopes);
321 mozilla::Unused << mParent->SendOriginsHavingData(scopes);
322 }
323
324 // We need to check if the device is in a low disk space situation, so
325 // we can forbid in that case any write in localStorage.
326 nsCOMPtr<nsIDiskSpaceWatcher> diskSpaceWatcher =
327 do_GetService("@mozilla.org/toolkit/disk-space-watcher;1");
328 if (!diskSpaceWatcher) {
329 return NS_OK;
330 }
331
332 bool lowDiskSpace = false;
333 diskSpaceWatcher->GetIsDiskFull(&lowDiskSpace);
334
335 if (lowDiskSpace) {
336 mozilla::Unused << mParent->SendObserve(
337 nsDependentCString("low-disk-space"), EmptyString(), EmptyCString());
338 }
339
340 return NS_OK;
341 }
342
343 RefPtr<DOMStorageDBParent> mParent;
344 };
345
346 } // namespace
347
DOMStorageDBParent()348 DOMStorageDBParent::DOMStorageDBParent()
349 : mIPCOpen(false)
350 {
351 DOMStorageObserver* observer = DOMStorageObserver::Self();
352 if (observer) {
353 observer->AddSink(this);
354 }
355
356 // We are always open by IPC only
357 AddIPDLReference();
358
359 // Cannot send directly from here since the channel
360 // is not completely built at this moment.
361 RefPtr<SendInitialChildDataRunnable> r =
362 new SendInitialChildDataRunnable(this);
363 NS_DispatchToCurrentThread(r);
364 }
365
~DOMStorageDBParent()366 DOMStorageDBParent::~DOMStorageDBParent()
367 {
368 DOMStorageObserver* observer = DOMStorageObserver::Self();
369 if (observer) {
370 observer->RemoveSink(this);
371 }
372 }
373
374 DOMStorageDBParent::CacheParentBridge*
NewCache(const nsACString & aOriginSuffix,const nsACString & aOriginNoSuffix)375 DOMStorageDBParent::NewCache(const nsACString& aOriginSuffix, const nsACString& aOriginNoSuffix)
376 {
377 return new CacheParentBridge(this, aOriginSuffix, aOriginNoSuffix);
378 }
379
380 void
ActorDestroy(ActorDestroyReason aWhy)381 DOMStorageDBParent::ActorDestroy(ActorDestroyReason aWhy)
382 {
383 // Implement me! Bug 1005169
384 }
385
386 bool
RecvAsyncPreload(const nsCString & aOriginSuffix,const nsCString & aOriginNoSuffix,const bool & aPriority)387 DOMStorageDBParent::RecvAsyncPreload(const nsCString& aOriginSuffix,
388 const nsCString& aOriginNoSuffix,
389 const bool& aPriority)
390 {
391 DOMStorageDBBridge* db = DOMStorageCache::StartDatabase();
392 if (!db) {
393 return false;
394 }
395
396 db->AsyncPreload(NewCache(aOriginSuffix, aOriginNoSuffix), aPriority);
397 return true;
398 }
399
400 bool
RecvAsyncGetUsage(const nsCString & aOriginNoSuffix)401 DOMStorageDBParent::RecvAsyncGetUsage(const nsCString& aOriginNoSuffix)
402 {
403 DOMStorageDBBridge* db = DOMStorageCache::StartDatabase();
404 if (!db) {
405 return false;
406 }
407
408 // The object releases it self in LoadUsage method
409 RefPtr<UsageParentBridge> usage = new UsageParentBridge(this, aOriginNoSuffix);
410 db->AsyncGetUsage(usage);
411 return true;
412 }
413
414 namespace {
415
416 // We need another implementation of DOMStorageCacheBridge to do
417 // synchronous IPC preload. This class just receives Load* notifications
418 // and fills the returning arguments of RecvPreload with the database
419 // values for us.
420 class SyncLoadCacheHelper : public DOMStorageCacheBridge
421 {
422 public:
SyncLoadCacheHelper(const nsCString & aOriginSuffix,const nsCString & aOriginNoSuffix,uint32_t aAlreadyLoadedCount,InfallibleTArray<nsString> * aKeys,InfallibleTArray<nsString> * aValues,nsresult * rv)423 SyncLoadCacheHelper(const nsCString& aOriginSuffix,
424 const nsCString& aOriginNoSuffix,
425 uint32_t aAlreadyLoadedCount,
426 InfallibleTArray<nsString>* aKeys,
427 InfallibleTArray<nsString>* aValues,
428 nsresult* rv)
429 : mMonitor("DOM Storage SyncLoad IPC")
430 , mSuffix(aOriginSuffix)
431 , mOrigin(aOriginNoSuffix)
432 , mKeys(aKeys)
433 , mValues(aValues)
434 , mRv(rv)
435 , mLoaded(false)
436 , mLoadedCount(aAlreadyLoadedCount)
437 {
438 // Precaution
439 *mRv = NS_ERROR_UNEXPECTED;
440 }
441
Origin() const442 virtual const nsCString Origin() const
443 {
444 return DOMStorageManager::CreateOrigin(mSuffix, mOrigin);
445 }
OriginNoSuffix() const446 virtual const nsCString& OriginNoSuffix() const { return mOrigin; }
OriginSuffix() const447 virtual const nsCString& OriginSuffix() const { return mSuffix; }
Loaded()448 virtual bool Loaded() { return mLoaded; }
LoadedCount()449 virtual uint32_t LoadedCount() { return mLoadedCount; }
LoadItem(const nsAString & aKey,const nsString & aValue)450 virtual bool LoadItem(const nsAString& aKey, const nsString& aValue)
451 {
452 // Called on the aCache background thread
453 MOZ_ASSERT(!mLoaded);
454 if (mLoaded) {
455 return false;
456 }
457
458 ++mLoadedCount;
459 mKeys->AppendElement(aKey);
460 mValues->AppendElement(aValue);
461 return true;
462 }
463
LoadDone(nsresult aRv)464 virtual void LoadDone(nsresult aRv)
465 {
466 // Called on the aCache background thread
467 MonitorAutoLock monitor(mMonitor);
468 MOZ_ASSERT(!mLoaded && mRv);
469 mLoaded = true;
470 if (mRv) {
471 *mRv = aRv;
472 mRv = nullptr;
473 }
474 monitor.Notify();
475 }
476
LoadWait()477 virtual void LoadWait()
478 {
479 // Called on the main thread, exits after LoadDone() call
480 MonitorAutoLock monitor(mMonitor);
481 while (!mLoaded) {
482 monitor.Wait();
483 }
484 }
485
486 private:
487 Monitor mMonitor;
488 nsCString mSuffix, mOrigin;
489 InfallibleTArray<nsString>* mKeys;
490 InfallibleTArray<nsString>* mValues;
491 nsresult* mRv;
492 bool mLoaded;
493 uint32_t mLoadedCount;
494 };
495
496 } // namespace
497
498 bool
RecvPreload(const nsCString & aOriginSuffix,const nsCString & aOriginNoSuffix,const uint32_t & aAlreadyLoadedCount,InfallibleTArray<nsString> * aKeys,InfallibleTArray<nsString> * aValues,nsresult * aRv)499 DOMStorageDBParent::RecvPreload(const nsCString& aOriginSuffix,
500 const nsCString& aOriginNoSuffix,
501 const uint32_t& aAlreadyLoadedCount,
502 InfallibleTArray<nsString>* aKeys,
503 InfallibleTArray<nsString>* aValues,
504 nsresult* aRv)
505 {
506 DOMStorageDBBridge* db = DOMStorageCache::StartDatabase();
507 if (!db) {
508 return false;
509 }
510
511 RefPtr<SyncLoadCacheHelper> cache(
512 new SyncLoadCacheHelper(aOriginSuffix, aOriginNoSuffix, aAlreadyLoadedCount, aKeys, aValues, aRv));
513
514 db->SyncPreload(cache, true);
515 return true;
516 }
517
518 bool
RecvAsyncAddItem(const nsCString & aOriginSuffix,const nsCString & aOriginNoSuffix,const nsString & aKey,const nsString & aValue)519 DOMStorageDBParent::RecvAsyncAddItem(const nsCString& aOriginSuffix,
520 const nsCString& aOriginNoSuffix,
521 const nsString& aKey,
522 const nsString& aValue)
523 {
524 DOMStorageDBBridge* db = DOMStorageCache::StartDatabase();
525 if (!db) {
526 return false;
527 }
528
529 nsresult rv = db->AsyncAddItem(NewCache(aOriginSuffix, aOriginNoSuffix), aKey, aValue);
530 if (NS_FAILED(rv) && mIPCOpen) {
531 mozilla::Unused << SendError(rv);
532 }
533
534 return true;
535 }
536
537 bool
RecvAsyncUpdateItem(const nsCString & aOriginSuffix,const nsCString & aOriginNoSuffix,const nsString & aKey,const nsString & aValue)538 DOMStorageDBParent::RecvAsyncUpdateItem(const nsCString& aOriginSuffix,
539 const nsCString& aOriginNoSuffix,
540 const nsString& aKey,
541 const nsString& aValue)
542 {
543 DOMStorageDBBridge* db = DOMStorageCache::StartDatabase();
544 if (!db) {
545 return false;
546 }
547
548 nsresult rv = db->AsyncUpdateItem(NewCache(aOriginSuffix, aOriginNoSuffix), aKey, aValue);
549 if (NS_FAILED(rv) && mIPCOpen) {
550 mozilla::Unused << SendError(rv);
551 }
552
553 return true;
554 }
555
556 bool
RecvAsyncRemoveItem(const nsCString & aOriginSuffix,const nsCString & aOriginNoSuffix,const nsString & aKey)557 DOMStorageDBParent::RecvAsyncRemoveItem(const nsCString& aOriginSuffix,
558 const nsCString& aOriginNoSuffix,
559 const nsString& aKey)
560 {
561 DOMStorageDBBridge* db = DOMStorageCache::StartDatabase();
562 if (!db) {
563 return false;
564 }
565
566 nsresult rv = db->AsyncRemoveItem(NewCache(aOriginSuffix, aOriginNoSuffix), aKey);
567 if (NS_FAILED(rv) && mIPCOpen) {
568 mozilla::Unused << SendError(rv);
569 }
570
571 return true;
572 }
573
574 bool
RecvAsyncClear(const nsCString & aOriginSuffix,const nsCString & aOriginNoSuffix)575 DOMStorageDBParent::RecvAsyncClear(const nsCString& aOriginSuffix,
576 const nsCString& aOriginNoSuffix)
577 {
578 DOMStorageDBBridge* db = DOMStorageCache::StartDatabase();
579 if (!db) {
580 return false;
581 }
582
583 nsresult rv = db->AsyncClear(NewCache(aOriginSuffix, aOriginNoSuffix));
584 if (NS_FAILED(rv) && mIPCOpen) {
585 mozilla::Unused << SendError(rv);
586 }
587
588 return true;
589 }
590
591 bool
RecvAsyncFlush()592 DOMStorageDBParent::RecvAsyncFlush()
593 {
594 DOMStorageDBBridge* db = DOMStorageCache::GetDatabase();
595 if (!db) {
596 return false;
597 }
598
599 db->AsyncFlush();
600 return true;
601 }
602
603 // DOMStorageObserverSink
604
605 nsresult
Observe(const char * aTopic,const nsAString & aOriginAttributesPattern,const nsACString & aOriginScope)606 DOMStorageDBParent::Observe(const char* aTopic,
607 const nsAString& aOriginAttributesPattern,
608 const nsACString& aOriginScope)
609 {
610 if (mIPCOpen) {
611 mozilla::Unused << SendObserve(nsDependentCString(aTopic),
612 nsString(aOriginAttributesPattern),
613 nsCString(aOriginScope));
614 }
615
616 return NS_OK;
617 }
618
619 namespace {
620
621 // Results must be sent back on the main thread
622 class LoadRunnable : public Runnable
623 {
624 public:
625 enum TaskType {
626 loadItem,
627 loadDone
628 };
629
LoadRunnable(DOMStorageDBParent * aParent,TaskType aType,const nsACString & aOriginSuffix,const nsACString & aOriginNoSuffix,const nsAString & aKey=EmptyString (),const nsAString & aValue=EmptyString ())630 LoadRunnable(DOMStorageDBParent* aParent,
631 TaskType aType,
632 const nsACString& aOriginSuffix,
633 const nsACString& aOriginNoSuffix,
634 const nsAString& aKey = EmptyString(),
635 const nsAString& aValue = EmptyString())
636 : mParent(aParent)
637 , mType(aType)
638 , mSuffix(aOriginSuffix)
639 , mOrigin(aOriginNoSuffix)
640 , mKey(aKey)
641 , mValue(aValue)
642 { }
643
LoadRunnable(DOMStorageDBParent * aParent,TaskType aType,const nsACString & aOriginSuffix,const nsACString & aOriginNoSuffix,nsresult aRv)644 LoadRunnable(DOMStorageDBParent* aParent,
645 TaskType aType,
646 const nsACString& aOriginSuffix,
647 const nsACString& aOriginNoSuffix,
648 nsresult aRv)
649 : mParent(aParent)
650 , mType(aType)
651 , mSuffix(aOriginSuffix)
652 , mOrigin(aOriginNoSuffix)
653 , mRv(aRv)
654 { }
655
656 private:
657 RefPtr<DOMStorageDBParent> mParent;
658 TaskType mType;
659 nsCString mSuffix, mOrigin;
660 nsString mKey;
661 nsString mValue;
662 nsresult mRv;
663
Run()664 NS_IMETHOD Run() override
665 {
666 if (!mParent->IPCOpen()) {
667 return NS_OK;
668 }
669
670 switch (mType)
671 {
672 case loadItem:
673 mozilla::Unused << mParent->SendLoadItem(mSuffix, mOrigin, mKey, mValue);
674 break;
675 case loadDone:
676 mozilla::Unused << mParent->SendLoadDone(mSuffix, mOrigin, mRv);
677 break;
678 }
679
680 return NS_OK;
681 }
682 };
683
684 } // namespace
685
686 // DOMStorageDBParent::CacheParentBridge
687
688 const nsCString
Origin() const689 DOMStorageDBParent::CacheParentBridge::Origin() const
690 {
691 return DOMStorageManager::CreateOrigin(mOriginSuffix, mOriginNoSuffix);
692 }
693
694 bool
LoadItem(const nsAString & aKey,const nsString & aValue)695 DOMStorageDBParent::CacheParentBridge::LoadItem(const nsAString& aKey, const nsString& aValue)
696 {
697 if (mLoaded) {
698 return false;
699 }
700
701 ++mLoadedCount;
702
703 RefPtr<LoadRunnable> r =
704 new LoadRunnable(mParent, LoadRunnable::loadItem, mOriginSuffix, mOriginNoSuffix, aKey, aValue);
705 NS_DispatchToMainThread(r);
706 return true;
707 }
708
709 void
LoadDone(nsresult aRv)710 DOMStorageDBParent::CacheParentBridge::LoadDone(nsresult aRv)
711 {
712 // Prevent send of duplicate LoadDone.
713 if (mLoaded) {
714 return;
715 }
716
717 mLoaded = true;
718
719 RefPtr<LoadRunnable> r =
720 new LoadRunnable(mParent, LoadRunnable::loadDone, mOriginSuffix, mOriginNoSuffix, aRv);
721 NS_DispatchToMainThread(r);
722 }
723
724 void
LoadWait()725 DOMStorageDBParent::CacheParentBridge::LoadWait()
726 {
727 // Should never be called on this implementation
728 MOZ_ASSERT(false);
729 }
730
731 // DOMStorageDBParent::UsageParentBridge
732
733 namespace {
734
735 class UsageRunnable : public Runnable
736 {
737 public:
UsageRunnable(DOMStorageDBParent * aParent,const nsACString & aOriginScope,const int64_t & aUsage)738 UsageRunnable(DOMStorageDBParent* aParent, const nsACString& aOriginScope, const int64_t& aUsage)
739 : mParent(aParent)
740 , mOriginScope(aOriginScope)
741 , mUsage(aUsage)
742 {}
743
744 private:
Run()745 NS_IMETHOD Run() override
746 {
747 if (!mParent->IPCOpen()) {
748 return NS_OK;
749 }
750
751 mozilla::Unused << mParent->SendLoadUsage(mOriginScope, mUsage);
752 return NS_OK;
753 }
754
755 RefPtr<DOMStorageDBParent> mParent;
756 nsCString mOriginScope;
757 int64_t mUsage;
758 };
759
760 } // namespace
761
762 void
LoadUsage(const int64_t aUsage)763 DOMStorageDBParent::UsageParentBridge::LoadUsage(const int64_t aUsage)
764 {
765 RefPtr<UsageRunnable> r = new UsageRunnable(mParent, mOriginScope, aUsage);
766 NS_DispatchToMainThread(r);
767 }
768
769 } // namespace dom
770 } // namespace mozilla
771