Bug 1670617 - Part 2: Make the CORS preflight cache partitioned by the originAttributes. r=ckerschb,necko-reviewers

We want to partition the CORS preflight cache by the network state
partitioning. So, we have done two things in the patch. First, we make
the CORS preflight cache to be aware of the OriginAttributes. Second, we
use the originAttributes of the network state partitioning in the CORS
preflight cache. As the result, the CORS preflight cache will be
partitioned by the originAttributes.partitionKey as well as other
originAttributes fields if present.

Differential Revision: https://phabricator.services.mozilla.com/D93683
This commit is contained in:
Tim Huang 2020-10-26 13:39:12 +00:00
Родитель 2546d22172
Коммит 18853bea78
10 изменённых файлов: 76 добавлений и 28 удалений

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

@ -671,6 +671,7 @@ BasePrincipal::AllowsRelaxStrictFileOriginPolicy(nsIURI* aURI, bool* aRes) {
NS_IMETHODIMP
BasePrincipal::GetPrefLightCacheKey(nsIURI* aURI, bool aWithCredentials,
const OriginAttributes& aOriginAttributes,
nsACString& _retval) {
_retval.Truncate();
constexpr auto space = " "_ns;
@ -696,7 +697,11 @@ BasePrincipal::GetPrefLightCacheKey(nsIURI* aURI, bool aWithCredentials,
rv = aURI->GetSpec(spec);
NS_ENSURE_SUCCESS(rv, rv);
_retval.Append(space + scheme + space + host + space + port + space + spec);
nsAutoCString originAttributesSuffix;
aOriginAttributes.CreateSuffix(originAttributesSuffix);
_retval.Append(space + scheme + space + host + space + port + space + spec +
space + originAttributesSuffix);
return NS_OK;
}

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

@ -154,6 +154,7 @@ class BasePrincipal : public nsJSPrincipals {
NS_IMETHOD IsSameOrigin(nsIURI* aURI, bool aIsPrivateWin,
bool* aRes) override;
NS_IMETHOD GetPrefLightCacheKey(nsIURI* aURI, bool aWithCredentials,
const OriginAttributes& aOriginAttributes,
nsACString& _retval) override;
NS_IMETHOD HasFirstpartyStorageAccess(mozIDOMWindow* aCheckWindow,
uint32_t* aRejectedReason,

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

@ -341,7 +341,9 @@ interface nsIPrincipal : nsISerializable
/*
* Generates a Cache-Key for the Cors-Preflight Cache
*/
ACString getPrefLightCacheKey(in nsIURI aURI ,in bool aWithCredentials);
[noscript]
ACString getPrefLightCacheKey(in nsIURI aURI ,in bool aWithCredentials,
in const_OriginAttributes aOriginAttributes);
/*

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

@ -2761,8 +2761,9 @@ void HttpChannelChild::GetClientSetCorsPreflightParameters(
}
NS_IMETHODIMP
HttpChannelChild::RemoveCorsPreflightCacheEntry(nsIURI* aURI,
nsIPrincipal* aPrincipal) {
HttpChannelChild::RemoveCorsPreflightCacheEntry(
nsIURI* aURI, nsIPrincipal* aPrincipal,
const OriginAttributes& aOriginAttributes) {
URIParams uri;
SerializeURI(aURI, uri);
PrincipalInfo principalInfo;
@ -2774,7 +2775,8 @@ HttpChannelChild::RemoveCorsPreflightCacheEntry(nsIURI* aURI,
// Be careful to not attempt to send a message to the parent after the
// actor has been destroyed.
if (CanSend()) {
result = SendRemoveCorsPreflightCacheEntry(uri, principalInfo);
result = SendRemoveCorsPreflightCacheEntry(uri, principalInfo,
aOriginAttributes);
}
return result ? NS_OK : NS_ERROR_FAILURE;
}

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

@ -1045,7 +1045,8 @@ HttpChannelParent::RecvMarkOfflineCacheEntryAsForeign() {
mozilla::ipc::IPCResult HttpChannelParent::RecvRemoveCorsPreflightCacheEntry(
const URIParams& uri,
const mozilla::ipc::PrincipalInfo& requestingPrincipal) {
const mozilla::ipc::PrincipalInfo& requestingPrincipal,
const OriginAttributes& originAttributes) {
nsCOMPtr<nsIURI> deserializedURI = DeserializeURI(uri);
if (!deserializedURI) {
return IPC_FAIL_NO_REASON(this);
@ -1055,7 +1056,8 @@ mozilla::ipc::IPCResult HttpChannelParent::RecvRemoveCorsPreflightCacheEntry(
return IPC_FAIL_NO_REASON(this);
}
nsCOMPtr<nsIPrincipal> principal = principalOrErr.unwrap();
nsCORSListenerProxy::RemoveFromCorsPreflightCache(deserializedURI, principal);
nsCORSListenerProxy::RemoveFromCorsPreflightCache(deserializedURI, principal,
originAttributes);
return IPC_OK();
}

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

@ -195,7 +195,8 @@ class HttpChannelParent final : public nsIInterfaceRequestor,
virtual mozilla::ipc::IPCResult RecvMarkOfflineCacheEntryAsForeign() override;
virtual mozilla::ipc::IPCResult RecvRemoveCorsPreflightCacheEntry(
const URIParams& uri,
const mozilla::ipc::PrincipalInfo& requestingPrincipal) override;
const mozilla::ipc::PrincipalInfo& requestingPrincipal,
const OriginAttributes& originAttributes) override;
virtual mozilla::ipc::IPCResult RecvBytesRead(const int32_t& aCount) override;
virtual mozilla::ipc::IPCResult RecvOpenOriginalCacheInputStream() override;
virtual mozilla::ipc::IPCResult RecvOpenAltDataCacheInputStream(

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

@ -16,6 +16,8 @@ include HttpChannelParams;
include "mozilla/net/NeckoMessageUtils.h";
using mozilla::OriginAttributes from "mozilla/ipc/BackgroundUtils.h";
namespace mozilla {
namespace net {
@ -69,7 +71,8 @@ parent:
// Child has detected a CORS check failure, so needs to tell the parent
// to remove any matching entry from the CORS preflight cache.
async RemoveCorsPreflightCacheEntry(URIParams uri,
PrincipalInfo requestingPrincipal);
PrincipalInfo requestingPrincipal,
OriginAttributes originAttributes);
// After receiving this message, the parent calls SendDeleteSelf, and makes
// sure not to send any more messages after that.

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

@ -7,6 +7,7 @@
#include "mozilla/Assertions.h"
#include "mozilla/LinkedList.h"
#include "mozilla/StaticPrefs_content.h"
#include "mozilla/StoragePrincipalHelper.h"
#include "nsCORSListenerProxy.h"
#include "nsIChannel.h"
@ -168,8 +169,10 @@ class nsPreflightCache {
bool Initialize() { return true; }
CacheEntry* GetEntry(nsIURI* aURI, nsIPrincipal* aPrincipal,
bool aWithCredentials, bool aCreate);
void RemoveEntries(nsIURI* aURI, nsIPrincipal* aPrincipal);
bool aWithCredentials,
const OriginAttributes& aOriginAttributes, bool aCreate);
void RemoveEntries(nsIURI* aURI, nsIPrincipal* aPrincipal,
const OriginAttributes& aOriginAttributes);
void Clear();
@ -243,10 +246,10 @@ bool nsPreflightCache::CacheEntry::CheckRequest(
nsPreflightCache::CacheEntry* nsPreflightCache::GetEntry(
nsIURI* aURI, nsIPrincipal* aPrincipal, bool aWithCredentials,
bool aCreate) {
const OriginAttributes& aOriginAttributes, bool aCreate) {
nsCString key;
if (NS_FAILED(
aPrincipal->GetPrefLightCacheKey(aURI, aWithCredentials, key))) {
if (NS_FAILED(aPrincipal->GetPrefLightCacheKey(aURI, aWithCredentials,
aOriginAttributes, key))) {
NS_WARNING("Invalid cache key!");
return nullptr;
}
@ -313,16 +316,20 @@ nsPreflightCache::CacheEntry* nsPreflightCache::GetEntry(
return newEntry;
}
void nsPreflightCache::RemoveEntries(nsIURI* aURI, nsIPrincipal* aPrincipal) {
void nsPreflightCache::RemoveEntries(
nsIURI* aURI, nsIPrincipal* aPrincipal,
const OriginAttributes& aOriginAttributes) {
CacheEntry* entry;
nsCString key;
if (NS_SUCCEEDED(aPrincipal->GetPrefLightCacheKey(aURI, true, key)) &&
if (NS_SUCCEEDED(aPrincipal->GetPrefLightCacheKey(aURI, true,
aOriginAttributes, key)) &&
mTable.Get(key, &entry)) {
entry->removeFrom(mList);
mTable.Remove(key);
}
if (NS_SUCCEEDED(aPrincipal->GetPrefLightCacheKey(aURI, false, key)) &&
if (NS_SUCCEEDED(aPrincipal->GetPrefLightCacheKey(aURI, false,
aOriginAttributes, key)) &&
mTable.Get(key, &entry)) {
entry->removeFrom(mList);
mTable.Remove(key);
@ -396,16 +403,20 @@ nsCORSListenerProxy::OnStartRequest(nsIRequest* aRequest) {
nsCOMPtr<nsIURI> uri;
NS_GetFinalChannelURI(channel, getter_AddRefs(uri));
if (uri) {
OriginAttributes attrs;
StoragePrincipalHelper::GetOriginAttributesForNetworkState(channel,
attrs);
if (sPreflightCache) {
// OK to use mRequestingPrincipal since preflights never get
// redirected.
sPreflightCache->RemoveEntries(uri, mRequestingPrincipal);
sPreflightCache->RemoveEntries(uri, mRequestingPrincipal, attrs);
} else {
nsCOMPtr<nsIHttpChannelChild> httpChannelChild =
do_QueryInterface(channel);
if (httpChannelChild) {
rv = httpChannelChild->RemoveCorsPreflightCacheEntry(
uri, mRequestingPrincipal);
uri, mRequestingPrincipal, attrs);
if (NS_FAILED(rv)) {
// Only warn here to ensure we fall through the request Cancel()
// and outer listener OnStartRequest() calls.
@ -681,16 +692,19 @@ nsCORSListenerProxy::AsyncOnChannelRedirect(
nsCOMPtr<nsIURI> oldURI;
NS_GetFinalChannelURI(aOldChannel, getter_AddRefs(oldURI));
if (oldURI) {
OriginAttributes attrs;
StoragePrincipalHelper::GetOriginAttributesForNetworkState(aOldChannel,
attrs);
if (sPreflightCache) {
// OK to use mRequestingPrincipal since preflights never get
// redirected.
sPreflightCache->RemoveEntries(oldURI, mRequestingPrincipal);
sPreflightCache->RemoveEntries(oldURI, mRequestingPrincipal, attrs);
} else {
nsCOMPtr<nsIHttpChannelChild> httpChannelChild =
do_QueryInterface(aOldChannel);
if (httpChannelChild) {
rv = httpChannelChild->RemoveCorsPreflightCacheEntry(
oldURI, mRequestingPrincipal);
oldURI, mRequestingPrincipal, attrs);
if (NS_FAILED(rv)) {
// Only warn here to ensure we call the channel Cancel() below
NS_WARNING("Failed to remove CORS preflight cache entry!");
@ -1120,8 +1134,11 @@ void nsCORSPreflightListener::AddResultToCache(nsIRequest* aRequest) {
TimeStamp expirationTime =
TimeStamp::NowLoRes() + TimeDuration::FromSeconds(age);
OriginAttributes attrs;
StoragePrincipalHelper::GetOriginAttributesForNetworkState(http, attrs);
nsPreflightCache::CacheEntry* entry = sPreflightCache->GetEntry(
uri, mReferrerPrincipal, mWithCredentials, true);
uri, mReferrerPrincipal, mWithCredentials, attrs, true);
if (!entry) {
return;
}
@ -1357,10 +1374,12 @@ nsCORSPreflightListener::GetInterface(const nsIID& aIID, void** aResult) {
}
void nsCORSListenerProxy::RemoveFromCorsPreflightCache(
nsIURI* aURI, nsIPrincipal* aRequestingPrincipal) {
nsIURI* aURI, nsIPrincipal* aRequestingPrincipal,
const OriginAttributes& aOriginAttributes) {
MOZ_ASSERT(XRE_IsParentProcess());
if (sPreflightCache) {
sPreflightCache->RemoveEntries(aURI, aRequestingPrincipal);
sPreflightCache->RemoveEntries(aURI, aRequestingPrincipal,
aOriginAttributes);
}
}
@ -1405,7 +1424,11 @@ nsresult nsCORSListenerProxy::StartCORSPreflight(
bool disableCache = Preferences::GetBool("devtools.cache.disabled");
if (sPreflightCache && !disableCache) {
entry = sPreflightCache->GetEntry(uri, principal, withCredentials, false);
OriginAttributes attrs;
StoragePrincipalHelper::GetOriginAttributesForNetworkState(aRequestChannel,
attrs);
entry = sPreflightCache->GetEntry(uri, principal, withCredentials, attrs,
false);
}
if (entry && entry->CheckRequest(method, aUnsafeHeaders)) {

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

@ -79,8 +79,9 @@ class nsCORSListenerProxy final : public nsIStreamListener,
// Only nsHttpChannel can invoke CORS preflights
friend class mozilla::net::nsHttpChannel;
static void RemoveFromCorsPreflightCache(nsIURI* aURI,
nsIPrincipal* aRequestingPrincipal);
static void RemoveFromCorsPreflightCache(
nsIURI* aURI, nsIPrincipal* aRequestingPrincipal,
const mozilla::OriginAttributes& aOriginAttributes);
[[nodiscard]] static nsresult StartCORSPreflight(
nsIChannel* aRequestChannel, nsICorsPreflightCallback* aCallback,
nsTArray<nsCString>& aACUnsafeHeaders, nsIChannel** aPreflightChannel);

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

@ -5,8 +5,15 @@
#include "nsISupports.idl"
%{ C++
namespace mozilla {
class OriginAttributes;
} // mozilla namespace
%}
[ptr] native RequestHeaderTuples(mozilla::net::RequestHeaderTuples);
[ref] native MaybeCorsPreflightArgsRef(mozilla::Maybe<mozilla::net::CorsPreflightArgs>);
[ref] native const_OriginAttributes(const mozilla::OriginAttributes);
interface nsIPrincipal;
interface nsIURI;
@ -26,5 +33,6 @@ interface nsIHttpChannelChild : nsISupports
// This method is called by nsCORSListenerProxy if we need to remove
// an entry from the CORS preflight cache in the parent process.
[must_use]
void removeCorsPreflightCacheEntry(in nsIURI aURI, in nsIPrincipal aRequestingPrincipal);
void removeCorsPreflightCacheEntry(in nsIURI aURI, in nsIPrincipal aRequestingPrincipal,
in const_OriginAttributes aOriginAttributes);
};