tor-browser

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

commit 33cb96b72fdf243a20a9b0ba7887b3bdc3611141
parent 2f04f4d43c3ea35fd5f1f3f0cfb52eb2a8fb0663
Author: Randell Jesup <rjesup@mozilla.com>
Date:   Tue,  7 Oct 2025 14:07:04 +0000

Bug 1917974: Make GetDictionaryFor async since we need to query the cache r=necko-reviewers,valentin

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

Diffstat:
Mnetwerk/cache2/Dictionary.cpp | 15+++++++++------
Mnetwerk/cache2/Dictionary.h | 11+++++------
Mnetwerk/protocol/http/nsHttpChannel.cpp | 63+++++++++++++++++++++++++++++----------------------------------
Mnetwerk/protocol/http/nsHttpHandler.cpp | 93++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Mnetwerk/protocol/http/nsHttpHandler.h | 2+-
5 files changed, 103 insertions(+), 81 deletions(-)

diff --git a/netwerk/cache2/Dictionary.cpp b/netwerk/cache2/Dictionary.cpp @@ -141,7 +141,7 @@ void DictionaryCacheEntry::UseCompleted() { // returns aShouldSuspend=true if we should suspend to wait for the prefetch bool DictionaryCacheEntry::Prefetch(nsILoadContextInfo* aLoadContextInfo, - const std::function<nsresult()>& aFunc) { + const std::function<void()>& aFunc) { DICTIONARY_LOG(("Prefetch for %s", mURI.get())); // Start reading the cache entry into memory and call completion // function when done @@ -424,14 +424,16 @@ nsresult DictionaryCache::RemoveEntry(nsIURI* aURI, const nsACString& aKey) { } // return an entry -already_AddRefed<DictionaryCacheEntry> DictionaryCache::GetDictionaryFor( - nsIURI* aURI) { +void DictionaryCache::GetDictionaryFor( + nsIURI* aURI, + const std::function<nsresult(DictionaryCacheEntry*)>& aCallback) { // Note: IETF 2.2.3 Multiple Matching Directories // We need to return match-dest matches first // If no match-dest, then the longest match nsCString prepath; if (NS_FAILED(aURI->GetPrePath(prepath))) { - return nullptr; + (aCallback)(nullptr); + return; } if (auto origin = mDictionaryCache.Lookup(prepath)) { // Find the longest match @@ -450,7 +452,8 @@ already_AddRefed<DictionaryCacheEntry> DictionaryCache::GetDictionaryFor( result->removeFrom(*(origin->get())); origin->get()->insertFront(result); } - return result.forget(); + (aCallback)(result); + return; } // 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 @@ -465,7 +468,7 @@ already_AddRefed<DictionaryCacheEntry> DictionaryCache::GetDictionaryFor( // for each origin (i.e. if this isn't a cache, but an in-memory index), // then this can be synchronous - return nullptr; + (aCallback)(nullptr); } static void MakeMetadataEntry() { diff --git a/netwerk/cache2/Dictionary.h b/netwerk/cache2/Dictionary.h @@ -69,12 +69,9 @@ class DictionaryCacheEntry final // Start reading the cache entry into memory and call completion // function when done bool Prefetch(nsILoadContextInfo* aLoadContextInfo, - const std::function<nsresult()>& aFunc); + const std::function<void()>& aFunc); - const nsACString& GetHash() const { - MOZ_ASSERT(NS_IsMainThread()); - return mHash; - } + const nsACString& GetHash() const { return mHash; } void SetHash(const nsACString& aHash) { MOZ_ASSERT(NS_IsMainThread()); @@ -177,7 +174,9 @@ class DictionaryCache final { nsresult RemoveEntry(nsIURI* aURI, const nsACString& aKey); // return an entry - already_AddRefed<DictionaryCacheEntry> GetDictionaryFor(nsIURI* aURI); + void GetDictionaryFor( + nsIURI* aURI, + const std::function<nsresult(DictionaryCacheEntry*)>& aCallback); size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { // XXX diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp @@ -545,33 +545,37 @@ nsresult nsHttpChannel::Init(nsIURI* uri, uint32_t caps, nsProxyInfo* proxyInfo, uint64_t channelId, nsILoadInfo* aLoadInfo) { nsresult rv = HttpBaseChannel::Init(uri, caps, proxyInfo, proxyResolveFlags, proxyURI, channelId, aLoadInfo); - if (NS_FAILED(rv)) return rv; - rv = gHttpHandler->AddAcceptAndDictionaryHeaders(uri, &mRequestHead, - IsHTTPS(), mDict); - if (NS_FAILED(rv)) return rv; - if (mDict) { - // mDict is set if we added Available-Dictionary - mDict->InUse(); - mUsingDictionary = true; - mShouldSuspendForDictionary = mDict->Prefetch( - GetLoadContextInfo(this), [self = RefPtr<nsHttpChannel>(this)]() { - // this is called when the prefetch is complete to - // un-Suspend the channel - MOZ_ASSERT(self->mDict->DictionaryReady()); - if (self->mSuspendedForDictionary) { - LOG( - ("nsHttpChannel::Init [this=%p] Resuming channel suspended for " - "Dictionary", - self.get())); - self->mSuspendedForDictionary = false; - self->Resume(); - } - return NS_OK; - }); - } - LOG1(("nsHttpChannel::Init [this=%p]\n", this)); + if (NS_FAILED(rv)) return rv; + // This may be async; the dictionary headers may need to fetch an origin + // dictionary cache entry from disk before adding the headers. We can + // continue with channel creation, and just block on this being done later + rv = gHttpHandler->AddAcceptAndDictionaryHeaders( + uri, &mRequestHead, IsHTTPS(), + [self = RefPtr(this)](DictionaryCacheEntry* aDict) { + self->mDict = aDict; + if (self->mDict) { + // mDict is set if we added Available-Dictionary + self->mDict->InUse(); + self->mUsingDictionary = true; + self->mShouldSuspendForDictionary = + self->mDict->Prefetch(GetLoadContextInfo(self), [self]() { + // this is called when the prefetch is complete to + // un-Suspend the channel + MOZ_ASSERT(self->mDict->DictionaryReady()); + if (self->mSuspendedForDictionary) { + LOG( + ("nsHttpChannel::Init [this=%p] Resuming channel " + "suspended for " + "Dictionary", + self.get())); + self->mSuspendedForDictionary = false; + self->Resume(); + } + }); + } + }); return rv; } @@ -1981,15 +1985,6 @@ nsresult nsHttpChannel::SetupChannelForTransaction() { MOZ_ASSERT(NS_SUCCEEDED(rv)); } } - } else { - // If we add a Range header, Accept-Encoding needs to be set to - // "identity" and any http additions to the headers aren't allowed to - // override that, so we don't try. Section 4.5 step 8.19 and 8.20 of - // HTTP-network-or-cache fetch - // https://fetch.spec.whatwg.org/#http-network-or-cache-fetch - rv = mHttpHandler->AddAcceptAndDictionaryHeaders( - mURI, &mRequestHead, mURI->SchemeIs("https"), mDict); - if (NS_FAILED(rv)) return rv; } // See bug #466080. Transfer LOAD_ANONYMOUS flag to socket-layer. diff --git a/netwerk/protocol/http/nsHttpHandler.cpp b/netwerk/protocol/http/nsHttpHandler.cpp @@ -656,51 +656,75 @@ nsresult nsHttpHandler::InitConnectionMgr() { // set by Fetch from the old request nsresult nsHttpHandler::AddAcceptAndDictionaryHeaders( nsIURI* aURI, nsHttpRequestHead* aRequest, bool aSecure, - RefPtr<DictionaryCacheEntry>& aDict) { + const std::function<void(DictionaryCacheEntry*)>& aCallback) { LOG(("Adding Dictionary headers")); - nsresult rv; + nsresult rv = NS_OK; // Add the "Accept-Encoding" header and possibly Dictionary headers if (aSecure) { // The dictionary info may require us to check the cache. // XXX This would require that AddAcceptAndDictionaryHeaders be effectively // async, perhaps by passing a lambda to call AddAcceptAndDictionaryHeaders // and then unblock the request - if (StaticPrefs::network_http_dictionaries_enable() && - (aDict = mDictionaryCache->GetDictionaryFor(aURI))) { - rv = aRequest->SetHeader(nsHttp::Accept_Encoding, - mDictionaryAcceptEncodings, false, - nsHttpHeaderArray::eVarietyRequestOverride); - if (NS_FAILED(rv)) { - return rv; - } - LOG(("Setting Accept-Encoding: %s", mDictionaryAcceptEncodings.get())); - - nsAutoCStringN<64> encodedHash = ":"_ns + aDict->GetHash() + ":"_ns; - - LOG(("Setting Available-Dictionary: %s", encodedHash.get())); - rv = aRequest->SetHeader(nsHttp::Available_Dictionary, encodedHash, false, - nsHttpHeaderArray::eVarietyRequestOverride); - if (NS_FAILED(rv)) { - return rv; - } - if (!aDict->GetId().IsEmpty()) { - rv = aRequest->SetHeader(nsHttp::Dictionary_Id, aDict->GetId(), false, - nsHttpHeaderArray::eVarietyRequestOverride); - if (NS_FAILED(rv)) { - return rv; - } - LOG(("Setting Dictionary-Id: %s", aDict->GetId().get())); - } - // Need to retain access to the dictionary until the request completes. - // Note that this includes if the dictionary we offered gets replaced - // by another request while we're waiting for a response; in that case we - // need to read in a copy of the dictionary into memory before overwriting - // it and store in dict temporarily. - aRequest->SetDictionary(aDict); + if (StaticPrefs::network_http_dictionaries_enable()) { + mDictionaryCache->GetDictionaryFor( + aURI, [self = RefPtr(this), aRequest, + aCallback](DictionaryCacheEntry* aDict) { + nsresult rv; + if (aDict) { + rv = aRequest->SetHeader( + nsHttp::Accept_Encoding, self->mDictionaryAcceptEncodings, + false, nsHttpHeaderArray::eVarietyRequestOverride); + if (NS_FAILED(rv)) { + (aCallback)(nullptr); + return rv; + } + LOG_DICTIONARIES(("Setting Accept-Encoding: %s", + self->mDictionaryAcceptEncodings.get())); + + nsAutoCStringN<64> encodedHash = + ":"_ns + aDict->GetHash() + ":"_ns; + + LOG_DICTIONARIES( + ("Setting Available-Dictionary: %s", encodedHash.get())); + rv = aRequest->SetHeader( + nsHttp::Available_Dictionary, encodedHash, false, + nsHttpHeaderArray::eVarietyRequestOverride); + if (NS_FAILED(rv)) { + (aCallback)(nullptr); + return rv; + } + if (!aDict->GetId().IsEmpty()) { + rv = aRequest->SetHeader( + nsHttp::Dictionary_Id, aDict->GetId(), false, + nsHttpHeaderArray::eVarietyRequestOverride); + if (NS_FAILED(rv)) { + (aCallback)(nullptr); + return rv; + } + LOG_DICTIONARIES( + ("Setting Dictionary-Id: %s", aDict->GetId().get())); + } + // Need to retain access to the dictionary until the request + // completes. Note that this includes if the dictionary we offered + // gets replaced by another request while we're waiting for a + // response; in that case we need to read in a copy of the + // dictionary into memory before overwriting it and store in dict + // temporarily. + aRequest->SetDictionary(aDict); + (aCallback)(aDict); + return NS_OK; + } + rv = aRequest->SetHeader( + nsHttp::Accept_Encoding, self->mHttpsAcceptEncodings, false, + nsHttpHeaderArray::eVarietyRequestOverride); + (aCallback)(nullptr); + return rv; + }); } else { rv = aRequest->SetHeader(nsHttp::Accept_Encoding, mHttpsAcceptEncodings, false, nsHttpHeaderArray::eVarietyRequestOverride); + (aCallback)(nullptr); } } else { // We need to not override a previous setting of 'identity' (for range @@ -712,6 +736,7 @@ nsresult nsHttpHandler::AddAcceptAndDictionaryHeaders( false, nsHttpHeaderArray::eVarietyRequestOverride); } + (aCallback)(nullptr); } return rv; diff --git a/netwerk/protocol/http/nsHttpHandler.h b/netwerk/protocol/http/nsHttpHandler.h @@ -119,7 +119,7 @@ class nsHttpHandler final : public nsIHttpProtocolHandler, [[nodiscard]] nsresult AddAcceptAndDictionaryHeaders( nsIURI* aURI, nsHttpRequestHead* aRequest, bool aSecure, - RefPtr<DictionaryCacheEntry>& aDict); + const std::function<void(DictionaryCacheEntry*)>& aCallback); [[nodiscard]] nsresult AddStandardRequestHeaders( nsHttpRequestHead*, nsIURI* aURI, ExtContentPolicyType aContentPolicyType, bool aShouldResistFingerprinting);