Bug 1832528 - Make cors mode part of the image cache key. r=tnikkel

So that we can hold entries loaded with different CORS modes, such as
masks and backgrounds.

Differential Revision: https://phabricator.services.mozilla.com/D177759
This commit is contained in:
Emilio Cobos Álvarez 2023-05-25 22:25:31 +00:00
parent 628ffa8efe
commit 7d479f6a4a
7 changed files with 70 additions and 57 deletions

View file

@ -30,6 +30,9 @@ enum CORSMode : uint8_t {
CORS_USE_CREDENTIALS
};
constexpr auto kFirstCORSMode = CORS_NONE;
constexpr auto kLastCORSMode = CORS_USE_CREDENTIALS;
} // namespace mozilla
#endif /* CORSMode_h_ */

View file

@ -12379,12 +12379,12 @@ void Document::MaybePreLoadImage(nsIURI* aUri,
ReferrerPolicyEnum aReferrerPolicy,
bool aIsImgSet, bool aLinkPreload,
const TimeStamp& aInitTimestamp) {
const CORSMode corsMode = dom::Element::StringToCORSMode(aCrossOriginAttr);
if (aLinkPreload) {
// Check if the image was already preloaded in this document to avoid
// duplicate preloading.
PreloadHashKey key = PreloadHashKey::CreateAsImage(
aUri, NodePrincipal(),
dom::Element::StringToCORSMode(aCrossOriginAttr));
PreloadHashKey key =
PreloadHashKey::CreateAsImage(aUri, NodePrincipal(), corsMode);
if (!mPreloadService.PreloadExists(key)) {
PreLoadImage(aUri, aCrossOriginAttr, aReferrerPolicy, aIsImgSet,
aLinkPreload, 0);
@ -12395,7 +12395,7 @@ void Document::MaybePreLoadImage(nsIURI* aUri,
// Early exit if the img is already present in the img-cache
// which indicates that the "real" load has already started and
// that we shouldn't preload it.
if (nsContentUtils::IsImageInCache(aUri, this)) {
if (nsContentUtils::IsImageAvailable(aUri, NodePrincipal(), corsMode, this)) {
return;
}

View file

@ -3844,19 +3844,6 @@ imgLoader* nsContentUtils::GetImgLoaderForChannel(nsIChannel* aChannel,
: imgLoader::NormalLoader();
}
// static
bool nsContentUtils::IsImageInCache(nsIURI* aURI, Document* aDocument) {
imgILoader* loader = GetImgLoaderForDocument(aDocument);
nsCOMPtr<imgICache> cache = do_QueryInterface(loader);
// If something unexpected happened we return false, otherwise if props
// is set, the image is cached and we return true
nsCOMPtr<nsIProperties> props;
nsresult rv =
cache->FindEntryProperties(aURI, aDocument, getter_AddRefs(props));
return (NS_SUCCEEDED(rv) && props);
}
// static
int32_t nsContentUtils::CORSModeToLoadImageFlags(mozilla::CORSMode aMode) {
switch (aMode) {
@ -10026,8 +10013,15 @@ bool nsContentUtils::IsImageAvailable(nsIContent* aLoadingNode, nsIURI* aURI,
MOZ_ASSERT(triggeringPrincipal);
Document* doc = aLoadingNode->OwnerDoc();
imgLoader* imgLoader = GetImgLoaderForDocument(doc);
return imgLoader->IsImageAvailable(aURI, triggeringPrincipal, aCORSMode, doc);
return IsImageAvailable(aURI, triggeringPrincipal, aCORSMode, doc);
}
bool nsContentUtils::IsImageAvailable(nsIURI* aURI,
nsIPrincipal* aTriggeringPrincipal,
CORSMode aCORSMode, Document* aDoc) {
imgLoader* imgLoader = GetImgLoaderForDocument(aDoc);
return imgLoader->IsImageAvailable(aURI, aTriggeringPrincipal, aCORSMode,
aDoc);
}
/* static */

View file

@ -1051,11 +1051,6 @@ class nsContentUtils {
static imgLoader* GetImgLoaderForChannel(nsIChannel* aChannel,
Document* aContext);
/**
* Returns whether the given URI is in the image cache.
*/
static bool IsImageInCache(nsIURI* aURI, Document* aDocument);
/**
* Method to get an imgIContainer from an image loading content
*
@ -3099,6 +3094,8 @@ class nsContentUtils {
static bool IsImageAvailable(nsIContent*, nsIURI*,
nsIPrincipal* aDefaultTriggeringPrincipal,
mozilla::CORSMode);
static bool IsImageAvailable(nsIURI*, nsIPrincipal* aTriggeringPrincipal,
mozilla::CORSMode, Document*);
/**
* Returns the content policy type that should be used for loading images

View file

@ -29,26 +29,30 @@ using namespace dom;
namespace image {
ImageCacheKey::ImageCacheKey(nsIURI* aURI, const OriginAttributes& aAttrs,
ImageCacheKey::ImageCacheKey(nsIURI* aURI, CORSMode aCORSMode,
const OriginAttributes& aAttrs,
Document* aDocument)
: mURI(aURI),
mOriginAttributes(aAttrs),
mControlledDocument(GetSpecialCaseDocumentToken(aDocument)),
mIsolationKey(GetIsolationKey(aDocument, aURI)) {}
mIsolationKey(GetIsolationKey(aDocument, aURI)),
mCORSMode(aCORSMode) {}
ImageCacheKey::ImageCacheKey(const ImageCacheKey& aOther)
: mURI(aOther.mURI),
mOriginAttributes(aOther.mOriginAttributes),
mControlledDocument(aOther.mControlledDocument),
mIsolationKey(aOther.mIsolationKey),
mHash(aOther.mHash) {}
mHash(aOther.mHash),
mCORSMode(aOther.mCORSMode) {}
ImageCacheKey::ImageCacheKey(ImageCacheKey&& aOther)
: mURI(std::move(aOther.mURI)),
mOriginAttributes(aOther.mOriginAttributes),
mControlledDocument(aOther.mControlledDocument),
mIsolationKey(aOther.mIsolationKey),
mHash(aOther.mHash) {}
mHash(aOther.mHash),
mCORSMode(aOther.mCORSMode) {}
bool ImageCacheKey::operator==(const ImageCacheKey& aOther) const {
// Don't share the image cache between a controlled document and anything
@ -67,6 +71,10 @@ bool ImageCacheKey::operator==(const ImageCacheKey& aOther) const {
return false;
}
if (mCORSMode != aOther.mCORSMode) {
return false;
}
// For non-blob URIs, compare the URIs.
bool equals = false;
nsresult rv = mURI->Equals(aOther.mURI, &equals);

View file

@ -18,6 +18,9 @@
class nsIURI;
namespace mozilla {
enum CORSMode : uint8_t;
namespace image {
/**
@ -30,8 +33,7 @@ namespace image {
*/
class ImageCacheKey final {
public:
ImageCacheKey(nsIURI* aURI, const OriginAttributes& aAttrs,
dom::Document* aDocument);
ImageCacheKey(nsIURI*, CORSMode, const OriginAttributes&, dom::Document*);
ImageCacheKey(const ImageCacheKey& aOther);
ImageCacheKey(ImageCacheKey&& aOther);
@ -47,6 +49,8 @@ class ImageCacheKey final {
/// A weak pointer to the URI.
nsIURI* URI() const { return mURI; }
CORSMode GetCORSMode() const { return mCORSMode; }
const OriginAttributes& OriginAttributesRef() const {
return mOriginAttributes;
}
@ -70,10 +74,11 @@ class ImageCacheKey final {
void EnsureHash() const;
nsCOMPtr<nsIURI> mURI;
OriginAttributes mOriginAttributes;
const OriginAttributes mOriginAttributes;
void* mControlledDocument;
nsCString mIsolationKey;
mutable Maybe<PLDHashNumber> mHash;
const CORSMode mCORSMode;
};
} // namespace image

View file

@ -1502,23 +1502,24 @@ nsresult imgLoader::RemoveEntriesInternal(nsIPrincipal* aPrincipal,
return NS_OK;
}
constexpr auto AllCORSModes() {
return MakeInclusiveEnumeratedRange(kFirstCORSMode, kLastCORSMode);
}
NS_IMETHODIMP
imgLoader::RemoveEntry(nsIURI* aURI, Document* aDoc) {
if (aURI) {
OriginAttributes attrs;
if (aDoc) {
nsCOMPtr<nsIPrincipal> principal = aDoc->NodePrincipal();
if (principal) {
attrs = principal->OriginAttributesRef();
}
}
ImageCacheKey key(aURI, attrs, aDoc);
if (RemoveFromCache(key)) {
return NS_OK;
}
if (!aURI) {
return NS_OK;
}
return NS_ERROR_NOT_AVAILABLE;
OriginAttributes attrs;
if (aDoc) {
attrs = aDoc->NodePrincipal()->OriginAttributesRef();
}
for (auto corsMode : AllCORSModes()) {
ImageCacheKey key(aURI, corsMode, attrs, aDoc);
RemoveFromCache(key);
}
return NS_OK;
}
NS_IMETHODIMP
@ -1534,20 +1535,22 @@ imgLoader::FindEntryProperties(nsIURI* uri, Document* aDoc,
}
}
ImageCacheKey key(uri, attrs, aDoc);
RefPtr<imgCacheEntry> entry;
if (mCache.Get(key, getter_AddRefs(entry)) && entry) {
for (auto corsMode : AllCORSModes()) {
ImageCacheKey key(uri, corsMode, attrs, aDoc);
RefPtr<imgCacheEntry> entry;
if (!mCache.Get(key, getter_AddRefs(entry)) || !entry) {
continue;
}
if (mCacheTracker && entry->HasNoProxies()) {
mCacheTracker->MarkUsed(entry);
}
RefPtr<imgRequest> request = entry->GetRequest();
if (request) {
nsCOMPtr<nsIProperties> properties = request->Properties();
properties.forget(_retval);
return NS_OK;
}
}
return NS_OK;
}
@ -2228,8 +2231,8 @@ static void MakeRequestStaticIfNeeded(
bool imgLoader::IsImageAvailable(nsIURI* aURI,
nsIPrincipal* aTriggeringPrincipal,
CORSMode aCORSMode, Document* aDocument) {
ImageCacheKey key(aURI, aTriggeringPrincipal->OriginAttributesRef(),
aDocument);
ImageCacheKey key(aURI, aCORSMode,
aTriggeringPrincipal->OriginAttributesRef(), aDocument);
RefPtr<imgCacheEntry> entry;
if (!mCache.Get(key, getter_AddRefs(entry)) || !entry) {
return false;
@ -2406,7 +2409,7 @@ nsresult imgLoader::LoadImage(
if (aTriggeringPrincipal) {
attrs = aTriggeringPrincipal->OriginAttributesRef();
}
ImageCacheKey key(aURI, attrs, aLoadingDocument);
ImageCacheKey key(aURI, corsmode, attrs, aLoadingDocument);
if (mCache.Get(key, getter_AddRefs(entry)) && entry) {
bool newChannelCreated = false;
if (ValidateEntry(entry, aURI, aInitialDocumentURI, aReferrerInfo,
@ -2643,7 +2646,9 @@ nsresult imgLoader::LoadImageWithChannel(nsIChannel* channel,
OriginAttributes attrs = loadInfo->GetOriginAttributes();
ImageCacheKey key(uri, attrs, aLoadingDocument);
// TODO: Get a meaningful cors mode from the caller probably?
const auto corsMode = CORS_NONE;
ImageCacheKey key(uri, corsMode, attrs, aLoadingDocument);
nsLoadFlags requestFlags = nsIRequest::LOAD_NORMAL;
channel->GetLoadFlags(&requestFlags);
@ -2676,7 +2681,7 @@ nsresult imgLoader::LoadImageWithChannel(nsIChannel* channel,
if (ValidateEntry(entry, uri, nullptr, nullptr, nullptr, aObserver,
aLoadingDocument, requestFlags, policyType, false,
nullptr, nullptr, nullptr, CORS_NONE, false, 0)) {
nullptr, nullptr, nullptr, corsMode, false, 0)) {
request = entry->GetRequest();
} else {
nsCOMPtr<nsICacheInfoChannel> cacheChan(do_QueryInterface(channel));
@ -2753,7 +2758,8 @@ nsresult imgLoader::LoadImageWithChannel(nsIChannel* channel,
// constructed above with the *current URI* and not the *original URI*. I'm
// pretty sure this is a bug, and it's preventing us from ever getting a
// cache hit in LoadImageWithChannel when redirects are involved.
ImageCacheKey originalURIKey(originalURI, attrs, aLoadingDocument);
ImageCacheKey originalURIKey(originalURI, corsMode, attrs,
aLoadingDocument);
// Default to doing a principal check because we don't know who
// started that load and whether their principal ended up being
@ -2772,7 +2778,7 @@ nsresult imgLoader::LoadImageWithChannel(nsIChannel* channel,
// can set aHadInsecureRedirect to false here.
rv = request->Init(originalURI, uri, /* aHadInsecureRedirect = */ false,
channel, channel, entry, aLoadingDocument, nullptr,
CORS_NONE, nullptr);
corsMode, nullptr);
NS_ENSURE_SUCCESS(rv, rv);
RefPtr<ProxyListener> pl =