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