diff --git a/image/ImageCacheKey.cpp b/image/ImageCacheKey.cpp index 32037ba94f60..cc5042546463 100644 --- a/image/ImageCacheKey.cpp +++ b/image/ImageCacheKey.cpp @@ -10,6 +10,10 @@ #include "ImageURL.h" #include "nsHostObjectProtocolHandler.h" #include "nsString.h" +#include "mozilla/dom/workers/ServiceWorkerManager.h" +#include "nsIDOMDocument.h" +#include "nsIDocument.h" +#include "nsPrintfCString.h" namespace mozilla { @@ -42,8 +46,9 @@ BlobSerial(ImageURL* aURI) return Nothing(); } -ImageCacheKey::ImageCacheKey(nsIURI* aURI) +ImageCacheKey::ImageCacheKey(nsIURI* aURI, nsIDOMDocument* aDocument) : mURI(new ImageURL(aURI)) + , mControlledDocument(GetControlledDocumentToken(aDocument)) , mIsChrome(URISchemeIs(mURI, "chrome")) { MOZ_ASSERT(NS_IsMainThread()); @@ -52,11 +57,12 @@ ImageCacheKey::ImageCacheKey(nsIURI* aURI) mBlobSerial = BlobSerial(mURI); } - mHash = ComputeHash(mURI, mBlobSerial); + mHash = ComputeHash(mURI, mBlobSerial, mControlledDocument); } -ImageCacheKey::ImageCacheKey(ImageURL* aURI) +ImageCacheKey::ImageCacheKey(ImageURL* aURI, nsIDOMDocument* aDocument) : mURI(aURI) + , mControlledDocument(GetControlledDocumentToken(aDocument)) , mIsChrome(URISchemeIs(mURI, "chrome")) { MOZ_ASSERT(aURI); @@ -65,12 +71,13 @@ ImageCacheKey::ImageCacheKey(ImageURL* aURI) mBlobSerial = BlobSerial(mURI); } - mHash = ComputeHash(mURI, mBlobSerial); + mHash = ComputeHash(mURI, mBlobSerial, mControlledDocument); } ImageCacheKey::ImageCacheKey(const ImageCacheKey& aOther) : mURI(aOther.mURI) , mBlobSerial(aOther.mBlobSerial) + , mControlledDocument(aOther.mControlledDocument) , mHash(aOther.mHash) , mIsChrome(aOther.mIsChrome) { } @@ -78,6 +85,7 @@ ImageCacheKey::ImageCacheKey(const ImageCacheKey& aOther) ImageCacheKey::ImageCacheKey(ImageCacheKey&& aOther) : mURI(Move(aOther.mURI)) , mBlobSerial(Move(aOther.mBlobSerial)) + , mControlledDocument(aOther.mControlledDocument) , mHash(aOther.mHash) , mIsChrome(aOther.mIsChrome) { } @@ -85,6 +93,10 @@ ImageCacheKey::ImageCacheKey(ImageCacheKey&& aOther) bool ImageCacheKey::operator==(const ImageCacheKey& aOther) const { + // Don't share the image cache between a controlled document and anything else. + if (mControlledDocument != aOther.mControlledDocument) { + return false; + } if (mBlobSerial || aOther.mBlobSerial) { // If at least one of us has a blob serial, just compare the blob serial and // the ref portion of the URIs. @@ -104,11 +116,13 @@ ImageCacheKey::Spec() const /* static */ uint32_t ImageCacheKey::ComputeHash(ImageURL* aURI, - const Maybe& aBlobSerial) + const Maybe& aBlobSerial, + void* aControlledDocument) { // Since we frequently call Hash() several times in a row on the same // ImageCacheKey, as an optimization we compute our hash once and store it. + nsPrintfCString ptr("%p", aControlledDocument); if (aBlobSerial) { // For blob URIs, we hash the serial number of the underlying blob, so that // different blob URIs which point to the same blob share a cache entry. We @@ -117,13 +131,32 @@ ImageCacheKey::ComputeHash(ImageURL* aURI, // the same. nsAutoCString ref; aURI->GetRef(ref); - return HashGeneric(*aBlobSerial, HashString(ref)); + return HashGeneric(*aBlobSerial, HashString(ref + ptr)); } // For non-blob URIs, we hash the URI spec. nsAutoCString spec; aURI->GetSpec(spec); - return HashString(spec); + return HashString(spec + ptr); +} + +/* static */ void* +ImageCacheKey::GetControlledDocumentToken(nsIDOMDocument* aDocument) +{ + // For non-controlled documents, we just return null. For controlled + // documents, we cast the pointer into a void* to avoid dereferencing + // it (since we only use it for comparisons), and return it. + void* pointer = nullptr; + using dom::workers::ServiceWorkerManager; + RefPtr swm = ServiceWorkerManager::GetInstance(); + nsCOMPtr doc = do_QueryInterface(aDocument); + if (doc && swm) { + ErrorResult rv; + if (swm->IsControlled(doc, rv)) { + pointer = doc; + } + } + return pointer; } } // namespace image diff --git a/image/ImageCacheKey.h b/image/ImageCacheKey.h index e2dc36c99cde..beca733064c1 100644 --- a/image/ImageCacheKey.h +++ b/image/ImageCacheKey.h @@ -12,6 +12,7 @@ #include "mozilla/Maybe.h" +class nsIDOMDocument; class nsIURI; namespace mozilla { @@ -24,12 +25,14 @@ class ImageURL; * * We key the cache on the initial URI (before any redirects), with some * canonicalization applied. See ComputeHash() for the details. + * Controlled documents do not share their cache entries with + * non-controlled documents, or other controlled documents. */ class ImageCacheKey final { public: - explicit ImageCacheKey(nsIURI* aURI); - explicit ImageCacheKey(ImageURL* aURI); + ImageCacheKey(nsIURI* aURI, nsIDOMDocument* aDocument); + ImageCacheKey(ImageURL* aURI, nsIDOMDocument* aDocument); ImageCacheKey(const ImageCacheKey& aOther); ImageCacheKey(ImageCacheKey&& aOther); @@ -45,10 +48,13 @@ public: private: static uint32_t ComputeHash(ImageURL* aURI, - const Maybe& aBlobSerial); + const Maybe& aBlobSerial, + void* aControlledDocument); + static void* GetControlledDocumentToken(nsIDOMDocument* aDocument); RefPtr mURI; Maybe mBlobSerial; + void* mControlledDocument; uint32_t mHash; bool mIsChrome; }; diff --git a/image/imgLoader.cpp b/image/imgLoader.cpp index 6fce95571286..880afcc09a1a 100644 --- a/image/imgLoader.cpp +++ b/image/imgLoader.cpp @@ -52,6 +52,7 @@ #include "nsIHttpChannelInternal.h" #include "nsILoadContext.h" #include "nsILoadGroupChild.h" +#include "nsIDOMDocument.h" using namespace mozilla; using namespace mozilla::image; @@ -1341,7 +1342,7 @@ imgLoader::FindEntryProperties(nsIURI* uri, { *_retval = nullptr; - ImageCacheKey key(uri); + ImageCacheKey key(uri, doc); imgCacheTable& cache = GetCache(key); RefPtr entry; @@ -2087,7 +2088,8 @@ imgLoader::LoadImage(nsIURI* aURI, // XXX For now ignore aCacheKey. We will need it in the future // for correctly dealing with image load requests that are a result // of post data. - ImageCacheKey key(aURI); + nsCOMPtr doc = do_QueryInterface(aCX); + ImageCacheKey key(aURI, doc); imgCacheTable& cache = GetCache(key); if (cache.Get(key, getter_AddRefs(entry)) && entry) { @@ -2311,7 +2313,8 @@ imgLoader::LoadImageWithChannel(nsIChannel* channel, nsCOMPtr uri; channel->GetURI(getter_AddRefs(uri)); - ImageCacheKey key(uri); + nsCOMPtr doc = do_QueryInterface(aCX); + ImageCacheKey key(uri, doc); nsLoadFlags requestFlags = nsIRequest::LOAD_NORMAL; channel->GetLoadFlags(&requestFlags); @@ -2405,7 +2408,7 @@ 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); + ImageCacheKey originalURIKey(originalURI, doc); // Default to doing a principal check because we don't know who // started that load and whether their principal ended up being diff --git a/image/imgRequest.cpp b/image/imgRequest.cpp index 62b6f1770a48..e6e10e4b78ec 100644 --- a/image/imgRequest.cpp +++ b/image/imgRequest.cpp @@ -501,7 +501,7 @@ imgRequest::RemoveFromCache() if (mCacheEntry) { mLoader->RemoveFromCache(mCacheEntry); } else { - mLoader->RemoveFromCache(ImageCacheKey(mURI)); + mLoader->RemoveFromCache(mCacheKey); } }