Bug 1354500 - Part 3: Remove indexedDB/PermissionRequestBase r=dom-storage-reviewers,asuth

Differential Revision: https://phabricator.services.mozilla.com/D151418
This commit is contained in:
Kagami Sascha Rosylight 2022-07-15 01:55:27 +00:00
parent cdb7d00f1e
commit 17bf285cb0
10 changed files with 31 additions and 813 deletions

View File

@ -52,7 +52,6 @@
#include "nsPIDOMWindow.h"
#include "nsThreadUtils.h"
#include "nsTraceRefcnt.h"
#include "PermissionRequestBase.h"
#include "ProfilerHelpers.h"
#include "ReportInternalError.h"
#include "ThreadLocal.h"
@ -328,30 +327,6 @@ nsresult GetResult(JSContext* aCx, const nsTArray<Key>* aKeys,
}
} // namespace detail
class PermissionRequestMainProcessHelper final : public PermissionRequestBase {
BackgroundFactoryRequestChild* mActor;
SafeRefPtr<IDBFactory> mFactory;
public:
PermissionRequestMainProcessHelper(BackgroundFactoryRequestChild* aActor,
SafeRefPtr<IDBFactory> aFactory,
Element* aOwnerElement,
nsIPrincipal* aPrincipal)
: PermissionRequestBase(aOwnerElement, aPrincipal),
mActor(aActor),
mFactory(std::move(aFactory)) {
MOZ_ASSERT(aActor);
MOZ_ASSERT(mFactory);
aActor->AssertIsOnOwningThread();
}
protected:
~PermissionRequestMainProcessHelper() = default;
private:
virtual void OnPromptComplete(PermissionValue aPermissionValue) override;
};
auto DeserializeStructuredCloneFiles(
IDBDatabase* aDatabase,
const nsTArray<SerializedStructuredCloneFile>& aSerializedFiles,
@ -654,178 +629,6 @@ PRFileDesc* GetFileDescriptorFromStream(nsIInputStream* aStream) {
return fileDesc;
}
class WorkerPermissionChallenge;
// This class calles WorkerPermissionChallenge::OperationCompleted() in the
// worker thread.
class WorkerPermissionOperationCompleted final : public WorkerControlRunnable {
RefPtr<WorkerPermissionChallenge> mChallenge;
public:
WorkerPermissionOperationCompleted(WorkerPrivate* aWorkerPrivate,
WorkerPermissionChallenge* aChallenge)
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
mChallenge(aChallenge) {
MOZ_ASSERT(NS_IsMainThread());
}
virtual bool WorkerRun(JSContext* aCx,
WorkerPrivate* aWorkerPrivate) override;
};
// This class used to do prompting in the main thread and main process.
class WorkerPermissionRequest final : public PermissionRequestBase {
RefPtr<WorkerPermissionChallenge> mChallenge;
public:
WorkerPermissionRequest(Element* aElement, nsIPrincipal* aPrincipal,
WorkerPermissionChallenge* aChallenge)
: PermissionRequestBase(aElement, aPrincipal), mChallenge(aChallenge) {
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aChallenge);
}
private:
~WorkerPermissionRequest() { MOZ_ASSERT(NS_IsMainThread()); }
virtual void OnPromptComplete(PermissionValue aPermissionValue) override;
};
class WorkerPermissionChallenge final : public Runnable {
public:
WorkerPermissionChallenge(WorkerPrivate* aWorkerPrivate,
BackgroundFactoryRequestChild* aActor,
SafeRefPtr<IDBFactory> aFactory,
PrincipalInfo&& aPrincipalInfo)
: Runnable("indexedDB::WorkerPermissionChallenge"),
mWorkerPrivate(aWorkerPrivate),
mActor(aActor),
mFactory(std::move(aFactory)),
mPrincipalInfo(std::move(aPrincipalInfo)) {
MOZ_ASSERT(mWorkerPrivate);
MOZ_ASSERT(aActor);
MOZ_ASSERT(mFactory);
mWorkerPrivate->AssertIsOnWorkerThread();
}
bool Dispatch() {
mWorkerPrivate->AssertIsOnWorkerThread();
if (NS_WARN_IF(!mWorkerPrivate->ModifyBusyCountFromWorker(true))) {
return false;
}
if (NS_WARN_IF(NS_FAILED(mWorkerPrivate->DispatchToMainThread(this)))) {
mWorkerPrivate->ModifyBusyCountFromWorker(false);
return false;
}
return true;
}
NS_IMETHOD
Run() override {
const bool completed = RunInternal();
if (completed) {
OperationCompleted();
}
return NS_OK;
}
void OperationCompleted() {
if (NS_IsMainThread()) {
const RefPtr<WorkerPermissionOperationCompleted> runnable =
new WorkerPermissionOperationCompleted(mWorkerPrivate, this);
MOZ_ALWAYS_TRUE(runnable->Dispatch());
return;
}
MOZ_ASSERT(mActor);
mActor->AssertIsOnOwningThread();
MaybeCollectGarbageOnIPCMessage();
const SafeRefPtr<IDBFactory> factory = std::move(mFactory);
Unused << factory; // XXX see Bug 1605075
mActor->SendPermissionRetry();
mActor = nullptr;
mWorkerPrivate->AssertIsOnWorkerThread();
mWorkerPrivate->ModifyBusyCountFromWorker(false);
}
private:
bool RunInternal() {
MOZ_ASSERT(NS_IsMainThread());
// Walk up to our containing page
WorkerPrivate* wp = mWorkerPrivate;
while (wp->GetParent()) {
wp = wp->GetParent();
}
nsPIDOMWindowInner* const window = wp->GetWindow();
if (!window) {
return true;
}
QM_TRY_UNWRAP(auto principal,
mozilla::ipc::PrincipalInfoToPrincipal(mPrincipalInfo), true);
if (XRE_IsParentProcess()) {
const nsCOMPtr<Element> ownerElement =
do_QueryInterface(window->GetChromeEventHandler());
if (NS_WARN_IF(!ownerElement)) {
return true;
}
RefPtr<WorkerPermissionRequest> helper =
new WorkerPermissionRequest(ownerElement, principal, this);
QM_TRY_INSPECT(const PermissionRequestBase::PermissionValue& permission,
helper->PromptIfNeeded(), true);
MOZ_ASSERT(permission == PermissionRequestBase::kPermissionAllowed ||
permission == PermissionRequestBase::kPermissionDenied ||
permission == PermissionRequestBase::kPermissionPrompt);
return permission != PermissionRequestBase::kPermissionPrompt;
}
BrowserChild* browserChild = BrowserChild::GetFrom(window);
MOZ_ASSERT(browserChild);
RefPtr<WorkerPermissionChallenge> self(this);
browserChild->SendIndexedDBPermissionRequest(principal)->Then(
GetCurrentSerialEventTarget(), __func__,
[self](const uint32_t& aPermission) { self->OperationCompleted(); },
[](const mozilla::ipc::ResponseRejectReason) {});
return false;
}
private:
WorkerPrivate* const mWorkerPrivate;
BackgroundFactoryRequestChild* mActor;
SafeRefPtr<IDBFactory> mFactory;
const PrincipalInfo mPrincipalInfo;
};
void WorkerPermissionRequest::OnPromptComplete(
PermissionValue aPermissionValue) {
MOZ_ASSERT(NS_IsMainThread());
mChallenge->OperationCompleted();
}
bool WorkerPermissionOperationCompleted::WorkerRun(
JSContext* aCx, WorkerPrivate* aWorkerPrivate) {
aWorkerPrivate->AssertIsOnWorkerThread();
mChallenge->OperationCompleted();
return true;
}
class MOZ_STACK_CLASS AutoSetCurrentFileHandle final {
using BackgroundChildImpl = mozilla::ipc::BackgroundChildImpl;
@ -1138,23 +941,6 @@ class BackgroundRequestChild::PreprocessHelper final
NS_DECL_NSIFILEMETADATACALLBACK
};
/*******************************************************************************
* Local class implementations
******************************************************************************/
void PermissionRequestMainProcessHelper::OnPromptComplete(
PermissionValue aPermissionValue) {
MOZ_ASSERT(mActor);
mActor->AssertIsOnOwningThread();
MaybeCollectGarbageOnIPCMessage();
mActor->SendPermissionRetry();
mActor = nullptr;
mFactory = nullptr;
}
/*******************************************************************************
* BackgroundRequestChildBase
******************************************************************************/
@ -1425,76 +1211,6 @@ mozilla::ipc::IPCResult BackgroundFactoryRequestChild::Recv__delete__(
return IPC_OK();
}
mozilla::ipc::IPCResult BackgroundFactoryRequestChild::RecvPermissionChallenge(
PrincipalInfo&& aPrincipalInfo) {
AssertIsOnOwningThread();
MaybeCollectGarbageOnIPCMessage();
if (!NS_IsMainThread()) {
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
workerPrivate->AssertIsOnWorkerThread();
RefPtr<WorkerPermissionChallenge> challenge = new WorkerPermissionChallenge(
workerPrivate, this, mFactory.clonePtr(), std::move(aPrincipalInfo));
if (!challenge->Dispatch()) {
QM_WARNONLY_TRY(OkIf(SendPermissionRetry()));
}
return IPC_OK();
}
QM_TRY_UNWRAP(auto principal,
mozilla::ipc::PrincipalInfoToPrincipal(aPrincipalInfo),
IPC_FAIL(this, "PrincipalInfoToPrincipal failed!"));
if (XRE_IsParentProcess()) {
nsCOMPtr<nsIGlobalObject> global = mFactory->GetParentObject();
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global);
MOZ_ASSERT(window);
nsCOMPtr<Element> ownerElement =
do_QueryInterface(window->GetChromeEventHandler());
if (NS_WARN_IF(!ownerElement)) {
// If this fails, the page was navigated. Fail the permission check by
// forcing an immediate retry.
QM_WARNONLY_TRY(OkIf(SendPermissionRetry()));
return IPC_OK();
}
RefPtr<PermissionRequestMainProcessHelper> helper =
new PermissionRequestMainProcessHelper(this, mFactory.clonePtr(),
ownerElement, principal);
QM_TRY_INSPECT(const PermissionRequestBase::PermissionValue& permission,
helper->PromptIfNeeded(),
IPC_FAIL(this, "PromptIfNeeded failed!"));
MOZ_ASSERT(permission == PermissionRequestBase::kPermissionAllowed ||
permission == PermissionRequestBase::kPermissionDenied ||
permission == PermissionRequestBase::kPermissionPrompt);
if (permission != PermissionRequestBase::kPermissionPrompt) {
SendPermissionRetry();
}
return IPC_OK();
}
RefPtr<BrowserChild> browserChild = mFactory->GetBrowserChild();
MOZ_ASSERT(browserChild);
browserChild->SendIndexedDBPermissionRequest(principal)->Then(
GetCurrentSerialEventTarget(), __func__,
[this](const uint32_t& aPermission) {
this->AssertIsOnOwningThread();
MaybeCollectGarbageOnIPCMessage();
this->SendPermissionRetry();
},
[](const mozilla::ipc::ResponseRejectReason) {});
return IPC_OK();
}
mozilla::ipc::IPCResult BackgroundFactoryRequestChild::RecvBlocked(
const uint64_t aCurrentVersion) {
AssertIsOnOwningThread();

View File

@ -34,7 +34,6 @@
#include "IndexedDatabaseManager.h"
#include "KeyPath.h"
#include "MainThreadUtils.h"
#include "PermissionRequestBase.h"
#include "ProfilerHelpers.h"
#include "ReportInternalError.h"
#include "SafeRefPtr.h"
@ -3106,15 +3105,6 @@ class FactoryOp
// if permission is granted.
Initial,
// Sending a permission challenge message to the child on the PBackground
// thread. Next step is PermissionRetry.
PermissionChallenge,
// Retrying permission check after a challenge on the main thread. Next step
// is either SendingResults if permission is denied or FinishOpen
// if permission is granted.
PermissionRetry,
// Ensuring quota manager is created and opening directory on the
// PBackground thread. Next step is either SendingResults if quota manager
// is not available or DirectoryOpenPending if quota manager is available.
@ -3236,12 +3226,6 @@ class FactoryOp
nsresult Open();
nsresult ChallengePermission();
void PermissionRetry();
nsresult RetryCheckPermission();
nsresult DirectoryOpen();
nsresult SendToIOThread();
@ -3287,13 +3271,11 @@ class FactoryOp
// IPDL methods.
void ActorDestroy(ActorDestroyReason aWhy) override;
mozilla::ipc::IPCResult RecvPermissionRetry() final;
virtual void SendBlockedNotification() = 0;
private:
mozilla::Result<PermissionRequestBase::PermissionValue, nsresult>
CheckPermission(ContentParent* aContentParent);
mozilla::Result<PermissionValue, nsresult> CheckPermission(
ContentParent* aContentParent);
static bool CheckAtLeastOneAppHasPermission(
ContentParent* aContentParent, const nsACString& aPermissionString);
@ -15126,14 +15108,6 @@ void FactoryOp::StringifyState(nsACString& aResult) const {
aResult.AppendLiteral("Initial");
return;
case State::PermissionChallenge:
aResult.AppendLiteral("PermissionChallenge");
return;
case State::PermissionRetry:
aResult.AppendLiteral("PermissionRetry");
return;
case State::FinishOpen:
aResult.AppendLiteral("FinishOpen");
return;
@ -15210,11 +15184,10 @@ nsresult FactoryOp::Open() {
QM_TRY_INSPECT(const auto& permission, CheckPermission(contentParent));
MOZ_ASSERT(permission == PermissionRequestBase::kPermissionAllowed ||
permission == PermissionRequestBase::kPermissionDenied ||
permission == PermissionRequestBase::kPermissionPrompt);
MOZ_ASSERT(permission == PermissionValue::kPermissionAllowed ||
permission == PermissionValue::kPermissionDenied);
if (permission == PermissionRequestBase::kPermissionDenied) {
if (permission == PermissionValue::kPermissionDenied) {
return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
}
@ -15242,13 +15215,7 @@ nsresult FactoryOp::Open() {
mDatabaseId.Append('*');
mDatabaseId.Append(NS_ConvertUTF16toUTF8(metadata.name()));
if (permission == PermissionRequestBase::kPermissionPrompt) {
mState = State::PermissionChallenge;
MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL));
return NS_OK;
}
MOZ_ASSERT(permission == PermissionRequestBase::kPermissionAllowed);
MOZ_ASSERT(permission == PermissionValue::kPermissionAllowed);
if (mInPrivateBrowsing) {
const auto lockedPrivateBrowsingInfoHashtable =
@ -15275,69 +15242,6 @@ nsresult FactoryOp::Open() {
return NS_OK;
}
nsresult FactoryOp::ChallengePermission() {
AssertIsOnOwningThread();
MOZ_ASSERT(mState == State::PermissionChallenge);
const PrincipalInfo& principalInfo = mCommonParams.principalInfo();
MOZ_ASSERT(principalInfo.type() == PrincipalInfo::TContentPrincipalInfo);
if (NS_WARN_IF(!SendPermissionChallenge(principalInfo))) {
return NS_ERROR_FAILURE;
}
mWaitingForPermissionRetry = true;
return NS_OK;
}
void FactoryOp::PermissionRetry() {
AssertIsOnOwningThread();
MOZ_ASSERT(mState == State::PermissionChallenge);
mContentParent = BackgroundParent::GetContentParent(Manager()->Manager());
mState = State::PermissionRetry;
mWaitingForPermissionRetry = false;
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this));
}
nsresult FactoryOp::RetryCheckPermission() {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mState == State::PermissionRetry);
MOZ_ASSERT(mCommonParams.principalInfo().type() ==
PrincipalInfo::TContentPrincipalInfo);
// Move this to the stack now to ensure that we release it on this thread.
const RefPtr<ContentParent> contentParent = std::move(mContentParent);
if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
!OperationMayProceed()) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
QM_TRY_INSPECT(const auto& permission, CheckPermission(contentParent));
MOZ_ASSERT(permission == PermissionRequestBase::kPermissionAllowed ||
permission == PermissionRequestBase::kPermissionDenied ||
permission == PermissionRequestBase::kPermissionPrompt);
if (permission == PermissionRequestBase::kPermissionDenied ||
permission == PermissionRequestBase::kPermissionPrompt) {
return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
}
MOZ_ASSERT(permission == PermissionRequestBase::kPermissionAllowed);
mState = State::FinishOpen;
MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL));
return NS_OK;
}
nsresult FactoryOp::DirectoryOpen() {
AssertIsOnOwningThread();
MOZ_ASSERT(mState == State::DirectoryOpenPending);
@ -15456,10 +15360,10 @@ void FactoryOp::FinishSendResults() {
mFactory = nullptr;
}
Result<PermissionRequestBase::PermissionValue, nsresult>
FactoryOp::CheckPermission(ContentParent* aContentParent) {
Result<PermissionValue, nsresult> FactoryOp::CheckPermission(
ContentParent* aContentParent) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mState == State::Initial || mState == State::PermissionRetry);
MOZ_ASSERT(mState == State::Initial);
const PrincipalInfo& principalInfo = mCommonParams.principalInfo();
if (principalInfo.type() != PrincipalInfo::TSystemPrincipalInfo) {
@ -15545,7 +15449,7 @@ FactoryOp::CheckPermission(ContentParent* aContentParent) {
mEnforcingQuota = false;
}
return PermissionRequestBase::kPermissionAllowed;
return PermissionValue::kPermissionAllowed;
}
MOZ_ASSERT(principalInfo.type() == PrincipalInfo::TContentPrincipalInfo);
@ -15556,26 +15460,21 @@ FactoryOp::CheckPermission(ContentParent* aContentParent) {
QM_TRY_UNWRAP(auto principalMetadata,
QuotaManager::GetInfoFromPrincipal(principal));
QM_TRY_INSPECT(const auto& permission,
([persistenceType, &origin = principalMetadata.mOrigin,
&principal = *principal]()
-> mozilla::Result<PermissionRequestBase::PermissionValue,
nsresult> {
if (persistenceType == PERSISTENCE_TYPE_PERSISTENT) {
if (QuotaManager::IsOriginInternal(origin)) {
return PermissionRequestBase::kPermissionAllowed;
}
#ifdef IDB_MOBILE
return Err(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
#else
return PermissionRequestBase::GetCurrentPermission(
principal);
#endif
}
return PermissionRequestBase::kPermissionAllowed;
})());
QM_TRY_INSPECT(
const auto& permission,
([persistenceType, &origin = principalMetadata.mOrigin,
&principal =
*principal]() -> mozilla::Result<PermissionValue, nsresult> {
if (persistenceType == PERSISTENCE_TYPE_PERSISTENT) {
if (QuotaManager::IsOriginInternal(origin)) {
return PermissionValue::kPermissionAllowed;
}
return Err(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
}
return PermissionValue::kPermissionAllowed;
})());
if (permission != PermissionRequestBase::kPermissionDenied &&
if (permission != PermissionValue::kPermissionDenied &&
State::Initial == mState) {
mOriginMetadata = {std::move(principalMetadata), persistenceType};
@ -15730,14 +15629,6 @@ FactoryOp::Run() {
QM_TRY(MOZ_TO_RESULT(Open()), NS_OK, handleError);
break;
case State::PermissionChallenge:
QM_TRY(MOZ_TO_RESULT(ChallengePermission()), NS_OK, handleError);
break;
case State::PermissionRetry:
QM_TRY(MOZ_TO_RESULT(RetryCheckPermission()), NS_OK, handleError);
break;
case State::FinishOpen:
QM_TRY(MOZ_TO_RESULT(FinishOpen()), NS_OK, handleError);
break;
@ -15812,32 +15703,6 @@ void FactoryOp::ActorDestroy(ActorDestroyReason aWhy) {
AssertIsOnBackgroundThread();
NoteActorDestroyed();
// Assume ActorDestroy can happen at any time, so we can't probe the current
// state since mState can be modified on any thread (only one thread at a time
// based on the state machine). However we can use mWaitingForPermissionRetry
// which is only touched on the owning thread. If mWaitingForPermissionRetry
// is true, we can also modify mState since we are guaranteed that there are
// no pending runnables which would probe mState to decide what code needs to
// run (there shouldn't be any running runnables on other threads either).
if (mWaitingForPermissionRetry) {
PermissionRetry();
}
// We don't have to handle the case when mWaitingForPermissionRetry is not
// true since it means that either nothing has been initialized yet, so
// nothing to cleanup or there are pending runnables that will detect that the
// actor has been destroyed and cleanup accordingly.
}
mozilla::ipc::IPCResult FactoryOp::RecvPermissionRetry() {
AssertIsOnOwningThread();
MOZ_ASSERT(!IsActorDestroyed());
PermissionRetry();
return IPC_OK();
}
OpenDatabaseOp::OpenDatabaseOp(SafeRefPtr<Factory> aFactory,
@ -21475,13 +21340,6 @@ mozilla::ipc::IPCResult Utils::RecvGetFileReferences(
return IPC_OK();
}
void PermissionRequestHelper::OnPromptComplete(
PermissionValue aPermissionValue) {
MOZ_ASSERT(NS_IsMainThread());
mResolver(aPermissionValue);
}
#ifdef DEBUG
NS_IMPL_ISUPPORTS(DEBUGThreadSlower, nsIThreadObserver)

View File

@ -8,9 +8,9 @@
#define mozilla_dom_indexeddb_actorsparent_h__
#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/dom/indexedDB/PermissionRequestBase.h"
#include "mozilla/dom/PBrowserParent.h"
#include "mozilla/RefPtr.h"
#include "nsIPermissionManager.h"
class nsIPrincipal;
@ -27,6 +27,12 @@ class Client;
namespace indexedDB {
enum class PermissionValue {
kPermissionAllowed = nsIPermissionManager::ALLOW_ACTION,
kPermissionDenied = nsIPermissionManager::DENY_ACTION,
kPermissionPrompt = nsIPermissionManager::PROMPT_ACTION
};
class LoggingInfo;
class PBackgroundIDBFactoryParent;
class PBackgroundIndexedDBUtilsParent;
@ -50,23 +56,6 @@ RefPtr<mozilla::dom::quota::Client> CreateQuotaClient();
FileHandleThreadPool* GetFileHandleThreadPool();
class PermissionRequestHelper final : public PermissionRequestBase {
public:
PermissionRequestHelper(
Element* aOwnerElement, nsIPrincipal* aPrincipal,
PBrowserParent::IndexedDBPermissionRequestResolver& aResolver)
: PermissionRequestBase(aOwnerElement, aPrincipal),
mResolver(aResolver) {}
protected:
~PermissionRequestHelper() override = default;
private:
PBrowserParent::IndexedDBPermissionRequestResolver mResolver;
void OnPromptComplete(PermissionValue aPermissionValue) override;
};
} // namespace indexedDB
} // namespace mozilla::dom

View File

@ -38,12 +38,7 @@ protocol PBackgroundIDBFactoryRequest
child:
async __delete__(FactoryRequestResponse response);
async PermissionChallenge(PrincipalInfo principalInfo);
async Blocked(uint64_t currentVersion);
parent:
async PermissionRetry();
};
} // namespace indexedDB

View File

@ -1,222 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "PermissionRequestBase.h"
#include "IndexedDBCommon.h"
#include "MainThreadUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/Services.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/quota/ResultExtensions.h"
#include "nsIObserverService.h"
#include "nsIPrincipal.h"
#include "nsXULAppAPI.h"
namespace mozilla::dom::indexedDB {
using namespace mozilla::services;
namespace {
#define IDB_PREFIX "indexedDB"
#define TOPIC_PREFIX IDB_PREFIX "-permissions-"
const nsLiteralCString kPermissionString = nsLiteralCString(IDB_PREFIX);
const char kPermissionPromptTopic[] = TOPIC_PREFIX "prompt";
#ifdef DEBUG
const char kPermissionResponseTopic[] = TOPIC_PREFIX "response";
#endif
#undef TOPIC_PREFIX
#undef IDB_PREFIX
const uint32_t kPermissionDefault = nsIPermissionManager::UNKNOWN_ACTION;
void AssertSanity() {
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(NS_IsMainThread());
}
} // namespace
PermissionRequestBase::PermissionRequestBase(Element* aOwnerElement,
nsIPrincipal* aPrincipal)
: mOwnerElement(aOwnerElement), mPrincipal(aPrincipal) {
AssertSanity();
MOZ_ASSERT(aOwnerElement);
MOZ_ASSERT(aPrincipal);
}
PermissionRequestBase::~PermissionRequestBase() { AssertSanity(); }
// static
Result<PermissionRequestBase::PermissionValue, nsresult>
PermissionRequestBase::GetCurrentPermission(nsIPrincipal& aPrincipal) {
AssertSanity();
const nsCOMPtr<nsIPermissionManager> permMan = GetPermissionManager();
QM_TRY(OkIf(permMan), Err(NS_ERROR_FAILURE));
QM_TRY_INSPECT(
const uint32_t& intPermission,
MOZ_TO_RESULT_INVOKE_MEMBER(permMan, TestExactPermissionFromPrincipal,
&aPrincipal, kPermissionString));
const PermissionValue permission =
PermissionValueForIntPermission(intPermission);
MOZ_ASSERT(permission == kPermissionAllowed ||
permission == kPermissionDenied ||
permission == kPermissionPrompt);
return permission;
}
// static
auto PermissionRequestBase::PermissionValueForIntPermission(
uint32_t aIntPermission) -> PermissionValue {
AssertSanity();
switch (aIntPermission) {
case kPermissionDefault:
return kPermissionPrompt;
case kPermissionAllowed:
return kPermissionAllowed;
case kPermissionDenied:
return kPermissionDenied;
default:
MOZ_CRASH("Bad permission!");
}
MOZ_CRASH("Should never get here!");
}
Result<PermissionRequestBase::PermissionValue, nsresult>
PermissionRequestBase::PromptIfNeeded() {
AssertSanity();
MOZ_ASSERT(mPrincipal);
// Tricky, we want to release the window and principal in all cases except
// when we successfully prompt.
nsCOMPtr<Element> element = std::move(mOwnerElement);
nsCOMPtr<nsIPrincipal> principal = std::move(mPrincipal);
QM_TRY_INSPECT(const PermissionValue& currentValue,
GetCurrentPermission(*principal));
MOZ_ASSERT(currentValue != kPermissionDefault);
if (currentValue == kPermissionPrompt) {
nsCOMPtr<nsIObserverService> obsSvc = GetObserverService();
QM_TRY(OkIf(obsSvc), Err(NS_ERROR_FAILURE));
// We're about to prompt so move the members back.
mOwnerElement = std::move(element);
mPrincipal = std::move(principal);
QM_TRY(
MOZ_TO_RESULT(obsSvc->NotifyObservers(static_cast<nsIObserver*>(this),
kPermissionPromptTopic, nullptr)),
QM_PROPAGATE, [this](const auto&) {
// Finally release if we failed the prompt.
mOwnerElement = nullptr;
mPrincipal = nullptr;
});
}
return currentValue;
}
void PermissionRequestBase::SetExplicitPermission(nsIPrincipal* aPrincipal,
uint32_t aIntPermission) {
AssertSanity();
MOZ_ASSERT(aPrincipal);
MOZ_ASSERT(aIntPermission == kPermissionAllowed ||
aIntPermission == kPermissionDenied);
nsCOMPtr<nsIPermissionManager> permMan = GetPermissionManager();
if (NS_WARN_IF(!permMan)) {
return;
}
nsresult rv =
permMan->AddFromPrincipal(aPrincipal, kPermissionString, aIntPermission,
nsIPermissionManager::EXPIRE_NEVER,
/* aExpireTime */ 0);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
}
NS_IMPL_ISUPPORTS(PermissionRequestBase, nsIObserver, nsIIDBPermissionsRequest)
NS_IMETHODIMP
PermissionRequestBase::GetBrowserElement(Element** aElement) {
AssertSanity();
*aElement = do_AddRef(mOwnerElement).take();
return NS_OK;
}
NS_IMETHODIMP
PermissionRequestBase::GetResponseObserver(nsIObserver** aObserver) {
AssertSanity();
*aObserver = do_AddRef(this).take();
return NS_OK;
}
NS_IMETHODIMP
PermissionRequestBase::Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData) {
AssertSanity();
MOZ_ASSERT(!strcmp(aTopic, kPermissionResponseTopic));
MOZ_ASSERT(mOwnerElement);
MOZ_ASSERT(mPrincipal);
const nsCOMPtr<Element> element = std::move(mOwnerElement);
Unused << element;
const nsCOMPtr<nsIPrincipal> principal = std::move(mPrincipal);
nsresult rv;
uint32_t promptResult = nsDependentString(aData).ToInteger(&rv);
MOZ_ALWAYS_SUCCEEDS(rv);
// The UI prompt code will only return one of these three values. We have to
// transform it to our values.
MOZ_ASSERT(promptResult == kPermissionDefault ||
promptResult == kPermissionAllowed ||
promptResult == kPermissionDenied);
if (promptResult != kPermissionDefault) {
// Save explicitly allowed or denied permissions now.
SetExplicitPermission(principal, promptResult);
}
PermissionValue permission;
switch (promptResult) {
case kPermissionDefault:
permission = kPermissionPrompt;
break;
case kPermissionAllowed:
permission = kPermissionAllowed;
break;
case kPermissionDenied:
permission = kPermissionDenied;
break;
default:
MOZ_CRASH("Bad prompt result!");
}
OnPromptComplete(permission);
return NS_OK;
}
} // namespace mozilla::dom::indexedDB

View File

@ -1,70 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_indexeddb_permissionrequestbase_h__
#define mozilla_dom_indexeddb_permissionrequestbase_h__
#include "mozilla/Attributes.h"
#include "nsCOMPtr.h"
#include "nsIIDBPermissionsRequest.h"
#include "nsIObserver.h"
#include "nsIPermissionManager.h"
#include "nsISupportsImpl.h"
#include "nsString.h"
class nsIPrincipal;
namespace mozilla::dom {
class Element;
namespace indexedDB {
class PermissionRequestBase : public nsIObserver,
public nsIIDBPermissionsRequest {
nsCOMPtr<Element> mOwnerElement;
nsCOMPtr<nsIPrincipal> mPrincipal;
public:
enum PermissionValue {
kPermissionAllowed = nsIPermissionManager::ALLOW_ACTION,
kPermissionDenied = nsIPermissionManager::DENY_ACTION,
kPermissionPrompt = nsIPermissionManager::PROMPT_ACTION
};
NS_DECL_ISUPPORTS
// This function will not actually prompt. It will never return
// kPermissionDefault but will instead translate the permission manager value
// into the correct value for the given type.
static Result<PermissionValue, nsresult> GetCurrentPermission(
nsIPrincipal& aPrincipal);
static PermissionValue PermissionValueForIntPermission(
uint32_t aIntPermission);
// This function will prompt if needed. It may only be called once.
Result<PermissionValue, nsresult> PromptIfNeeded();
protected:
PermissionRequestBase(Element* aOwnerElement, nsIPrincipal* aPrincipal);
// Reference counted.
virtual ~PermissionRequestBase();
virtual void OnPromptComplete(PermissionValue aPermissionValue) = 0;
private:
void SetExplicitPermission(nsIPrincipal* aPrincipal, uint32_t aIntPermission);
NS_DECL_NSIOBSERVER
NS_DECL_NSIIDBPERMISSIONSREQUEST
};
} // namespace indexedDB
} // namespace mozilla::dom
#endif // mozilla_dom_indexeddb_permissionrequestbase_h__

View File

@ -50,7 +50,6 @@ EXPORTS.mozilla.dom.indexedDB += [
"IDBResult.h",
"Key.h",
"KeyPath.h",
"PermissionRequestBase.h",
"SerializationHelpers.h",
"ThreadLocal.h",
]
@ -77,7 +76,6 @@ UNIFIED_SOURCES += [
"IndexedDatabaseManager.cpp",
"IndexedDBCommon.cpp",
"KeyPath.cpp",
"PermissionRequestBase.cpp",
"ProfilerHelpers.cpp",
"ReportInternalError.cpp",
"SchemaUpgrades.cpp",

View File

@ -1361,36 +1361,6 @@ bool BrowserParent::DeallocPFilePickerParent(PFilePickerParent* actor) {
return true;
}
IPCResult BrowserParent::RecvIndexedDBPermissionRequest(
nsIPrincipal* aPrincipal, IndexedDBPermissionRequestResolver&& aResolve) {
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIPrincipal> principal(aPrincipal);
if (!principal) {
return IPC_FAIL_NO_REASON(this);
}
if (NS_WARN_IF(!mFrameElement)) {
return IPC_FAIL_NO_REASON(this);
}
RefPtr<indexedDB::PermissionRequestHelper> actor =
new indexedDB::PermissionRequestHelper(mFrameElement, principal,
aResolve);
mozilla::Result permissionOrErr = actor->PromptIfNeeded();
if (permissionOrErr.isErr()) {
return IPC_FAIL_NO_REASON(this);
}
if (permissionOrErr.inspect() !=
indexedDB::PermissionRequestBase::kPermissionPrompt) {
aResolve(permissionOrErr.inspect());
}
return IPC_OK();
}
already_AddRefed<PSessionStoreParent>
BrowserParent::AllocPSessionStoreParent() {
RefPtr<BrowserSessionStore> sessionStore =

View File

@ -604,9 +604,6 @@ class BrowserParent final : public PBrowserParent,
bool DeallocPFilePickerParent(PFilePickerParent* actor);
mozilla::ipc::IPCResult RecvIndexedDBPermissionRequest(
nsIPrincipal* aPrincipal, IndexedDBPermissionRequestResolver&& aResolve);
bool GetGlobalJSObject(JSContext* cx, JSObject** globalp);
void StartPersistence(CanonicalBrowsingContext* aContext,

View File

@ -441,19 +441,6 @@ parent:
async PFilePicker(nsString aTitle, int16_t aMode);
/**
* Initiates an asynchronous request for one of the special indexedDB
* permissions for the provided principal.
*
* @param principal
* The principal of the request.
*
* NOTE: The principal is untrusted in the parent process. Only
* principals that can live in the content process should
* provided.
*/
async IndexedDBPermissionRequest(nsIPrincipal aPrincipal) returns (uint32_t permission);
/**
* Tells the containing widget whether the given input block results in a
* swipe. Should be called in response to a WidgetWheelEvent that has