mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
Bug 1362791 - Enable testing permissions using URIs without having to mint principals; r=mystor
The permissions manager store uses principal origins with suffix in the key entry, but for the API entry points where we accept a raw nsIURI, we currently mint a new codebase principal with a blank OriginAttributes only to read out the origin string effectively, since the suffix is guaranteed to always be an empty string in this case. This can be slow, so this patch adds a fast path to bypass minting a new principal and uses ContentPrincipal::GenerateOriginNoSuffixFromURI() to generate the origin string from the input nsIURI directly.
This commit is contained in:
parent
05a604bb4f
commit
214e03003f
@ -14,6 +14,10 @@ UNIFIED_SOURCES += [
|
||||
'nsPopupWindowManager.cpp',
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/caps',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 2; 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/. */
|
||||
@ -41,6 +42,7 @@
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "mozilla/AbstractThread.h"
|
||||
#include "ContentPrincipal.h"
|
||||
|
||||
static nsPermissionManager *gPermissionManager = nullptr;
|
||||
|
||||
@ -238,6 +240,37 @@ GetNextSubDomainForHost(const nsACString& aHost)
|
||||
return subDomain;
|
||||
}
|
||||
|
||||
// This function produces a nsIURI which is identical to the current
|
||||
// nsIURI, except that it has one less subdomain segment. It returns
|
||||
// `nullptr` if there are no more segments to remove.
|
||||
already_AddRefed<nsIURI>
|
||||
GetNextSubDomainURI(nsIURI* aURI)
|
||||
{
|
||||
nsAutoCString host;
|
||||
nsresult rv = aURI->GetHost(host);
|
||||
if (NS_FAILED(rv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCString domain = GetNextSubDomainForHost(host);
|
||||
if (domain.IsEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
rv = aURI->Clone(getter_AddRefs(uri));
|
||||
if (NS_FAILED(rv) || !uri) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rv = uri->SetHost(domain);
|
||||
if (NS_FAILED(rv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return uri.forget();
|
||||
}
|
||||
|
||||
// This function produces a nsIPrincipal which is identical to the current
|
||||
// nsIPrincipal, except that it has one less subdomain segment. It returns
|
||||
// `nullptr` if there are no more segments to remove.
|
||||
@ -250,26 +283,9 @@ GetNextSubDomainPrincipal(nsIPrincipal* aPrincipal)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsAutoCString host;
|
||||
rv = uri->GetHost(host);
|
||||
if (NS_FAILED(rv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCString domain = GetNextSubDomainForHost(host);
|
||||
if (domain.IsEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Create a new principal which is identical to the current one, but with the new host
|
||||
nsCOMPtr<nsIURI> newURI;
|
||||
rv = uri->Clone(getter_AddRefs(newURI));
|
||||
if (NS_FAILED(rv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rv = newURI->SetHost(domain);
|
||||
if (NS_FAILED(rv)) {
|
||||
nsCOMPtr<nsIURI> newURI = GetNextSubDomainURI(uri);
|
||||
if (!newURI) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -711,6 +727,18 @@ nsPermissionManager::PermissionKey::CreateFromPrincipal(nsIPrincipal* aPrincipal
|
||||
return new PermissionKey(origin);
|
||||
}
|
||||
|
||||
nsPermissionManager::PermissionKey*
|
||||
nsPermissionManager::PermissionKey::CreateFromURI(nsIURI* aURI, nsresult& aResult)
|
||||
{
|
||||
nsAutoCString origin;
|
||||
aResult = ContentPrincipal::GenerateOriginNoSuffixFromURI(aURI, origin);
|
||||
if (NS_WARN_IF(NS_FAILED(aResult))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new PermissionKey(origin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple callback used by |AsyncClose| to trigger a treatment once
|
||||
* the database is closed.
|
||||
@ -2069,11 +2097,7 @@ nsPermissionManager::TestExactPermission(nsIURI *aURI,
|
||||
const char *aType,
|
||||
uint32_t *aPermission)
|
||||
{
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
nsresult rv = GetPrincipal(aURI, getter_AddRefs(principal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return TestExactPermissionFromPrincipal(principal, aType, aPermission);
|
||||
return CommonTestPermission(aURI, aType, aPermission, true, true);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -2097,11 +2121,7 @@ nsPermissionManager::TestPermission(nsIURI *aURI,
|
||||
const char *aType,
|
||||
uint32_t *aPermission)
|
||||
{
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
nsresult rv = GetPrincipal(aURI, getter_AddRefs(principal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return TestPermissionFromPrincipal(principal, aType, aPermission);
|
||||
return CommonTestPermission(aURI, aType, aPermission, false, true);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -2198,16 +2218,19 @@ nsPermissionManager::GetPermissionObject(nsIPrincipal* aPrincipal,
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsPermissionManager::CommonTestPermission(nsIPrincipal* aPrincipal,
|
||||
const char *aType,
|
||||
uint32_t *aPermission,
|
||||
bool aExactHostMatch,
|
||||
bool aIncludingSession)
|
||||
nsPermissionManager::CommonTestPermissionInternal(nsIPrincipal* aPrincipal,
|
||||
nsIURI * aURI,
|
||||
const char * aType,
|
||||
uint32_t * aPermission,
|
||||
bool aExactHostMatch,
|
||||
bool aIncludingSession)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aPrincipal);
|
||||
MOZ_ASSERT(aPrincipal || aURI);
|
||||
MOZ_ASSERT_IF(aPrincipal, !aURI);
|
||||
NS_ENSURE_ARG_POINTER(aPrincipal || aURI);
|
||||
NS_ENSURE_ARG_POINTER(aType);
|
||||
|
||||
if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
|
||||
if (aPrincipal && nsContentUtils::IsSystemPrincipal(aPrincipal)) {
|
||||
*aPermission = nsIPermissionManager::ALLOW_ACTION;
|
||||
return NS_OK;
|
||||
}
|
||||
@ -2225,8 +2248,8 @@ nsPermissionManager::CommonTestPermission(nsIPrincipal* aPrincipal,
|
||||
|
||||
for (size_t i = 0; i < whitelist->Length(); ++i) {
|
||||
uint32_t perm;
|
||||
rv = CommonTestPermission(whitelist->ElementAt(i), aType, &perm, aExactHostMatch,
|
||||
aIncludingSession);
|
||||
rv = CommonTestPermission(whitelist->ElementAt(i), aType, &perm,
|
||||
aExactHostMatch, aIncludingSession);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (perm == nsIPermissionManager::ALLOW_ACTION) {
|
||||
*aPermission = perm;
|
||||
@ -2240,14 +2263,24 @@ nsPermissionManager::CommonTestPermission(nsIPrincipal* aPrincipal,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(PermissionAvaliable(aPrincipal, aType));
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsCOMPtr<nsIPrincipal> prin = aPrincipal;
|
||||
if (!prin) {
|
||||
prin = mozilla::BasePrincipal::CreateCodebasePrincipal(aURI, OriginAttributes());
|
||||
}
|
||||
MOZ_ASSERT(PermissionAvaliable(prin, aType));
|
||||
}
|
||||
#endif
|
||||
|
||||
int32_t typeIndex = GetTypeIndex(aType, false);
|
||||
// If type == -1, the type isn't known,
|
||||
// so just return NS_OK
|
||||
if (typeIndex == -1) return NS_OK;
|
||||
|
||||
PermissionHashKey* entry = GetPermissionHashKey(aPrincipal, typeIndex, aExactHostMatch);
|
||||
PermissionHashKey* entry = aPrincipal ?
|
||||
GetPermissionHashKey(aPrincipal, typeIndex, aExactHostMatch) :
|
||||
GetPermissionHashKey(aURI, typeIndex, aExactHostMatch);
|
||||
if (!entry ||
|
||||
(!aIncludingSession &&
|
||||
entry->GetPermission(typeIndex).mNonSessionExpireType ==
|
||||
@ -2317,6 +2350,74 @@ nsPermissionManager::GetPermissionHashKey(nsIPrincipal* aPrincipal,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Returns PermissionHashKey for a given { host, appId, isInBrowserElement } tuple.
|
||||
// This is not simply using PermissionKey because we will walk-up domains in
|
||||
// case of |host| contains sub-domains.
|
||||
// Returns null if nothing found.
|
||||
// Also accepts host on the format "<foo>". This will perform an exact match
|
||||
// lookup as the string doesn't contain any dots.
|
||||
nsPermissionManager::PermissionHashKey*
|
||||
nsPermissionManager::GetPermissionHashKey(nsIURI* aURI,
|
||||
uint32_t aType,
|
||||
bool aExactHostMatch)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
nsresult rv = GetPrincipal(aURI, getter_AddRefs(principal));
|
||||
MOZ_ASSERT_IF(NS_SUCCEEDED(rv),
|
||||
PermissionAvaliable(principal, mTypeArray[aType].get()));
|
||||
}
|
||||
#endif
|
||||
|
||||
nsresult rv;
|
||||
RefPtr<PermissionKey> key =
|
||||
PermissionKey::CreateFromURI(aURI, rv);
|
||||
if (!key) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PermissionHashKey* entry = mPermissionTable.GetEntry(key);
|
||||
|
||||
if (entry) {
|
||||
PermissionEntry permEntry = entry->GetPermission(aType);
|
||||
|
||||
// if the entry is expired, remove and keep looking for others.
|
||||
// Note that EXPIRE_SESSION only honors expireTime if it is nonzero.
|
||||
if ((permEntry.mExpireType == nsIPermissionManager::EXPIRE_TIME ||
|
||||
(permEntry.mExpireType == nsIPermissionManager::EXPIRE_SESSION &&
|
||||
permEntry.mExpireTime != 0)) &&
|
||||
permEntry.mExpireTime <= (PR_Now() / 1000)) {
|
||||
entry = nullptr;
|
||||
// If we need to remove a permission we mint a principal. This is a bit
|
||||
// inefficient, but hopefully this code path isn't super common.
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
nsresult rv = GetPrincipal(aURI, getter_AddRefs(principal));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
RemoveFromPrincipal(principal, mTypeArray[aType].get());
|
||||
} else if (permEntry.mPermission == nsIPermissionManager::UNKNOWN_ACTION) {
|
||||
entry = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (entry) {
|
||||
return entry;
|
||||
}
|
||||
|
||||
// If aExactHostMatch wasn't true, we can check if the base domain has a permission entry.
|
||||
if (!aExactHostMatch) {
|
||||
nsCOMPtr<nsIURI> uri = GetNextSubDomainURI(aURI);
|
||||
if (uri) {
|
||||
return GetPermissionHashKey(uri, aType, aExactHostMatch);
|
||||
}
|
||||
}
|
||||
|
||||
// No entry, really...
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsPermissionManager::GetEnumerator(nsISimpleEnumerator **aEnum)
|
||||
{
|
||||
if (XRE_IsContentProcess()) {
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* -*- 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/. */
|
||||
@ -76,6 +77,8 @@ public:
|
||||
public:
|
||||
static PermissionKey* CreateFromPrincipal(nsIPrincipal* aPrincipal,
|
||||
nsresult& aResult);
|
||||
static PermissionKey* CreateFromURI(nsIURI* aURI,
|
||||
nsresult& aResult);
|
||||
|
||||
explicit PermissionKey(const nsACString& aOrigin)
|
||||
: mOrigin(aOrigin)
|
||||
@ -273,12 +276,36 @@ private:
|
||||
PermissionHashKey* GetPermissionHashKey(nsIPrincipal* aPrincipal,
|
||||
uint32_t aType,
|
||||
bool aExactHostMatch);
|
||||
PermissionHashKey* GetPermissionHashKey(nsIURI* aURI,
|
||||
uint32_t aType,
|
||||
bool aExactHostMatch);
|
||||
|
||||
nsresult CommonTestPermission(nsIPrincipal* aPrincipal,
|
||||
const char *aType,
|
||||
uint32_t *aPermission,
|
||||
const char * aType,
|
||||
uint32_t * aPermission,
|
||||
bool aExactHostMatch,
|
||||
bool aIncludingSession)
|
||||
{
|
||||
return CommonTestPermissionInternal(aPrincipal, nullptr, aType,
|
||||
aPermission, aExactHostMatch,
|
||||
aIncludingSession);
|
||||
}
|
||||
nsresult CommonTestPermission(nsIURI * aURI,
|
||||
const char* aType,
|
||||
uint32_t * aPermission,
|
||||
bool aExactHostMatch,
|
||||
bool aIncludingSession);
|
||||
bool aIncludingSession)
|
||||
{
|
||||
return CommonTestPermissionInternal(nullptr, aURI, aType, aPermission,
|
||||
aExactHostMatch, aIncludingSession);
|
||||
}
|
||||
// Only one of aPrincipal or aURI is allowed to be passed in.
|
||||
nsresult CommonTestPermissionInternal(nsIPrincipal* aPrincipal,
|
||||
nsIURI * aURI,
|
||||
const char * aType,
|
||||
uint32_t * aPermission,
|
||||
bool aExactHostMatch,
|
||||
bool aIncludingSession);
|
||||
|
||||
nsresult OpenDatabase(nsIFile* permissionsFile);
|
||||
nsresult InitDB(bool aRemoveFile);
|
||||
|
Loading…
Reference in New Issue
Block a user