Bug 1907009 - Part 1: Add CacheExpirationTime type. r=emilio

Differential Revision: https://phabricator.services.mozilla.com/D217957
This commit is contained in:
Tooru Fujisawa 2024-08-06 05:38:23 +00:00
Родитель 9448ef530c
Коммит 1abe447481
14 изменённых файлов: 139 добавлений и 79 удалений

Просмотреть файл

@ -0,0 +1,70 @@
/* -*- 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/. */
#ifndef mozilla_dom_CacheExpirationTime_h___
#define mozilla_dom_CacheExpirationTime_h___
#include <stdint.h> // uint32_t
#include "mozilla/Assertions.h" // MOZ_ASSERT
#include "prtime.h" // PRTime, PR_USEC_PER_SEC
/*
* The expiration time for sub resource cache.
*/
struct CacheExpirationTime {
private:
uint32_t mTime;
static constexpr uint32_t kNever = 0;
constexpr CacheExpirationTime() : mTime(kNever) {}
explicit constexpr CacheExpirationTime(uint32_t aTime) : mTime(aTime) {}
static uint32_t SecondsFromPRTime(PRTime aTime) {
return uint32_t(int64_t(aTime) / int64_t(PR_USEC_PER_SEC));
}
public:
static CacheExpirationTime AlreadyExpired() {
return CacheExpirationTime(SecondsFromPRTime(PR_Now()) - 1);
}
static constexpr CacheExpirationTime Never() {
return CacheExpirationTime(kNever);
}
static constexpr CacheExpirationTime ExpireAt(uint32_t aTime) {
return CacheExpirationTime(aTime);
}
bool IsExpired() const {
if (IsNever()) {
return false;
}
return mTime <= SecondsFromPRTime(PR_Now());
}
bool IsNever() const { return mTime == kNever; }
bool IsShorterThan(const CacheExpirationTime& aOther) const {
MOZ_ASSERT(!IsNever());
MOZ_ASSERT(!aOther.IsNever());
return mTime < aOther.mTime;
}
void SetMinimum(const CacheExpirationTime& aOther) {
if (aOther.IsNever()) {
return;
}
if (IsNever() || aOther.IsShorterThan(*this)) {
mTime = aOther.mTime;
}
}
};
#endif /* mozilla_dom_CacheExpirationTime_h___ */

Просмотреть файл

