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