tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit f014fa8be1bc8b6762b33bd9b18bb4c779666c59
parent eacd93da22cb7b5f5a5065dbdb00c954ecfc7c1c
Author: Randell Jesup <rjesup@mozilla.com>
Date:   Tue,  7 Oct 2025 17:55:58 +0000

Bug 1917974: Add OPEN_COMPLETE_ONLY and use it for Compression Dictionary Prefetch r=necko-reviewers,valentin

Differential Revision: https://phabricator.services.mozilla.com/D258166

Diffstat:
Mnetwerk/cache2/CacheEntry.cpp | 7+++++++
Mnetwerk/cache2/CacheEntry.h | 4++++
Mnetwerk/cache2/CacheStorageService.cpp | 7+++++++
Mnetwerk/cache2/Dictionary.cpp | 26+++++++++++++++++++-------
Mnetwerk/cache2/Dictionary.h | 4++++
Mnetwerk/cache2/nsICacheEntry.idl | 5+++++
Mnetwerk/cache2/nsICacheStorage.idl | 5+++++
7 files changed, 51 insertions(+), 7 deletions(-)

diff --git a/netwerk/cache2/CacheEntry.cpp b/netwerk/cache2/CacheEntry.cpp @@ -1095,6 +1095,13 @@ nsresult CacheEntry::GetOnStopTime(uint64_t* aTime) { return mFile->GetOnStopTime(aTime); } +nsresult CacheEntry::GetReady(bool* aReady) { + mozilla::MutexAutoLock lock(mLock); + // XXX REVALIDATING? + *aReady = mState == READY; + return NS_OK; +} + nsresult CacheEntry::SetNetworkTimes(uint64_t aOnStartTime, uint64_t aOnStopTime) { if (NS_SUCCEEDED(mFileStatus)) { diff --git a/netwerk/cache2/CacheEntry.h b/netwerk/cache2/CacheEntry.h @@ -76,6 +76,7 @@ class CacheEntry final : public nsIRunnable, nsresult SetExpirationTime(uint32_t expirationTime); nsresult GetOnStartTime(uint64_t* aTime); nsresult GetOnStopTime(uint64_t* aTime); + nsresult GetReady(bool* aReady); nsresult SetNetworkTimes(uint64_t onStartTime, uint64_t onStopTime); nsresult SetContentType(uint8_t aContentType); nsresult ForceValidFor(uint32_t aSecondsToTheFuture); @@ -471,6 +472,9 @@ class CacheEntryHandle final : public nsICacheEntry { NS_IMETHOD GetOnStopTime(uint64_t* aOnStopTime) override { return mEntry->GetOnStopTime(aOnStopTime); } + NS_IMETHOD GetReady(bool* aReady) override { + return mEntry->GetReady(aReady); + } NS_IMETHOD SetNetworkTimes(uint64_t onStartTime, uint64_t onStopTime) override { return mEntry->SetNetworkTimes(onStartTime, onStopTime); diff --git a/netwerk/cache2/CacheStorageService.cpp b/netwerk/cache2/CacheStorageService.cpp @@ -1606,6 +1606,13 @@ nsresult CacheStorageService::AddStorageEntry( StaticPrefs::network_cache_bug1708673()) { return NS_ERROR_CACHE_KEY_NOT_FOUND; } + if (entryExists && (aFlags & nsICacheStorage::OPEN_COMPLETE_ONLY)) { + bool ready = false; + entry->GetReady(&ready); + if (!ready) { + return NS_ERROR_CACHE_KEY_NOT_FOUND; + } + } bool replace = aFlags & nsICacheStorage::OPEN_TRUNCATE; diff --git a/netwerk/cache2/Dictionary.cpp b/netwerk/cache2/Dictionary.cpp @@ -94,6 +94,10 @@ bool DictionaryCacheEntry::Match(const nsACString& aFilePath, // We don't have the file yet return false; } + if (mNotCached) { + // Not actually in the cache + return false; + } // Not worth checking if we wouldn't use it // XXX Check match-dest if (mPattern.Length() > aLongest) { @@ -157,7 +161,7 @@ nsresult DictionaryCacheEntry::Prefetch(nsILoadContextInfo* aLoadContextInfo, if (mWaitingPrefetch.IsEmpty()) { if (!mDictionaryDataComplete) { // We haven't requested it yet from the Cache and don't have it in memory - // already + // already. // We can't use sCacheStorage because we need the correct LoadContextInfo nsCOMPtr<nsICacheStorageService> cacheStorageService( components::CacheStorage::Service()); @@ -172,10 +176,20 @@ nsresult DictionaryCacheEntry::Prefetch(nsILoadContextInfo* aLoadContextInfo, aShouldSuspend = false; return NS_ERROR_FAILURE; } + // If the file isn't available in the cache, AsyncOpenURIString() + // will synchronously make a callback to OnCacheEntryAvailable() with + // nullptr. We can key off that to fail Prefetch(), and also to + // remove ourselves from the origin. if (NS_FAILED(cacheStorage->AsyncOpenURIString( - mURI, ""_ns, nsICacheStorage::OPEN_READONLY, this))) { - // For some reason the cache no longer has this entry; + mURI, ""_ns, + nsICacheStorage::OPEN_READONLY | + nsICacheStorage::OPEN_COMPLETE_ONLY, + this)) || + mNotCached) { + // For some reason the cache no longer has this entry; fail Prefetch + // and also remove this from our origin aShouldSuspend = false; + // XXX Remove from origin return NS_ERROR_FAILURE; } mWaitingPrefetch.AppendElement(aFunc); @@ -492,11 +506,9 @@ DictionaryCacheEntry::OnCacheEntryAvailable(nsICacheEntry* entry, bool isNew, } DICTIONARY_LOG(("Waiting for data")); } else { - // This shouldn't happen.... we should only be fetching something we know - // is in the cache. - // Presumably status is something like NS_ERROR_FILE_NOT_FOUND // XXX Error out any channels waiting on this cache entry. Also, - // remove the dictionary entry from the origin? + // remove the dictionary entry from the origin. + mNotCached = true; // For Prefetch() DICTIONARY_LOG(("Prefetched cache entry not available!")); } diff --git a/netwerk/cache2/Dictionary.h b/netwerk/cache2/Dictionary.h @@ -64,6 +64,7 @@ class DictionaryCacheEntry final : public nsICacheEntryOpenCallback, // returns true if the pattern for the dictionary matches the path given bool Match(const nsACString& aFilePath, uint32_t& aLongest); + // This will fail if the cache entry is no longer available. // Start reading the cache entry into memory and call completion // function when done nsresult Prefetch(nsILoadContextInfo* aLoadContextInfo, bool& aShouldSuspend, @@ -200,6 +201,9 @@ class DictionaryCacheEntry final : public nsICacheEntryOpenCallback, // We should suspend until the ond entry has been read bool mShouldSuspend{false}; + // The cache entry has been removed + bool mNotCached{false}; + // We're blocked from taking over for the old entry for now bool mBlocked{false}; }; diff --git a/netwerk/cache2/nsICacheEntry.idl b/netwerk/cache2/nsICacheEntry.idl @@ -60,6 +60,11 @@ interface nsICacheEntry : nsISupports readonly attribute boolean persistent; /** + * Get if the cache file is READY + */ + readonly attribute boolean ready; + + /** * Get the number of times the cache entry has been opened. */ readonly attribute uint32_t fetchCount; diff --git a/netwerk/cache2/nsICacheStorage.idl b/netwerk/cache2/nsICacheStorage.idl @@ -63,6 +63,11 @@ interface nsICacheStorage : nsISupports const uint32_t OPEN_INTERCEPTED = 1 << 6; /** + * Only open an existing entry which is complete (i.e. not being written) + */ + const uint32_t OPEN_COMPLETE_ONLY = 1 << 7; + + /** * Asynchronously opens a cache entry for the specified URI. * Result is fetched asynchronously via the callback. *