Bug 1202085 - Part 4: Add an ID for controlled document to the image cache key; r=seth

This ID will be null for non-controlled documents and also for image cache
entries for which a document is not available, and it will be the numerical
value of the document pointer for controlled documents.

This effectively makes sure that a controlled document doesn't share its
image cache entries with anything else.
This commit is contained in:
Ehsan Akhgari 2015-10-27 14:12:46 -04:00
Родитель 98b8da3eb6
Коммит 3c9fd0e9e1
4 изменённых файлов: 57 добавлений и 15 удалений

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

@ -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<uint64_t>& aBlobSerial)
const Maybe<uint64_t>& 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<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDocument);
if (doc && swm) {
ErrorResult rv;
if (swm->IsControlled(doc, rv)) {
pointer = doc;
}
}
return pointer;
}
} // namespace image

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

@ -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<uint64_t>& aBlobSerial);
const Maybe<uint64_t>& aBlobSerial,
void* aControlledDocument);
static void* GetControlledDocumentToken(nsIDOMDocument* aDocument);
RefPtr<ImageURL> mURI;
Maybe<uint64_t> mBlobSerial;
void* mControlledDocument;
uint32_t mHash;
bool mIsChrome;
};

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

@ -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<imgCacheEntry> 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<nsIDOMDocument> 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<nsIURI> uri;
channel->GetURI(getter_AddRefs(uri));
ImageCacheKey key(uri);
nsCOMPtr<nsIDOMDocument> 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

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

@ -501,7 +501,7 @@ imgRequest::RemoveFromCache()
if (mCacheEntry) {
mLoader->RemoveFromCache(mCacheEntry);
} else {
mLoader->RemoveFromCache(ImageCacheKey(mURI));
mLoader->RemoveFromCache(mCacheKey);
}
}