Bug 1700051: part 35) Reduce accessibility of `mSoftText.mDOMMapping` to `private...
[gecko.git] / dom / quota / StorageManager.cpp
blob152e097a1ec4a659a3e1af5ecf597ebc58655918
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 file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "StorageManager.h"
9 #include <cstdint>
10 #include <cstdlib>
11 #include <utility>
12 #include "ErrorList.h"
13 #include "MainThreadUtils.h"
14 #include "js/CallArgs.h"
15 #include "js/TypeDecls.h"
16 #include "mozilla/Attributes.h"
17 #include "mozilla/ErrorResult.h"
18 #include "mozilla/MacroForEach.h"
19 #include "mozilla/Maybe.h"
20 #include "mozilla/Mutex.h"
21 #include "mozilla/RefPtr.h"
22 #include "mozilla/Telemetry.h"
23 #include "mozilla/TelemetryScalarEnums.h"
24 #include "mozilla/dom/BindingDeclarations.h"
25 #include "mozilla/dom/Document.h"
26 #include "mozilla/dom/Promise.h"
27 #include "mozilla/dom/PromiseWorkerProxy.h"
28 #include "mozilla/dom/StorageManagerBinding.h"
29 #include "mozilla/dom/WorkerCommon.h"
30 #include "mozilla/dom/WorkerPrivate.h"
31 #include "mozilla/dom/WorkerRunnable.h"
32 #include "mozilla/dom/WorkerStatus.h"
33 #include "mozilla/dom/quota/QuotaManagerService.h"
34 #include "nsContentPermissionHelper.h"
35 #include "nsContentUtils.h"
36 #include "nsDebug.h"
37 #include "nsError.h"
38 #include "nsIGlobalObject.h"
39 #include "nsIPrincipal.h"
40 #include "nsIQuotaCallbacks.h"
41 #include "nsIQuotaManagerService.h"
42 #include "nsIQuotaRequests.h"
43 #include "nsIQuotaResults.h"
44 #include "nsIVariant.h"
45 #include "nsLiteralString.h"
46 #include "nsPIDOMWindow.h"
47 #include "nsString.h"
48 #include "nsStringFlags.h"
49 #include "nsTLiteralString.h"
50 #include "nscore.h"
52 class JSObject;
53 struct JSContext;
54 struct nsID;
56 namespace mozilla {
57 class Runnable;
60 using namespace mozilla::dom::quota;
62 namespace mozilla::dom {
64 namespace {
66 // This class is used to get quota usage, request persist and check persisted
67 // status callbacks.
68 class RequestResolver final : public nsIQuotaCallback {
69 public:
70 enum Type { Estimate, Persist, Persisted };
72 private:
73 class FinishWorkerRunnable;
75 // If this resolver was created for a window then mPromise must be non-null.
76 // Otherwise mProxy must be non-null.
77 RefPtr<Promise> mPromise;
78 RefPtr<PromiseWorkerProxy> mProxy;
80 nsresult mResultCode;
81 StorageEstimate mStorageEstimate;
82 const Type mType;
83 bool mPersisted;
85 public:
86 RequestResolver(Type aType, Promise* aPromise)
87 : mPromise(aPromise),
88 mResultCode(NS_OK),
89 mType(aType),
90 mPersisted(false) {
91 MOZ_ASSERT(NS_IsMainThread());
92 MOZ_ASSERT(aPromise);
95 RequestResolver(Type aType, PromiseWorkerProxy* aProxy)
96 : mProxy(aProxy), mResultCode(NS_OK), mType(aType), mPersisted(false) {
97 MOZ_ASSERT(NS_IsMainThread());
98 MOZ_ASSERT(aProxy);
101 void ResolveOrReject();
103 NS_DECL_THREADSAFE_ISUPPORTS
104 NS_DECL_NSIQUOTACALLBACK
106 private:
107 ~RequestResolver() = default;
109 nsresult GetStorageEstimate(nsIVariant* aResult);
111 nsresult GetPersisted(nsIVariant* aResult);
113 nsresult OnCompleteInternal(nsIQuotaRequest* aRequest);
115 nsresult Finish();
118 // This class is used to return promise on worker thread.
119 class RequestResolver::FinishWorkerRunnable final : public WorkerRunnable {
120 RefPtr<RequestResolver> mResolver;
122 public:
123 explicit FinishWorkerRunnable(RequestResolver* aResolver)
124 : WorkerRunnable(aResolver->mProxy->GetWorkerPrivate()),
125 mResolver(aResolver) {
126 MOZ_ASSERT(NS_IsMainThread());
127 MOZ_ASSERT(aResolver);
130 bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override;
133 class EstimateWorkerMainThreadRunnable final : public WorkerMainThreadRunnable {
134 RefPtr<PromiseWorkerProxy> mProxy;
136 public:
137 EstimateWorkerMainThreadRunnable(WorkerPrivate* aWorkerPrivate,
138 PromiseWorkerProxy* aProxy)
139 : WorkerMainThreadRunnable(aWorkerPrivate,
140 "StorageManager :: Estimate"_ns),
141 mProxy(aProxy) {
142 MOZ_ASSERT(aWorkerPrivate);
143 aWorkerPrivate->AssertIsOnWorkerThread();
144 MOZ_ASSERT(aProxy);
147 bool MainThreadRun() override;
150 class PersistedWorkerMainThreadRunnable final
151 : public WorkerMainThreadRunnable {
152 RefPtr<PromiseWorkerProxy> mProxy;
154 public:
155 PersistedWorkerMainThreadRunnable(WorkerPrivate* aWorkerPrivate,
156 PromiseWorkerProxy* aProxy)
157 : WorkerMainThreadRunnable(aWorkerPrivate,
158 "StorageManager :: Persisted"_ns),
159 mProxy(aProxy) {
160 MOZ_ASSERT(aWorkerPrivate);
161 aWorkerPrivate->AssertIsOnWorkerThread();
162 MOZ_ASSERT(aProxy);
165 bool MainThreadRun() override;
168 /*******************************************************************************
169 * PersistentStoragePermissionRequest
170 ******************************************************************************/
172 class PersistentStoragePermissionRequest final
173 : public ContentPermissionRequestBase {
174 RefPtr<Promise> mPromise;
176 public:
177 PersistentStoragePermissionRequest(nsIPrincipal* aPrincipal,
178 nsPIDOMWindowInner* aWindow,
179 Promise* aPromise)
180 : ContentPermissionRequestBase(aPrincipal, aWindow,
181 "dom.storageManager"_ns,
182 "persistent-storage"_ns),
183 mPromise(aPromise) {
184 MOZ_ASSERT(aWindow);
185 MOZ_ASSERT(aPromise);
188 nsresult Start();
190 NS_DECL_ISUPPORTS_INHERITED
191 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(PersistentStoragePermissionRequest,
192 ContentPermissionRequestBase)
194 // nsIContentPermissionRequest
195 NS_IMETHOD Cancel(void) override;
196 NS_IMETHOD Allow(JS::HandleValue choices) override;
198 private:
199 ~PersistentStoragePermissionRequest() = default;
202 nsresult Estimate(nsIPrincipal* aPrincipal, nsIQuotaCallback* aCallback,
203 nsIQuotaRequest** aRequest) {
204 MOZ_ASSERT(aPrincipal);
205 MOZ_ASSERT(aCallback);
206 MOZ_ASSERT(aRequest);
208 // Firefox and Quota Manager have always used the schemeless origin group
209 // (https://storage.spec.whatwg.org/#schemeless-origin-group) for quota limit
210 // purposes. This has been to prevent a site/eTLD+1 from claiming more than
211 // its fair share of storage through the use of sub-domains. Because the limit
212 // is at the group level and the usage needs to make sense in the context of
213 // that limit, we also expose the group usage. Bug 1374970 reflects this
214 // reality and bug 1305665 tracks our plan to eliminate our use of groups for
215 // this.
217 nsCOMPtr<nsIQuotaManagerService> qms = QuotaManagerService::GetOrCreate();
218 if (NS_WARN_IF(!qms)) {
219 return NS_ERROR_FAILURE;
222 nsCOMPtr<nsIQuotaRequest> request;
223 nsresult rv = qms->Estimate(aPrincipal, getter_AddRefs(request));
224 if (NS_WARN_IF(NS_FAILED(rv))) {
225 return rv;
228 MOZ_ALWAYS_SUCCEEDS(request->SetCallback(aCallback));
230 request.forget(aRequest);
231 return NS_OK;
234 nsresult Persisted(nsIPrincipal* aPrincipal, nsIQuotaCallback* aCallback,
235 nsIQuotaRequest** aRequest) {
236 MOZ_ASSERT(aPrincipal);
237 MOZ_ASSERT(aCallback);
238 MOZ_ASSERT(aRequest);
240 nsCOMPtr<nsIQuotaManagerService> qms = QuotaManagerService::GetOrCreate();
241 if (NS_WARN_IF(!qms)) {
242 return NS_ERROR_FAILURE;
245 nsCOMPtr<nsIQuotaRequest> request;
246 nsresult rv = qms->Persisted(aPrincipal, getter_AddRefs(request));
247 if (NS_WARN_IF(NS_FAILED(rv))) {
248 return rv;
251 // All the methods in nsIQuotaManagerService shouldn't synchronously fire
252 // any callbacks when they are being executed. Even when a result is ready,
253 // a new runnable should be dispatched to current thread to fire the callback
254 // asynchronously. It's safe to set the callback after we call Persisted().
255 MOZ_ALWAYS_SUCCEEDS(request->SetCallback(aCallback));
257 request.forget(aRequest);
259 return NS_OK;
262 already_AddRefed<Promise> ExecuteOpOnMainOrWorkerThread(
263 nsIGlobalObject* aGlobal, RequestResolver::Type aType, ErrorResult& aRv) {
264 MOZ_ASSERT(aGlobal);
265 MOZ_ASSERT_IF(aType == RequestResolver::Type::Persist, NS_IsMainThread());
267 RefPtr<Promise> promise = Promise::Create(aGlobal, aRv);
268 if (NS_WARN_IF(!promise)) {
269 return nullptr;
272 if (NS_IsMainThread()) {
273 nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
274 if (NS_WARN_IF(!window)) {
275 aRv.Throw(NS_ERROR_FAILURE);
276 return nullptr;
279 nsCOMPtr<Document> doc = window->GetExtantDoc();
280 if (NS_WARN_IF(!doc)) {
281 aRv.Throw(NS_ERROR_FAILURE);
282 return nullptr;
285 nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal();
286 MOZ_ASSERT(principal);
288 // Storage Standard 7. API
289 // If origin is an opaque origin, then reject promise with a TypeError.
290 if (principal->GetIsNullPrincipal()) {
291 switch (aType) {
292 case RequestResolver::Type::Persisted:
293 promise->MaybeRejectWithTypeError(
294 "persisted() called for opaque origin");
295 break;
296 case RequestResolver::Type::Persist:
297 promise->MaybeRejectWithTypeError(
298 "persist() called for opaque origin");
299 break;
300 case RequestResolver::Type::Estimate:
301 promise->MaybeRejectWithTypeError(
302 "estimate() called for opaque origin");
303 break;
306 return promise.forget();
309 switch (aType) {
310 case RequestResolver::Type::Persisted: {
311 RefPtr<RequestResolver> resolver =
312 new RequestResolver(RequestResolver::Type::Persisted, promise);
314 RefPtr<nsIQuotaRequest> request;
315 aRv = Persisted(principal, resolver, getter_AddRefs(request));
317 break;
320 case RequestResolver::Type::Persist: {
321 RefPtr<PersistentStoragePermissionRequest> request =
322 new PersistentStoragePermissionRequest(principal, window, promise);
324 // In private browsing mode, no permission prompt.
325 if (nsContentUtils::IsInPrivateBrowsing(doc)) {
326 aRv = request->Cancel();
327 } else if (!request->CheckPermissionDelegate()) {
328 aRv = request->Cancel();
329 } else {
330 aRv = request->Start();
333 break;
336 case RequestResolver::Type::Estimate: {
337 RefPtr<RequestResolver> resolver =
338 new RequestResolver(RequestResolver::Type::Estimate, promise);
340 RefPtr<nsIQuotaRequest> request;
341 aRv = Estimate(principal, resolver, getter_AddRefs(request));
343 break;
346 default:
347 MOZ_CRASH("Invalid aRequest type!");
350 if (NS_WARN_IF(aRv.Failed())) {
351 return nullptr;
354 return promise.forget();
357 WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
358 MOZ_ASSERT(workerPrivate);
360 RefPtr<PromiseWorkerProxy> promiseProxy =
361 PromiseWorkerProxy::Create(workerPrivate, promise);
362 if (NS_WARN_IF(!promiseProxy)) {
363 return nullptr;
366 switch (aType) {
367 case RequestResolver::Type::Estimate: {
368 RefPtr<EstimateWorkerMainThreadRunnable> runnnable =
369 new EstimateWorkerMainThreadRunnable(promiseProxy->GetWorkerPrivate(),
370 promiseProxy);
371 runnnable->Dispatch(Canceling, aRv);
373 break;
376 case RequestResolver::Type::Persisted: {
377 RefPtr<PersistedWorkerMainThreadRunnable> runnnable =
378 new PersistedWorkerMainThreadRunnable(
379 promiseProxy->GetWorkerPrivate(), promiseProxy);
380 runnnable->Dispatch(Canceling, aRv);
382 break;
385 default:
386 MOZ_CRASH("Invalid aRequest type");
389 if (NS_WARN_IF(aRv.Failed())) {
390 return nullptr;
393 return promise.forget();
396 } // namespace
398 /*******************************************************************************
399 * Local class implementations
400 ******************************************************************************/
402 void RequestResolver::ResolveOrReject() {
403 class MOZ_STACK_CLASS AutoCleanup final {
404 RefPtr<PromiseWorkerProxy> mProxy;
406 public:
407 explicit AutoCleanup(PromiseWorkerProxy* aProxy) : mProxy(aProxy) {
408 MOZ_ASSERT(aProxy);
411 ~AutoCleanup() {
412 MOZ_ASSERT(mProxy);
414 mProxy->CleanUp();
418 RefPtr<Promise> promise;
419 Maybe<AutoCleanup> autoCleanup;
421 if (mPromise) {
422 promise = mPromise;
423 } else {
424 MOZ_ASSERT(mProxy);
426 promise = mProxy->WorkerPromise();
428 // Only clean up for worker case.
429 autoCleanup.emplace(mProxy);
432 MOZ_ASSERT(promise);
434 if (mType == Type::Estimate) {
435 if (NS_SUCCEEDED(mResultCode)) {
436 promise->MaybeResolve(mStorageEstimate);
437 } else {
438 promise->MaybeRejectWithTypeError(
439 "Internal error while estimating storage usage");
442 return;
445 MOZ_ASSERT(mType == Type::Persist || mType == Type::Persisted);
447 if (NS_SUCCEEDED(mResultCode)) {
448 promise->MaybeResolve(mPersisted);
449 } else {
450 promise->MaybeResolve(false);
454 NS_IMPL_ISUPPORTS(RequestResolver, nsIQuotaCallback)
456 nsresult RequestResolver::GetStorageEstimate(nsIVariant* aResult) {
457 MOZ_ASSERT(aResult);
458 MOZ_ASSERT(mType == Type::Estimate);
460 MOZ_ASSERT(aResult->GetDataType() == nsIDataType::VTYPE_INTERFACE_IS);
462 nsID* iid;
463 nsCOMPtr<nsISupports> supports;
464 nsresult rv = aResult->GetAsInterface(&iid, getter_AddRefs(supports));
465 if (NS_WARN_IF(NS_FAILED(rv))) {
466 return rv;
469 free(iid);
471 nsCOMPtr<nsIQuotaEstimateResult> estimateResult = do_QueryInterface(supports);
472 MOZ_ASSERT(estimateResult);
474 MOZ_ALWAYS_SUCCEEDS(
475 estimateResult->GetUsage(&mStorageEstimate.mUsage.Construct()));
477 MOZ_ALWAYS_SUCCEEDS(
478 estimateResult->GetLimit(&mStorageEstimate.mQuota.Construct()));
480 return NS_OK;
483 nsresult RequestResolver::GetPersisted(nsIVariant* aResult) {
484 MOZ_ASSERT(aResult);
485 MOZ_ASSERT(mType == Type::Persist || mType == Type::Persisted);
487 #ifdef DEBUG
488 uint16_t dataType = aResult->GetDataType();
489 #endif
491 if (mType == Type::Persist) {
492 MOZ_ASSERT(dataType == nsIDataType::VTYPE_VOID);
494 mPersisted = true;
495 return NS_OK;
498 MOZ_ASSERT(dataType == nsIDataType::VTYPE_BOOL);
500 bool persisted;
501 nsresult rv = aResult->GetAsBool(&persisted);
502 if (NS_WARN_IF(NS_FAILED(rv))) {
503 return rv;
506 mPersisted = persisted;
507 return NS_OK;
510 nsresult RequestResolver::OnCompleteInternal(nsIQuotaRequest* aRequest) {
511 MOZ_ASSERT(NS_IsMainThread());
512 MOZ_ASSERT(aRequest);
514 nsresult resultCode;
515 nsresult rv = aRequest->GetResultCode(&resultCode);
516 if (NS_WARN_IF(NS_FAILED(rv))) {
517 return rv;
520 if (NS_FAILED(resultCode)) {
521 return resultCode;
524 nsCOMPtr<nsIVariant> result;
525 rv = aRequest->GetResult(getter_AddRefs(result));
526 if (NS_WARN_IF(NS_FAILED(rv))) {
527 return rv;
530 if (mType == Type::Estimate) {
531 rv = GetStorageEstimate(result);
532 } else {
533 MOZ_ASSERT(mType == Type::Persist || mType == Type::Persisted);
535 rv = GetPersisted(result);
537 if (NS_WARN_IF(NS_FAILED(rv))) {
538 return rv;
541 return NS_OK;
544 nsresult RequestResolver::Finish() {
545 // In a main thread request.
546 if (!mProxy) {
547 MOZ_ASSERT(mPromise);
549 ResolveOrReject();
550 return NS_OK;
554 // In a worker thread request.
555 MutexAutoLock lock(mProxy->Lock());
557 if (NS_WARN_IF(mProxy->CleanedUp())) {
558 return NS_ERROR_FAILURE;
561 RefPtr<FinishWorkerRunnable> runnable = new FinishWorkerRunnable(this);
562 if (NS_WARN_IF(!runnable->Dispatch())) {
563 return NS_ERROR_FAILURE;
567 return NS_OK;
570 NS_IMETHODIMP
571 RequestResolver::OnComplete(nsIQuotaRequest* aRequest) {
572 MOZ_ASSERT(NS_IsMainThread());
573 MOZ_ASSERT(aRequest);
575 mResultCode = OnCompleteInternal(aRequest);
577 nsresult rv = Finish();
578 if (NS_WARN_IF(NS_FAILED(rv))) {
579 return rv;
582 return NS_OK;
585 bool RequestResolver::FinishWorkerRunnable::WorkerRun(
586 JSContext* aCx, WorkerPrivate* aWorkerPrivate) {
587 MOZ_ASSERT(aCx);
588 MOZ_ASSERT(aWorkerPrivate);
589 aWorkerPrivate->AssertIsOnWorkerThread();
591 MOZ_ASSERT(mResolver);
592 mResolver->ResolveOrReject();
594 return true;
597 bool EstimateWorkerMainThreadRunnable::MainThreadRun() {
598 MOZ_ASSERT(NS_IsMainThread());
600 nsCOMPtr<nsIPrincipal> principal;
603 MutexAutoLock lock(mProxy->Lock());
604 if (mProxy->CleanedUp()) {
605 return true;
607 principal = mProxy->GetWorkerPrivate()->GetPrincipal();
610 MOZ_ASSERT(principal);
612 RefPtr<RequestResolver> resolver =
613 new RequestResolver(RequestResolver::Type::Estimate, mProxy);
615 RefPtr<nsIQuotaRequest> request;
616 nsresult rv = Estimate(principal, resolver, getter_AddRefs(request));
617 if (NS_WARN_IF(NS_FAILED(rv))) {
618 return false;
621 return true;
624 bool PersistedWorkerMainThreadRunnable::MainThreadRun() {
625 MOZ_ASSERT(NS_IsMainThread());
627 nsCOMPtr<nsIPrincipal> principal;
630 MutexAutoLock lock(mProxy->Lock());
631 if (mProxy->CleanedUp()) {
632 return true;
634 principal = mProxy->GetWorkerPrivate()->GetPrincipal();
637 MOZ_ASSERT(principal);
639 RefPtr<RequestResolver> resolver =
640 new RequestResolver(RequestResolver::Type::Persisted, mProxy);
642 RefPtr<nsIQuotaRequest> request;
643 nsresult rv = Persisted(principal, resolver, getter_AddRefs(request));
644 if (NS_WARN_IF(NS_FAILED(rv))) {
645 return false;
648 return true;
651 nsresult PersistentStoragePermissionRequest::Start() {
652 MOZ_ASSERT(NS_IsMainThread());
654 PromptResult pr;
655 #ifdef MOZ_WIDGET_ANDROID
656 // on Android calling `ShowPrompt` here calls
657 // `nsContentPermissionUtils::AskPermission` once, and a response of
658 // `PromptResult::Pending` calls it again. This results in multiple requests
659 // for storage access, so we check the prompt prefs only to ensure we only
660 // request it once.
661 pr = CheckPromptPrefs();
662 #else
663 nsresult rv = ShowPrompt(pr);
664 if (NS_WARN_IF(NS_FAILED(rv))) {
665 return rv;
667 #endif
668 if (pr == PromptResult::Granted) {
669 return Allow(JS::UndefinedHandleValue);
671 if (pr == PromptResult::Denied) {
672 return Cancel();
675 return nsContentPermissionUtils::AskPermission(this, mWindow);
678 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(
679 PersistentStoragePermissionRequest, ContentPermissionRequestBase)
681 NS_IMPL_CYCLE_COLLECTION_INHERITED(PersistentStoragePermissionRequest,
682 ContentPermissionRequestBase, mPromise)
684 NS_IMETHODIMP
685 PersistentStoragePermissionRequest::Cancel() {
686 MOZ_ASSERT(NS_IsMainThread());
687 MOZ_ASSERT(mPromise);
689 RefPtr<RequestResolver> resolver =
690 new RequestResolver(RequestResolver::Type::Persisted, mPromise);
692 RefPtr<nsIQuotaRequest> request;
694 return Persisted(mPrincipal, resolver, getter_AddRefs(request));
697 NS_IMETHODIMP
698 PersistentStoragePermissionRequest::Allow(JS::HandleValue aChoices) {
699 MOZ_ASSERT(NS_IsMainThread());
701 RefPtr<RequestResolver> resolver =
702 new RequestResolver(RequestResolver::Type::Persist, mPromise);
704 nsCOMPtr<nsIQuotaManagerService> qms = QuotaManagerService::GetOrCreate();
705 if (NS_WARN_IF(!qms)) {
706 return NS_ERROR_FAILURE;
709 RefPtr<nsIQuotaRequest> request;
711 nsresult rv = qms->Persist(mPrincipal, getter_AddRefs(request));
712 if (NS_WARN_IF(NS_FAILED(rv))) {
713 return rv;
716 MOZ_ALWAYS_SUCCEEDS(request->SetCallback(resolver));
718 return NS_OK;
721 /*******************************************************************************
722 * StorageManager
723 ******************************************************************************/
725 StorageManager::StorageManager(nsIGlobalObject* aGlobal) : mOwner(aGlobal) {
726 MOZ_ASSERT(aGlobal);
729 StorageManager::~StorageManager() = default;
731 already_AddRefed<Promise> StorageManager::Persisted(ErrorResult& aRv) {
732 MOZ_ASSERT(mOwner);
734 return ExecuteOpOnMainOrWorkerThread(mOwner, RequestResolver::Type::Persisted,
735 aRv);
738 already_AddRefed<Promise> StorageManager::Persist(ErrorResult& aRv) {
739 MOZ_ASSERT(mOwner);
741 Telemetry::ScalarAdd(Telemetry::ScalarID::NAVIGATOR_STORAGE_PERSIST_COUNT, 1);
742 return ExecuteOpOnMainOrWorkerThread(mOwner, RequestResolver::Type::Persist,
743 aRv);
746 already_AddRefed<Promise> StorageManager::Estimate(ErrorResult& aRv) {
747 MOZ_ASSERT(mOwner);
749 Telemetry::ScalarAdd(Telemetry::ScalarID::NAVIGATOR_STORAGE_ESTIMATE_COUNT,
751 return ExecuteOpOnMainOrWorkerThread(mOwner, RequestResolver::Type::Estimate,
752 aRv);
755 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(StorageManager, mOwner)
757 NS_IMPL_CYCLE_COLLECTING_ADDREF(StorageManager)
758 NS_IMPL_CYCLE_COLLECTING_RELEASE(StorageManager)
760 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StorageManager)
761 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
762 NS_INTERFACE_MAP_ENTRY(nsISupports)
763 NS_INTERFACE_MAP_END
765 JSObject* StorageManager::WrapObject(JSContext* aCx,
766 JS::Handle<JSObject*> aGivenProto) {
767 return StorageManager_Binding::Wrap(aCx, this, aGivenProto);
770 } // namespace mozilla::dom