tor-browser

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

commit 06974fe1c159fa16f26a317af39023c39b04e618
parent 77792ab3e3180d04ce426dec9b6bb4f6ad30f2d2
Author: Randell Jesup <rjesup@mozilla.com>
Date:   Tue,  7 Oct 2025 17:55:53 +0000

Bug 1917974: Accumulate Dictionary hash values r=necko-reviewers,sunil

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

Diffstat:
Mnetwerk/cache2/CacheEntry.cpp | 6++++++
Mnetwerk/cache2/CacheEntry.h | 7+++++--
Mnetwerk/cache2/CacheFile.cpp | 23++++++++++++++++++++++-
Mnetwerk/cache2/CacheFile.h | 5+++++
Mnetwerk/cache2/CacheFileOutputStream.cpp | 6++++++
Mnetwerk/cache2/CacheFileOutputStream.h | 4++++
Mnetwerk/cache2/Dictionary.cpp | 42+++++++++++++++++++++++++++++++++++++++++-
Mnetwerk/cache2/Dictionary.h | 12++++++++++++
Mnetwerk/cache2/nsICacheEntry.idl | 14++++++++++++++
9 files changed, 115 insertions(+), 4 deletions(-)

diff --git a/netwerk/cache2/CacheEntry.cpp b/netwerk/cache2/CacheEntry.cpp @@ -295,6 +295,12 @@ nsresult CacheEntry::HashingKey(const nsACString& aStorageID, return NS_OK; } +nsresult CacheEntry::SetDictionary(DictionaryCacheEntry* aDict) { + mDict = aDict; + mFile->SetDictionary(aDict); + return NS_OK; +} + void CacheEntry::AsyncOpen(nsICacheEntryOpenCallback* aCallback, uint32_t aFlags) { bool readonly = aFlags & nsICacheStorage::OPEN_READONLY; diff --git a/netwerk/cache2/CacheEntry.h b/netwerk/cache2/CacheEntry.h @@ -105,6 +105,8 @@ class CacheEntry final : public nsIRunnable, nsIInputStream** _retval); nsresult GetLoadContextInfo(nsILoadContextInfo** aInfo); + nsresult SetDictionary(DictionaryCacheEntry* aDict); + public: uint32_t GetMetadataMemoryConsumption(); nsCString const& GetStorageID() const { return mStorageID; } @@ -131,8 +133,6 @@ class CacheEntry final : public nsIRunnable, TimeStamp const& LoadStart() const { return mLoadStart; } - void SetDictionary(DictionaryCacheEntry* aDict) { mDict = aDict; } - enum EPurge { PURGE_DATA_ONLY_DISK_BACKED, PURGE_WHOLE_ONLY_DISK_BACKED, @@ -547,6 +547,9 @@ class CacheEntryHandle final : public nsICacheEntry { nsILoadContextInfo** aLoadContextInfo) override { return mEntry->GetLoadContextInfo(aLoadContextInfo); } + NS_IMETHOD SetDictionary(DictionaryCacheEntry* aDict) override { + return mEntry->SetDictionary(aDict); + } // Specific implementation: NS_IMETHOD Dismiss() override; diff --git a/netwerk/cache2/CacheFile.cpp b/netwerk/cache2/CacheFile.cpp @@ -290,6 +290,14 @@ nsresult CacheFile::Init(const nsACString& aKey, bool aCreateNew, return NS_OK; } +void CacheFile::SetDictionary(DictionaryCacheEntry* aDict) { + CacheFileAutoLock lock(this); + mDict = aDict; + if (OutputStreamExists(false)) { + mOutput->SetDictionary(aDict); + } +} + void CacheFile::Key(nsACString& aKey) { CacheFileAutoLock lock(this); aKey = mKey; @@ -483,6 +491,10 @@ nsresult CacheFile::OnFileOpened(CacheFileHandle* aHandle, nsresult aResult) { mOpeningFile = false; + if (mDict && OutputStreamExists(false)) { + mOutput->SetDictionary(mDict); + } + autoDoom.mListener.swap(mDoomAfterOpenListener); if (mMemoryOnly) { @@ -898,6 +910,10 @@ nsresult CacheFile::OpenOutputStream(CacheOutputCloseListener* aCloseListener, "[this=%p]", mOutput, this)); + if (mDict) { + mOutput->SetDictionary(mDict); + } + mDataAccessed = true; *_retval = do_AddRef(mOutput).take(); return NS_OK; @@ -2105,7 +2121,12 @@ void CacheFile::RemoveOutput(CacheFileOutputStream* aOutput, nsresult aStatus) { return; } - mOutput = nullptr; + // This is to finalize the Hash calculation + if (mDict) { + mDict->FinishFile(); + } + + mOutput = nullptr; // XXX should this be after NotifyCloseListener? // Cancel all queued chunk and update listeners that cannot be satisfied NotifyListenersAboutOutputRemoval(); diff --git a/netwerk/cache2/CacheFile.h b/netwerk/cache2/CacheFile.h @@ -8,6 +8,7 @@ #include "CacheFileChunk.h" #include "CacheFileIOManager.h" #include "CacheFileMetadata.h" +#include "Dictionary.h" #include "nsRefPtrHashtable.h" #include "nsClassHashtable.h" #include "mozilla/Mutex.h" @@ -125,6 +126,8 @@ class MOZ_CAPABILITY("mutex") CacheFile final bool IsWriteInProgress(); bool EntryWouldExceedLimit(int64_t aOffset, int64_t aSize, bool aIsAltData); + void SetDictionary(DictionaryCacheEntry* aDict); + // Memory reporting size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const; size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; @@ -225,6 +228,8 @@ class MOZ_CAPABILITY("mutex") CacheFile final nsCString mAltDataType MOZ_GUARDED_BY(this); // The type of the saved alt-data. May be empty. + RefPtr<DictionaryCacheEntry> mDict MOZ_GUARDED_BY(this); + RefPtr<CacheFileHandle> mHandle MOZ_GUARDED_BY(this); RefPtr<CacheFileMetadata> mMetadata MOZ_GUARDED_BY(this); nsCOMPtr<CacheFileListener> mListener MOZ_GUARDED_BY(this); diff --git a/netwerk/cache2/CacheFileOutputStream.cpp b/netwerk/cache2/CacheFileOutputStream.cpp @@ -127,6 +127,12 @@ CacheFileOutputStream::Write(const char* aBuf, uint32_t aCount, *_retval = aCount; + if (mDict) { + // We need to calculate the hash for the entry as we save it + // We don't necessarily need to save the data in memory, however + mDict->AccumulateHash(aBuf, aCount); + } + while (aCount) { EnsureCorrectChunk(false); if (NS_FAILED(mStatus)) { diff --git a/netwerk/cache2/CacheFileOutputStream.h b/netwerk/cache2/CacheFileOutputStream.h @@ -9,6 +9,7 @@ #include "nsISeekableStream.h" #include "nsCOMPtr.h" #include "CacheFileChunk.h" +#include "Dictionary.h" namespace mozilla { namespace net { @@ -39,6 +40,8 @@ class CacheFileOutputStream : public nsIAsyncOutputStream, void NotifyCloseListener(); bool IsAlternativeData() const { return mAlternativeData; }; + void SetDictionary(DictionaryCacheEntry* aDict) { mDict = aDict; } + // Memory reporting size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; @@ -62,6 +65,7 @@ class CacheFileOutputStream : public nsIAsyncOutputStream, nsCOMPtr<nsIOutputStreamCallback> mCallback; uint32_t mCallbackFlags; nsCOMPtr<nsIEventTarget> mCallbackTarget; + RefPtr<DictionaryCacheEntry> mDict; }; } // namespace net diff --git a/netwerk/cache2/Dictionary.cpp b/netwerk/cache2/Dictionary.cpp @@ -55,7 +55,7 @@ using namespace mozilla; namespace mozilla { namespace net { -static LazyLogModule gDictionaryLog("CompressionDictionaries"); +LazyLogModule gDictionaryLog("CompressionDictionaries"); #define DICTIONARY_LOG(args) \ MOZ_LOG(gDictionaryLog, mozilla::LogLevel::Debug, args) @@ -118,6 +118,46 @@ void DictionaryCacheEntry::Prefetch() { // XXX } +void DictionaryCacheEntry::AccumulateHash(const char* aBuf, int32_t aCount) { + if (!mCrypto) { + // If mCrypto is null, and mDictionaryData is set, we've already got the + // data for this dictionary. + if (!mDictionaryData.empty()) { + DICTIONARY_LOG(("%p: Trying to rewrite to Dictionary uri %s, pattern %s", + this, PromiseFlatCString(mURI).get(), + PromiseFlatCString(mPattern).get())); + return; + } + nsresult rv; + mCrypto = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + rv = mCrypto->Init(nsICryptoHash::SHA256); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Cache InitCrypto failed"); + } + mCrypto->Update(reinterpret_cast<const uint8_t*>(aBuf), aCount); + DICTIONARY_LOG(("Accumulate Hash %p: %d bytes, total %zu", this, aCount, + mDictionaryData.length())); +} + +void DictionaryCacheEntry::AccumulateFile(const char* aBuf, int32_t aCount) { + AccumulateHash(aBuf, aCount); // error? + Unused << mDictionaryData.append(aBuf, aCount); + DICTIONARY_LOG(("Accumulate %p: %d bytes, total %zu", this, aCount, + mDictionaryData.length())); +} + +void DictionaryCacheEntry::FinishFile() { + MOZ_ASSERT(NS_IsMainThread()); + if (mCrypto) { + DICTIONARY_LOG(("Hash was %s", mHash.get())); + mCrypto->Finish(true, mHash); + DICTIONARY_LOG(("Set dictionary hash for %p to %s", this, mHash.get())); + mCrypto = nullptr; + } +} + // static already_AddRefed<DictionaryCache> DictionaryCache::GetInstance() { if (!gDictionaryCache) { diff --git a/netwerk/cache2/Dictionary.h b/netwerk/cache2/Dictionary.h @@ -89,6 +89,17 @@ class DictionaryCacheEntry final const Vector<uint8_t>& GetDictionary() const { return mDictionaryData; } + void AccumulateHash(const char* aBuf, int32_t aCount); + void AccumulateFile(const char* aBuf, int32_t aCount); + + void FinishFile(); + + // return a pointer to the data and length + uint8_t* DictionaryData(size_t* aLength) const { + *aLength = mDictionaryData.length(); + return (uint8_t*)mDictionaryData.begin(); + } + size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { // XXX return mallocSizeOf(this); @@ -107,6 +118,7 @@ class DictionaryCacheEntry final uint32_t mUsers{0}; // active requests using this entry // in-memory copy of the entry to use to decompress incoming data Vector<uint8_t> mDictionaryData; + bool mDictionaryDataComplete{false}; // for accumulating SHA-256 hash values for dictionaries nsCOMPtr<nsICryptoHash> mCrypto; diff --git a/netwerk/cache2/nsICacheEntry.idl b/netwerk/cache2/nsICacheEntry.idl @@ -12,6 +12,13 @@ interface nsILoadContextInfo; interface nsIOutputStream; interface nsITransportSecurityInfo; +%{C++ +namespace mozilla::net { +class DictionaryCacheEntry; +} +%} +[ptr] native DictionaryCacheEntry(mozilla::net::DictionaryCacheEntry); + [scriptable, uuid(607c2a2c-0a48-40b9-a956-8cf2bb9857cf)] interface nsICacheEntry : nsISupports { @@ -309,6 +316,13 @@ interface nsICacheEntry : nsISupports * Get the nsILoadContextInfo of the cache entry */ readonly attribute nsILoadContextInfo loadContextInfo; + + /** + * This method gets called to indicate that this entry will be used + * as a Dictionary in the future, so we know to calculate a hash for it. + */ + [noscript] void SetDictionary(in DictionaryCacheEntry dict); + }; /**