Bug 1286717 - Part 1: Expose persist/persisted to StorageManager, r=janv, r=baku

This commit is contained in:
Shawn Huang 2017-04-17 15:06:27 +08:00
Родитель b24e38d3fc
Коммит c9c55c765e
3 изменённых файлов: 620 добавлений и 122 удалений

Просмотреть файл

@ -11,6 +11,7 @@
#include "mozilla/dom/StorageManagerBinding.h" #include "mozilla/dom/StorageManagerBinding.h"
#include "mozilla/dom/WorkerPrivate.h" #include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/ErrorResult.h" #include "mozilla/ErrorResult.h"
#include "nsContentPermissionHelper.h"
#include "nsIQuotaCallbacks.h" #include "nsIQuotaCallbacks.h"
#include "nsIQuotaRequests.h" #include "nsIQuotaRequests.h"
#include "nsPIDOMWindow.h" #include "nsPIDOMWindow.h"
@ -22,10 +23,21 @@ namespace dom {
namespace { namespace {
// This class is used to get quota usage callback. // This class is used to get quota usage, request persist and check persisted
class EstimateResolver final // status callbacks.
: public nsIQuotaUsageCallback class RequestResolver final
: public nsIQuotaCallback
, public nsIQuotaUsageCallback
{ {
public:
enum Type
{
Estimate,
Persist,
Persisted
};
private:
class FinishWorkerRunnable; class FinishWorkerRunnable;
// If this resolver was created for a window then mPromise must be non-null. // If this resolver was created for a window then mPromise must be non-null.
@ -35,44 +47,69 @@ class EstimateResolver final
nsresult mResultCode; nsresult mResultCode;
StorageEstimate mStorageEstimate; StorageEstimate mStorageEstimate;
const Type mType;
bool mPersisted;
public: public:
explicit EstimateResolver(Promise* aPromise) RequestResolver(Type aType, Promise* aPromise)
: mPromise(aPromise) : mPromise(aPromise)
, mResultCode(NS_OK) , mResultCode(NS_OK)
, mType(aType)
, mPersisted(false)
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aPromise); MOZ_ASSERT(aPromise);
} }
explicit EstimateResolver(PromiseWorkerProxy* aProxy) RequestResolver(Type aType, PromiseWorkerProxy* aProxy)
: mProxy(aProxy) : mProxy(aProxy)
, mResultCode(NS_OK) , mResultCode(NS_OK)
, mType(aType)
, mPersisted(false)
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aProxy); MOZ_ASSERT(aProxy);
} }
Type
GetType() const
{
return mType;
}
void void
ResolveOrReject(Promise* aPromise); ResolveOrReject();
NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIQUOTACALLBACK
NS_DECL_NSIQUOTAUSAGECALLBACK NS_DECL_NSIQUOTAUSAGECALLBACK
private: private:
~EstimateResolver() ~RequestResolver()
{ } { }
nsresult
GetStorageEstimate(nsIVariant* aResult);
nsresult
GetPersisted(nsIVariant* aResult);
template <typename T>
nsresult
OnCompleteOrUsageResult(T* aRequest);
nsresult
Finish();
}; };
// This class is used to return promise on worker thread. // This class is used to return promise on worker thread.
class EstimateResolver::FinishWorkerRunnable final class RequestResolver::FinishWorkerRunnable final
: public WorkerRunnable : public WorkerRunnable
{ {
RefPtr<EstimateResolver> mResolver; RefPtr<RequestResolver> mResolver;
public: public:
explicit FinishWorkerRunnable(EstimateResolver* aResolver) explicit FinishWorkerRunnable(RequestResolver* aResolver)
: WorkerRunnable(aResolver->mProxy->GetWorkerPrivate()) : WorkerRunnable(aResolver->mProxy->GetWorkerPrivate())
, mResolver(aResolver) , mResolver(aResolver)
{ {
@ -80,11 +117,11 @@ public:
MOZ_ASSERT(aResolver); MOZ_ASSERT(aResolver);
} }
virtual bool bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override; WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override;
}; };
class EstimateWorkerMainThreadRunnable class EstimateWorkerMainThreadRunnable final
: public WorkerMainThreadRunnable : public WorkerMainThreadRunnable
{ {
RefPtr<PromiseWorkerProxy> mProxy; RefPtr<PromiseWorkerProxy> mProxy;
@ -101,10 +138,69 @@ public:
MOZ_ASSERT(aProxy); MOZ_ASSERT(aProxy);
} }
virtual bool bool
MainThreadRun() override; MainThreadRun() override;
}; };
class PersistedWorkerMainThreadRunnable final
: public WorkerMainThreadRunnable
{
RefPtr<PromiseWorkerProxy> 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<nsIPrincipal> mPrincipal;
nsCOMPtr<nsPIDOMWindowInner> mWindow;
RefPtr<Promise> mPromise;
nsCOMPtr<nsIContentPermissionRequester> 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 nsresult
GetUsageForPrincipal(nsIPrincipal* aPrincipal, GetUsageForPrincipal(nsIPrincipal* aPrincipal,
nsIQuotaUsageCallback* aCallback, nsIQuotaUsageCallback* aCallback,
@ -119,7 +215,10 @@ GetUsageForPrincipal(nsIPrincipal* aPrincipal,
return NS_ERROR_FAILURE; 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))) { if (NS_WARN_IF(NS_FAILED(rv))) {
return rv; return rv;
} }
@ -128,20 +227,228 @@ GetUsageForPrincipal(nsIPrincipal* aPrincipal,
}; };
nsresult nsresult
GetStorageEstimate(nsIQuotaUsageRequest* aRequest, Persisted(nsIPrincipal* aPrincipal,
StorageEstimate& aStorageEstimate) nsIQuotaCallback* aCallback,
nsIQuotaRequest** aRequest)
{ {
MOZ_ASSERT(aPrincipal);
MOZ_ASSERT(aCallback);
MOZ_ASSERT(aRequest); MOZ_ASSERT(aRequest);
nsCOMPtr<nsIVariant> result; nsCOMPtr<nsIQuotaManagerService> qms = QuotaManagerService::GetOrCreate();
nsresult rv = aRequest->GetResult(getter_AddRefs(result)); if (NS_WARN_IF(!qms)) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIQuotaRequest> request;
nsresult rv = qms->Persisted(aPrincipal, getter_AddRefs(request));
if (NS_WARN_IF(NS_FAILED(rv))) { if (NS_WARN_IF(NS_FAILED(rv))) {
return 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<Promise>
ExecuteOpOnMainOrWorkerThread(nsIGlobalObject* aGlobal,
RequestResolver::Type aType,
ErrorResult& aRv)
{
MOZ_ASSERT(aGlobal);
MOZ_ASSERT_IF(aType == RequestResolver::Type::Persist,
NS_IsMainThread());
RefPtr<Promise> promise = Promise::Create(aGlobal, aRv);
if (NS_WARN_IF(!promise)) {
return nullptr;
}
if (NS_IsMainThread()) {
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
if (NS_WARN_IF(!window)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
if (NS_WARN_IF(!doc)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal();
MOZ_ASSERT(principal);
switch (aType) {
case RequestResolver::Type::Persisted: {
RefPtr<RequestResolver> resolver =
new RequestResolver(RequestResolver::Type::Persisted, promise);
RefPtr<nsIQuotaRequest> request;
aRv = Persisted(principal, resolver, getter_AddRefs(request));
break;
}
case RequestResolver::Type::Persist: {
RefPtr<PersistentStoragePermissionRequest> request =
new PersistentStoragePermissionRequest(principal, window, promise);
aRv = request->Start();
break;
}
case RequestResolver::Type::Estimate: {
RefPtr<RequestResolver> resolver =
new RequestResolver(RequestResolver::Type::Estimate, promise);
RefPtr<nsIQuotaUsageRequest> 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<PromiseWorkerProxy> promiseProxy =
PromiseWorkerProxy::Create(workerPrivate, promise);
if (NS_WARN_IF(!promiseProxy)) {
return nullptr;
}
switch (aType) {
case RequestResolver::Type::Estimate: {
RefPtr<EstimateWorkerMainThreadRunnable> runnnable =
new EstimateWorkerMainThreadRunnable(promiseProxy->GetWorkerPrivate(),
promiseProxy);
runnnable->Dispatch(Terminating, aRv);
break;
}
case RequestResolver::Type::Persisted: {
RefPtr<PersistedWorkerMainThreadRunnable> 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<PromiseWorkerProxy> mProxy;
public:
explicit AutoCleanup(PromiseWorkerProxy* aProxy)
: mProxy(aProxy)
{
MOZ_ASSERT(aProxy);
}
~AutoCleanup()
{
MOZ_ASSERT(mProxy);
mProxy->CleanUp();
}
};
RefPtr<Promise> promise;
Maybe<AutoCleanup> 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; nsID* iid;
nsCOMPtr<nsISupports> supports; nsCOMPtr<nsISupports> supports;
rv = result->GetAsInterface(&iid, getter_AddRefs(supports)); nsresult rv = aResult->GetAsInterface(&iid, getter_AddRefs(supports));
if (NS_WARN_IF(NS_FAILED(rv))) { if (NS_WARN_IF(NS_FAILED(rv))) {
return rv; return rv;
} }
@ -153,89 +460,151 @@ GetStorageEstimate(nsIQuotaUsageRequest* aRequest,
MOZ_ASSERT(originUsageResult); MOZ_ASSERT(originUsageResult);
MOZ_ALWAYS_SUCCEEDS( MOZ_ALWAYS_SUCCEEDS(
originUsageResult->GetUsage(&aStorageEstimate.mUsage.Construct())); originUsageResult->GetUsage(&mStorageEstimate.mUsage.Construct()));
MOZ_ALWAYS_SUCCEEDS( MOZ_ALWAYS_SUCCEEDS(
originUsageResult->GetLimit(&aStorageEstimate.mQuota.Construct())); originUsageResult->GetLimit(&mStorageEstimate.mQuota.Construct()));
return NS_OK; return NS_OK;
} }
} // namespace nsresult
RequestResolver::GetPersisted(nsIVariant* aResult)
/*******************************************************************************
* Local class implementations
******************************************************************************/
void
EstimateResolver::ResolveOrReject(Promise* aPromise)
{ {
MOZ_ASSERT(aPromise); MOZ_ASSERT(aResult);
MOZ_ASSERT(mType == Type::Persist || mType == Type::Persisted);
if (NS_SUCCEEDED(mResultCode)) { #ifdef DEBUG
aPromise->MaybeResolve(mStorageEstimate); uint16_t dataType;
} else { MOZ_ALWAYS_SUCCEEDS(aResult->GetDataType(&dataType));
aPromise->MaybeReject(mResultCode); #endif
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) template <typename T>
nsresult
NS_IMETHODIMP RequestResolver::OnCompleteOrUsageResult(T* aRequest)
EstimateResolver::OnUsageResult(nsIQuotaUsageRequest *aRequest)
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aRequest); MOZ_ASSERT(aRequest);
nsresult rv = aRequest->GetResultCode(&mResultCode); nsresult resultCode;
nsresult rv = aRequest->GetResultCode(&resultCode);
if (NS_WARN_IF(NS_FAILED(rv))) { if (NS_WARN_IF(NS_FAILED(rv))) {
mResultCode = rv; return rv;
} else if (NS_SUCCEEDED(mResultCode)) {
rv = GetStorageEstimate(aRequest, mStorageEstimate);
if (NS_WARN_IF(NS_FAILED(rv))) {
mResultCode = rv;
}
} }
if (NS_FAILED(resultCode)) {
return resultCode;
}
nsCOMPtr<nsIVariant> 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. // In a main thread request.
if (!mProxy) { if (!mProxy) {
MOZ_ASSERT(mPromise); MOZ_ASSERT(mPromise);
ResolveOrReject(mPromise); ResolveOrReject();
return NS_OK; 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())) { if (NS_WARN_IF(mProxy->CleanedUp())) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
}
RefPtr<FinishWorkerRunnable> runnable = new FinishWorkerRunnable(this);
if (NS_WARN_IF(!runnable->Dispatch())) {
return NS_ERROR_FAILURE;
}
} }
RefPtr<FinishWorkerRunnable> runnable = new FinishWorkerRunnable(this); return NS_OK;
if (NS_WARN_IF(!runnable->Dispatch())) { }
return NS_ERROR_FAILURE;
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; return NS_OK;
} }
bool bool
EstimateResolver:: RequestResolver::
FinishWorkerRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) FinishWorkerRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
{ {
MOZ_ASSERT(aCx);
MOZ_ASSERT(aWorkerPrivate); MOZ_ASSERT(aWorkerPrivate);
aWorkerPrivate->AssertIsOnWorkerThread(); aWorkerPrivate->AssertIsOnWorkerThread();
RefPtr<PromiseWorkerProxy> proxy = mResolver->mProxy; MOZ_ASSERT(mResolver);
MOZ_ASSERT(proxy); mResolver->ResolveOrReject();
RefPtr<Promise> promise = proxy->WorkerPromise();
MOZ_ASSERT(promise);
mResolver->ResolveOrReject(promise);
proxy->CleanUp();
return true; return true;
} }
@ -257,7 +626,8 @@ EstimateWorkerMainThreadRunnable::MainThreadRun()
MOZ_ASSERT(principal); MOZ_ASSERT(principal);
RefPtr<EstimateResolver> resolver = new EstimateResolver(mProxy); RefPtr<RequestResolver> resolver =
new RequestResolver(RequestResolver::Type::Estimate, mProxy);
RefPtr<nsIQuotaUsageRequest> request; RefPtr<nsIQuotaUsageRequest> request;
nsresult rv = nsresult rv =
@ -269,6 +639,156 @@ EstimateWorkerMainThreadRunnable::MainThreadRun()
return true; return true;
} }
bool
PersistedWorkerMainThreadRunnable::MainThreadRun()
{
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIPrincipal> principal;
{
MutexAutoLock lock(mProxy->Lock());
if (mProxy->CleanedUp()) {
return true;
}
principal = mProxy->GetWorkerPrivate()->GetPrincipal();
}
MOZ_ASSERT(principal);
RefPtr<RequestResolver> resolver =
new RequestResolver(RequestResolver::Type::Persisted, mProxy);
RefPtr<nsIQuotaRequest> 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<RequestResolver> resolver =
new RequestResolver(RequestResolver::Type::Persisted, mPromise);
RefPtr<nsIQuotaRequest> request;
return Persisted(mPrincipal, resolver, getter_AddRefs(request));
}
NS_IMETHODIMP
PersistentStoragePermissionRequest::Allow(JS::HandleValue aChoices)
{
MOZ_ASSERT(NS_IsMainThread());
RefPtr<RequestResolver> resolver =
new RequestResolver(RequestResolver::Type::Persist, mPromise);
nsCOMPtr<nsIQuotaManagerService> qms = QuotaManagerService::GetOrCreate();
if (NS_WARN_IF(!qms)) {
return NS_ERROR_FAILURE;
}
RefPtr<nsIQuotaRequest> 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<nsIContentPermissionRequester> requester = mRequester;
requester.forget(aRequester);
return NS_OK;
}
NS_IMETHODIMP
PersistentStoragePermissionRequest::GetTypes(nsIArray** aTypes)
{
MOZ_ASSERT(aTypes);
nsTArray<nsString> emptyOptions;
return nsContentPermissionUtils::CreatePermissionArray(
NS_LITERAL_CSTRING("persistent-storage"),
NS_LITERAL_CSTRING("unused"),
emptyOptions,
aTypes);
}
/******************************************************************************* /*******************************************************************************
* StorageManager * StorageManager
******************************************************************************/ ******************************************************************************/
@ -283,64 +803,34 @@ StorageManager::~StorageManager()
{ {
} }
already_AddRefed<Promise>
StorageManager::Persisted(ErrorResult& aRv)
{
MOZ_ASSERT(mOwner);
return ExecuteOpOnMainOrWorkerThread(mOwner,
RequestResolver::Type::Persisted,
aRv);
}
already_AddRefed<Promise>
StorageManager::Persist(ErrorResult& aRv)
{
MOZ_ASSERT(mOwner);
return ExecuteOpOnMainOrWorkerThread(mOwner,
RequestResolver::Type::Persist,
aRv);
}
already_AddRefed<Promise> already_AddRefed<Promise>
StorageManager::Estimate(ErrorResult& aRv) StorageManager::Estimate(ErrorResult& aRv)
{ {
MOZ_ASSERT(mOwner); MOZ_ASSERT(mOwner);
RefPtr<Promise> promise = Promise::Create(mOwner, aRv); return ExecuteOpOnMainOrWorkerThread(mOwner,
if (NS_WARN_IF(!promise)) { RequestResolver::Type::Estimate,
return nullptr; aRv);
}
if (NS_IsMainThread()) {
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mOwner);
if (NS_WARN_IF(!window)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
if (NS_WARN_IF(!doc)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal();
MOZ_ASSERT(principal);
RefPtr<EstimateResolver> resolver = new EstimateResolver(promise);
RefPtr<nsIQuotaUsageRequest> 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<PromiseWorkerProxy> promiseProxy =
PromiseWorkerProxy::Create(workerPrivate, promise);
if (NS_WARN_IF(!promiseProxy)) {
return nullptr;
}
RefPtr<EstimateWorkerMainThreadRunnable> runnnable =
new EstimateWorkerMainThreadRunnable(promiseProxy->GetWorkerPrivate(),
promiseProxy);
runnnable->Dispatch(Terminating, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return promise.forget();
} }
// static // static

Просмотреть файл

@ -39,6 +39,12 @@ public:
} }
// WebIDL // WebIDL
already_AddRefed<Promise>
Persisted(ErrorResult& aRv);
already_AddRefed<Promise>
Persist(ErrorResult& aRv);
already_AddRefed<Promise> already_AddRefed<Promise>
Estimate(ErrorResult& aRv); Estimate(ErrorResult& aRv);

Просмотреть файл

@ -12,10 +12,12 @@
Exposed=(Window,Worker), Exposed=(Window,Worker),
Func="mozilla::dom::StorageManager::PrefEnabled"] Func="mozilla::dom::StorageManager::PrefEnabled"]
interface StorageManager { interface StorageManager {
// [Throws] [Throws]
// Promise<boolean> persisted(); Promise<boolean> persisted();
// [Throws]
// [Exposed=Window] Promise<boolean> persist(); [Exposed=Window, Throws]
Promise<boolean> persist();
[Throws] [Throws]
Promise<StorageEstimate> estimate(); Promise<StorageEstimate> estimate();
}; };