From 6514cd85bfe198df399d3f6d6a3325b21572c031 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 30 Jul 2020 08:55:24 +0000 Subject: [PATCH] Bug 1655933 - Allow images from non-static documents to get reused in their static clones without validation. r=tnikkel This allows to print images that we'd otherwise reload. Differential Revision: https://phabricator.services.mozilla.com/D85263 --- image/imgLoader.cpp | 21 ++++++--------------- image/imgRequest.cpp | 23 +++++++++++++++++++++++ image/imgRequest.h | 4 ++++ 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/image/imgLoader.cpp b/image/imgLoader.cpp index d26ae7a0b5a0..f5f5bd1f52e9 100644 --- a/image/imgLoader.cpp +++ b/image/imgLoader.cpp @@ -672,7 +672,7 @@ static bool ShouldLoadCachedImage(imgRequest* aImgRequest, /* Call content policies on cached images - Bug 1082837 * Cached images are keyed off of the first uri in a redirect chain. * Hence content policies don't get a chance to test the intermediate hops - * or the final desitnation. Here we test the final destination using + * or the final destination. Here we test the final destination using * mFinalURI off of the imgRequest and passing it into content policies. * For Mixed Content Blocker, we do an additional check to determine if any * of the intermediary hops went through an insecure redirect with the @@ -1845,18 +1845,7 @@ bool imgLoader::ValidateEntry( bool validateRequest = false; - // If the request's loadId is the same as the aLoadingDocument, then it is ok - // to use this one because it has already been validated for this context. - // - // XXX: nullptr seems to be a 'special' key value that indicates that NO - // validation is required. - // XXX: we also check the window ID because the loadID() can return a reused - // pointer of a document. This can still happen for non-document image - // cache entries. - void* key = (void*)aLoadingDocument; - uint64_t innerWindowID = - aLoadingDocument ? aLoadingDocument->InnerWindowID() : 0; - if (request->LoadId() != key || request->InnerWindowID() != innerWindowID) { + if (!request->CanReuseWithoutValidation(aLoadingDocument)) { // If we would need to revalidate this entry, but we're being told to // bypass the cache, we don't allow this entry to be used. if (aLoadFlags & nsIRequest::LOAD_BYPASS_CACHE) { @@ -1876,10 +1865,10 @@ bool imgLoader::ValidateEntry( ("imgLoader::ValidateEntry validating cache entry. " "validateRequest = %d", validateRequest)); - } else if (!key && MOZ_LOG_TEST(gImgLog, LogLevel::Debug)) { + } else if (!aLoadingDocument && MOZ_LOG_TEST(gImgLog, LogLevel::Debug)) { MOZ_LOG(gImgLog, LogLevel::Debug, ("imgLoader::ValidateEntry BYPASSING cache validation for %s " - "because of NULL LoadID", + "because of NULL loading document", aURI->GetSpecOrDefault().get())); } @@ -1954,6 +1943,8 @@ bool imgLoader::ValidateEntry( if (validateRequest && aCanMakeNewChannel) { LOG_SCOPE(gImgLog, "imgLoader::ValidateRequest |cache hit| must validate"); + uint64_t innerWindowID = + aLoadingDocument ? aLoadingDocument->InnerWindowID() : 0; return ValidateRequestWithNewChannel( request, aURI, aInitialDocumentURI, aReferrerInfo, aLoadGroup, aObserver, aLoadingDocument, innerWindowID, aLoadFlags, aLoadPolicyType, diff --git a/image/imgRequest.cpp b/image/imgRequest.cpp index bcb9803b245a..e3630b5c47f9 100644 --- a/image/imgRequest.cpp +++ b/image/imgRequest.cpp @@ -148,6 +148,29 @@ nsresult imgRequest::Init(nsIURI* aURI, nsIURI* aFinalURI, return NS_OK; } +bool imgRequest::CanReuseWithoutValidation(dom::Document* aDoc) const { + // If the request's loadId is the same as the aLoadingDocument, then it is ok + // to use this one because it has already been validated for this context. + // XXX: nullptr seems to be a 'special' key value that indicates that NO + // validation is required. + // XXX: we also check the window ID because the loadID() can return a reused + // pointer of a document. This can still happen for non-document image + // cache entries. + void* key = (void*)aDoc; + uint64_t innerWindowID = aDoc ? aDoc->InnerWindowID() : 0; + if (LoadId() == key && InnerWindowID() == innerWindowID) { + return true; + } + + // As a special-case, if this is a print preview document, also validate on + // the original document. This allows to print uncacheable images. + if (dom::Document* original = aDoc ? aDoc->GetOriginalDocument() : nullptr) { + return CanReuseWithoutValidation(original); + } + + return false; +} + void imgRequest::ClearLoader() { mLoader = nullptr; } already_AddRefed imgRequest::GetProgressTracker() const { diff --git a/image/imgRequest.h b/image/imgRequest.h index d94915bd2458..e2f6a8a637e1 100644 --- a/image/imgRequest.h +++ b/image/imgRequest.h @@ -74,6 +74,10 @@ class imgRequest final : public nsIStreamListener, // Callers must call imgRequestProxy::Notify later. void AddProxy(imgRequestProxy* proxy); + // Whether a given document is allowed to reuse this request without any + // revalidation. + bool CanReuseWithoutValidation(mozilla::dom::Document*) const; + nsresult RemoveProxy(imgRequestProxy* proxy, nsresult aStatus); // Cancel, but also ensure that all work done in Init() is undone. Call this