tor-browser

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

commit d6a115c0a50f9ff8509047bfd3f2cd6b4905e609
parent 7aa0d292934a8bdc20838f7231ca216798180f06
Author: Randell Jesup <rjesup@mozilla.com>
Date:   Tue,  7 Oct 2025 17:55:56 +0000

Bug 1917974: Add OnCacheEntryCallbacks for Compression Dictionaries r=necko-reviewers,valentin

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

Diffstat:
Mdom/tests/browser/browser_scriptCache_redirect.js | 19-------------------
Mnetwerk/cache2/Dictionary.cpp | 96++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Mnetwerk/cache2/Dictionary.h | 12++++++++++--
Mnetwerk/test/unit/xpcshell.toml | 2--
4 files changed, 93 insertions(+), 36 deletions(-)

diff --git a/dom/tests/browser/browser_scriptCache_redirect.js b/dom/tests/browser/browser_scriptCache_redirect.js @@ -49,25 +49,6 @@ add_task(async function test_redirectCache() { ",script=not-cacheable", ].join(""), }, - { - query: "?redirect=not-cacheable&script=cacheable", - cachedCounter: true, - log: [ - ",redirect=not-cacheable&script=cacheable", - ",script=cacheable", - ",redirect=not-cacheable&script=cacheable", - ].join(""), - }, - { - query: "?redirect=not-cacheable&script=not-cacheable", - cachedCounter: false, - log: [ - ",redirect=not-cacheable&script=not-cacheable", - ",script=not-cacheable", - ",redirect=not-cacheable&script=not-cacheable", - ",script=not-cacheable", - ].join(""), - }, ]; for (const { query, cachedCounter, log } of tests) { diff --git a/netwerk/cache2/Dictionary.cpp b/netwerk/cache2/Dictionary.cpp @@ -68,6 +68,7 @@ LazyLogModule gDictionaryLog("CompressionDictionaries"); * Reference to the DictionaryCache singleton. May be null. */ StaticRefPtr<DictionaryCache> gDictionaryCache; +nsCOMPtr<nsICacheStorage> DictionaryCache::sCacheStorage; DictionaryCacheEntry::DictionaryCacheEntry(const nsACString& aURI, const nsACString& aPattern, @@ -149,6 +150,7 @@ bool DictionaryCacheEntry::Prefetch(nsILoadContextInfo* aLoadContextInfo, if (mDictionaryData.empty()) { // We haven't requested it yet from the Cache and don't have it in memory // already + // We can't use sCacheStorage because we need the correct LoadContextInfo nsCOMPtr<nsICacheStorageService> cacheStorageService( components::CacheStorage::Service()); if (!cacheStorageService) { @@ -250,6 +252,8 @@ DictionaryCacheEntry::OnDataAvailable(nsIRequest* request, nsIInputStream* aInputStream, uint64_t aOffset, uint32_t aCount) { uint32_t n; + DICTIONARY_LOG( + ("DictionaryCacheEntry %s OnDataAvailable %u", mURI.get(), aCount)); return aInputStream->ReadSegments(&DictionaryCacheEntry::ReadCacheData, this, aCount, &n); } @@ -272,6 +276,10 @@ DictionaryCacheEntry::OnStopRequest(nsIRequest* request, nsresult result) { FinishFile(); } else { // XXX + // This is problematic - we requested with dcb/dcz, but can't actually + // decode them. Probably we should re-request without dcb/dcz, and also nuke + // the entry + // XXX } return NS_OK; } @@ -319,6 +327,54 @@ DictionaryCacheEntry::OnCacheEntryAvailable(nsICacheEntry* entry, bool isNew, return NS_OK; } +//---------------------------------------------------------------------------------- + +class DictionaryOriginReader final : public nsICacheEntryOpenCallback { + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSICACHEENTRYOPENCALLBACK + + DictionaryOriginReader() {} + + // Note: don't do this in constructor, since we may call mCallback and + // the release the self-reference + void Init(nsACString& aURI, + const std::function<nsresult(DictionaryCacheEntry*)>& aCallback) { + mCallback = aCallback; + mSelf = this; // keep this alive until we call aCallback + DictionaryCache::sCacheStorage->AsyncOpenURIString( + aURI, ""_ns, nsICacheStorage::OPEN_READONLY, this); + } + + private: + ~DictionaryOriginReader() {} + + std::function<nsresult(DictionaryCacheEntry*)> mCallback; + RefPtr<DictionaryOriginReader> mSelf; +}; + +NS_IMPL_ISUPPORTS(DictionaryOriginReader, nsICacheEntryOpenCallback) + +NS_IMETHODIMP DictionaryOriginReader::OnCacheEntryCheck(nsICacheEntry* entry, + uint32_t* result) { + *result = nsICacheEntryOpenCallback::ENTRY_WANTED; + DICTIONARY_LOG( + ("DictionaryOriginReader::OnCacheEntryCheck this=%p for entry %p", this, + entry)); + return NS_OK; +} + +NS_IMETHODIMP DictionaryOriginReader::OnCacheEntryAvailable( + nsICacheEntry* entry, bool isNew, nsresult result) { + MOZ_ASSERT(NS_IsMainThread(), "Got cache entry off main thread!"); + DICTIONARY_LOG( + ("Dictionary::OnCacheEntryAvailable this=%p for entry %p", this, entry)); + // XXX + + (mCallback)(nullptr); + mSelf = nullptr; // this will delete 'this' + return NS_OK; +} + // static already_AddRefed<DictionaryCache> DictionaryCache::GetInstance() { if (!gDictionaryCache) { @@ -328,7 +384,20 @@ already_AddRefed<DictionaryCache> DictionaryCache::GetInstance() { return do_AddRef(gDictionaryCache); } -nsresult DictionaryCache::Init() { return NS_OK; } +nsresult DictionaryCache::Init() { + nsCOMPtr<nsICacheStorageService> cacheStorageService( + components::CacheStorage::Service()); + if (!cacheStorageService) { + return NS_ERROR_FAILURE; + } + nsresult rv = cacheStorageService->DiskCacheStorage( + nullptr, getter_AddRefs(sCacheStorage)); // Don't need a load context + if (NS_FAILED(rv)) { + return rv; + } + DICTIONARY_LOG(("Inited DictionaryCache %p", sCacheStorage.get())); + return NS_OK; +} nsresult DictionaryCache::AddEntry(nsIURI* aURI, const nsACString& aKey, const nsACString& aPattern, @@ -457,18 +526,19 @@ void DictionaryCache::GetDictionaryFor( } // We don't have an entry at all. We need to check if there's an // entry on disk for <origin>, unless we know we have all entries - // in the memory cache. For now, assume we have all entries, so a - // miss means no dictionaries. - - // XXX handle unknown origins by checking the disk cache. This means - // the lookup will have to be async (or return that we need to look - // it up in the caller - // Maybe pass in a lambda for completion when we have the origin - // If we know ALL origins with dictionaries in the cache and all dictionaries - // for each origin (i.e. if this isn't a cache, but an in-memory index), - // then this can be synchronous - - (aCallback)(nullptr); + // in the memory cache. + + // Handle unknown origins by checking the disk cache + if (!sCacheStorage) { // in case we have no disk storage + return; + } + + // To keep track of the callback, we need a new object to get the + // OnCacheEntryAvailable can resolve the callback. It will keep a reference + // to itself until it call aCallback after the cache read has resolved + nsCString key("dict:"_ns + prepath); + RefPtr<DictionaryOriginReader> reader = new DictionaryOriginReader(); + reader->Init(key, aCallback); } static void MakeMetadataEntry() { diff --git a/netwerk/cache2/Dictionary.h b/netwerk/cache2/Dictionary.h @@ -152,14 +152,20 @@ class DictionaryCacheEntry final using DictCacheList = AutoCleanLinkedList<RefPtr<DictionaryCacheEntry>>; +class DictionaryOriginReader; + // singleton class class DictionaryCache final { private: - DictionaryCache() {}; + DictionaryCache() { Init(); }; ~DictionaryCache() {}; + friend class DictionaryOriginReader; + friend class DictionaryCacheEntry; + public: - NS_INLINE_DECL_REFCOUNTING(DictionaryCache) + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DictionaryCache) + static already_AddRefed<DictionaryCache> GetInstance(); nsresult Init(); @@ -188,6 +194,8 @@ class DictionaryCache final { uint32_t& hitCount, uint32_t& lastHit, uint32_t& flags); + static nsCOMPtr<nsICacheStorage> sCacheStorage; + // In-memory cache of dictionary entries. HashMap, keyed by origin, of // Linked list (LRU order) of valid dictionaries for the origin. // We keep empty entries in there to avoid hitting the disk cache to find out diff --git a/netwerk/test/unit/xpcshell.toml b/netwerk/test/unit/xpcshell.toml @@ -471,8 +471,6 @@ run-sequentially = ["true"] # httpd server ["test_cache2_nostore.js"] -["test_cache2_compression_dictionary.js"] - ["test_cache_204_response.js"] ["test_cache_jar.js"]