# HG changeset patch # User Shawn Huang # Parent 9d45dba11d91b7184b969825e1fa56121e673f97 Bug 1286717 - Part 1: Expose persist/persisted to StorageManager, r=janv diff --git a/dom/quota/StorageManager.cpp b/dom/quota/StorageManager.cpp --- a/dom/quota/StorageManager.cpp +++ b/dom/quota/StorageManager.cpp @@ -6,241 +6,610 @@ #include "StorageManager.h" #include "mozilla/dom/PromiseWorkerProxy.h" #include "mozilla/dom/quota/QuotaManagerService.h" #include "mozilla/dom/StorageManagerBinding.h" #include "mozilla/dom/WorkerPrivate.h" #include "mozilla/ErrorResult.h" +#include "nsContentPermissionHelper.h" #include "nsIQuotaCallbacks.h" #include "nsIQuotaRequests.h" #include "nsPIDOMWindow.h" using namespace mozilla::dom::workers; namespace mozilla { namespace dom { namespace { -// This class is used to get quota usage callback. -class EstimateResolver final - : public nsIQuotaUsageCallback +// This class is used to get quota usage, request persist and check persisted +// status callbacks. +class RequestResolver final + : public nsIQuotaCallback + , public nsIQuotaUsageCallback { +public: + enum Type + { + Estimate, + Persist, + Persisted + }; + +private: class FinishWorkerRunnable; // If this resolver was created for a window then mPromise must be non-null. // Otherwise mProxy must be non-null. RefPtr mPromise; RefPtr mProxy; nsresult mResultCode; StorageEstimate mStorageEstimate; + const Type mType; + bool mPersisted; public: - explicit EstimateResolver(Promise* aPromise) + RequestResolver(Type aType, Promise* aPromise) : mPromise(aPromise) , mResultCode(NS_OK) + , mType(aType) + , mPersisted(false) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aPromise); } - explicit EstimateResolver(PromiseWorkerProxy* aProxy) + RequestResolver(Type aType, PromiseWorkerProxy* aProxy) : mProxy(aProxy) , mResultCode(NS_OK) + , mType(aType) + , mPersisted(false) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aProxy); } + Type + GetType() const + { + return mType; + } + void - ResolveOrReject(Promise* aPromise); + ResolveOrReject(); NS_DECL_THREADSAFE_ISUPPORTS - + NS_DECL_NSIQUOTACALLBACK NS_DECL_NSIQUOTAUSAGECALLBACK private: - ~EstimateResolver() + ~RequestResolver() { } + + nsresult + GetStorageEstimate(nsIVariant* aResult); + + nsresult + GetPersisted(nsIVariant* aResult); + + template + nsresult + OnCompleteOrUsageResult(T* aRequest); + + nsresult + Finish(); }; // This class is used to return promise on worker thread. -class EstimateResolver::FinishWorkerRunnable final +class RequestResolver::FinishWorkerRunnable final : public WorkerRunnable { - RefPtr mResolver; + RefPtr mResolver; public: - explicit FinishWorkerRunnable(EstimateResolver* aResolver) + explicit FinishWorkerRunnable(RequestResolver* aResolver) : WorkerRunnable(aResolver->mProxy->GetWorkerPrivate()) , mResolver(aResolver) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aResolver); } - virtual bool + bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override; }; -class EstimateWorkerMainThreadRunnable +class EstimateWorkerMainThreadRunnable final : public WorkerMainThreadRunnable { RefPtr mProxy; public: EstimateWorkerMainThreadRunnable(WorkerPrivate* aWorkerPrivate, PromiseWorkerProxy* aProxy) : WorkerMainThreadRunnable(aWorkerPrivate, NS_LITERAL_CSTRING("StorageManager :: Estimate")) , mProxy(aProxy) { MOZ_ASSERT(aWorkerPrivate); aWorkerPrivate->AssertIsOnWorkerThread(); MOZ_ASSERT(aProxy); } - virtual bool + bool MainThreadRun() override; }; +class PersistedWorkerMainThreadRunnable final + : public WorkerMainThreadRunnable +{ + RefPtr mProxy; + +public: + PersistedWorkerMainThreadRunnable(WorkerPrivate* aWorkerPrivate, + PromiseWorkerProxy* aProxy) + : WorkerMainThreadRunnable(aWorkerPrivate, + NS_LITERAL_CSTRING("StorageManager :: Persisted")) + , mProxy(aProxy) + { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + MOZ_ASSERT(aProxy); + } + + bool + MainThreadRun() override; +}; + +/******************************************************************************* + * PersistentStoragePermissionRequest + ******************************************************************************/ + +class PersistentStoragePermissionRequest final + : public nsIContentPermissionRequest +{ + nsCOMPtr mPrincipal; + nsCOMPtr mWindow; + RefPtr mPromise; + nsCOMPtr mRequester; + +public: + PersistentStoragePermissionRequest(nsIPrincipal* aPrincipal, + nsPIDOMWindowInner* aWindow, + Promise* aPromise) + : mPrincipal(aPrincipal) + , mWindow(aWindow) + , mPromise(aPromise) + { + MOZ_ASSERT(aPrincipal); + MOZ_ASSERT(aWindow); + MOZ_ASSERT(aPromise); + + mRequester = new nsContentPermissionRequester(mWindow); + } + + nsresult + Start(); + + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSICONTENTPERMISSIONREQUEST + +private: + ~PersistentStoragePermissionRequest() + { } +}; + nsresult GetUsageForPrincipal(nsIPrincipal* aPrincipal, nsIQuotaUsageCallback* aCallback, nsIQuotaUsageRequest** aRequest) { MOZ_ASSERT(aPrincipal); MOZ_ASSERT(aCallback); MOZ_ASSERT(aRequest); nsCOMPtr qms = QuotaManagerService::GetOrCreate(); if (NS_WARN_IF(!qms)) { return NS_ERROR_FAILURE; } - nsresult rv = qms->GetUsageForPrincipal(aPrincipal, aCallback, true, aRequest); + nsresult rv = qms->GetUsageForPrincipal(aPrincipal, + aCallback, + true, + aRequest); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } return NS_OK; }; nsresult -GetStorageEstimate(nsIQuotaUsageRequest* aRequest, - StorageEstimate& aStorageEstimate) +Persisted(nsIPrincipal* aPrincipal, + nsIQuotaCallback* aCallback, + nsIQuotaRequest** aRequest) { + MOZ_ASSERT(aPrincipal); + MOZ_ASSERT(aCallback); MOZ_ASSERT(aRequest); - nsCOMPtr result; - nsresult rv = aRequest->GetResult(getter_AddRefs(result)); + nsCOMPtr qms = QuotaManagerService::GetOrCreate(); + if (NS_WARN_IF(!qms)) { + return NS_ERROR_FAILURE; + } + + nsCOMPtr request; + nsresult rv = qms->Persisted(aPrincipal, getter_AddRefs(request)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } + // All the methods in nsIQuotaManagerService shouldn't synchronously fire + // any callbacks when they are being executed. Even when a result is ready, + // a new runnable should be dispatched to current thread to fire the callback + // asynchronously. It's safe to set the callback after we call Persisted(). + MOZ_ALWAYS_SUCCEEDS(request->SetCallback(aCallback)); + + request.forget(aRequest); + + return NS_OK; +}; + +already_AddRefed +ExecuteOpOnMainOrWorkerThread(nsIGlobalObject* aGlobal, + RequestResolver::Type aType, + ErrorResult& aRv) +{ + MOZ_ASSERT(aGlobal); + MOZ_ASSERT_IF(aType == RequestResolver::Type::Persist, + NS_IsMainThread()); + + RefPtr promise = Promise::Create(aGlobal, aRv); + if (NS_WARN_IF(!promise)) { + return nullptr; + } + + if (NS_IsMainThread()) { + nsCOMPtr window = do_QueryInterface(aGlobal); + if (NS_WARN_IF(!window)) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + nsCOMPtr doc = window->GetExtantDoc(); + if (NS_WARN_IF(!doc)) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + nsCOMPtr principal = doc->NodePrincipal(); + MOZ_ASSERT(principal); + + switch (aType) { + case RequestResolver::Type::Persisted: { + RefPtr resolver = + new RequestResolver(RequestResolver::Type::Persisted, promise); + + RefPtr request; + aRv = Persisted(principal, resolver, getter_AddRefs(request)); + + break; + } + + case RequestResolver::Type::Persist: { + RefPtr request = + new PersistentStoragePermissionRequest(principal, window, promise); + + aRv = request->Start(); + + break; + } + + case RequestResolver::Type::Estimate: { + RefPtr resolver = + new RequestResolver(RequestResolver::Type::Estimate, promise); + + RefPtr request; + aRv = GetUsageForPrincipal(principal, + resolver, + getter_AddRefs(request)); + + break; + } + + default: + MOZ_CRASH("Invalid aRequest type!"); + } + + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + return promise.forget(); + } + + WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); + MOZ_ASSERT(workerPrivate); + + RefPtr promiseProxy = + PromiseWorkerProxy::Create(workerPrivate, promise); + if (NS_WARN_IF(!promiseProxy)) { + return nullptr; + } + + switch (aType) { + case RequestResolver::Type::Estimate: { + RefPtr runnnable = + new EstimateWorkerMainThreadRunnable(promiseProxy->GetWorkerPrivate(), + promiseProxy); + runnnable->Dispatch(Terminating, aRv); + + break; + } + + case RequestResolver::Type::Persisted: { + RefPtr runnnable = + new PersistedWorkerMainThreadRunnable(promiseProxy->GetWorkerPrivate(), + promiseProxy); + runnnable->Dispatch(Terminating, aRv); + + break; + } + + default: + MOZ_CRASH("Invalid aRequest type"); + } + + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + return promise.forget(); +}; + +} // namespace + +/******************************************************************************* + * Local class implementations + ******************************************************************************/ + +void +RequestResolver::ResolveOrReject() +{ + class MOZ_STACK_CLASS AutoCleanup final + { + RefPtr mProxy; + + public: + explicit AutoCleanup(PromiseWorkerProxy* aProxy) + : mProxy(aProxy) + { + MOZ_ASSERT(aProxy); + } + + ~AutoCleanup() + { + MOZ_ASSERT(mProxy); + + mProxy->CleanUp(); + } + }; + + RefPtr promise; + Maybe autoCleanup; + + if (mPromise) { + promise = mPromise; + } else { + MOZ_ASSERT(mProxy); + + promise = mProxy->WorkerPromise(); + + // Only clean up for worker case. + autoCleanup.emplace(mProxy); + } + + MOZ_ASSERT(promise); + + if (mType == Type::Estimate) { + if (NS_SUCCEEDED(mResultCode)) { + promise->MaybeResolve(mStorageEstimate); + } else { + promise->MaybeReject(NS_ERROR_DOM_TYPE_ERR); + } + + return; + } + + MOZ_ASSERT(mType == Type::Persist || mType == Type::Persisted); + + if (NS_SUCCEEDED(mResultCode)) { + promise->MaybeResolve(mPersisted); + } else { + promise->MaybeResolve(false); + } +} + +NS_IMPL_ISUPPORTS(RequestResolver, nsIQuotaUsageCallback, nsIQuotaCallback) + +nsresult +RequestResolver::GetStorageEstimate(nsIVariant* aResult) +{ + MOZ_ASSERT(aResult); + MOZ_ASSERT(mType == Type::Estimate); + +#ifdef DEBUG + uint16_t dataType; + MOZ_ALWAYS_SUCCEEDS(aResult->GetDataType(&dataType)); + MOZ_ASSERT(dataType == nsIDataType::VTYPE_INTERFACE_IS); +#endif + nsID* iid; nsCOMPtr supports; - rv = result->GetAsInterface(&iid, getter_AddRefs(supports)); + nsresult rv = aResult->GetAsInterface(&iid, getter_AddRefs(supports)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } free(iid); nsCOMPtr originUsageResult = do_QueryInterface(supports); MOZ_ASSERT(originUsageResult); MOZ_ALWAYS_SUCCEEDS( - originUsageResult->GetUsage(&aStorageEstimate.mUsage.Construct())); + originUsageResult->GetUsage(&mStorageEstimate.mUsage.Construct())); MOZ_ALWAYS_SUCCEEDS( - originUsageResult->GetLimit(&aStorageEstimate.mQuota.Construct())); + originUsageResult->GetLimit(&mStorageEstimate.mQuota.Construct())); return NS_OK; } -} // namespace - -/******************************************************************************* - * Local class implementations - ******************************************************************************/ +nsresult +RequestResolver::GetPersisted(nsIVariant* aResult) +{ + MOZ_ASSERT(aResult); + MOZ_ASSERT(mType == Type::Persist || mType == Type::Persisted); -void -EstimateResolver::ResolveOrReject(Promise* aPromise) -{ - MOZ_ASSERT(aPromise); +#ifdef DEBUG + uint16_t dataType; + MOZ_ALWAYS_SUCCEEDS(aResult->GetDataType(&dataType)); +#endif - if (NS_SUCCEEDED(mResultCode)) { - aPromise->MaybeResolve(mStorageEstimate); - } else { - aPromise->MaybeReject(mResultCode); + if (mType == Type::Persist) { + MOZ_ASSERT(dataType == nsIDataType::VTYPE_VOID); + + mPersisted = true; + return NS_OK; } + + MOZ_ASSERT(dataType == nsIDataType::VTYPE_BOOL); + + bool persisted; + nsresult rv = aResult->GetAsBool(&persisted); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + mPersisted = persisted; + return NS_OK; } -NS_IMPL_ISUPPORTS(EstimateResolver, nsIQuotaUsageCallback) - -NS_IMETHODIMP -EstimateResolver::OnUsageResult(nsIQuotaUsageRequest *aRequest) +template +nsresult +RequestResolver::OnCompleteOrUsageResult(T* aRequest) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aRequest); - nsresult rv = aRequest->GetResultCode(&mResultCode); + nsresult resultCode; + nsresult rv = aRequest->GetResultCode(&resultCode); if (NS_WARN_IF(NS_FAILED(rv))) { - mResultCode = rv; - } else if (NS_SUCCEEDED(mResultCode)) { - rv = GetStorageEstimate(aRequest, mStorageEstimate); - if (NS_WARN_IF(NS_FAILED(rv))) { - mResultCode = rv; - } + return rv; } + if (NS_FAILED(resultCode)) { + return resultCode; + } + + nsCOMPtr result; + rv = aRequest->GetResult(getter_AddRefs(result)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (mType == Type::Estimate) { + rv = GetStorageEstimate(result); + } else { + MOZ_ASSERT(mType == Type::Persist || mType == Type::Persisted); + + rv = GetPersisted(result); + } + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + return NS_OK; +} + +nsresult +RequestResolver::Finish() +{ // In a main thread request. if (!mProxy) { MOZ_ASSERT(mPromise); - ResolveOrReject(mPromise); + ResolveOrReject(); return NS_OK; } - // In a worker thread request. - MutexAutoLock lock(mProxy->Lock()); + { + // In a worker thread request. + MutexAutoLock lock(mProxy->Lock()); - if (NS_WARN_IF(mProxy->CleanedUp())) { - return NS_ERROR_FAILURE; + if (NS_WARN_IF(mProxy->CleanedUp())) { + return NS_ERROR_FAILURE; + } + + RefPtr runnable = new FinishWorkerRunnable(this); + if (NS_WARN_IF(!runnable->Dispatch())) { + return NS_ERROR_FAILURE; + } } - RefPtr runnable = new FinishWorkerRunnable(this); - if (NS_WARN_IF(!runnable->Dispatch())) { - return NS_ERROR_FAILURE; + return NS_OK; +} + +NS_IMETHODIMP +RequestResolver::OnComplete(nsIQuotaRequest *aRequest) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aRequest); + + mResultCode = OnCompleteOrUsageResult(aRequest); + + nsresult rv = Finish(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + return NS_OK; +} + +NS_IMETHODIMP +RequestResolver::OnUsageResult(nsIQuotaUsageRequest *aRequest) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aRequest); + + mResultCode = OnCompleteOrUsageResult(aRequest); + + nsresult rv = Finish(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; } return NS_OK; } bool -EstimateResolver:: +RequestResolver:: FinishWorkerRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) { + MOZ_ASSERT(aCx); MOZ_ASSERT(aWorkerPrivate); aWorkerPrivate->AssertIsOnWorkerThread(); - RefPtr proxy = mResolver->mProxy; - MOZ_ASSERT(proxy); - - RefPtr promise = proxy->WorkerPromise(); - MOZ_ASSERT(promise); - - mResolver->ResolveOrReject(promise); - - proxy->CleanUp(); + MOZ_ASSERT(mResolver); + mResolver->ResolveOrReject(); return true; } bool EstimateWorkerMainThreadRunnable::MainThreadRun() { MOZ_ASSERT(NS_IsMainThread()); @@ -252,100 +621,221 @@ EstimateWorkerMainThreadRunnable::MainTh if (mProxy->CleanedUp()) { return true; } principal = mProxy->GetWorkerPrivate()->GetPrincipal(); } MOZ_ASSERT(principal); - RefPtr resolver = new EstimateResolver(mProxy); + RefPtr resolver = + new RequestResolver(RequestResolver::Type::Estimate, mProxy); RefPtr request; nsresult rv = GetUsageForPrincipal(principal, resolver, getter_AddRefs(request)); if (NS_WARN_IF(NS_FAILED(rv))) { return false; } return true; } +bool +PersistedWorkerMainThreadRunnable::MainThreadRun() +{ + MOZ_ASSERT(NS_IsMainThread()); + + nsCOMPtr principal; + + { + MutexAutoLock lock(mProxy->Lock()); + if (mProxy->CleanedUp()) { + return true; + } + principal = mProxy->GetWorkerPrivate()->GetPrincipal(); + } + + MOZ_ASSERT(principal); + + RefPtr resolver = + new RequestResolver(RequestResolver::Type::Persisted, mProxy); + + RefPtr request; + nsresult rv = Persisted(principal, resolver, getter_AddRefs(request)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return false; + } + + return true; +} + +nsresult +PersistentStoragePermissionRequest::Start() +{ + MOZ_ASSERT(NS_IsMainThread()); + + // Grant permission if pref'ed on. + if (Preferences::GetBool("dom.storageManager.prompt.testing", false)) { + if (Preferences::GetBool("dom.storageManager.prompt.testing.allow", + false)) { + return Allow(JS::UndefinedHandleValue); + } + + return Cancel(); + } + + return nsContentPermissionUtils::AskPermission(this, mWindow); +} + +NS_IMPL_ISUPPORTS(PersistentStoragePermissionRequest, + nsIContentPermissionRequest) + +NS_IMETHODIMP +PersistentStoragePermissionRequest::GetPrincipal(nsIPrincipal** aPrincipal) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aPrincipal); + MOZ_ASSERT(mPrincipal); + + NS_ADDREF(*aPrincipal = mPrincipal); + + return NS_OK; +} + +NS_IMETHODIMP +PersistentStoragePermissionRequest::GetWindow(mozIDOMWindow** aRequestingWindow) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aRequestingWindow); + MOZ_ASSERT(mWindow); + + NS_ADDREF(*aRequestingWindow = mWindow); + + return NS_OK; +} + +NS_IMETHODIMP +PersistentStoragePermissionRequest::GetElement(nsIDOMElement** aElement) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aElement); + + *aElement = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +PersistentStoragePermissionRequest::Cancel() +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(mPromise); + + RefPtr resolver = + new RequestResolver(RequestResolver::Type::Persisted, mPromise); + + RefPtr request; + + return Persisted(mPrincipal, resolver, getter_AddRefs(request)); +} + +NS_IMETHODIMP +PersistentStoragePermissionRequest::Allow(JS::HandleValue aChoices) +{ + MOZ_ASSERT(NS_IsMainThread()); + + RefPtr resolver = + new RequestResolver(RequestResolver::Type::Persist, mPromise); + + nsCOMPtr qms = QuotaManagerService::GetOrCreate(); + if (NS_WARN_IF(!qms)) { + return NS_ERROR_FAILURE; + } + + RefPtr request; + + nsresult rv = qms->Persist(mPrincipal, getter_AddRefs(request)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + MOZ_ALWAYS_SUCCEEDS(request->SetCallback(resolver)); + + return NS_OK; +} + +NS_IMETHODIMP +PersistentStoragePermissionRequest::GetRequester( + nsIContentPermissionRequester** aRequester) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aRequester); + + nsCOMPtr requester = mRequester; + requester.forget(aRequester); + + return NS_OK; +} + +NS_IMETHODIMP +PersistentStoragePermissionRequest::GetTypes(nsIArray** aTypes) +{ + MOZ_ASSERT(aTypes); + + nsTArray emptyOptions; + + return nsContentPermissionUtils::CreatePermissionArray( + NS_LITERAL_CSTRING("persistent-storage"), + NS_LITERAL_CSTRING("unused"), + emptyOptions, + aTypes); +} + /******************************************************************************* * StorageManager ******************************************************************************/ StorageManager::StorageManager(nsIGlobalObject* aGlobal) : mOwner(aGlobal) { MOZ_ASSERT(aGlobal); } StorageManager::~StorageManager() { } already_AddRefed +StorageManager::Persisted(ErrorResult& aRv) +{ + MOZ_ASSERT(mOwner); + + return ExecuteOpOnMainOrWorkerThread(mOwner, + RequestResolver::Type::Persisted, + aRv); +} + +already_AddRefed +StorageManager::Persist(ErrorResult& aRv) +{ + MOZ_ASSERT(mOwner); + + return ExecuteOpOnMainOrWorkerThread(mOwner, + RequestResolver::Type::Persist, + aRv); +} + +already_AddRefed StorageManager::Estimate(ErrorResult& aRv) { MOZ_ASSERT(mOwner); - RefPtr promise = Promise::Create(mOwner, aRv); - if (NS_WARN_IF(!promise)) { - return nullptr; - } - - if (NS_IsMainThread()) { - nsCOMPtr window = do_QueryInterface(mOwner); - if (NS_WARN_IF(!window)) { - aRv.Throw(NS_ERROR_FAILURE); - return nullptr; - } - - nsCOMPtr doc = window->GetExtantDoc(); - if (NS_WARN_IF(!doc)) { - aRv.Throw(NS_ERROR_FAILURE); - return nullptr; - } - - nsCOMPtr principal = doc->NodePrincipal(); - MOZ_ASSERT(principal); - - RefPtr resolver = new EstimateResolver(promise); - - RefPtr request; - nsresult rv = - GetUsageForPrincipal(principal, resolver, getter_AddRefs(request)); - if (NS_WARN_IF(NS_FAILED(rv))) { - aRv.Throw(rv); - return nullptr; - } - - return promise.forget(); - } - - WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); - MOZ_ASSERT(workerPrivate); - - RefPtr promiseProxy = - PromiseWorkerProxy::Create(workerPrivate, promise); - if (NS_WARN_IF(!promiseProxy)) { - return nullptr; - } - - RefPtr runnnable = - new EstimateWorkerMainThreadRunnable(promiseProxy->GetWorkerPrivate(), - promiseProxy); - - runnnable->Dispatch(Terminating, aRv); - if (NS_WARN_IF(aRv.Failed())) { - return nullptr; - } - - return promise.forget(); + return ExecuteOpOnMainOrWorkerThread(mOwner, + RequestResolver::Type::Estimate, + aRv); } // static bool StorageManager::PrefEnabled(JSContext* aCx, JSObject* aObj) { if (NS_IsMainThread()) { return Preferences::GetBool("dom.storageManager.enabled"); diff --git a/dom/quota/StorageManager.h b/dom/quota/StorageManager.h --- a/dom/quota/StorageManager.h +++ b/dom/quota/StorageManager.h @@ -35,16 +35,22 @@ public: nsIGlobalObject* GetParentObject() const { return mOwner; } // WebIDL already_AddRefed + Persisted(ErrorResult& aRv); + + already_AddRefed + Persist(ErrorResult& aRv); + + already_AddRefed Estimate(ErrorResult& aRv); NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(StorageManager) // nsWrapperCache virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; diff --git a/dom/webidl/StorageManager.webidl b/dom/webidl/StorageManager.webidl --- a/dom/webidl/StorageManager.webidl +++ b/dom/webidl/StorageManager.webidl @@ -7,20 +7,22 @@ * https://storage.spec.whatwg.org/#storagemanager * */ [SecureContext, Exposed=(Window,Worker), Func="mozilla::dom::StorageManager::PrefEnabled"] interface StorageManager { - // [Throws] - // Promise persisted(); - // [Throws] - // [Exposed=Window] Promise persist(); + [Throws] + Promise persisted(); + + [Exposed=Window, Throws] + Promise persist(); + [Throws] Promise estimate(); }; dictionary StorageEstimate { unsigned long long usage; unsigned long long quota; };