Files
firefox/dom/script/SharedScriptCache.cpp
T
Tooru Fujisawa 64ff55f333 Bug 1991607 - Part 1: Let ScriptHashKey and ScriptLoadData receive LoadedScript-related parameters separately. r=bthrall
This is a preparation for the later patches.

ScriptFetchOptions and URI fields are duplicated between ScriptLoadRequest and
LoadedScript, and this patch stack is going to remove them from
ScriptLoadRequest.

At the point of ScriptLoader::TryUseCache, LoadedScript is not yet created,
and ScriptHashKey needs to receive ScriptFetchOptions and URI in addition to
ScriptLoadRequest.

In order to avoid misuse, ScriptHashKey constructor is split into two variants.
One receives ScriptLoadRequest+ScriptFetchOptions+nsIURI, which is for
the case LoadedScript is not yet created,
and the other receives ScriptLoadRequest+LoadedScript, which is for the case
LoadedScript is already created.

Differential Revision: https://phabricator.services.mozilla.com/D267349
2025-10-22 11:20:36 +00:00

169 lines
5.9 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "SharedScriptCache.h"
#include "ScriptLoadHandler.h" // ScriptLoadHandler
#include "ScriptLoader.h" // ScriptLoader
#include "mozilla/Maybe.h" // Maybe, Some, Nothing
#include "mozilla/dom/ContentParent.h" // dom::ContentParent
#include "nsIMemoryReporter.h" // nsIMemoryReporter, MOZ_DEFINE_MALLOC_SIZE_OF, RegisterWeakMemoryReporter, UnregisterWeakMemoryReporter, MOZ_COLLECT_REPORT, KIND_HEAP, UNITS_BYTES
#include "nsIPrefBranch.h" // nsIPrefBranch, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID
#include "nsIPrefService.h" // NS_PREFSERVICE_CONTRACTID
#include "nsIPrincipal.h" // nsIPrincipal
#include "nsISupportsImpl.h" // NS_IMPL_ISUPPORTS
#include "nsStringFwd.h" // nsACString
namespace mozilla::dom {
ScriptHashKey::ScriptHashKey(
ScriptLoader* aLoader, const JS::loader::ScriptLoadRequest* aRequest,
const JS::loader::ScriptFetchOptions* aFetchOptions,
const nsCOMPtr<nsIURI> aURI)
: PLDHashEntryHdr(),
mURI(aURI),
mLoaderPrincipal(aLoader->LoaderPrincipal()),
mPartitionPrincipal(aLoader->PartitionedPrincipal()),
mCORSMode(aFetchOptions->mCORSMode),
mSRIMetadata(aRequest->mIntegrity),
mKind(aRequest->mKind),
mNonce(aFetchOptions->mNonce),
mIsLinkRelPreload(aRequest->GetScriptLoadContext()->IsPreload()) {
if (mKind == JS::loader::ScriptKind::eClassic) {
if (aRequest->GetScriptLoadContext()->HasScriptElement()) {
aRequest->GetScriptLoadContext()->GetHintCharset(mHintCharset);
}
}
MOZ_COUNT_CTOR(ScriptHashKey);
}
ScriptHashKey::ScriptHashKey(ScriptLoader* aLoader,
const JS::loader::ScriptLoadRequest* aRequest,
const JS::loader::LoadedScript* aLoadedScript)
: ScriptHashKey(aLoader, aRequest, aRequest->mFetchOptions,
aRequest->mURI) {}
ScriptHashKey::ScriptHashKey(const ScriptLoadData& aLoadData)
: ScriptHashKey(aLoadData.CacheKey()) {}
bool ScriptHashKey::KeyEquals(const ScriptHashKey& aKey) const {
if (mKind != aKey.mKind) {
return false;
}
{
bool eq;
if (NS_FAILED(mURI->Equals(aKey.mURI, &eq)) || !eq) {
return false;
}
}
if (!mPartitionPrincipal->Equals(aKey.mPartitionPrincipal)) {
return false;
}
if (mCORSMode != aKey.mCORSMode) {
return false;
}
if (mNonce != aKey.mNonce) {
return false;
}
// NOTE: module always use UTF-8.
if (mKind == JS::loader::ScriptKind::eClassic) {
if (mHintCharset != aKey.mHintCharset) {
return false;
}
}
if (!mSRIMetadata.CanTrustBeDelegatedTo(aKey.mSRIMetadata) ||
!aKey.mSRIMetadata.CanTrustBeDelegatedTo(mSRIMetadata)) {
return false;
}
return true;
}
NS_IMPL_ISUPPORTS(ScriptLoadData, nsISupports)
ScriptLoadData::ScriptLoadData(ScriptLoader* aLoader,
JS::loader::ScriptLoadRequest* aRequest,
JS::loader::LoadedScript* aLoadedScript)
: mExpirationTime(aRequest->ExpirationTime()),
mLoader(aLoader),
mKey(aLoader, aRequest, aLoadedScript),
mLoadedScript(aLoadedScript),
mNetworkMetadata(aRequest->mNetworkMetadata) {}
NS_IMPL_ISUPPORTS(SharedScriptCache, nsIMemoryReporter)
MOZ_DEFINE_MALLOC_SIZE_OF(SharedScriptCacheMallocSizeOf)
SharedScriptCache::SharedScriptCache() = default;
void SharedScriptCache::Init() {
RegisterWeakMemoryReporter(this);
// URL classification (tracking protection etc) are handled inside
// nsHttpChannel.
// The cache reflects the policy for whether to block or not, and once
// the policy is modified, we should discard the cache, to avoid running
// a cached script which is supposed to be blocked.
auto ClearCache = [](const char*, void*) { Clear(); };
Preferences::RegisterPrefixCallback(ClearCache, "urlclassifier.");
Preferences::RegisterCallback(ClearCache,
"privacy.trackingprotection.enabled");
}
SharedScriptCache::~SharedScriptCache() { UnregisterWeakMemoryReporter(this); }
void SharedScriptCache::LoadCompleted(SharedScriptCache* aCache,
ScriptLoadData& aData) {}
NS_IMETHODIMP
SharedScriptCache::CollectReports(nsIHandleReportCallback* aHandleReport,
nsISupports* aData, bool aAnonymize) {
MOZ_COLLECT_REPORT("explicit/js-non-window/cache", KIND_HEAP, UNITS_BYTES,
SharedScriptCacheMallocSizeOf(this) +
SizeOfExcludingThis(SharedScriptCacheMallocSizeOf),
"Memory used for SharedScriptCache to share script "
"across documents");
return NS_OK;
}
void SharedScriptCache::Clear(const Maybe<bool>& aChrome,
const Maybe<nsCOMPtr<nsIPrincipal>>& aPrincipal,
const Maybe<nsCString>& aSchemelessSite,
const Maybe<OriginAttributesPattern>& aPattern,
const Maybe<nsCString>& aURL) {
using ContentParent = dom::ContentParent;
if (XRE_IsParentProcess()) {
for (auto* cp : ContentParent::AllProcesses(ContentParent::eLive)) {
(void)cp->SendClearScriptCache(aChrome, aPrincipal, aSchemelessSite,
aPattern, aURL);
}
}
if (sSingleton) {
sSingleton->ClearInProcess(aChrome, aPrincipal, aSchemelessSite, aPattern,
aURL);
}
}
/* static */
void SharedScriptCache::PrepareForLastCC() {
if (sSingleton) {
sSingleton->mComplete.Clear();
sSingleton->mPending.Clear();
sSingleton->mLoading.Clear();
}
}
} // namespace mozilla::dom