Bug 1614831 - Speed up the transmission of permissions to content processes upon navigation; r=baku

Differential Revision: https://phabricator.services.mozilla.com/D63674

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Ehsan Akhgari 2020-02-24 15:21:51 +00:00
Родитель 4f58cf3e36
Коммит a8ca0713ed
4 изменённых файлов: 67 добавлений и 42 удалений

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

@ -1466,7 +1466,7 @@ void ContentParent::Init() {
// Ensure that the default set of permissions are avaliable in the content
// process before we try to load any URIs in it.
EnsurePermissionsByKey(EmptyCString());
EnsurePermissionsByKey(EmptyCString(), EmptyCString());
RefPtr<GeckoMediaPluginServiceParent> gmps(
GeckoMediaPluginServiceParent::GetSingleton());
@ -5644,11 +5644,11 @@ nsresult ContentParent::AboutToLoadHttpFtpDocumentForChild(
nsresult ContentParent::TransmitPermissionsForPrincipal(
nsIPrincipal* aPrincipal) {
// Create the key, and send it down to the content process.
nsTArray<nsCString> keys =
nsTArray<Pair<nsCString, nsCString>> pairs =
nsPermissionManager::GetAllKeysForPrincipal(aPrincipal);
MOZ_ASSERT(keys.Length() >= 1);
for (auto& key : keys) {
EnsurePermissionsByKey(key);
MOZ_ASSERT(pairs.Length() >= 1);
for (auto& pair : pairs) {
EnsurePermissionsByKey(pair.first(), pair.second());
}
return NS_OK;
@ -5688,7 +5688,8 @@ void ContentParent::TransmitBlobURLsForPrincipal(nsIPrincipal* aPrincipal) {
}
}
void ContentParent::EnsurePermissionsByKey(const nsCString& aKey) {
void ContentParent::EnsurePermissionsByKey(const nsCString& aKey,
const nsCString& aOrigin) {
// NOTE: Make sure to initialize the permission manager before updating the
// mActivePermissionKeys list. If the permission manager is being initialized
// by this call to GetPermissionManager, and we've added the key to
@ -5705,7 +5706,7 @@ void ContentParent::EnsurePermissionsByKey(const nsCString& aKey) {
mActivePermissionKeys.PutEntry(aKey);
nsTArray<IPC::Permission> perms;
if (permManager->GetPermissionsWithKey(aKey, perms)) {
if (permManager->GetPermissionsFromOriginOrKey(aOrigin, aKey, perms)) {
Unused << SendSetPermissionsWithKey(aKey, perms);
}
}

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

@ -874,7 +874,7 @@ class ContentParent final
//
// See nsIPermissionManager::GetPermissionsForKey for more information on
// these keys.
void EnsurePermissionsByKey(const nsCString& aKey);
void EnsurePermissionsByKey(const nsCString& aKey, const nsCString& aOrigin);
static void ForceKillTimerCallback(nsITimer* aTimer, void* aClosure);

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

@ -3040,8 +3040,9 @@ void nsPermissionManager::UpdateDB(
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
bool nsPermissionManager::GetPermissionsWithKey(
const nsACString& aPermissionKey, nsTArray<IPC::Permission>& aPerms) {
bool nsPermissionManager::GetPermissionsFromOriginOrKey(
const nsACString& aOrigin, const nsACString& aKey,
nsTArray<IPC::Permission>& aPerms) {
aPerms.Clear();
if (NS_WARN_IF(XRE_IsContentProcess())) {
return false;
@ -3051,28 +3052,41 @@ bool nsPermissionManager::GetPermissionsWithKey(
PermissionHashKey* entry = iter.Get();
nsAutoCString permissionKey;
// We can't check for individual OA strip perms here.
// Don't force strip origin attributes.
GetKeyForOrigin(entry->GetKey()->mOrigin, false, permissionKey);
if (aOrigin.IsEmpty()) {
// We can't check for individual OA strip perms here.
// Don't force strip origin attributes.
GetKeyForOrigin(entry->GetKey()->mOrigin, false, permissionKey);
// If the keys don't match, and we aren't getting the default "" key, then
// we can exit early. We have to keep looking if we're getting the default
// key, as we may see a preload permission which should be transmitted.
if (aPermissionKey != permissionKey && !aPermissionKey.IsEmpty()) {
// If the keys don't match, and we aren't getting the default "" key, then
// we can exit early. We have to keep looking if we're getting the default
// key, as we may see a preload permission which should be transmitted.
if (aKey != permissionKey && !aKey.IsEmpty()) {
continue;
}
} else if (aOrigin != entry->GetKey()->mOrigin) {
// If the origins don't match, then we can exit early. We have to keep
// looking if we're getting the default origin, as we may see a preload
// permission which should be transmitted.
continue;
}
for (const auto& permEntry : entry->GetPermissions()) {
// Given how "default" permissions work and the possibility of them being
// overridden with UNKNOWN_ACTION, we might see this value here - but we
// do not want to send it to the content process.
// Given how "default" permissions work and the possibility of them
// being overridden with UNKNOWN_ACTION, we might see this value here -
// but we do not want to send it to the content process.
if (permEntry.mPermission == nsIPermissionManager::UNKNOWN_ACTION) {
continue;
}
bool isPreload = IsPreloadPermission(mTypeArray[permEntry.mType]);
if ((isPreload && aPermissionKey.IsEmpty()) ||
(!isPreload && aPermissionKey == permissionKey)) {
bool shouldAppend;
if (aOrigin.IsEmpty()) {
shouldAppend = (isPreload && aKey.IsEmpty()) ||
(!isPreload && aKey == permissionKey);
} else {
shouldAppend = (!isPreload && aOrigin == entry->GetKey()->mOrigin);
}
if (shouldAppend) {
aPerms.AppendElement(
IPC::Permission(entry->GetKey()->mOrigin,
mTypeArray[permEntry.mType], permEntry.mPermission,
@ -3205,26 +3219,30 @@ void nsPermissionManager::GetKeyForPermission(nsIPrincipal* aPrincipal,
}
/* static */
nsTArray<nsCString> nsPermissionManager::GetAllKeysForPrincipal(
nsIPrincipal* aPrincipal) {
nsTArray<Pair<nsCString, nsCString>>
nsPermissionManager::GetAllKeysForPrincipal(nsIPrincipal* aPrincipal) {
MOZ_ASSERT(aPrincipal);
nsTArray<nsCString> keys;
nsTArray<Pair<nsCString, nsCString>> pairs;
nsCOMPtr<nsIPrincipal> prin = aPrincipal;
while (prin) {
// Add the key to the list
nsCString* key = keys.AppendElement();
// Add the pair to the list
Pair<nsCString, nsCString>* pair =
pairs.AppendElement(MakePair(EmptyCString(), EmptyCString()));
GetKeyForPrincipal(prin, false, pair->first());
// We can't check for individual OA strip perms here.
// Don't force strip origin attributes.
GetKeyForPrincipal(prin, false, *key);
GetKeyForPrincipal(prin, false, pair->first());
Unused << prin->GetOrigin(pair->second());
// Get the next subdomain principal and loop back around.
prin = GetNextSubDomainPrincipal(prin);
}
MOZ_ASSERT(keys.Length() >= 1,
"Every principal should have at least one key.");
return keys;
MOZ_ASSERT(pairs.Length() >= 1,
"Every principal should have at least one pair item.");
return pairs;
}
NS_IMETHODIMP
@ -3274,16 +3292,17 @@ void nsPermissionManager::WhenPermissionsAvailable(nsIPrincipal* aPrincipal,
}
nsTArray<RefPtr<GenericNonExclusivePromise>> promises;
for (auto& key : GetAllKeysForPrincipal(aPrincipal)) {
for (auto& pair : GetAllKeysForPrincipal(aPrincipal)) {
RefPtr<GenericNonExclusivePromise::Private> promise;
if (!mPermissionKeyPromiseMap.Get(key, getter_AddRefs(promise))) {
if (!mPermissionKeyPromiseMap.Get(pair.first(), getter_AddRefs(promise))) {
// In this case we have found a permission which isn't available 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 GenericNonExclusivePromise::Private(__func__);
mPermissionKeyPromiseMap.Put(
key, RefPtr<GenericNonExclusivePromise::Private>(promise).forget());
pair.first(),
RefPtr<GenericNonExclusivePromise::Private>(promise).forget());
}
if (promise) {

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

@ -24,6 +24,7 @@
#include "mozilla/BasePrincipal.h"
#include "mozilla/ExpandedPrincipal.h"
#include "mozilla/MozPromise.h"
#include "mozilla/Pair.h"
#include "mozilla/Unused.h"
#include "mozilla/Variant.h"
#include "mozilla/Vector.h"
@ -278,7 +279,7 @@ class nsPermissionManager final : public nsIPermissionManager,
*
* Get all permissions keys which could correspond to the given principal.
* This method, like GetKeyForPrincipal, is infallible and should always
* produce at least one key.
* produce at least one (key, origin) pair.
*
* Unlike GetKeyForPrincipal, this method also gets the keys for base domains
* of the given principal. All keys returned by this method must be available
@ -286,8 +287,10 @@ class nsPermissionManager final : public nsIPermissionManager,
* checked in the `aExactHostMatch = false` situation.
*
* @param aPrincipal The Principal which the key is to be extracted from.
* @return returns an array of (key, origin) pairs.
*/
static nsTArray<nsCString> GetAllKeysForPrincipal(nsIPrincipal* aPrincipal);
static nsTArray<mozilla::Pair<nsCString, nsCString>> GetAllKeysForPrincipal(
nsIPrincipal* aPrincipal);
// From ContentChild.
nsresult RemoveAllFromIPC();
@ -313,15 +316,17 @@ class nsPermissionManager final : public nsIPermissionManager,
* determining the permission key for a given principal.
*
* This method may only be called in the parent process. It fills the nsTArray
* argument with the IPC::Permission objects which have a matching permission
* key.
* argument with the IPC::Permission objects which have a matching origin.
*
* @param permissionKey The key to use to find the permissions of interest.
* @param origin The origin to use to find the permissions of interest.
* @param key The key to use to find the permissions of interest. Only used
* when the origin argument is empty.
* @param perms An array which will be filled with the permissions which
* match the given permission key.
* match the given origin.
*/
bool GetPermissionsWithKey(const nsACString& aPermissionKey,
nsTArray<IPC::Permission>& aPerms);
bool GetPermissionsFromOriginOrKey(const nsACString& aOrigin,
const nsACString& aKey,
nsTArray<IPC::Permission>& aPerms);
/**
* See `nsPermissionManager::GetPermissionsWithKey` for more info on