mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 07:13:20 +00:00
Bug 1355608 - Part 1: Add tools to nsPermissionManager to await permissions becoming avaliable, r=baku
MozReview-Commit-ID: 1HDS8zw6dpF
This commit is contained in:
parent
4966d64d16
commit
d9adddc93f
@ -40,11 +40,12 @@
|
||||
#include "nsToolkitCompsCID.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "mozilla/AbstractThread.h"
|
||||
|
||||
static nsPermissionManager *gPermissionManager = nullptr;
|
||||
|
||||
using mozilla::dom::ContentParent;
|
||||
using mozilla::Unused; // ha!
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
static bool
|
||||
IsChildProcess()
|
||||
@ -848,6 +849,15 @@ nsPermissionManager::nsPermissionManager()
|
||||
|
||||
nsPermissionManager::~nsPermissionManager()
|
||||
{
|
||||
// NOTE: Make sure to reject each of the promises in mPermissionKeyPromiseMap
|
||||
// before destroying.
|
||||
for (auto iter = mPermissionKeyPromiseMap.Iter(); !iter.Done(); iter.Next()) {
|
||||
if (iter.Data()) {
|
||||
iter.Data()->Reject(NS_ERROR_FAILURE, __func__);
|
||||
}
|
||||
}
|
||||
mPermissionKeyPromiseMap.Clear();
|
||||
|
||||
RemoveAllFromMemory();
|
||||
gPermissionManager = nullptr;
|
||||
}
|
||||
@ -3044,13 +3054,20 @@ nsPermissionManager::SetPermissionsWithKey(const nsACString& aPermissionKey,
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// Record that we have seen the permissions with the given permission key.
|
||||
if (NS_WARN_IF(mAvailablePermissionKeys.Contains(aPermissionKey))) {
|
||||
RefPtr<GenericPromise::Private> promise;
|
||||
bool foundKey = mPermissionKeyPromiseMap.Get(aPermissionKey, getter_AddRefs(promise));
|
||||
if (promise) {
|
||||
MOZ_ASSERT(foundKey);
|
||||
// NOTE: This will resolve asynchronously, so we can mark it as resolved
|
||||
// now, and be confident that we will have filled in the database before any
|
||||
// callbacks run.
|
||||
promise->Resolve(true, __func__);
|
||||
} else if (foundKey) {
|
||||
// NOTE: We shouldn't be sent two InitializePermissionsWithKey for the same
|
||||
// key, but it's possible.
|
||||
return NS_OK;
|
||||
}
|
||||
mAvailablePermissionKeys.PutEntry(aPermissionKey);
|
||||
mPermissionKeyPromiseMap.Put(aPermissionKey, nullptr);
|
||||
|
||||
// Add the permissions locally to our process
|
||||
for (IPC::Permission& perm : aPerms) {
|
||||
@ -3171,7 +3188,11 @@ nsPermissionManager::PermissionAvaliable(nsIPrincipal* aPrincipal, const char* a
|
||||
nsAutoCString permissionKey;
|
||||
// NOTE: GetKeyForPermission accepts a null aType.
|
||||
GetKeyForPermission(aPrincipal, aType, permissionKey);
|
||||
if (!mAvailablePermissionKeys.Contains(permissionKey)) {
|
||||
|
||||
// If we have a pending promise for the permission key in question, we don't
|
||||
// have the permission avaliable, so report a warning and return false.
|
||||
RefPtr<GenericPromise::Private> promise;
|
||||
if (!mPermissionKeyPromiseMap.Get(permissionKey, getter_AddRefs(promise)) || promise) {
|
||||
// Emit a useful diagnostic warning with the permissionKey for the process
|
||||
// which hasn't received permissions yet.
|
||||
NS_WARNING(nsPrintfCString("This content process hasn't received the "
|
||||
@ -3181,3 +3202,49 @@ nsPermissionManager::PermissionAvaliable(nsIPrincipal* aPrincipal, const char* a
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPermissionManager::WhenPermissionsAvailable(nsIPrincipal* aPrincipal,
|
||||
nsIRunnable* aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(aRunnable);
|
||||
|
||||
if (!XRE_IsContentProcess()) {
|
||||
aRunnable->Run();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsTArray<RefPtr<GenericPromise>> promises;
|
||||
for (auto& key : GetAllKeysForPrincipal(aPrincipal)) {
|
||||
RefPtr<GenericPromise::Private> promise;
|
||||
if (!mPermissionKeyPromiseMap.Get(key, getter_AddRefs(promise))) {
|
||||
// In this case we have found a permission which isn't avaliable in the
|
||||
// content process and hasn't been requested yet. We need to create a new
|
||||
// promise, and send the request to the parent (if we have not already
|
||||
// done so).
|
||||
promise = new GenericPromise::Private(__func__);
|
||||
mPermissionKeyPromiseMap.Put(key, RefPtr<GenericPromise::Private>(promise).forget());
|
||||
}
|
||||
|
||||
if (promise) {
|
||||
promises.AppendElement(Move(promise));
|
||||
}
|
||||
}
|
||||
|
||||
// If all of our permissions are avaliable, immediately run the runnable. This
|
||||
// avoids any extra overhead during fetch interception which is performance
|
||||
// sensitive.
|
||||
if (promises.IsEmpty()) {
|
||||
aRunnable->Run();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<nsIRunnable> runnable = aRunnable;
|
||||
GenericPromise::All(AbstractThread::GetCurrent(), promises)->Then(
|
||||
AbstractThread::GetCurrent(), __func__,
|
||||
[runnable] () { runnable->Run(); },
|
||||
[] () {
|
||||
NS_WARNING("nsPermissionManager permission promise rejected. We're probably shutting down.");
|
||||
});
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -18,6 +18,9 @@
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "mozilla/MozPromise.h"
|
||||
|
||||
namespace mozilla {
|
||||
class OriginAttributesPattern;
|
||||
@ -323,6 +326,8 @@ private:
|
||||
*/
|
||||
bool PermissionAvaliable(nsIPrincipal* aPrincipal, const char* aType);
|
||||
|
||||
nsRefPtrHashtable<nsCStringHashKey, mozilla::GenericPromise::Private> mPermissionKeyPromiseMap;
|
||||
|
||||
nsCOMPtr<mozIStorageConnection> mDBConn;
|
||||
nsCOMPtr<mozIStorageAsyncStatement> mStmtInsert;
|
||||
nsCOMPtr<mozIStorageAsyncStatement> mStmtDelete;
|
||||
@ -337,9 +342,6 @@ private:
|
||||
// An array to store the strings identifying the different types.
|
||||
nsTArray<nsCString> mTypeArray;
|
||||
|
||||
// The base domains which have their permissions loaded in the current process.
|
||||
nsTHashtable<nsCStringHashKey> mAvailablePermissionKeys;
|
||||
|
||||
// Initially, |false|. Set to |true| once shutdown has started, to avoid
|
||||
// reopening the database.
|
||||
bool mIsShuttingDown;
|
||||
|
@ -36,6 +36,7 @@ interface nsIPrincipal;
|
||||
interface mozIDOMWindow;
|
||||
interface nsIPermission;
|
||||
interface nsISimpleEnumerator;
|
||||
interface nsIRunnable;
|
||||
|
||||
%{ C++
|
||||
namespace IPC {
|
||||
@ -326,6 +327,22 @@ interface nsIPermissionManager : nsISupports
|
||||
* @param aPrincipal The principal to broadcast permissions for.
|
||||
*/
|
||||
void broadcastPermissionsForPrincipalToAllContentProcesses(in nsIPrincipal aPrincipal);
|
||||
|
||||
/**
|
||||
* Add a callback which should be run when all permissions are available for
|
||||
* the given nsIPrincipal. This method invokes the callback runnable
|
||||
* synchronously when the permissions are already available.
|
||||
*
|
||||
* NOTE: This method will not request the permissions be sent by the parent
|
||||
* process. This should only be used to wait for permissions which may not
|
||||
* have arrived yet in order to ensure they are present.
|
||||
*
|
||||
* @param aPrincipal The principal to wait for permissions to be available for.
|
||||
* @param aRunnable The runnable to run when permissions are available for the
|
||||
* given principal.
|
||||
*/
|
||||
void whenPermissionsAvailable(in nsIPrincipal aPrincipal,
|
||||
in nsIRunnable aRunnable);
|
||||
};
|
||||
|
||||
%{ C++
|
||||
|
Loading…
Reference in New Issue
Block a user