@ -157,6 +157,7 @@ EXPORTS.mozilla.dom += [
"BodyConsumer.h",
"BodyUtil.h",
"BorrowedAttrInfo.h",
"CacheExpirationTime.h",
"CCGCScheduler.h",
"CharacterData.h",
"ChildIterator.h",

Просмотреть файл

@ -145,6 +145,7 @@
#include "mozilla/dom/BrowserParent.h"
#include "mozilla/dom/BrowsingContext.h"
#include "mozilla/dom/BrowsingContextGroup.h"
#include "mozilla/dom/CacheExpirationTime.h"
#include "mozilla/dom/CallbackFunction.h"
#include "mozilla/dom/CallbackObject.h"
#include "mozilla/dom/ChromeMessageBroadcaster.h"
@ -11402,7 +11403,9 @@ nsContentUtils::GetSubresourceCacheValidationInfo(nsIRequest* aRequest,
if (nsCOMPtr<nsICacheInfoChannel> cache = do_QueryInterface(aRequest)) {
uint32_t value = 0;
if (NS_SUCCEEDED(cache->GetCacheTokenExpirationTime(&value))) {
info.mExpirationTime.emplace(value);
// NOTE: If the cache doesn't expire, the value should be
// nsICacheEntry::NO_EXPIRATION_TIME.
info.mExpirationTime.emplace(CacheExpirationTime::ExpireAt(value));
}
}
@ -11439,12 +11442,24 @@ nsContentUtils::GetSubresourceCacheValidationInfo(nsIRequest* aRequest,
if (knownCacheable) {
MOZ_ASSERT(!info.mExpirationTime);
MOZ_ASSERT(!info.mMustRevalidate);
info.mExpirationTime = Some(0); // 0 means "doesn't expire".
info.mExpirationTime = Some(CacheExpirationTime::Never());
}
return info;
}
CacheExpirationTime nsContentUtils::GetSubresourceCacheExpirationTime(
nsIRequest* aRequest, nsIURI* aURI) {
auto info = GetSubresourceCacheValidationInfo(aRequest, aURI);
// For now, we never cache entries that we have to revalidate, or whose
// channel don't support caching.
if (info.mMustRevalidate || !info.mExpirationTime) {
return CacheExpirationTime::AlreadyExpired();
}
return *info.mExpirationTime;
}
/* static */
bool nsContentUtils::ShouldBypassSubResourceCache(Document* aDoc) {
RefPtr<nsILoadGroup> lg = aDoc->GetDocumentLoadGroup();

Просмотреть файл

@ -39,6 +39,7 @@
#include "mozilla/TimeStamp.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/CacheExpirationTime.h"
#include "mozilla/dom/FromParser.h"
#include "mozilla/dom/FetchPriority.h"
#include "mozilla/fallible.h"
@ -3440,17 +3441,24 @@ class nsContentUtils {
struct SubresourceCacheValidationInfo {
// The expiration time, in seconds, if known.
mozilla::Maybe<uint32_t> mExpirationTime;
mozilla::Maybe<CacheExpirationTime> mExpirationTime;
bool mMustRevalidate = false;
};
/**
* Gets cache validation info for subresources such as images or CSS
* stylesheets.
* Gets cache validation info for subresources such as images, CSS
* stylesheets, or JS.
*/
static SubresourceCacheValidationInfo GetSubresourceCacheValidationInfo(
nsIRequest*, nsIURI*);
/**
* Gets cache expiration time for subresources such as images, CSS
* stylesheets, or JS.
*/
static CacheExpirationTime GetSubresourceCacheExpirationTime(nsIRequest*,
nsIURI*);
/**
* Returns true if the request associated with the document should bypass the
* shared sub resource cache.

Просмотреть файл

@ -24,6 +24,7 @@
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/Utf8.h"
#include "mozilla/Vector.h"
#include "mozilla/dom/CacheExpirationTime.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/SRICheck.h"
#include "mozilla/dom/ScriptDecoding.h"
@ -127,21 +128,11 @@ ScriptLoadHandler::~ScriptLoadHandler() = default;
NS_IMPL_ISUPPORTS(ScriptLoadHandler, nsIIncrementalStreamLoaderObserver,
nsIChannelEventSink, nsIInterfaceRequestor)
static uint32_t CalculateExpirationTime(nsIRequest* aRequest, nsIURI* aURI) {
auto info = nsContentUtils::GetSubresourceCacheValidationInfo(aRequest, aURI);
// For now, we never cache entries that we have to revalidate, or whose
// channel don't support caching.
if (info.mMustRevalidate || !info.mExpirationTime) {
return nsContentUtils::SecondsFromPRTime(PR_Now()) - 1;
}
return *info.mExpirationTime;
}
NS_IMETHODIMP
ScriptLoadHandler::OnStartRequest(nsIRequest* aRequest) {
mRequest->SetMinimumExpirationTime(
CalculateExpirationTime(aRequest, mRequest->mURI));
nsContentUtils::GetSubresourceCacheExpirationTime(aRequest,
mRequest->mURI));
return NS_OK;
}
@ -502,7 +493,7 @@ nsresult ScriptLoadHandler::AsyncOnChannelRedirect(
nsIChannel* aOld, nsIChannel* aNew, uint32_t aFlags,
nsIAsyncVerifyRedirectCallback* aCallback) {
mRequest->SetMinimumExpirationTime(
CalculateExpirationTime(aOld, mRequest->mURI));
nsContentUtils::GetSubresourceCacheExpirationTime(aOld, mRequest->mURI));
aCallback->OnRedirectVerifyCallback(NS_OK);

Просмотреть файл

@ -15,6 +15,7 @@
#include "mozilla/CORSMode.h" // mozilla::CORSMode
#include "mozilla/MemoryReporting.h" // MallocSizeOf
#include "mozilla/SharedSubResourceCache.h" // SharedSubResourceCache, SharedSubResourceCacheLoadingValueBase
#include "mozilla/dom/CacheExpirationTime.h" // CacheExpirationTime
#include "nsIMemoryReporter.h" // nsIMemoryReporter, NS_DECL_NSIMEMORYREPORTER
#include "nsIObserver.h" // nsIObserver, NS_DECL_NSIOBSERVER
#include "nsIPrincipal.h" // nsIPrincipal
@ -145,14 +146,14 @@ class ScriptLoadData final
return mLoadedScript.get();
}
uint32_t ExpirationTime() const { return mExpirationTime; }
const CacheExpirationTime& ExpirationTime() const { return mExpirationTime; }
ScriptLoader& Loader() { return *mLoader; }
const ScriptHashKey& CacheKey() const { return mKey; }
private:
uint32_t mExpirationTime = 0;
CacheExpirationTime mExpirationTime = CacheExpirationTime::Never();
ScriptLoader* mLoader;
ScriptHashKey mKey;
RefPtr<JS::loader::LoadedScript> mLoadedScript;

Просмотреть файл

@ -31,6 +31,7 @@
#include "mozilla/StaticPrefs_image.h"
#include "mozilla/StaticPrefs_network.h"
#include "mozilla/StoragePrincipalHelper.h"
#include "mozilla/dom/CacheExpirationTime.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/FetchPriority.h"
#include "mozilla/dom/nsMixedContentBlocker.h"
@ -1001,7 +1002,7 @@ imgCacheEntry::imgCacheEntry(imgLoader* loader, imgRequest* request,
mDataSize(0),
mTouchedTime(SecondsFromPRTime(PR_Now())),
mLoadTime(SecondsFromPRTime(PR_Now())),
mExpiryTime(0),
mExpiryTime(CacheExpirationTime::Never()),
mMustValidate(false),
// We start off as evicted so we don't try to update the cache.
// PutIntoCache will set this to false.
@ -1906,8 +1907,7 @@ bool imgLoader::ValidateEntry(
// If the expiration time is zero, then the request has not gotten far enough
// to know when it will expire, or we know it will never expire (see
// nsContentUtils::GetSubresourceCacheValidationInfo).
uint32_t expiryTime = aEntry->GetExpiryTime();
bool hasExpired = expiryTime && expiryTime <= SecondsFromPRTime(PR_Now());
bool hasExpired = aEntry->GetExpiryTime().IsExpired();
// Special treatment for file URLs - aEntry has expired if file has changed
if (nsCOMPtr<nsIFileURL> fileUrl = do_QueryInterface(aURI)) {

Просмотреть файл

@ -26,6 +26,7 @@
#include "nsIChannel.h"
#include "nsIThreadRetargetableStreamListener.h"
#include "imgIRequest.h"
#include "mozilla/dom/CacheExpirationTime.h"
class imgLoader;
class imgRequestProxy;
@ -65,17 +66,17 @@ class imgCacheEntry {
void UpdateLoadTime();
uint32_t GetExpiryTime() const { return mExpiryTime; }
void AccumulateExpiryTime(uint32_t aExpiryTime, bool aForceTouch = false) {
// 0 means "doesn't expire".
// Otherwise, calculate the minimum value.
if (aExpiryTime == 0) {
const CacheExpirationTime& GetExpiryTime() const { return mExpiryTime; }
void AccumulateExpiryTime(const CacheExpirationTime& aExpiryTime,
bool aForceTouch = false) {
if (aExpiryTime.IsNever()) {
if (aForceTouch) {
Touch();
}
return;
}
if (mExpiryTime == 0 || aExpiryTime < mExpiryTime) {
if (mExpiryTime.IsNever() || aExpiryTime.IsShorterThan(mExpiryTime)) {
mExpiryTime = aExpiryTime;
Touch();
} else {
@ -130,7 +131,7 @@ class imgCacheEntry {
uint32_t mDataSize;
int32_t mTouchedTime;
uint32_t mLoadTime;
uint32_t mExpiryTime;
CacheExpirationTime mExpiryTime;
nsExpirationState mExpirationState;
bool mMustValidate : 1;
bool mEvicted : 1;

Просмотреть файл

@ -602,8 +602,7 @@ void imgRequest::SetCacheValidation(imgCacheEntry* aCacheEntry,
if (!info.mExpirationTime) {
// If the channel doesn't support caching, then ensure this expires the
// next time it is used.
info.mExpirationTime.emplace(nsContentUtils::SecondsFromPRTime(PR_Now()) -
1);
info.mExpirationTime.emplace(CacheExpirationTime::AlreadyExpired());
}
aCacheEntry->AccumulateExpiryTime(*info.mExpirationTime, aForceTouch);
// Cache entries default to not needing to validate. We ensure that

Просмотреть файл

@ -164,13 +164,7 @@ bool ScriptLoadRequest::IsCacheable() const {
return false;
}
if (mExpirationTime == 0) {
return true;
}
uint32_t now = nsContentUtils::SecondsFromPRTime(PR_Now());
return mExpirationTime > now;
return !mExpirationTime.IsExpired();
}
void ScriptLoadRequest::CacheEntryFound(LoadedScript* aLoadedScript) {

Просмотреть файл

@ -13,6 +13,7 @@
#include "js/TypeDecls.h"
#include "mozilla/Atomics.h"
#include "mozilla/Assertions.h"
#include "mozilla/dom/CacheExpirationTime.h"
#include "mozilla/dom/SRIMetadata.h"
#include "mozilla/LinkedList.h"
#include "mozilla/Maybe.h"
@ -114,17 +115,10 @@ class ScriptLoadRequest : public nsISupports,
bool IsCacheable() const;
uint32_t ExpirationTime() const { return mExpirationTime; }
CacheExpirationTime ExpirationTime() const { return mExpirationTime; }
void SetMinimumExpirationTime(uint32_t aExpirationTime) {
// 0 means "doesn't expire".
// Otherwise, calculate the minimum value.
if (aExpirationTime == 0) {
return;
}
if (mExpirationTime == 0 || aExpirationTime < mExpirationTime) {
mExpirationTime = aExpirationTime;
}
void SetMinimumExpirationTime(const CacheExpirationTime& aExpirationTime) {
mExpirationTime.SetMinimum(aExpirationTime);
}
virtual bool IsTopLevel() const { return true; };
@ -284,7 +278,7 @@ class ScriptLoadRequest : public nsISupports,
// imported modules
enum mozilla::dom::ReferrerPolicy mReferrerPolicy;
uint32_t mExpirationTime = 0;
CacheExpirationTime mExpirationTime = CacheExpirationTime::Never();
RefPtr<ScriptFetchOptions> mFetchOptions;
const SRIMetadata mIntegrity;

Просмотреть файл

@ -33,6 +33,7 @@
#include "nsRefPtrHashtable.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/StoragePrincipalHelper.h"
#include "mozilla/dom/CacheExpirationTime.h"
#include "mozilla/dom/Document.h"
#include "nsContentUtils.h"
#include "mozilla/StaticPtr.h"
@ -163,7 +164,7 @@ class SharedSubResourceCache {
struct CompleteSubResource {
RefPtr<Value> mResource;
uint32_t mExpirationTime = 0;
CacheExpirationTime mExpirationTime = CacheExpirationTime::Never();
bool mWasSyncLoad = false;
inline bool Expired() const;
@ -485,8 +486,7 @@ void SharedSubResourceCache<Traits, Derived>::LoadStarted(
template <typename Traits, typename Derived>
bool SharedSubResourceCache<Traits, Derived>::CompleteSubResource::Expired()
const {
return mExpirationTime &&
mExpirationTime <= nsContentUtils::SecondsFromPRTime(PR_Now());
return mExpirationTime.IsExpired();
}
template <typename Traits, typename Derived>

Просмотреть файл

@ -13,6 +13,7 @@
#include "mozilla/PreloaderBase.h"
#include "mozilla/SharedSubResourceCache.h"
#include "mozilla/NotNull.h"
#include "mozilla/dom/CacheExpirationTime.h"
#include "nsProxyRelease.h"
namespace mozilla {
@ -123,7 +124,7 @@ class SheetLoadData final
// The expiration time of the channel that has loaded this data, if
// applicable.
uint32_t mExpirationTime = 0;
CacheExpirationTime mExpirationTime = CacheExpirationTime::Never();
// Number of sheets we @import-ed that are still loading
uint32_t mPendingChildren;
@ -247,7 +248,7 @@ class SheetLoadData final
bool ShouldDefer() const { return mWasAlternate || !mMediaMatched; }
RefPtr<StyleSheet> ValueForCache() const;
uint32_t ExpirationTime() const { return mExpirationTime; }
CacheExpirationTime ExpirationTime() const { return mExpirationTime; }
// If there are no child sheets outstanding, mark us as complete.
// Otherwise, the children are holding strong refs to the data
@ -277,15 +278,8 @@ class SheetLoadData final
void Cancel() override { mIsCancelled = true; }
void AccumulateExpirationTime(uint32_t aExpirationTime) {
// 0 means "doesn't expire".
// Otherwise, calculate the minimum value.
if (aExpirationTime == 0) {
return;
}
if (mExpirationTime == 0 || aExpirationTime < mExpirationTime) {
mExpirationTime = aExpirationTime;
}
void SetMinimumExpirationTime(const CacheExpirationTime& aExpirationTime) {
mExpirationTime.SetMinimum(aExpirationTime);
}
private:

Просмотреть файл

@ -9,6 +9,7 @@
#include "mozilla/Encoding.h"
#include "mozilla/glean/GleanMetrics.h"
#include "mozilla/TaskQueue.h"
#include "mozilla/dom/CacheExpirationTime.h"
#include "nsContentUtils.h"
#include "nsIAsyncVerifyRedirectCallback.h"
#include "nsIChannel.h"
@ -38,17 +39,6 @@ NS_IMPL_ISUPPORTS(StreamLoader, nsIStreamListener,
nsIThreadRetargetableStreamListener, nsIChannelEventSink,
nsIInterfaceRequestor)
static uint32_t CalculateExpirationTime(nsIRequest* aRequest, nsIURI* aURI) {
auto info = nsContentUtils::GetSubresourceCacheValidationInfo(aRequest, aURI);
// For now, we never cache entries that we have to revalidate, or whose
// channel don't support caching.
if (info.mMustRevalidate || !info.mExpirationTime) {
return nsContentUtils::SecondsFromPRTime(PR_Now()) - 1;
}
return *info.mExpirationTime;
}
/* nsIRequestObserver implementation */
NS_IMETHODIMP
StreamLoader::OnStartRequest(nsIRequest* aRequest) {
@ -87,8 +77,9 @@ StreamLoader::OnStartRequest(nsIRequest* aRequest) {
rr->RetargetDeliveryTo(queue);
}
mSheetLoadData->AccumulateExpirationTime(
CalculateExpirationTime(aRequest, mSheetLoadData->mURI));
mSheetLoadData->SetMinimumExpirationTime(
nsContentUtils::GetSubresourceCacheExpirationTime(aRequest,
mSheetLoadData->mURI));
// We need to block block resolution of parse promise until we receive
// OnStopRequest on Main thread. This is necessary because parse promise
@ -268,8 +259,9 @@ StreamLoader::GetInterface(const nsIID& aIID, void** aResult) {
nsresult StreamLoader::AsyncOnChannelRedirect(
nsIChannel* aOld, nsIChannel* aNew, uint32_t aFlags,
nsIAsyncVerifyRedirectCallback* aCallback) {
mSheetLoadData->AccumulateExpirationTime(
CalculateExpirationTime(aOld, mSheetLoadData->mURI));
mSheetLoadData->SetMinimumExpirationTime(
nsContentUtils::GetSubresourceCacheExpirationTime(aOld,
mSheetLoadData->mURI));
aCallback->OnRedirectVerifyCallback(NS_OK);