commit 7aa0d292934a8bdc20838f7231ca216798180f06
parent 9df6342af25e7dea0f32c678320e8e4c1f1376dd
Author: Randell Jesup <rjesup@mozilla.com>
Date: Tue, 7 Oct 2025 17:55:56 +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:
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);