0

PrefetchNewWaitLoop: Remove feature flag kPrefetchNewWaitLoop

This CL removes a feature flag `kPrefetchNewWaitLoop` and paths for
disabled case.

More rename and integrations are done in the following CLs.

Bug: 353490734
Unresolved-Comment-Reason: Leaving discussion on a comment.
Validate-Test-Flakiness: skip
Change-Id: I32066358079bd11e16116b42a6cdfb0d63f433c2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6325955
Reviewed-by: Kent Tamura <tkent@chromium.org>
Reviewed-by: Taiyo Mizuhashi <taiyo@chromium.org>
Commit-Queue: Ken Okada <kenoss@chromium.org>
Reviewed-by: Hiroshige Hayashizaki <hiroshige@chromium.org>
Reviewed-by: Takashi Toyoshima <toyoshim@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1430545}
This commit is contained in:
kenoss
2025-03-10 16:17:02 -07:00
committed by Chromium LUCI CQ
parent cb105d797d
commit c6c712a9fd
21 changed files with 136 additions and 1183 deletions

@ -971,7 +971,6 @@ public final class ProductionSupportedFlagList {
Flag.baseFeature(
AwFeatures.WEBVIEW_DIGITAL_ASSET_LINKS_LOAD_INCLUDES,
"Enable loading include statements when checking digital asset links."),
Flag.baseFeature("PrefetchNewWaitLoop"),
Flag.baseFeature("DirectCompositorThreadIpc"),
Flag.baseFeature(
AwFeatures.WEBVIEW_WEBAUTHN,

@ -211,29 +211,9 @@ bool StatusUpdateIsPossibleAfterFailure(PrefetchStatus status) {
}
}
void RecordWasBlockedUntilHeadWhenServingHistogram(
const PrefetchType& prefetch_type,
bool blocked_until_head) {
CHECK(!UseNewWaitLoop());
if (IsSpeculationRuleType(prefetch_type.trigger_type())) {
base::UmaHistogramBoolean(
base::StrCat(
{"PrefetchProxy.AfterClick.WasBlockedUntilHeadWhenServing.",
GetPrefetchEagernessHistogramSuffix(
prefetch_type.GetEagerness())}),
blocked_until_head);
} else {
// TODO(crbug.com/40946257, crbug.com/40898833): Extend the metrics for
// embedder triggers.
}
}
void RecordPrefetchMatchingBlockedNavigationWithPrefetchHistogram(
const PrefetchType& prefetch_type,
bool blocked_until_head) {
CHECK(UseNewWaitLoop());
if (IsSpeculationRuleType(prefetch_type.trigger_type())) {
base::UmaHistogramBoolean(
base::StrCat({"PrefetchProxy.AfterClick."
@ -247,31 +227,10 @@ void RecordPrefetchMatchingBlockedNavigationWithPrefetchHistogram(
}
}
void RecordBlockUntilHeadDurationHistogram(
const PrefetchType& prefetch_type,
const base::TimeDelta& blocked_duration,
bool served) {
CHECK(!UseNewWaitLoop());
if (IsSpeculationRuleType(prefetch_type.trigger_type())) {
base::UmaHistogramTimes(
base::StrCat({"PrefetchProxy.AfterClick.BlockUntilHeadDuration.",
served ? "Served." : "NotServed.",
GetPrefetchEagernessHistogramSuffix(
prefetch_type.GetEagerness())}),
blocked_duration);
} else {
// TODO(crbug.com/40946257, crbug.com/40898833): Extend the metrics for
// embedder triggers.
}
}
void MaybeRecordBlockUntilHeadDuration2Histogram(
const PrefetchType& prefetch_type,
const std::optional<base::TimeDelta>& blocked_duration,
bool served) {
CHECK(UseNewWaitLoop());
if (IsSpeculationRuleType(prefetch_type.trigger_type())) {
base::UmaHistogramTimes(
base::StrCat({"PrefetchProxy.AfterClick.BlockUntilHeadDuration2NoBias.",
@ -597,9 +556,7 @@ PrefetchContainer::~PrefetchContainer() {
// https://chromium-review.googlesource.com/c/chromium/src/+/5657659/comments/0cfb14c0_3050963e
//
// TODO(crbug.com/356314759): Do it.
if (UseNewWaitLoop()) {
OnWillBeDestroyed();
}
OnWillBeDestroyed();
CancelStreamingURLLoaderIfNotServing();
@ -634,15 +591,9 @@ PrefetchContainer::~PrefetchContainer() {
if (prefetch_document_manager_) {
prefetch_document_manager_->PrefetchWillBeDestroyed(this);
}
if (!UseNewWaitLoop()) {
UnblockPrefetchMatchResolver();
}
}
void PrefetchContainer::OnWillBeDestroyed() {
CHECK(UseNewWaitLoop());
for (auto& observer : observers_) {
observer.OnWillBeDestroyed(*this);
}
@ -1330,39 +1281,7 @@ void PrefetchContainer::Reader::OnPrefetchProbeResult(
}
}
void PrefetchContainer::StartBlockUntilHead(
base::OnceCallback<void(PrefetchContainer&)>
on_maybe_determined_head_callback,
base::TimeDelta timeout) {
CHECK(!UseNewWaitLoop());
on_maybe_determined_head_callback_ =
std::move(on_maybe_determined_head_callback);
if (timeout.is_positive()) {
// TODO(crbug.com/40274818): See the comment on
// `OnGetPrefetchToServe()`.
block_until_head_timer_ = std::make_unique<base::OneShotTimer>();
block_until_head_timer_->Start(
FROM_HERE, timeout,
base::BindOnce(&PrefetchContainer::UnblockPrefetchMatchResolver,
GetWeakPtr()));
}
}
void PrefetchContainer::OnDeterminedHead() {
CHECK(!UseNewWaitLoop());
// Propagates the header to `no_vary_search_data_` if a non-redirect response
// header is got.
MaybeSetNoVarySearchData();
UnblockPrefetchMatchResolver();
}
void PrefetchContainer::OnDeterminedHead2() {
CHECK(UseNewWaitLoop());
// Propagates the header to `no_vary_search_data_` if a non-redirect response
// header is got.
MaybeSetNoVarySearchData();
@ -1387,16 +1306,6 @@ void PrefetchContainer::MaybeSetNoVarySearchData() {
*GetNonRedirectHead(), GetURL(), rfhi_can_be_null);
}
void PrefetchContainer::UnblockPrefetchMatchResolver() {
CHECK(!UseNewWaitLoop());
block_until_head_timer_.reset();
if (on_maybe_determined_head_callback_) {
std::move(on_maybe_determined_head_callback_).Run(*this);
}
}
void PrefetchContainer::StartTimeoutTimerIfNeeded(
base::OnceClosure on_timeout_callback) {
if (ttl_in_sec_.is_positive()) {
@ -1662,8 +1571,6 @@ void PrefetchContainer::OnDetectedCookiesChange() {
void PrefetchContainer::OnDetectedCookiesChange2(
std::optional<bool>
is_unblock_for_cookies_changed_triggered_by_this_prefetch_container) {
CHECK(UseNewWaitLoop());
// If `kPrefetchNewWaitLoop` is enabled, multiple `PrefetchMatchResolver2` can
// wait the same `PrefetchContainer`. So, `OnDetectedCookiesChange2()` can be
// called multiple times, unlike `OnDetectedCookiesChange()`.
@ -1706,69 +1613,6 @@ void PrefetchContainer::OnPrefetchStarted() {
SetLoadState(PrefetchContainer::LoadState::kStarted);
}
// TODO(crbug.com/40274818): We might be waiting on PrefetchContainer's head
// from multiple navigations.
// E.g. We might wait from one navigation but not use the prefetch, and
// then we can use the prefetch in a separate navigation without waiting
// for the head. We need to keep track of blocked_until_head_start_time_ per
// each navigation for this PrefetchContainer.
void PrefetchContainer::OnGetPrefetchToServe(bool blocked_until_head) {
CHECK(!UseNewWaitLoop());
// OnGetPrefetchToServe is called before we start waiting for head, and
// when the prefetch is used from `prefetches_ready_to_serve_`.
// If the prefetch had to wait for head, `blocked_until_head_start_time_`
// will already be set. Only record in the histogram when the
// `blocked_until_head_start_time_` is not set yet.
if (!blocked_until_head_start_time_) {
RecordWasBlockedUntilHeadWhenServingHistogram(prefetch_type_,
blocked_until_head);
}
if (blocked_until_head) {
blocked_until_head_start_time_ = base::TimeTicks::Now();
}
}
void PrefetchContainer::OnReturnPrefetchToServe(bool served,
const GURL& navigated_url) {
CHECK(!UseNewWaitLoop());
if (served) {
RecordAfterClickRedirectChainSize(redirect_chain_.size());
navigated_to_ = true;
}
if (blocked_until_head_start_time_.has_value()) {
RecordBlockUntilHeadDurationHistogram(
prefetch_type_,
base::TimeTicks::Now() - blocked_until_head_start_time_.value(),
served);
}
// Note that `PreloadingAttemptImpl::SetIsAccurateTriggering()` is called for
// prefetch in
//
// - A. `PreloadingDataImpl::DidStartNavigation()`
// - B. Here
//
// A covers prefetches that satisfy `bool(GetNonRedirectHead())` at that
// timing. B covers almost all ones that were once potentially matching to the
// navigation, including that was `kBlockUntilHead` state.
//
// Note that multiple calls are safe and set a correct value.
//
// Historical note: Before No-Vary-Search hint, the decision to use a
// prefetched response was made at A. With No-Vary-Search hint the decision to
// use an in-flight prefetched response is delayed until the headers are
// received from the server. This happens after `DidStartNavigation()`. At
// this point in the code we have already decided we are going to use the
// prefetch, so we can safely call `SetIsAccurateTriggering()`.
if (auto attempt = preloading_attempt()) {
static_cast<PreloadingAttemptImpl*>(attempt.get())
->SetIsAccurateTriggering(navigated_url);
}
}
bool PrefetchContainer::HasSameReferringURLForMetrics(
const PrefetchContainer& other) const {
return referring_url_hash_.has_value() &&
@ -2089,14 +1933,10 @@ void PrefetchContainer::OnInitialPrefetchFailedIneligible(
}
void PrefetchContainer::AddObserver(Observer* observer) {
CHECK(UseNewWaitLoop());
observers_.AddObserver(observer);
}
void PrefetchContainer::RemoveObserver(Observer* observer) {
CHECK(UseNewWaitLoop());
observers_.RemoveObserver(observer);
}
@ -2127,8 +1967,6 @@ void PrefetchContainer::OnUnregisterCandidate(
// TODO(crbug.com/356314759): Avoid calling this with `is_in_dtor_`
// true.
CHECK(UseNewWaitLoop());
if (is_served) {
navigated_to_ = true;
RecordAfterClickRedirectChainSize(redirect_chain_.size());
@ -2140,7 +1978,24 @@ void PrefetchContainer::OnUnregisterCandidate(
MaybeRecordBlockUntilHeadDuration2Histogram(prefetch_type_, blocked_duration,
is_served);
// See the comment in `PrefetchContainer::OnReturnPrefetchToServe()`.
// Note that `PreloadingAttemptImpl::SetIsAccurateTriggering()` is called for
// prefetch in
//
// - A. `PreloadingDataImpl::DidStartNavigation()`
// - B. Here
//
// A covers prefetches that satisfy `bool(GetNonRedirectHead())` at that
// timing. B covers almost all ones that were once potentially matching to the
// navigation, including that was `kBlockUntilHead` state.
//
// Note that multiple calls are safe and set a correct value.
//
// Historical note: Before No-Vary-Search hint, the decision to use a
// prefetched response was made at A. With No-Vary-Search hint the decision to
// use an in-flight prefetched response is delayed until the headers are
// received from the server. This happens after `DidStartNavigation()`. At
// this point in the code we have already decided we are going to use the
// prefetch, so we can safely call `SetIsAccurateTriggering()`.
if (auto attempt = preloading_attempt()) {
static_cast<PreloadingAttemptImpl*>(attempt.get())
->SetIsAccurateTriggering(navigated_url);

@ -226,9 +226,6 @@ class CONTENT_EXPORT PrefetchContainer {
//
// Be careful about using this. This is designed only for
// `PrefetchMatchResolver2`.
//
// These callback are called only if `kPrefetchNewWaitLoop` is enabled.
// Observer interface to listen to lifecycle events of `PrefetchContainer`.
class Observer : public base::CheckedObserver {
public:
// Called at the head of dtor.
@ -446,11 +443,6 @@ class CONTENT_EXPORT PrefetchContainer {
// The |PrefetchDocumentManager| that requested |this|.
PrefetchDocumentManager* GetPrefetchDocumentManager() const;
// Called when |PrefetchService::GetPrefetchToServe| and
// |PrefetchService::ReturnPrefetchToServe| with |this|.
void OnGetPrefetchToServe(bool blocked_until_head);
void OnReturnPrefetchToServe(bool served, const GURL& navigated_url);
// Returns whether or not this prefetch has been considered to serve for a
// navigation in the past. If it has, then it shouldn't be used for any future
// navigations.
@ -516,7 +508,6 @@ class CONTENT_EXPORT PrefetchContainer {
//
// This method must be called at most once in the lifecycle of
// `PrefetchContainer`.
void OnDeterminedHead();
void OnDeterminedHead2();
// Unblocks waiting `PrefetchMatchResolver`.
//
@ -1015,12 +1006,6 @@ class CONTENT_EXPORT PrefetchContainer {
// blocked waiting for the head of this prefetch to be received.
std::unique_ptr<base::OneShotTimer> block_until_head_timer_;
// Callback for non-blocking call `StartBlockUntilHead()`.
//
// TODO(crbug.com/353490734): Remove it.
base::OnceCallback<void(PrefetchContainer&)>
on_maybe_determined_head_callback_;
// Additional headers for WebView initiated prefetch.
// This must be empty for non-WebView initiated prefetches.
// TODO(crbug.com/369859822): Revisit the semantics if needed.

@ -872,87 +872,7 @@ TEST_P(PrefetchContainerTest, IneligibleRedirect) {
PrefetchStatus::kPrefetchFailedIneligibleRedirect);
}
TEST_P(PrefetchContainerTest, BlockUntilHeadHistograms) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatures({}, {features::kPrefetchNewWaitLoop});
struct TestCase {
blink::mojom::SpeculationEagerness eagerness;
bool block_until_head;
base::TimeDelta block_until_head_duration;
bool served;
};
std::vector<TestCase> test_cases{
{blink::mojom::SpeculationEagerness::kEager, true, base::Milliseconds(10),
true},
{blink::mojom::SpeculationEagerness::kModerate, false,
base::Milliseconds(20), false},
{blink::mojom::SpeculationEagerness::kConservative, true,
base::Milliseconds(40), false}};
base::HistogramTester histogram_tester;
for (const auto& test_case : test_cases) {
PrefetchContainer prefetch_container(
*main_rfhi(), blink::DocumentToken(), GURL("https://test.com"),
PrefetchType(PreloadingTriggerType::kSpeculationRule,
/*use_prefetch_proxy=*/true, test_case.eagerness),
blink::mojom::Referrer(),
/*no_vary_search_hint=*/std::nullopt,
/*prefetch_document_manager=*/nullptr,
PreloadPipelineInfo::Create(
/*planned_max_preloading_type=*/PreloadingType::kPrefetch));
prefetch_container.OnGetPrefetchToServe(test_case.block_until_head);
if (test_case.block_until_head) {
task_environment()->FastForwardBy(test_case.block_until_head_duration);
}
prefetch_container.OnReturnPrefetchToServe(test_case.served,
GURL("https://test.com"));
}
histogram_tester.ExpectBucketCount(
"PrefetchProxy.AfterClick.WasBlockedUntilHeadWhenServing.Eager", true, 1);
histogram_tester.ExpectBucketCount(
"PrefetchProxy.AfterClick.WasBlockedUntilHeadWhenServing.Eager", false,
0);
histogram_tester.ExpectBucketCount(
"PrefetchProxy.AfterClick.WasBlockedUntilHeadWhenServing.Moderate", true,
0);
histogram_tester.ExpectBucketCount(
"PrefetchProxy.AfterClick.WasBlockedUntilHeadWhenServing.Moderate", false,
1);
histogram_tester.ExpectBucketCount(
"PrefetchProxy.AfterClick.WasBlockedUntilHeadWhenServing.Conservative",
true, 1);
histogram_tester.ExpectBucketCount(
"PrefetchProxy.AfterClick.WasBlockedUntilHeadWhenServing.Conservative",
false, 0);
histogram_tester.ExpectUniqueTimeSample(
"PrefetchProxy.AfterClick.BlockUntilHeadDuration.Served.Eager",
base::Milliseconds(10), 1);
histogram_tester.ExpectTotalCount(
"PrefetchProxy.AfterClick.BlockUntilHeadDuration.NotServed.Eager", 0);
histogram_tester.ExpectTotalCount(
"PrefetchProxy.AfterClick.BlockUntilHeadDuration.Served.Moderate", 0);
histogram_tester.ExpectTotalCount(
"PrefetchProxy.AfterClick.BlockUntilHeadDuration.NotServed.Moderate", 0);
histogram_tester.ExpectTotalCount(
"PrefetchProxy.AfterClick.BlockUntilHeadDuration.Served.Conservative", 0);
histogram_tester.ExpectUniqueTimeSample(
"PrefetchProxy.AfterClick.BlockUntilHeadDuration.NotServed.Conservative",
base::Milliseconds(40), 1);
}
TEST_P(PrefetchContainerTest, BlockUntilHeadHistograms2) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatures({features::kPrefetchNewWaitLoop}, {});
struct TestCase {
blink::mojom::SpeculationEagerness eagerness;
bool is_served;

@ -24,12 +24,6 @@ BASE_FEATURE(kPrefetchReusable,
const base::FeatureParam<int> kPrefetchReusableBodySizeLimit{
&kPrefetchReusable, "prefetch_reusable_body_size_limit", 4194304};
BASE_FEATURE_PARAM(bool,
kPrefetchReusableUseNewWaitLoop,
&kPrefetchReusable,
"PrefetchReusableUseNewWaitLoop",
false);
BASE_FEATURE(kPrefetchNIKScope,
"PrefetchNIKScope",
base::FEATURE_DISABLED_BY_DEFAULT);
@ -68,10 +62,6 @@ BASE_FEATURE(kPrefetchNewLimits,
"PrefetchNewLimits",
base::FEATURE_ENABLED_BY_DEFAULT);
BASE_FEATURE(kPrefetchNewWaitLoop,
"PrefetchNewWaitLoop",
base::FEATURE_ENABLED_BY_DEFAULT);
BASE_FEATURE(kPrefetchServiceWorkerNoFetchHandlerFix,
"PrefetchServiceWorkerNoFetchHandlerFix",
base::FEATURE_DISABLED_BY_DEFAULT);

@ -28,9 +28,6 @@ CONTENT_EXPORT BASE_DECLARE_FEATURE(kPrefetchReusable);
CONTENT_EXPORT extern const base::FeatureParam<int>
kPrefetchReusableBodySizeLimit;
CONTENT_EXPORT BASE_DECLARE_FEATURE_PARAM(bool,
kPrefetchReusableUseNewWaitLoop);
// If enabled, navigational prefetch is scoped to the referring document's
// network isolation key instead of the old behavior of the referring document
// itself. See crbug.com/1502326
@ -76,12 +73,6 @@ CONTENT_EXPORT BASE_DECLARE_FEATURE(kPrefetchCookieIndices);
// limit values (see content/browser/preloading/prefetch/prefetch_params.cc).
CONTENT_EXPORT BASE_DECLARE_FEATURE(kPrefetchNewLimits);
// If enabled, use the new wait loop, which is driven by
// `PrefetchMatchResolver2` instead of `PrefetchService`.
//
// TODO(crbug.com/353490734): Remove this.
CONTENT_EXPORT BASE_DECLARE_FEATURE(kPrefetchNewWaitLoop);
// Fix for prefetching a URL controlled by a ServiceWorker without fetch
// handler. Currently this stops prefetching for such cases
// (https://crbug.com/379076354).

@ -39,138 +39,6 @@ std::vector<K> Keys(const std::map<K, V>& map) {
} // namespace
PrefetchMatchResolver::PrefetchMatchResolver(
NavigationHandle& navigation_handle) {}
PrefetchMatchResolver::~PrefetchMatchResolver() = default;
base::WeakPtr<PrefetchMatchResolver> PrefetchMatchResolver::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
void PrefetchMatchResolver::SetOnPrefetchToServeReadyCallback(
PrefetchMatchResolver::OnPrefetchToServeReady on_prefetch_to_serve_ready) {
on_prefetch_to_serve_ready_callback_ = std::move(on_prefetch_to_serve_ready);
DVLOG(1) << *this
<< "::SetCallback:" << &on_prefetch_to_serve_ready_callback_;
}
PrefetchMatchResolver::OnPrefetchToServeReady
PrefetchMatchResolver::ReleaseOnPrefetchToServeReadyCallback() {
DVLOG(1) << *this
<< "::ReleaseCallback:" << &on_prefetch_to_serve_ready_callback_;
CHECK(on_prefetch_to_serve_ready_callback_);
return std::move(on_prefetch_to_serve_ready_callback_);
}
void PrefetchMatchResolver::PrefetchServed(PrefetchContainer::Reader reader) {
ReleaseOnPrefetchToServeReadyCallback().Run(std::move(reader));
}
void PrefetchMatchResolver::PrefetchNotAvailable() {
DVLOG(1) << *this << "::PrefetchNotAvailable";
ReleaseOnPrefetchToServeReadyCallback().Run({});
}
void PrefetchMatchResolver::PrefetchNotUsable(
const PrefetchContainer& prefetch_container) {
DVLOG(1) << *this << "::PrefetchNotUsable:" << prefetch_container.GetURL();
CHECK(!in_progress_prefetch_matches_.contains(prefetch_container.GetURL()));
MaybeFallbackToRegularNavigationWhenPrefetchNotUsable();
}
void PrefetchMatchResolver::PrefetchNotUsable(const GURL& prefetch_url) {
DVLOG(1) << *this << "::PrefetchNotUsable: " << prefetch_url;
CHECK(!in_progress_prefetch_matches_.contains(prefetch_url));
MaybeFallbackToRegularNavigationWhenPrefetchNotUsable();
}
void PrefetchMatchResolver::WaitForPrefetch(
PrefetchContainer& prefetch_container) {
DVLOG(1) << *this << "::WaitForPrefetch: " << prefetch_container.GetURL();
in_progress_prefetch_matches_[prefetch_container.GetURL()] =
prefetch_container.GetWeakPtr();
}
void PrefetchMatchResolver::EndWaitForPrefetch(const GURL& prefetch_url) {
CHECK(in_progress_prefetch_matches_.count(prefetch_url));
in_progress_prefetch_matches_.erase(prefetch_url);
}
bool PrefetchMatchResolver::IsWaitingForPrefetch(
const PrefetchContainer& prefetch_container) const {
DVLOG(1) << *this
<< "::IsWaitingForPrefetchP: " << prefetch_container.GetURL();
return IsWaitingForPrefetch(prefetch_container.GetURL());
}
bool PrefetchMatchResolver::IsWaitingForPrefetch(
const GURL& prefetch_url) const {
DVLOG(1) << *this << "::IsWaitingForPrefetchU: " << prefetch_url;
return in_progress_prefetch_matches_.count(prefetch_url);
}
void PrefetchMatchResolver::
MaybeFallbackToRegularNavigationWhenPrefetchNotUsable() {
DVLOG(1) << *this
<< "::MaybeFallbackToRegularNavigationWhenPrefetchNotUsable";
if (IsWaitingOnPrefetchHead()) {
return;
}
// We are not waiting on any more prefetches in progress. Resolve to no
// prefetch available.
PrefetchNotAvailable();
}
void PrefetchMatchResolver::
FallbackToRegularNavigationWhenMatchedPrefetchCookiesChanged(
PrefetchContainer& prefetch_container,
const GURL& navigated_url) {
// The prefetch_container has already received its head.
CHECK(!IsWaitingForPrefetch(prefetch_container));
prefetch_container.OnDetectedCookiesChange();
prefetch_container.OnReturnPrefetchToServe(/*served=*/false, navigated_url);
DVLOG(1) << *this
<< "::FallbackToRegularNavigationWhenMatchedPrefetchCookiesChanged:"
<< prefetch_container << " not served because Cookies changed.";
// Do the same for other prefetches in `in_progress_prefetch_matches_`.
for (auto& [prefetch_url, weak_prefetch_container] :
in_progress_prefetch_matches_) {
if (!weak_prefetch_container) {
continue;
}
weak_prefetch_container->OnDetectedCookiesChange();
weak_prefetch_container->OnReturnPrefetchToServe(/*served=*/false,
navigated_url);
DVLOG(1)
<< *this
<< "::FallbackToRegularNavigationWhenMatchedPrefetchCookiesChanged:"
<< *weak_prefetch_container << " not served because Cookies changed.";
}
// Remove all of the prefetches from `in_progress_prefetch_matches_` and let
// the browser know to fallback to regular navigation instead.
in_progress_prefetch_matches_.clear();
PrefetchNotAvailable();
}
bool PrefetchMatchResolver::IsWaitingOnPrefetchHead() const {
DVLOG(1) << *this << "::IsWaitingOnPrefetchHead";
return !in_progress_prefetch_matches_.empty();
}
CONTENT_EXPORT std::ostream& operator<<(
std::ostream& ostream,
const PrefetchMatchResolver& prefetch_match_resolver) {
return ostream << "PrefetchMatchResolver[" << &prefetch_match_resolver
<< ", waiting_on = "
<< prefetch_match_resolver.in_progress_prefetch_matches_.size()
<< " ]";
}
NAVIGATION_HANDLE_USER_DATA_KEY_IMPL(PrefetchMatchResolver);
PrefetchMatchResolver2::CandidateData::CandidateData() = default;
PrefetchMatchResolver2::CandidateData::~CandidateData() = default;

@ -19,74 +19,6 @@ namespace content {
class PrefetchContainer;
// TODO(crbug.com/40274818): Problem: how do we inform this class of prefetches
// being started while we are waiting for existing in-progress prefetches ?
// PrefetchService should probably do it.
class CONTENT_EXPORT PrefetchMatchResolver
: public NavigationHandleUserData<PrefetchMatchResolver> {
public:
PrefetchMatchResolver(const PrefetchMatchResolver&) = delete;
PrefetchMatchResolver& operator=(const PrefetchMatchResolver&) = delete;
~PrefetchMatchResolver() override;
base::WeakPtr<PrefetchMatchResolver> GetWeakPtr();
using OnPrefetchToServeReady =
base::OnceCallback<void(PrefetchContainer::Reader prefetch_to_serve)>;
void SetOnPrefetchToServeReadyCallback(
OnPrefetchToServeReady on_prefetch_to_serve_ready);
// A prefetch can be served, so let the browser know that it can use the
// prefetch for the navigation.
void PrefetchServed(PrefetchContainer::Reader reader);
// The prefetch container / prefetch_url cannot be used. If there are no
// more potential prefetches to wait for, let the browser know to fallback
// to normal navigation.
void PrefetchNotUsable(const PrefetchContainer& prefetch_container);
void PrefetchNotUsable(const GURL& prefetch_url);
// A prefetch is not available so let the browser know to fallback to regular
// navigation instead.
void PrefetchNotAvailable();
// If Cookies have changed, then none of the matched prefetches can be served.
// Remove all of the prefetches from `in_progress_prefetch_matches_` and let
// the browser know to fallback to regular navigation instead.
void FallbackToRegularNavigationWhenMatchedPrefetchCookiesChanged(
PrefetchContainer& prefetch_container,
const GURL& navigated_url);
void WaitForPrefetch(PrefetchContainer& prefetch_container);
void EndWaitForPrefetch(const GURL& prefetch_url);
// Check if we are waiting already for the head of this `prefetch_container`.
bool IsWaitingForPrefetch(const PrefetchContainer& prefetch_container) const;
bool IsWaitingForPrefetch(const GURL& prefetch_url) const;
private:
friend NavigationHandleUserData<PrefetchMatchResolver>;
explicit PrefetchMatchResolver(NavigationHandle& navigation_handle);
void MaybeFallbackToRegularNavigationWhenPrefetchNotUsable();
bool IsWaitingOnPrefetchHead() const;
OnPrefetchToServeReady ReleaseOnPrefetchToServeReadyCallback();
// Once the prefetch (if any) that can be used to serve a navigation to
// |url| is identified, this callback is called with that
// prefetch.
OnPrefetchToServeReady on_prefetch_to_serve_ready_callback_;
// Keep track of all prefetches that we are waiting for head on.
std::map<GURL, base::WeakPtr<PrefetchContainer>>
in_progress_prefetch_matches_;
base::WeakPtrFactory<PrefetchMatchResolver> weak_ptr_factory_{this};
// For debug logs.
CONTENT_EXPORT friend std::ostream& operator<<(
std::ostream& ostream,
const PrefetchMatchResolver& prefetch_match_resolver);
friend NavigationHandleUserData;
NAVIGATION_HANDLE_USER_DATA_KEY_DECL();
};
// Manages matching process of prefetch
// https://wicg.github.io/nav-speculation/prefetch.html#wait-for-a-matching-prefetch-record
//
@ -98,21 +30,7 @@ class CONTENT_EXPORT PrefetchMatchResolver
// Lifetime of this class is from the call of `FindPrefetch()` to calling
// `callback_`. This is owned by itself. See the comment on `self_`.
//
// Note about "2": This is the new implementation of the matching process
// of prefetch that is used when `UseNewWaitLoop()` returns true. The old
// implementation is `PrefetchMatchResolver`, so this is named "2".
// Differences are, for example:
//
// - `PrefetchMatchResolver2` has strict precondition/postcondition
// e.g. `CHECK_EQ(candidates_.size(), 0u);` when the matching process
// starts/ends.
// - `PrefetchMatchResolver` is `NavigationHandleUserData`
// and can be used multiple times for redirects, while
// `PrefetchMatchResolver2` forbids it in architecture level.
//
// That's the reason why we decided to implement the separate class.
//
// TODO(crbug.com/353490734): Remove the above `Note about "2"`.
// TODO(crbug.com/353490734): Rename it to `PrefetchMatchResolver`.
class CONTENT_EXPORT PrefetchMatchResolver2 final
: public PrefetchContainer::Observer {
public:

@ -250,14 +250,6 @@ bool PrefetchBrowserInitiatedTriggersEnabled() {
features::kPrefetchBrowserInitiatedTriggers);
}
bool UseNewWaitLoop() {
return base::FeatureList::IsEnabled(features::kPrefetchNewWaitLoop) ||
(base::FeatureList::IsEnabled(features::kPrefetchReusable) &&
features::kPrefetchReusableUseNewWaitLoop.Get()) ||
base::FeatureList::IsEnabled(
features::kPrerender2FallbackPrefetchSpecRules);
}
size_t GetPrefetchDataPipeTeeBodySizeLimit() {
return std::max(
static_cast<size_t>(features::kPrefetchReusableBodySizeLimit.Get()),

@ -118,11 +118,6 @@ bool PrefetchNIKScopeEnabled();
// Please see crbug.com/40946257 for more details.
bool PrefetchBrowserInitiatedTriggersEnabled();
// Returns true iff prefetch code should use new wait loop in
// `PrefetchMatchResolver2::FindPrefetch()` instead of
// `PrefetchService::GetPrefetchToServe()`.
CONTENT_EXPORT bool UseNewWaitLoop();
size_t GetPrefetchDataPipeTeeBodySizeLimit();
} // namespace content

@ -1453,10 +1453,7 @@ void PrefetchService::SendPrefetchRequest(
base::Unretained(this), prefetch_container),
base::BindRepeating(&PrefetchService::OnPrefetchRedirect,
base::Unretained(this), prefetch_container),
UseNewWaitLoop() ? base::BindOnce(&PrefetchContainer::OnDeterminedHead2,
prefetch_container)
: base::BindOnce(&PrefetchContainer::OnDeterminedHead,
prefetch_container),
base::BindOnce(&PrefetchContainer::OnDeterminedHead2, prefetch_container),
prefetch_container->GetResponseReaderForCurrentPrefetch());
prefetch_container->SetStreamingURLLoader(std::move(streaming_loader));
@ -1729,236 +1726,6 @@ PrefetchService::GetAllForUrlWithoutRefAndQueryForTesting(
key, owned_prefetches_);
}
PrefetchService::HandlePrefetchContainerResult
PrefetchService::HandlePrefetchContainerToServe(
const PrefetchContainer::Key& key,
PrefetchContainer& prefetch_container,
PrefetchMatchResolver& prefetch_match_resolver) {
const GURL& url = key.url();
DVLOG(1) << "PrefetchService::HandlePrefetchContainerToServe("
<< prefetch_container << "): Start";
if (prefetch_container.HasPrefetchBeenConsideredToServe()) {
DVLOG(1) << "PrefetchService::HandlePrefetchContainerToServe("
<< prefetch_container << "): Skipped already considered to serve.";
return HandlePrefetchContainerResult::kNotUsable;
}
// If prefetch is servable that means it already was matched to navigation
// url. Return it.
switch (prefetch_container.GetServableState(PrefetchCacheableDuration())) {
case PrefetchContainer::ServableState::kServable: {
DVLOG(1) << "PrefetchService::HandlePrefetchContainerToServe(" << url
<< "): " << prefetch_container << " is servable";
prefetch_container.OnGetPrefetchToServe(/*blocked_until_head=*/false);
return ReturnPrefetchToServe(
key, prefetch_container.GetURL(), prefetch_container.CreateReader(),
prefetch_match_resolver,
FallbackToRegularNavigationWhenPrefetchNotUsable(false));
}
case PrefetchContainer::ServableState::kShouldBlockUntilHeadReceived: {
DVLOG(1) << "PrefetchService::HandlePrefetchContainerToServe(" << url
<< "): " << prefetch_container << " is blocked until head";
if (prefetch_match_resolver.IsWaitingForPrefetch(prefetch_container)) {
// TODO(crbug.com/40274818): Figure out if this path is actually
// possible. The reason I believe it is not possible is because the
// second time `GetPrefetchToServe` is called it executes
// HandlePrefetchContainerToServe first for the prefetch container
// that is marked as "ready". Since when we mark a prefetch as "ready"
// we immediately execute GetPrefetchToServe the container will be
// servable so we will return in the if above and serve that prefetch.
return HandlePrefetchContainerResult::kWaitForHead;
}
prefetch_container.OnGetPrefetchToServe(/*blocked_until_head=*/true);
auto on_maybe_determined_head =
base::BindOnce(&PrefetchService::OnMaybeDeterminedHead,
weak_method_factory_.GetWeakPtr(), key,
prefetch_match_resolver.GetWeakPtr());
base::TimeDelta timeout =
PrefetchBlockUntilHeadTimeout(prefetch_container.GetPrefetchType());
prefetch_container.StartBlockUntilHead(
std::move(on_maybe_determined_head), std::move(timeout));
prefetch_match_resolver.WaitForPrefetch(prefetch_container);
return HandlePrefetchContainerResult::kWaitForHead;
}
case PrefetchContainer::ServableState::kNotServable: {
DVLOG(1) << "PrefetchService::HandlePrefetchContainerToServe(" << key
<< "): " << prefetch_container << " is not servable";
prefetch_container.OnReturnPrefetchToServe(/*served=*/false, url);
return HandlePrefetchContainerResult::kNotUsable;
}
case PrefetchContainer::ServableState::kShouldBlockUntilEligibilityGot:
NOTREACHED();
}
}
void PrefetchService::GetPrefetchToServe(
const PrefetchContainer::Key& key,
base::WeakPtr<PrefetchServingPageMetricsContainer>
serving_page_metrics_container,
PrefetchMatchResolver& prefetch_match_resolver) {
CHECK(!UseNewWaitLoop());
DumpPrefetchesForDebug();
// `!UseNewWaitLoop()` implies that `kPrerender2FallbackPrefetchSpecRules` is
// disabled. So, this path doesn't collect `PrefetchContainer` with
// `kShouldBlockUntilEligibilityGot` regardless the value of
// `is_nav_prerender`. Thus, we use false without seeing the navigation.
const bool is_nav_prerender = false;
auto [potential_matching_prefetches, _] = CollectMatchCandidates(
key, is_nav_prerender, std::move(serving_page_metrics_container));
DVLOG(1) << "PrefetchService::GetPrefetchToServe(" << key
<< "): Potential matched with "
<< potential_matching_prefetches.size() << " prefetch containers.";
bool waiting_on_prefetch_head = false;
for (auto* prefetch_container : potential_matching_prefetches) {
constexpr auto final_state_prefetch_container_results =
base::MakeFixedFlatSet<HandlePrefetchContainerResult>(
{HandlePrefetchContainerResult::kToBeServed,
HandlePrefetchContainerResult::kNotToBeServedCookiesChanged});
CHECK(prefetch_container);
auto result = HandlePrefetchContainerToServe(key, *prefetch_container,
prefetch_match_resolver);
if (final_state_prefetch_container_results.contains(result)) {
return;
}
waiting_on_prefetch_head |=
(result == HandlePrefetchContainerResult::kWaitForHead);
}
// If there is at least one prefetch that we are waiting for the head then
// stop.
if (waiting_on_prefetch_head) {
DVLOG(1) << "PrefetchService::GetPrefetchToServe(" << key
<< "): waiting on prefetch head";
return;
}
// If not waiting on any prefetches it means there is no match. Let the
// browser know to request url from the web server.
DVLOG(1) << "PrefetchService::GetPrefetchToServe(" << key
<< "): No PrefetchContainer is servable";
ReturnPrefetchToServe(key, {}, {}, prefetch_match_resolver);
}
void PrefetchService::OnMaybeDeterminedHead(
const PrefetchContainer::Key& key,
base::WeakPtr<PrefetchMatchResolver> prefetch_match_resolver,
PrefetchContainer& prefetch_container) {
const GURL& prefetch_url = prefetch_container.GetURL();
DVLOG(1) << "PrefetchService::OnMaybeDeterminedHead:" << "prefetch_url = "
<< prefetch_url;
if (!prefetch_match_resolver) {
// Since prefetch_match_resolver is a NavigationHandleUserData,
// if it is null it means the navigation has finished so there is nothing to
// do here.
return;
}
// This method is called only for prefetches that we have started waiting on.
// We make sure that this is true by checking with prefetch_match_resolver.
CHECK(prefetch_match_resolver->IsWaitingForPrefetch(prefetch_url));
// We need to make sure we are not waiting on this prefetch_url anymore.
prefetch_match_resolver->EndWaitForPrefetch(prefetch_url);
// Make sure we are not waiting on this prefetch_url anymore.
CHECK(!prefetch_match_resolver->IsWaitingForPrefetch(prefetch_url));
if (prefetch_container.is_in_dtor()) {
DVLOG(1) << "PrefetchService::OnMaybeDeterminedHead(" << key
<< "): deleted while waiting for head";
ReturnPrefetchToServe(key, prefetch_url, {}, *prefetch_match_resolver);
return;
}
DVLOG(1) << "PrefetchService::OnMaybeDeterminedHead(" << key
<< "): PrefetchContainer head received for " << prefetch_url << "!";
const GURL& nav_url = key.url();
switch (prefetch_container.GetServableState(PrefetchCacheableDuration())) {
case PrefetchContainer::ServableState::kShouldBlockUntilEligibilityGot:
NOTREACHED();
case PrefetchContainer::ServableState::kNotServable:
case PrefetchContainer::ServableState::kShouldBlockUntilHeadReceived: {
DVLOG(1) << "PrefetchService::OnMaybeDeterminedHead(" << key
<< "): " << prefetch_container << " not servable!";
prefetch_container.OnReturnPrefetchToServe(/*served=*/false, nav_url);
ReturnPrefetchToServe(key, prefetch_url, {}, *prefetch_match_resolver);
return;
}
case PrefetchContainer::ServableState::kServable:
break;
}
if (prefetch_container.IsExactMatch(nav_url)) {
HandlePrefetchContainerToServe(key, prefetch_container,
*prefetch_match_resolver);
return;
}
// No-Vary-Search response header is already populated by
// `PrefetchContainer::OnDeterminedHead()`.
if (!prefetch_container.IsNoVarySearchHeaderMatch(nav_url)) {
prefetch_container.OnReturnPrefetchToServe(/*served=*/false, nav_url);
prefetch_container.UpdateServingPageMetrics();
ReturnPrefetchToServe(key, prefetch_url, {}, *prefetch_match_resolver);
return;
}
DVLOG(1) << "PrefetchService::OnMaybeDeterminedHead::" << "url = " << nav_url
<< "::" << "matches by NVS header the prefetch "
<< prefetch_container.GetURL();
HandlePrefetchContainerToServe(key, prefetch_container,
*prefetch_match_resolver);
}
PrefetchService::HandlePrefetchContainerResult
PrefetchService::ReturnPrefetchToServe(
const PrefetchContainer::Key& key,
const GURL& prefetch_url,
PrefetchContainer::Reader reader,
PrefetchMatchResolver& prefetch_match_resolver,
FallbackToRegularNavigationWhenPrefetchNotUsable
when_prefetch_not_used_fallback_to_regular_navigation) {
if (prefetch_url.is_empty()) {
// In this case there is no matching prefetch.
if (when_prefetch_not_used_fallback_to_regular_navigation) {
prefetch_match_resolver.PrefetchNotAvailable();
}
return HandlePrefetchContainerResult::kNotAvailable;
}
if (!reader) {
// In this case the prefetch cannot be used for some reason.
if (when_prefetch_not_used_fallback_to_regular_navigation) {
prefetch_match_resolver.PrefetchNotUsable(prefetch_url);
}
return HandlePrefetchContainerResult::kNotUsable;
}
PrefetchContainer* prefetch_container = reader.GetPrefetchContainer();
CHECK(prefetch_container);
// We know `prefetch_container` is servable when we get here.
CHECK_EQ(prefetch_container->GetServableState(PrefetchCacheableDuration()),
PrefetchContainer::ServableState::kServable);
prefetch_container->UpdateServingPageMetrics();
if (reader.HaveDefaultContextCookiesChanged()) {
prefetch_match_resolver
.FallbackToRegularNavigationWhenMatchedPrefetchCookiesChanged(
*prefetch_container, key.url());
return HandlePrefetchContainerResult::kNotToBeServedCookiesChanged;
}
if (!reader.HasIsolatedCookieCopyStarted()) {
CopyIsolatedCookies(reader);
}
DVLOG(1) << "PrefetchService::ReturnPrefetchToServe" << *prefetch_container
<< " is served!";
prefetch_container->OnReturnPrefetchToServe(
/*served=*/true, key.url());
prefetch_match_resolver.PrefetchServed(std::move(reader));
return HandlePrefetchContainerResult::kToBeServed;
}
// static
void PrefetchService::SetServiceWorkerContextForTesting(
ServiceWorkerContext* context) {

@ -409,16 +409,6 @@ class PrefetchServiceTestBase : public PrefetchingMetricsTestBase {
{});
}
void InitScopedFeatureListForNewWaitLoop(bool should_enable) {
if (should_enable) {
scoped_feature_list_for_new_wait_loop_.InitWithFeatures(
{features::kPrefetchNewWaitLoop}, {});
} else {
scoped_feature_list_for_new_wait_loop_.InitWithFeatures(
{}, {features::kPrefetchNewWaitLoop});
}
}
void MakePrefetchService(std::unique_ptr<MockPrefetchServiceDelegate>
mock_prefetch_service_delegate) {
test_content_browser_client_ =
@ -792,16 +782,6 @@ class PrefetchServiceTestBase : public PrefetchingMetricsTestBase {
*mock_navigation_handle_);
}
PrefetchMatchResolver* GetPrefetchMatchResolverForMostRecentNavigation() {
if (!mock_navigation_handle_) {
return nullptr;
}
PrefetchMatchResolver::CreateForNavigationHandle(*mock_navigation_handle_);
return PrefetchMatchResolver::GetForNavigationHandle(
*mock_navigation_handle_);
}
base::WeakPtr<PrefetchServingPageMetricsContainer>
GetServingPageMetricsContainerForMostRecentNavigation() {
if (!mock_navigation_handle_) {
@ -847,22 +827,11 @@ class PrefetchServiceTestBase : public PrefetchingMetricsTestBase {
base::Unretained(&request_handler_keep_alive_));
PrefetchService* prefetch_service =
BrowserContextImpl::From(browser_context())->GetPrefetchService();
if (UseNewWaitLoop()) {
auto key = PrefetchContainer::Key(initiator_document_token, url);
PrefetchMatchResolver2::FindPrefetch(
std::move(key), /*is_nav_prerender=*/false, *prefetch_service,
GetServingPageMetricsContainerForMostRecentNavigation(),
std::move(callback));
} else {
PrefetchMatchResolver* prefetch_match_resolver =
GetPrefetchMatchResolverForMostRecentNavigation();
prefetch_match_resolver->SetOnPrefetchToServeReadyCallback(
std::move(callback));
prefetch_service->GetPrefetchToServe(
PrefetchContainer::Key(initiator_document_token, url),
GetServingPageMetricsContainerForMostRecentNavigation(),
*prefetch_match_resolver);
}
}
PrefetchContainer::Reader GetPrefetchToServe(
@ -905,8 +874,6 @@ class PrefetchServiceTestBase : public PrefetchingMetricsTestBase {
int initiator_process_id,
const std::optional<blink::LocalFrameToken>& initiator_local_frame_token,
const std::optional<blink::DocumentToken>& initiator_document_token) {
CHECK(UseNewWaitLoop());
// Use std::unique_ptr as the below uses raw pointers and references.
auto res = std::make_unique<NavigationResult>();
@ -1189,18 +1156,14 @@ class PrefetchServiceTestBase : public PrefetchingMetricsTestBase {
variations::VariationsIdsProvider::Mode::kIgnoreSignedInState};
};
class PrefetchServiceTest : public PrefetchServiceTestBase,
public ::testing::WithParamInterface<bool> {
class PrefetchServiceTest : public PrefetchServiceTestBase {
public:
void InitScopedFeatureList() override {
InitScopedFeatureListForNewWaitLoop(GetParam());
PrefetchServiceTestBase::InitScopedFeatureList();
}
};
INSTANTIATE_TEST_SUITE_P(, PrefetchServiceTest, testing::Bool());
TEST_P(PrefetchServiceTest, SuccessCase) {
TEST_F(PrefetchServiceTest, SuccessCase) {
base::HistogramTester histogram_tester;
MakePrefetchService(
@ -1229,7 +1192,6 @@ TEST_P(PrefetchServiceTest, SuccessCase) {
histogram_tester.ExpectUniqueSample(
"PrefetchProxy.AfterClick.RedirectChainSize", 1, 1);
if (UseNewWaitLoop()) {
histogram_tester.ExpectUniqueSample(
base::StringPrintf("PrefetchProxy.AfterClick."
"PrefetchMatchingBlockedNavigationWithPrefetch.%s",
@ -1237,18 +1199,9 @@ TEST_P(PrefetchServiceTest, SuccessCase) {
blink::mojom::SpeculationEagerness::kEager)
.c_str()),
false, 1);
} else {
histogram_tester.ExpectUniqueSample(
base::StringPrintf(
"PrefetchProxy.AfterClick.WasBlockedUntilHeadWhenServing.%s",
GetPrefetchEagernessHistogramSuffix(
blink::mojom::SpeculationEagerness::kEager)
.c_str()),
false, 1);
}
}
TEST_P(PrefetchServiceTest, SuccessCase_Browser) {
TEST_F(PrefetchServiceTest, SuccessCase_Browser) {
base::test::ScopedFeatureList scoped_feature_list(
features::kPrefetchBrowserInitiatedTriggers);
base::HistogramTester histogram_tester;
@ -1315,7 +1268,7 @@ TEST_P(PrefetchServiceTest, SuccessCase_Browser) {
GURL("https://example.com/?b=1"));
}
TEST_P(PrefetchServiceTest, SuccessCase_Browser_NoVarySearch) {
TEST_F(PrefetchServiceTest, SuccessCase_Browser_NoVarySearch) {
base::test::ScopedFeatureList scoped_feature_list(
features::kPrefetchBrowserInitiatedTriggers);
base::HistogramTester histogram_tester;
@ -1386,7 +1339,7 @@ TEST_P(PrefetchServiceTest, SuccessCase_Browser_NoVarySearch) {
GURL("https://example.com/?a=1"));
}
TEST_P(PrefetchServiceTest, FailureCase_Browser_ServerErrorResponseCode) {
TEST_F(PrefetchServiceTest, FailureCase_Browser_ServerErrorResponseCode) {
base::test::ScopedFeatureList scoped_feature_list(
features::kPrefetchBrowserInitiatedTriggers);
base::HistogramTester histogram_tester;
@ -1443,7 +1396,7 @@ TEST_P(PrefetchServiceTest, FailureCase_Browser_ServerErrorResponseCode) {
EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com?b=1")));
}
TEST_P(PrefetchServiceTest, FailureCase_Browser_NetError) {
TEST_F(PrefetchServiceTest, FailureCase_Browser_NetError) {
base::HistogramTester histogram_tester;
MakePrefetchService(
std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>(
@ -1488,7 +1441,7 @@ TEST_P(PrefetchServiceTest, FailureCase_Browser_NetError) {
EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com?c=1")));
}
TEST_P(PrefetchServiceTest, FailureCase_Browser_NotEligibleNonHttps) {
TEST_F(PrefetchServiceTest, FailureCase_Browser_NotEligibleNonHttps) {
base::HistogramTester histogram_tester;
MakePrefetchService(
std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>(
@ -1530,7 +1483,7 @@ TEST_P(PrefetchServiceTest, FailureCase_Browser_NotEligibleNonHttps) {
EXPECT_FALSE(GetPrefetchToServe(GURL("http://example.com")));
}
TEST_P(PrefetchServiceTest, BrowserContextPrefetchRespectsTTL) {
TEST_F(PrefetchServiceTest, BrowserContextPrefetchRespectsTTL) {
base::HistogramTester histogram_tester;
MakePrefetchService(
std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>(
@ -1574,7 +1527,7 @@ TEST_P(PrefetchServiceTest, BrowserContextPrefetchRespectsTTL) {
EXPECT_FALSE(serveable_reader);
}
TEST_P(PrefetchServiceTest, PrefetchDoesNotMatchIfDocumentTokenDoesNotMatch) {
TEST_F(PrefetchServiceTest, PrefetchDoesNotMatchIfDocumentTokenDoesNotMatch) {
base::HistogramTester histogram_tester;
MakePrefetchService(
@ -1603,7 +1556,7 @@ TEST_P(PrefetchServiceTest, PrefetchDoesNotMatchIfDocumentTokenDoesNotMatch) {
different_document_token));
}
TEST_P(PrefetchServiceTest, SuccessCase_Embedder) {
TEST_F(PrefetchServiceTest, SuccessCase_Embedder) {
base::test::ScopedFeatureList scoped_feature_list(
features::kPrefetchBrowserInitiatedTriggers);
@ -1649,7 +1602,7 @@ TEST_P(PrefetchServiceTest, SuccessCase_Embedder) {
"PrefetchProxy.AfterClick.RedirectChainSize", 1, 1);
}
TEST_P(PrefetchServiceTest,
TEST_F(PrefetchServiceTest,
PrefetchDoesNotMatchIfDocumentTokenDoesNotMatch_Embedder) {
base::test::ScopedFeatureList scoped_feature_list(
features::kPrefetchBrowserInitiatedTriggers);
@ -1694,7 +1647,7 @@ TEST_P(PrefetchServiceTest,
GetPrefetchToServe(GURL("https://example.com"), MainDocumentToken()));
}
TEST_P(PrefetchServiceTest, NoPrefetchingPreloadingDisabled) {
TEST_F(PrefetchServiceTest, NoPrefetchingPreloadingDisabled) {
base::HistogramTester histogram_tester;
std::unique_ptr<MockPrefetchServiceDelegate> mock_prefetch_service_delegate =
@ -1729,7 +1682,7 @@ TEST_P(PrefetchServiceTest, NoPrefetchingPreloadingDisabled) {
ExpectServingMetrics(PrefetchStatus::kPrefetchIneligiblePreloadingDisabled);
}
TEST_P(PrefetchServiceTest, NoPrefetchingDomainNotInAllowList) {
TEST_F(PrefetchServiceTest, NoPrefetchingDomainNotInAllowList) {
base::HistogramTester histogram_tester;
std::unique_ptr<MockPrefetchServiceDelegate> mock_prefetch_service_delegate =
@ -1768,12 +1721,9 @@ TEST_P(PrefetchServiceTest, NoPrefetchingDomainNotInAllowList) {
EXPECT_FALSE(serving_page_metrics->prefetch_status);
}
class PrefetchServiceAllowAllDomainsTest
: public PrefetchServiceTestBase,
public ::testing::WithParamInterface<bool> {
class PrefetchServiceAllowAllDomainsTest : public PrefetchServiceTestBase {
public:
void InitScopedFeatureList() override {
InitScopedFeatureListForNewWaitLoop(GetParam());
scoped_feature_list_.InitWithFeaturesAndParameters(
{{features::kPrefetchUseContentRefactor,
{{"ineligible_decoy_request_probability", "0"},
@ -1783,9 +1733,7 @@ class PrefetchServiceAllowAllDomainsTest
}
};
INSTANTIATE_TEST_SUITE_P(, PrefetchServiceAllowAllDomainsTest, testing::Bool());
TEST_P(PrefetchServiceAllowAllDomainsTest, AllowAllDomains) {
TEST_F(PrefetchServiceAllowAllDomainsTest, AllowAllDomains) {
base::HistogramTester histogram_tester;
std::unique_ptr<MockPrefetchServiceDelegate> mock_prefetch_service_delegate =
@ -1909,7 +1857,7 @@ TEST_F(PrefetchServiceAllowAllDomainsForExtendedPreloadingTest,
EXPECT_FALSE(serving_page_metrics->prefetch_status);
}
TEST_P(PrefetchServiceTest, NonProxiedPrefetchDoesNotRequireAllowList) {
TEST_F(PrefetchServiceTest, NonProxiedPrefetchDoesNotRequireAllowList) {
NavigationSimulator::NavigateAndCommitFromBrowser(
web_contents(), GURL("https://example.com/referrer"));
base::HistogramTester histogram_tester;
@ -1946,7 +1894,7 @@ TEST_P(PrefetchServiceTest, NonProxiedPrefetchDoesNotRequireAllowList) {
ExpectServingMetricsSuccess(/*required_private_prefetch_proxy=*/false);
}
TEST_P(PrefetchServiceTest, NotEligibleHostnameNonUnique) {
TEST_F(PrefetchServiceTest, NotEligibleHostnameNonUnique) {
base::HistogramTester histogram_tester;
MakePrefetchService(
@ -1975,7 +1923,7 @@ TEST_P(PrefetchServiceTest, NotEligibleHostnameNonUnique) {
ExpectServingMetrics(PrefetchStatus::kPrefetchIneligibleHostIsNonUnique);
}
TEST_P(PrefetchServiceTest, NotEligibleDataSaverEnabled) {
TEST_F(PrefetchServiceTest, NotEligibleDataSaverEnabled) {
base::HistogramTester histogram_tester;
std::unique_ptr<MockPrefetchServiceDelegate> mock_prefetch_service_delegate =
@ -2010,7 +1958,7 @@ TEST_P(PrefetchServiceTest, NotEligibleDataSaverEnabled) {
ExpectServingMetrics(PrefetchStatus::kPrefetchIneligibleDataSaverEnabled);
}
TEST_P(PrefetchServiceTest, NotEligibleNonHttps) {
TEST_F(PrefetchServiceTest, NotEligibleNonHttps) {
base::HistogramTester histogram_tester;
MakePrefetchService(
@ -2036,7 +1984,7 @@ TEST_P(PrefetchServiceTest, NotEligibleNonHttps) {
ExpectServingMetrics(PrefetchStatus::kPrefetchIneligibleSchemeIsNotHttps);
}
TEST_P(PrefetchServiceTest, NotEligiblePrefetchProxyNotAvailable) {
TEST_F(PrefetchServiceTest, NotEligiblePrefetchProxyNotAvailable) {
base::HistogramTester histogram_tester;
std::unique_ptr<MockPrefetchServiceDelegate> mock_prefetch_service_delegate =
@ -2071,7 +2019,7 @@ TEST_P(PrefetchServiceTest, NotEligiblePrefetchProxyNotAvailable) {
PrefetchStatus::kPrefetchIneligiblePrefetchProxyNotAvailable);
}
TEST_P(PrefetchServiceTest,
TEST_F(PrefetchServiceTest,
EligiblePrefetchProxyNotAvailableNonProxiedPrefetch) {
base::HistogramTester histogram_tester;
@ -2105,7 +2053,7 @@ TEST_P(PrefetchServiceTest,
ExpectServingMetricsSuccess(/*required_private_prefetch_proxy=*/false);
}
TEST_P(PrefetchServiceTest, NotEligibleOriginWithinRetryAfterWindow) {
TEST_F(PrefetchServiceTest, NotEligibleOriginWithinRetryAfterWindow) {
base::HistogramTester histogram_tester;
std::unique_ptr<MockPrefetchServiceDelegate> mock_prefetch_service_delegate =
@ -2138,7 +2086,7 @@ TEST_P(PrefetchServiceTest, NotEligibleOriginWithinRetryAfterWindow) {
ExpectServingMetrics(PrefetchStatus::kPrefetchIneligibleRetryAfter);
}
TEST_P(PrefetchServiceTest, EligibleNonHttpsNonProxiedPotentiallyTrustworthy) {
TEST_F(PrefetchServiceTest, EligibleNonHttpsNonProxiedPotentiallyTrustworthy) {
base::HistogramTester histogram_tester;
MakePrefetchService(
@ -2163,7 +2111,7 @@ TEST_P(PrefetchServiceTest, EligibleNonHttpsNonProxiedPotentiallyTrustworthy) {
ExpectServingMetricsSuccess(/*required_private_prefetch_proxy=*/false);
}
TEST_P(PrefetchServiceTest, NotEligibleServiceWorkerRegistered) {
TEST_F(PrefetchServiceTest, NotEligibleServiceWorkerRegistered) {
base::HistogramTester histogram_tester;
MakePrefetchService(
@ -2195,7 +2143,7 @@ TEST_P(PrefetchServiceTest, NotEligibleServiceWorkerRegistered) {
ExpectServingMetrics(PrefetchStatus::kPrefetchIneligibleUserHasServiceWorker);
}
TEST_P(PrefetchServiceTest,
TEST_F(PrefetchServiceTest,
NotEligibleServiceWorkerRegisteredServiceWorkerCheckUKM) {
// ukm::TestAutoSetUkmRecorder ukm_recorder;
MakePrefetchService(
@ -2249,7 +2197,7 @@ TEST_P(PrefetchServiceTest,
kServiceWorkerRegisteredCheckDurationBucketSpacing));
}
TEST_P(PrefetchServiceTest, EligibleServiceWorkerNotRegistered) {
TEST_F(PrefetchServiceTest, EligibleServiceWorkerNotRegistered) {
base::HistogramTester histogram_tester;
MakePrefetchService(
@ -2281,7 +2229,7 @@ TEST_P(PrefetchServiceTest, EligibleServiceWorkerNotRegistered) {
ExpectServingMetricsSuccess();
}
TEST_P(PrefetchServiceTest,
TEST_F(PrefetchServiceTest,
EligibleServiceWorkerNotRegisteredServiceWorkerCheckUKM) {
MakePrefetchService(
std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>());
@ -2337,7 +2285,7 @@ TEST_P(PrefetchServiceTest,
kServiceWorkerRegisteredCheckDurationBucketSpacing));
}
TEST_P(PrefetchServiceTest, EligibleServiceWorkerRegistered) {
TEST_F(PrefetchServiceTest, EligibleServiceWorkerRegistered) {
base::HistogramTester histogram_tester;
MakePrefetchService(
@ -2369,7 +2317,7 @@ TEST_P(PrefetchServiceTest, EligibleServiceWorkerRegistered) {
ExpectServingMetricsSuccess();
}
TEST_P(PrefetchServiceTest,
TEST_F(PrefetchServiceTest,
EligibleServiceWorkerRegisteredServiceWorkerCheckUKM) {
ukm::TestAutoSetUkmRecorder ukm_recorder;
MakePrefetchService(
@ -2424,7 +2372,7 @@ TEST_P(PrefetchServiceTest,
kServiceWorkerRegisteredCheckDurationBucketSpacing));
}
TEST_P(PrefetchServiceTest, EligibleServiceWorkerNotRegisteredAtThisPath) {
TEST_F(PrefetchServiceTest, EligibleServiceWorkerNotRegisteredAtThisPath) {
base::HistogramTester histogram_tester;
MakePrefetchService(
@ -2457,7 +2405,7 @@ TEST_P(PrefetchServiceTest, EligibleServiceWorkerNotRegisteredAtThisPath) {
ExpectServingMetricsSuccess();
}
TEST_P(PrefetchServiceTest, NotEligibleUserHasCookies) {
TEST_F(PrefetchServiceTest, NotEligibleUserHasCookies) {
base::HistogramTester histogram_tester;
MakePrefetchService(
@ -2485,7 +2433,7 @@ TEST_P(PrefetchServiceTest, NotEligibleUserHasCookies) {
ExpectServingMetrics(PrefetchStatus::kPrefetchIneligibleUserHasCookies);
}
TEST_P(PrefetchServiceTest, EligibleUserHasCookiesForDifferentUrl) {
TEST_F(PrefetchServiceTest, EligibleUserHasCookiesForDifferentUrl) {
base::HistogramTester histogram_tester;
MakePrefetchService(
@ -2513,7 +2461,7 @@ TEST_P(PrefetchServiceTest, EligibleUserHasCookiesForDifferentUrl) {
ExpectServingMetricsSuccess();
}
TEST_P(PrefetchServiceTest, EligibleSameOriginPrefetchCanHaveExistingCookies) {
TEST_F(PrefetchServiceTest, EligibleSameOriginPrefetchCanHaveExistingCookies) {
NavigationSimulator::NavigateAndCommitFromBrowser(
web_contents(), GURL("https://example.com/referrer"));
base::HistogramTester histogram_tester;
@ -2543,7 +2491,7 @@ TEST_P(PrefetchServiceTest, EligibleSameOriginPrefetchCanHaveExistingCookies) {
}
// TODO(crbug.com/40249481): Test flaky on trybots.
TEST_P(PrefetchServiceTest,
TEST_F(PrefetchServiceTest,
DISABLED_CHROMEOS(FailedCookiesChangedAfterPrefetchStarted)) {
base::HistogramTester histogram_tester;
@ -2605,7 +2553,7 @@ TEST_P(PrefetchServiceTest,
}
// TODO(crbug.com/40249481): Test flaky on trybots.
TEST_P(PrefetchServiceTest,
TEST_F(PrefetchServiceTest,
DISABLED_CHROMEOS(SameOriginPrefetchIgnoresProxyRequirement)) {
NavigationSimulator::NavigateAndCommitFromBrowser(
web_contents(), GURL("https://example.com/referrer"));
@ -2639,7 +2587,7 @@ TEST_P(PrefetchServiceTest,
}
// TODO(crbug.com/40249481): Test flaky on trybots.
TEST_P(PrefetchServiceTest,
TEST_F(PrefetchServiceTest,
DISABLED_CHROMEOS(NotEligibleSameSiteCrossOriginPrefetchRequiresProxy)) {
NavigationSimulator::NavigateAndCommitFromBrowser(
web_contents(), GURL("https://example.com/referrer"));
@ -2675,7 +2623,7 @@ TEST_P(PrefetchServiceTest,
kPrefetchIneligibleSameSiteCrossOriginPrefetchRequiredProxy);
}
TEST_P(PrefetchServiceTest, NotEligibleExistingConnectProxy) {
TEST_F(PrefetchServiceTest, NotEligibleExistingConnectProxy) {
base::HistogramTester histogram_tester;
MakePrefetchService(
@ -2709,7 +2657,7 @@ TEST_P(PrefetchServiceTest, NotEligibleExistingConnectProxy) {
PrefetchService::SetNetworkContextForProxyLookupForTesting(nullptr);
}
TEST_P(PrefetchServiceTest, EligibleExistingConnectProxyButSameOriginPrefetch) {
TEST_F(PrefetchServiceTest, EligibleExistingConnectProxyButSameOriginPrefetch) {
NavigationSimulator::NavigateAndCommitFromBrowser(
web_contents(), GURL("https://example.com/referrer"));
base::HistogramTester histogram_tester;
@ -2744,7 +2692,7 @@ TEST_P(PrefetchServiceTest, EligibleExistingConnectProxyButSameOriginPrefetch) {
PrefetchService::SetNetworkContextForProxyLookupForTesting(nullptr);
}
TEST_P(PrefetchServiceTest, FailedNon2XXResponseCode) {
TEST_F(PrefetchServiceTest, FailedNon2XXResponseCode) {
base::HistogramTester histogram_tester;
MakePrefetchService(
@ -2773,7 +2721,7 @@ TEST_P(PrefetchServiceTest, FailedNon2XXResponseCode) {
/*prefetch_header_latency=*/true);
}
TEST_P(PrefetchServiceTest, FailedNetError) {
TEST_F(PrefetchServiceTest, FailedNetError) {
base::HistogramTester histogram_tester;
MakePrefetchService(
@ -2799,7 +2747,7 @@ TEST_P(PrefetchServiceTest, FailedNetError) {
ExpectServingMetrics(PrefetchStatus::kPrefetchFailedNetError);
}
TEST_P(PrefetchServiceTest, HandleRetryAfterResponse) {
TEST_F(PrefetchServiceTest, HandleRetryAfterResponse) {
base::HistogramTester histogram_tester;
std::unique_ptr<MockPrefetchServiceDelegate> mock_prefetch_service_delegate =
@ -2838,7 +2786,7 @@ TEST_P(PrefetchServiceTest, HandleRetryAfterResponse) {
/*prefetch_header_latency=*/true);
}
TEST_P(PrefetchServiceTest, SuccessNonHTML) {
TEST_F(PrefetchServiceTest, SuccessNonHTML) {
base::HistogramTester histogram_tester;
MakePrefetchService(
@ -2870,7 +2818,7 @@ TEST_P(PrefetchServiceTest, SuccessNonHTML) {
// the cookies for the prefetched URL. It then creates two NavigationRequests
// (to the same URL) and calls GetPrefetchToServe for each request. This can
// happen in practice when a user clicks on a link to a URL twice).
TEST_P(PrefetchServiceTest,
TEST_F(PrefetchServiceTest,
MultipleNavigationRequestsCallGetPrefetchAfterCookieChange) {
MakePrefetchService(
std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>());
@ -2910,7 +2858,7 @@ TEST_P(PrefetchServiceTest,
EXPECT_FALSE(future_2.Get().GetPrefetchContainer());
}
TEST_P(PrefetchServiceTest, NotServeableNavigationInDifferentRenderFrameHost) {
TEST_F(PrefetchServiceTest, NotServeableNavigationInDifferentRenderFrameHost) {
base::HistogramTester histogram_tester;
MakePrefetchService(
@ -2947,12 +2895,9 @@ TEST_P(PrefetchServiceTest, NotServeableNavigationInDifferentRenderFrameHost) {
EXPECT_FALSE(serving_page_metrics);
}
class PrefetchServiceWithHTMLOnlyTest
: public PrefetchServiceTestBase,
public ::testing::WithParamInterface<bool> {
class PrefetchServiceWithHTMLOnlyTest : public PrefetchServiceTestBase {
public:
void InitScopedFeatureList() override {
InitScopedFeatureListForNewWaitLoop(GetParam());
scoped_feature_list_.InitWithFeaturesAndParameters(
{{features::kPrefetchUseContentRefactor,
{{"ineligible_decoy_request_probability", "0"},
@ -2962,9 +2907,7 @@ class PrefetchServiceWithHTMLOnlyTest
}
};
INSTANTIATE_TEST_SUITE_P(, PrefetchServiceWithHTMLOnlyTest, testing::Bool());
TEST_P(PrefetchServiceWithHTMLOnlyTest, FailedNonHTMLWithHTMLOnly) {
TEST_F(PrefetchServiceWithHTMLOnlyTest, FailedNonHTMLWithHTMLOnly) {
base::HistogramTester histogram_tester;
MakePrefetchService(
@ -3148,15 +3091,7 @@ TEST_F(PrefetchServiceAlwaysMakeDecoyRequestTest,
/*prefetch_header_latency=*/true);
}
class PrefetchServiceIncognitoTest
: public PrefetchServiceTestBase,
public ::testing::WithParamInterface<bool> {
public:
void InitScopedFeatureList() override {
InitScopedFeatureListForNewWaitLoop(GetParam());
PrefetchServiceTestBase::InitScopedFeatureList();
}
class PrefetchServiceIncognitoTest : public PrefetchServiceTestBase {
protected:
std::unique_ptr<BrowserContext> CreateBrowserContext() override {
auto browser_context = std::make_unique<TestBrowserContext>();
@ -3165,9 +3100,7 @@ class PrefetchServiceIncognitoTest
}
};
INSTANTIATE_TEST_SUITE_P(, PrefetchServiceIncognitoTest, testing::Bool());
TEST_P(PrefetchServiceIncognitoTest, OffTheRecordEligible) {
TEST_F(PrefetchServiceIncognitoTest, OffTheRecordEligible) {
base::HistogramTester histogram_tester;
MakePrefetchService(
@ -3186,7 +3119,7 @@ TEST_P(PrefetchServiceIncognitoTest, OffTheRecordEligible) {
ExpectPrefetchSuccess(histogram_tester, std::size(kHTMLBody));
}
TEST_P(PrefetchServiceTest, NonDefaultStoragePartition) {
TEST_F(PrefetchServiceTest, NonDefaultStoragePartition) {
base::HistogramTester histogram_tester;
MakePrefetchService(
@ -3216,12 +3149,9 @@ TEST_P(PrefetchServiceTest, NonDefaultStoragePartition) {
/*required_private_prefetch_proxy=*/false);
}
class PrefetchServiceStreamingURLLoaderTest
: public PrefetchServiceTestBase,
public ::testing::WithParamInterface<bool> {
class PrefetchServiceStreamingURLLoaderTest : public PrefetchServiceTestBase {
public:
void InitScopedFeatureList() override {
InitScopedFeatureListForNewWaitLoop(GetParam());
scoped_feature_list_.InitWithFeaturesAndParameters(
{{features::kPrefetchUseContentRefactor,
{{"ineligible_decoy_request_probability", "0"},
@ -3231,12 +3161,8 @@ class PrefetchServiceStreamingURLLoaderTest
}
};
INSTANTIATE_TEST_SUITE_P(,
PrefetchServiceStreamingURLLoaderTest,
testing::Bool());
// TODO(crbug.com/40249481): Test flaky on trybots.
TEST_P(PrefetchServiceStreamingURLLoaderTest,
TEST_F(PrefetchServiceStreamingURLLoaderTest,
DISABLED_CHROMEOS(StreamingURLLoaderSuccessCase)) {
base::HistogramTester histogram_tester;
@ -3313,7 +3239,7 @@ TEST_P(PrefetchServiceStreamingURLLoaderTest,
}
// TODO(crbug.com/40249481): Test flaky on trybots.
TEST_P(PrefetchServiceTest, DISABLED_CHROMEOS(NoVarySearchSuccessCase)) {
TEST_F(PrefetchServiceTest, DISABLED_CHROMEOS(NoVarySearchSuccessCase)) {
base::HistogramTester histogram_tester;
MakePrefetchService(
@ -3346,7 +3272,7 @@ TEST_P(PrefetchServiceTest, DISABLED_CHROMEOS(NoVarySearchSuccessCase)) {
ExpectServingMetricsSuccess();
}
TEST_P(PrefetchServiceTest, NoVarySearchSuccessCase_Embedder) {
TEST_F(PrefetchServiceTest, NoVarySearchSuccessCase_Embedder) {
base::test::ScopedFeatureList scoped_feature_list(
features::kPrefetchBrowserInitiatedTriggers);
base::HistogramTester histogram_tester;
@ -3394,7 +3320,7 @@ TEST_P(PrefetchServiceTest, NoVarySearchSuccessCase_Embedder) {
}
// TODO(crbug.com/40249481): Test flaky on trybots.
TEST_P(PrefetchServiceTest, DISABLED_CHROMEOS(PrefetchEligibleRedirect)) {
TEST_F(PrefetchServiceTest, DISABLED_CHROMEOS(PrefetchEligibleRedirect)) {
base::HistogramTester histogram_tester;
MakePrefetchService(
@ -3445,7 +3371,7 @@ TEST_P(PrefetchServiceTest, DISABLED_CHROMEOS(PrefetchEligibleRedirect)) {
}
// TODO(crbug.com/40249481): Test flaky on trybots.
TEST_P(PrefetchServiceTest, DISABLED_CHROMEOS(IneligibleRedirectCookies)) {
TEST_F(PrefetchServiceTest, DISABLED_CHROMEOS(IneligibleRedirectCookies)) {
base::HistogramTester histogram_tester;
MakePrefetchService(
@ -3507,7 +3433,7 @@ TEST_P(PrefetchServiceTest, DISABLED_CHROMEOS(IneligibleRedirectCookies)) {
}
// TODO(crbug.com/40249481): Test flaky on trybots.
TEST_P(PrefetchServiceTest,
TEST_F(PrefetchServiceTest,
DISABLED_CHROMEOS(IneligibleRedirectServiceWorker)) {
base::HistogramTester histogram_tester;
@ -3566,7 +3492,7 @@ TEST_P(PrefetchServiceTest,
}
// TODO(crbug.com/40249481): Test flaky on trybots.
TEST_P(PrefetchServiceTest, DISABLED_CHROMEOS(InvalidRedirect)) {
TEST_F(PrefetchServiceTest, DISABLED_CHROMEOS(InvalidRedirect)) {
base::HistogramTester histogram_tester;
MakePrefetchService(
@ -3613,7 +3539,7 @@ TEST_P(PrefetchServiceTest, DISABLED_CHROMEOS(InvalidRedirect)) {
}
// TODO(crbug.com/40249481): Test flaky on trybots.
TEST_P(PrefetchServiceTest,
TEST_F(PrefetchServiceTest,
DISABLED_CHROMEOS(PrefetchSameOriginEligibleRedirect)) {
NavigationSimulator::NavigateAndCommitFromBrowser(
web_contents(), GURL("https://example.com/referrer"));
@ -3669,7 +3595,7 @@ TEST_P(PrefetchServiceTest,
// TODO(crbug.com/40249481): Test flaky on trybots.
// TODO(crbug.com/40265797): This test is testing the current
// functionality, and should be removed while fixing this bug.
TEST_P(PrefetchServiceTest,
TEST_F(PrefetchServiceTest,
DISABLED_CHROMEOS(IneligibleSameSiteCrossOriginRequiresProxyRedirect)) {
NavigationSimulator::NavigateAndCommitFromBrowser(
web_contents(), GURL("https://example.com/referrer"));
@ -3725,7 +3651,7 @@ TEST_P(PrefetchServiceTest,
}
// TODO(crbug.com/40249481): Test flaky on trybots.
TEST_P(PrefetchServiceTest,
TEST_F(PrefetchServiceTest,
DISABLED_CHROMEOS(RedirectDefaultToIsolatedNetworkContextTransition)) {
NavigationSimulator::NavigateAndCommitFromBrowser(
web_contents(), GURL("https://example.com/referrer"));
@ -3785,7 +3711,7 @@ TEST_P(PrefetchServiceTest,
}
// TODO(crbug.com/40249481): Test flaky on trybots.
TEST_P(PrefetchServiceTest,
TEST_F(PrefetchServiceTest,
DISABLED_CHROMEOS(
RedirectDefaultToIsolatedNetworkContextTransitionWithProxy)) {
NavigationSimulator::NavigateAndCommitFromBrowser(
@ -3849,7 +3775,7 @@ TEST_P(PrefetchServiceTest,
}
// TODO(crbug.com/40249481): Test flaky on trybots.
TEST_P(PrefetchServiceTest,
TEST_F(PrefetchServiceTest,
DISABLED_CHROMEOS(RedirectIsolatedToDefaultNetworkContextTransition)) {
NavigationSimulator::NavigateAndCommitFromBrowser(
web_contents(), GURL("https://example.com/referrer"));
@ -3920,8 +3846,7 @@ class PrefetchServiceAllowRedirectsAndAlwaysBlockUntilHeadTest
{"prefetch_container_lifetime_s", "-1"},
{"block_until_head_eager_prefetch", "true"},
{"block_until_head_moderate_prefetch", "true"},
{"block_until_head_conservative_prefetch", "true"}}},
{features::kPrefetchNewWaitLoop, {}}},
{"block_until_head_conservative_prefetch", "true"}}}},
{});
}
};
@ -3999,7 +3924,7 @@ TEST_F(PrefetchServiceAllowRedirectsAndAlwaysBlockUntilHeadTest,
}
// TODO(crbug.com/40249481): Test flaky on trybots.
TEST_P(PrefetchServiceTest,
TEST_F(PrefetchServiceTest,
DISABLED_CHROMEOS(RedirectInsufficientReferrerPolicy)) {
NavigationSimulator::NavigateAndCommitFromBrowser(
web_contents(), GURL("https://referrer.com"));
@ -4057,13 +3982,14 @@ class PrefetchServiceNeverBlockUntilHeadTest : public PrefetchServiceTestBase {
public:
void InitScopedFeatureList() override {
scoped_feature_list_.InitWithFeaturesAndParameters(
{{features::kPrefetchUseContentRefactor,
{{"ineligible_decoy_request_probability", "0"},
{"prefetch_container_lifetime_s", "-1"},
{"block_until_head_eager_prefetch", "false"},
{"block_until_head_moderate_prefetch", "false"},
{"block_until_head_conservative_prefetch", "false"}}},
{features::kPrefetchNewWaitLoop, {}}},
{
{features::kPrefetchUseContentRefactor,
{{"ineligible_decoy_request_probability", "0"},
{"prefetch_container_lifetime_s", "-1"},
{"block_until_head_eager_prefetch", "false"},
{"block_until_head_moderate_prefetch", "false"},
{"block_until_head_conservative_prefetch", "false"}}},
},
{});
}
};
@ -4136,8 +4062,7 @@ class PrefetchServiceAlwaysBlockUntilHeadTest
{"block_until_head_timeout_eager_prefetch", "1000"},
{"block_until_head_timeout_moderate_prefetch", "1000"},
{"block_until_head_timeout_conservative_prefetch", "1000"},
}},
{features::kPrefetchNewWaitLoop, {}}},
}}},
{});
}
};
@ -5048,58 +4973,6 @@ TEST_P(PrefetchServiceAlwaysBlockUntilHeadTest,
// Request the prefetch from the PrefetchService. Since both prefetch
// candidates are not eligible serveable_reader will be falsy.
EXPECT_FALSE(GetPrefetchToServe(GURL("https://example.com/index.html")));
// Behavioral change.
//
// kenoss@ believes that `PrefetchServingPageMetrics` is broken (at least non
// reliable state).
//
// In this test, `PrefetchContainer::UpdateServingPageMetrics()` is called
// four times: (For simplicity of description, we assumet that
// `kPrefetchNewWaitLoop`.)
//
// - Prefetch for https://example.com/index.html, path is
// PrefetchMatchResolver2::FindPrefetchInternal()
// -> PrefetchService::CollectMatchCandidates()
// -> PrefetchContainer::UpdateServingPageMetrics()
// value is 0.456 s.
// - Prefetch for https://example.com/index.html?a=1, path is
// PrefetchMatchResolver2::FindPrefetchInternal()
// -> PrefetchService::CollectMatchCandidates()
// -> PrefetchContainer::UpdateServingPageMetrics()
// value is std::nullopt.
// - Prefetch for https://example.com/index.html, path is
// PrefetchMatchResolver2::FindPrefetchInternal()
// -> PrefetchMatchResolver2::UnblockForCookiesChanged()
// -> PrefetchContainer::OnDetectedCookiesChange2()
// -> PrefetchContainer::OnDetectedCookiesChange()
// -> PrefetchContainer::UpdateServingPageMetrics()
// value is 0.456 s.
// - Prefetch for https://example.com/index.html?a=1, path is
// PrefetchMatchResolver2::FindPrefetchInternal()
// -> PrefetchMatchResolver2::UnblockForCookiesChanged()
// -> PrefetchContainer::OnDetectedCookiesChange2()
// -> PrefetchContainer::OnDetectedCookiesChange()
// -> PrefetchContainer::UpdateServingPageMetrics()
// value is std::nullopt.
//
// If `kPrefetchNewWaitLoop` is enabled, the calling order of the third and
// the fourth is unstable because
// `PrefetchMatchResolver2::UnblockForCookiesChanged()` uses an iteration of
// `std::map` and those prefetch refer the same
// `PrefetchServingPageMetricsContanier`. The essential problem is 1. they
// share the same `PrefetchServingPageMetricsContanier`. 2. There is no
// coordination.
//
// I don't think this metrics is worth to preserve until the root cause is
// fixed.
//
// TODO(crbug.com/360094997): Reconstruct `PrefetchServingPageMetrics`.
if (!UseNewWaitLoop()) {
ExpectServingMetrics(PrefetchStatus::kPrefetchNotUsedCookiesChanged,
/*prefetch_header_latency=*/true,
/*required_private_prefetch_proxy=*/false);
}
}
// TODO(crbug.com/40249481): Test flaky on trybots.
@ -5172,9 +5045,6 @@ TEST_P(PrefetchServiceAlwaysBlockUntilHeadTest,
PrefetchContainer::Reader serveable_reader = future.Take();
// Both prefetch candidates are not eligible.
EXPECT_FALSE(serveable_reader);
EXPECT_FALSE(
GetPrefetchMatchResolverForMostRecentNavigation()->IsWaitingForPrefetch(
GURL(kTestUrl + "?a=1")));
// Send the body and completion status of the request,
SendBodyContentOfResponseAndWait(kHTMLBody);
@ -6405,14 +6275,7 @@ blink::UserAgentMetadata GetFakeUserAgentMetadata() {
return metadata;
}
class PrefetchServiceClientHintsTest
: public PrefetchServiceTestBase,
public ::testing::WithParamInterface<bool> {
public:
void InitScopedFeatureList() override {
InitScopedFeatureListForNewWaitLoop(GetParam());
}
class PrefetchServiceClientHintsTest : public PrefetchServiceTestBase {
protected:
std::unique_ptr<BrowserContext> CreateBrowserContext() override {
auto browser_context = PrefetchServiceTestBase::CreateBrowserContext();
@ -6430,9 +6293,7 @@ class PrefetchServiceClientHintsTest
GetFakeUserAgentMetadata()};
};
INSTANTIATE_TEST_SUITE_P(, PrefetchServiceClientHintsTest, testing::Bool());
TEST_P(PrefetchServiceClientHintsTest, NoClientHintsWhenDisabled) {
TEST_F(PrefetchServiceClientHintsTest, NoClientHintsWhenDisabled) {
base::test::ScopedFeatureList disable_prefetch_ch;
disable_prefetch_ch.InitAndDisableFeature(features::kPrefetchClientHints);
@ -6454,7 +6315,7 @@ TEST_P(PrefetchServiceClientHintsTest, NoClientHintsWhenDisabled) {
EXPECT_FALSE(pending->request.headers.HasHeader("Sec-CH-UA"));
}
TEST_P(PrefetchServiceClientHintsTest, LowEntropyClientHints) {
TEST_F(PrefetchServiceClientHintsTest, LowEntropyClientHints) {
base::test::ScopedFeatureList enable_prefetch_ch;
enable_prefetch_ch.InitAndEnableFeature(features::kPrefetchClientHints);
@ -6476,7 +6337,7 @@ TEST_P(PrefetchServiceClientHintsTest, LowEntropyClientHints) {
EXPECT_TRUE(pending->request.headers.HasHeader("Sec-CH-UA"));
}
TEST_P(PrefetchServiceClientHintsTest, HighEntropyClientHints) {
TEST_F(PrefetchServiceClientHintsTest, HighEntropyClientHints) {
base::test::ScopedFeatureList enable_prefetch_ch;
enable_prefetch_ch.InitAndEnableFeature(features::kPrefetchClientHints);
@ -6514,7 +6375,7 @@ TEST_P(PrefetchServiceClientHintsTest, HighEntropyClientHints) {
EXPECT_GT(viewport_width_int, 0);
}
TEST_P(PrefetchServiceClientHintsTest, CrossSiteNone) {
TEST_F(PrefetchServiceClientHintsTest, CrossSiteNone) {
base::test::ScopedFeatureList enable_prefetch_ch;
enable_prefetch_ch.InitAndEnableFeatureWithParameters(
features::kPrefetchClientHints, {{"cross_site_behavior", "none"}});
@ -6544,7 +6405,7 @@ TEST_P(PrefetchServiceClientHintsTest, CrossSiteNone) {
EXPECT_FALSE(pending->request.headers.HasHeader("Sec-CH-Viewport-Width"));
}
TEST_P(PrefetchServiceClientHintsTest, CrossSiteLowEntropy) {
TEST_F(PrefetchServiceClientHintsTest, CrossSiteLowEntropy) {
base::test::ScopedFeatureList enable_prefetch_ch;
enable_prefetch_ch.InitAndEnableFeatureWithParameters(
features::kPrefetchClientHints, {{"cross_site_behavior", "low_entropy"}});
@ -6574,7 +6435,7 @@ TEST_P(PrefetchServiceClientHintsTest, CrossSiteLowEntropy) {
EXPECT_FALSE(pending->request.headers.HasHeader("Sec-CH-Viewport-Width"));
}
TEST_P(PrefetchServiceClientHintsTest, CrossSiteAll) {
TEST_F(PrefetchServiceClientHintsTest, CrossSiteAll) {
base::test::ScopedFeatureList enable_prefetch_ch;
enable_prefetch_ch.InitAndEnableFeatureWithParameters(
features::kPrefetchClientHints, {{"cross_site_behavior", "all"}});
@ -6604,7 +6465,7 @@ TEST_P(PrefetchServiceClientHintsTest, CrossSiteAll) {
EXPECT_TRUE(pending->request.headers.HasHeader("Sec-CH-Viewport-Width"));
}
TEST_P(PrefetchServiceTest, CancelWhileBlockedOnHead) {
TEST_F(PrefetchServiceTest, CancelWhileBlockedOnHead) {
MakePrefetchService(
std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>());
NavigateAndCommit(GURL("https://example.com/"));
@ -6649,13 +6510,9 @@ TEST_P(PrefetchServiceTest, CancelWhileBlockedOnHead) {
// `PrefetchService` calls `PrefetchStreamingURLLoader::HandleRedirect`) causes
// no crash, and the corresponding prefetch should not be served.
// A regression test for crbug.com/396133768.
TEST_P(
TEST_F(
PrefetchServiceTest,
DISABLED_CHROMEOS(URLLoaderDisconnectedWhileHandlingRedirectEligibilty)) {
if (!UseNewWaitLoop()) {
GTEST_SKIP() << "This test requires PrefetchNewWaitLoop";
}
MakePrefetchService(
std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>());
PrefetchService* prefetch_service =
@ -6741,14 +6598,10 @@ TEST_P(
// unblocks the navigation that potentially matches the corresponding
// prefetch and thus was blocked in the match resolver (BlockUntilHead).
// A regression test for crbug.com/396133768.√
TEST_P(
TEST_F(
PrefetchServiceTest,
DISABLED_CHROMEOS(
URLLoaderDisconnectedWhileHandlingRedirectEligibilty_BlockUntilHead)) {
if (!UseNewWaitLoop()) {
GTEST_SKIP() << "This test requires PrefetchNewWaitLoop";
}
MakePrefetchService(
std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>());
PrefetchService* prefetch_service =
@ -6843,12 +6696,11 @@ TEST_P(
// success.
// - Navigation Y started, which matches to A. Unblocked synchronously as
// success.
TEST_P(
TEST_F(
PrefetchServiceTest,
DISABLED_CHROMEOS(MultipleConcurrentNavigationSuccessBeforeNavigations)) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatures(
{features::kPrefetchNewWaitLoop, features::kPrefetchReusable}, {});
scoped_feature_list.InitWithFeatures({features::kPrefetchReusable}, {});
base::HistogramTester histogram_tester;
@ -6906,12 +6758,11 @@ TEST_P(
// - Navigation X started, which matches to A. Blocked by A.
// - Navigation Y started, which matches to A. Blocked by A.
// - A received non-redirect header. Unblocks them as success.
TEST_P(
TEST_F(
PrefetchServiceTest,
DISABLED_CHROMEOS(MultipleConcurrentNavigationBlockUntilHeadThenSuccess)) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatures(
{features::kPrefetchNewWaitLoop, features::kPrefetchReusable}, {});
scoped_feature_list.InitWithFeatures({features::kPrefetchReusable}, {});
base::HistogramTester histogram_tester;
@ -6979,12 +6830,11 @@ TEST_P(
// - Navigation Y started, which is potentially matches and not eventually
// matches to A. Blocked by A.
// - A received non-redirect header. Unblocks them as success/fail.
TEST_P(PrefetchServiceTest,
TEST_F(PrefetchServiceTest,
DISABLED_CHROMEOS(
MultipleConcurrentNavigationBlockUntilHeadThenSuccessFail)) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatures(
{features::kPrefetchNewWaitLoop, features::kPrefetchReusable}, {});
scoped_feature_list.InitWithFeatures({features::kPrefetchReusable}, {});
base::HistogramTester histogram_tester;
@ -7058,12 +6908,11 @@ TEST_P(PrefetchServiceTest,
//
// This test checks that it is safe to call
// `PrefetchContainer::OnDetectedCookiesChange2()` multiple times.
TEST_P(PrefetchServiceTest,
TEST_F(PrefetchServiceTest,
DISABLED_CHROMEOS(
MultipleConcurrentNavigationBlockUntilHeadThenCookiesChanged)) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatures(
{features::kPrefetchNewWaitLoop, features::kPrefetchReusable}, {});
scoped_feature_list.InitWithFeatures({features::kPrefetchReusable}, {});
base::HistogramTester histogram_tester;
@ -7118,7 +6967,7 @@ TEST_P(PrefetchServiceTest,
// this test actually.)
// - The eligibility check of A scceeds. Matching process proceeds and ends as
// success.
TEST_P(PrefetchServiceTest,
TEST_F(PrefetchServiceTest,
DISABLED_CHROMEOS(PrefetchAheadOfPrerenderSuccess)) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatures(
@ -7205,7 +7054,7 @@ TEST_P(PrefetchServiceTest,
// (Regard X as prerender, while we don't assume that in this test actually.)
// - The eligibility check of A failed (due to non https). Matching process ends
// with no prefetch.
TEST_P(PrefetchServiceTest,
TEST_F(PrefetchServiceTest,
DISABLED_CHROMEOS(PrefetchAheadOfPrerenderIneligible)) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatures(
@ -7260,7 +7109,7 @@ TEST_P(PrefetchServiceTest,
// `PrefetchContainer::UpdateServingPageMetrics()`.
}
TEST_P(PrefetchServiceTest,
TEST_F(PrefetchServiceTest,
DISABLED_CHROMEOS(IsPrefetchDuplicateSameNoVarySearchHint)) {
base::test::ScopedFeatureList scoped_feature_list(
features::kPrefetchBrowserInitiatedTriggers);
@ -7306,7 +7155,6 @@ TEST_P(PrefetchServiceTest,
class PrefetchServiceAddPrefetchContainerTest : public PrefetchServiceTestBase {
public:
void InitScopedFeatureList() override {
InitScopedFeatureListForNewWaitLoop(true);
PrefetchServiceTestBase::InitScopedFeatureList();
scoped_feature_list_for_prerender2_fallback_.InitWithFeatures(

@ -97,10 +97,8 @@ void MakeServableStreamingURLLoaderForTest(
network::mojom::URLResponseHeadPtr response_head) {
NOTREACHED();
}),
UseNewWaitLoop() ? base::BindOnce(&PrefetchContainer::OnDeterminedHead2,
prefetch_container->GetWeakPtr())
: base::BindOnce(&PrefetchContainer::OnDeterminedHead,
prefetch_container->GetWeakPtr()),
base::BindOnce(&PrefetchContainer::OnDeterminedHead2,
prefetch_container->GetWeakPtr()),
weak_response_reader);
prefetch_container->SetStreamingURLLoader(weak_streaming_loader);
@ -146,10 +144,8 @@ MakeManuallyServableStreamingURLLoaderForTest(
network::mojom::URLResponseHeadPtr response_head) {
NOTREACHED();
}),
UseNewWaitLoop() ? base::BindOnce(&PrefetchContainer::OnDeterminedHead2,
prefetch_container->GetWeakPtr())
: base::BindOnce(&PrefetchContainer::OnDeterminedHead,
prefetch_container->GetWeakPtr()),
base::BindOnce(&PrefetchContainer::OnDeterminedHead2,
prefetch_container->GetWeakPtr()),
prefetch_container->GetResponseReaderForCurrentPrefetch());
prefetch_container->SetStreamingURLLoader(weak_streaming_loader);
@ -216,10 +212,8 @@ void MakeServableStreamingURLLoaderWithRedirectForTest(
&on_response_complete_loop),
CreatePrefetchRedirectCallbackForTest(&on_receive_redirect_loop,
&redirect_info, &redirect_head),
UseNewWaitLoop() ? base::BindOnce(&PrefetchContainer::OnDeterminedHead2,
prefetch_container->GetWeakPtr())
: base::BindOnce(&PrefetchContainer::OnDeterminedHead,
prefetch_container->GetWeakPtr()),
base::BindOnce(&PrefetchContainer::OnDeterminedHead2,
prefetch_container->GetWeakPtr()),
weak_first_response_reader);
prefetch_container->SetStreamingURLLoader(weak_streaming_loader);
@ -296,10 +290,8 @@ void MakeServableStreamingURLLoadersWithNetworkTransitionRedirectForTest(
}),
CreatePrefetchRedirectCallbackForTest(&on_receive_redirect_loop,
&redirect_info, &redirect_head),
UseNewWaitLoop() ? base::BindOnce(&PrefetchContainer::OnDeterminedHead2,
prefetch_container->GetWeakPtr())
: base::BindOnce(&PrefetchContainer::OnDeterminedHead,
prefetch_container->GetWeakPtr()),
base::BindOnce(&PrefetchContainer::OnDeterminedHead2,
prefetch_container->GetWeakPtr()),
prefetch_container->GetResponseReaderForCurrentPrefetch());
prefetch_container->SetStreamingURLLoader(weak_first_streaming_loader);
@ -360,11 +352,8 @@ void MakeServableStreamingURLLoadersWithNetworkTransitionRedirectForTest(
network::mojom::URLResponseHeadPtr response_head) {
NOTREACHED();
}),
UseNewWaitLoop()
? base::BindOnce(&PrefetchContainer::OnDeterminedHead2,
prefetch_container->GetWeakPtr())
: base::BindOnce(&PrefetchContainer::OnDeterminedHead,
prefetch_container->GetWeakPtr()),
base::BindOnce(&PrefetchContainer::OnDeterminedHead2,
prefetch_container->GetWeakPtr()),
weak_second_response_reader);
prefetch_container->SetStreamingURLLoader(weak_second_streaming_loader);

@ -88,28 +88,11 @@ void PrefetchURLLoaderInterceptor::MaybeCreateLoader(
PrefetchContainer* prefetch_container =
redirect_reader_.GetPrefetchContainer();
CHECK(prefetch_container);
if (UseNewWaitLoop()) {
// Use `std::nullopt` as we need to record the crash key to identify
// which case in `PrefetchMatchResolver2` is the cause.
prefetch_container->OnDetectedCookiesChange2(
/*is_unblock_for_cookies_changed_triggered_by_this_prefetch_container*/
std::nullopt);
} else {
// Note: This method can only be called once per PrefetchContainer (we
// have a CHECK in the method). This is guaranteed to be the first time
// we call this method for |prefetch_container|, as the other callsite
// (in PrefetchService::ReturnPrefetchToServe) would have prevented the
// prefetch from being used to serve the navigation (making this
// unreachable as |redirect_reader_| would never have been set to
// |prefetch_container|). This will also never be called for
// |prefetch_container| again as we don't use it to serve any subsequent
// redirect hops for this navigation (we unset |redirect_reader_|
// below), and
// |PrefetchService::CollectMatchCandidates|
// ignores any prefetches with the status kPrefetchNotUsedCookiesChanged
// (which is set in |PrefetchContainer::OnDetectedCookiesChange|).
prefetch_container->OnDetectedCookiesChange();
}
// Use `std::nullopt` as we need to record the crash key to identify
// which case in `PrefetchMatchResolver2` is the cause.
prefetch_container->OnDetectedCookiesChange2(
/*is_unblock_for_cookies_changed_triggered_by_this_prefetch_container*/
std::nullopt);
} else {
OnGotPrefetchToServe(
frame_tree_node_id_, tentative_resource_request.url,
@ -140,28 +123,14 @@ void PrefetchURLLoaderInterceptor::MaybeCreateLoader(
return;
}
// During the lifetime of the PrefetchUrlLoaderInterceptor there is only one
// cross-document navigation waiting for its final response.
// We only need to worry about one active navigation while trying to match
// prefetch_container in PrefetchService.
// This navigation is represented by `prefetch_match_resolver`.
// See documentation here as why this is true:
// https://chromium.googlesource.com/chromium/src/+/main/docs/navigation_concepts.md#concurrent-navigations
NavigationRequest* navigation_request = frame_tree_node->navigation_request();
PrefetchMatchResolver::CreateForNavigationHandle(*navigation_request);
PrefetchMatchResolver* prefetch_match_resolver =
PrefetchMatchResolver::GetForNavigationHandle(*navigation_request);
CHECK(prefetch_match_resolver);
GetPrefetch(
tentative_resource_request, *prefetch_match_resolver,
tentative_resource_request,
base::BindOnce(&PrefetchURLLoaderInterceptor::OnGetPrefetchComplete,
weak_factory_.GetWeakPtr()));
}
void PrefetchURLLoaderInterceptor::GetPrefetch(
const network::ResourceRequest& tentative_resource_request,
PrefetchMatchResolver& prefetch_match_resolver,
base::OnceCallback<void(PrefetchContainer::Reader)> get_prefetch_callback)
const {
TRACE_EVENT0("loading", "PrefetchURLLoaderInterceptor::GetPrefetch");
@ -191,7 +160,6 @@ void PrefetchURLLoaderInterceptor::GetPrefetch(
auto key = PrefetchContainer::Key(initiator_document_token_,
tentative_resource_request_url);
if (UseNewWaitLoop()) {
const bool is_nav_prerender = [&]() -> bool {
auto* frame_tree_node =
FrameTreeNode::GloballyFindByID(frame_tree_node_id_);
@ -205,13 +173,6 @@ void PrefetchURLLoaderInterceptor::GetPrefetch(
PrefetchMatchResolver2::FindPrefetch(
std::move(key), is_nav_prerender, *prefetch_service,
serving_page_metrics_container_, std::move(callback));
} else {
prefetch_match_resolver.SetOnPrefetchToServeReadyCallback(
std::move(callback));
prefetch_service->GetPrefetchToServe(std::move(key),
serving_page_metrics_container_,
prefetch_match_resolver);
}
}
void PrefetchURLLoaderInterceptor::OnGetPrefetchComplete(

@ -21,7 +21,6 @@ namespace content {
class BrowserContext;
class PrefetchContainer;
class PrefetchMatchResolver;
using PrefetchCompleteCallbackForTesting =
base::RepeatingCallback<void(PrefetchContainer*)>;
@ -62,13 +61,7 @@ class CONTENT_EXPORT PrefetchURLLoaderInterceptor final
// from `PrefetchService` and then goes through other checks in
// `PrefetchUrlLoaderHelper`.
// The |get_prefetch_callback| is called with this associated prefetch.
// TODO(crbug.com/40274818): It might be better to store
// PrefetchMatchResolver as part of PrefetchUrlLoaderInterceptor
// as this is related to serving a navigation. It would simplify GetPrefetch
// call.
void GetPrefetch(const network::ResourceRequest& tentative_resource_request,
PrefetchMatchResolver& potential_prefetch_matches_container,
base::OnceCallback<void(PrefetchContainer::Reader)>
get_prefetch_callback) const;

@ -460,13 +460,11 @@ namespace {
class PrefetchURLLoaderInterceptorTest
: public PrefetchURLLoaderInterceptorTestBase,
public ::testing::WithParamInterface<
std::tuple<PrefetchReusableForTests,
/*should_enable_new_wait_loop*/ bool>> {
public ::testing::WithParamInterface<PrefetchReusableForTests> {
void SetUp() override {
PrefetchURLLoaderInterceptorTestBase::SetUp();
switch (std::get<0>(GetParam())) {
switch (GetParam()) {
case PrefetchReusableForTests::kDisabled:
scoped_feature_list_for_reusable_.InitAndDisableFeature(
features::kPrefetchReusable);
@ -476,22 +474,13 @@ class PrefetchURLLoaderInterceptorTest
features::kPrefetchReusable);
break;
}
if (std::get<1>(GetParam())) {
scoped_feature_list_for_new_wait_loop_.InitAndEnableFeature(
features::kPrefetchNewWaitLoop);
} else {
scoped_feature_list_for_new_wait_loop_.InitAndDisableFeature(
features::kPrefetchNewWaitLoop);
}
}
};
INSTANTIATE_TEST_SUITE_P(
/* no prefix */,
PrefetchURLLoaderInterceptorTest,
testing::Combine(testing::ValuesIn(PrefetchReusableValuesForTests()),
testing::Bool()));
testing::ValuesIn(PrefetchReusableValuesForTests()));
TEST_P(PrefetchURLLoaderInterceptorTest,
DISABLE_ASAN(InterceptNavigationCookieCopyCompleted)) {
@ -1096,7 +1085,6 @@ class PrefetchURLLoaderInterceptorBecomeNotServableTest
: public PrefetchURLLoaderInterceptorTestBase,
public ::testing::WithParamInterface<
std::tuple<PrefetchReusableForTests,
/*should_enable_new_wait_loop*/ bool,
NotServableReason>> {
void SetUp() override {
PrefetchURLLoaderInterceptorTestBase::SetUp();
@ -1111,14 +1099,6 @@ class PrefetchURLLoaderInterceptorBecomeNotServableTest
features::kPrefetchReusable);
break;
}
if (std::get<1>(GetParam())) {
scoped_feature_list_for_new_wait_loop_.InitAndEnableFeature(
features::kPrefetchNewWaitLoop);
} else {
scoped_feature_list_for_new_wait_loop_.InitAndDisableFeature(
features::kPrefetchNewWaitLoop);
}
}
};
@ -1189,7 +1169,7 @@ TEST_P(PrefetchURLLoaderInterceptorBecomeNotServableTest, DISABLE_ASAN(Basic)) {
// Simulate the prefetch becoming not servable anymore.
PrefetchRequestHandler another_request;
switch (std::get<2>(GetParam())) {
switch (std::get<1>(GetParam())) {
case NotServableReason::kOnCompleteFailure:
producer_handle.reset();
pending_request.client->OnComplete(
@ -1236,7 +1216,7 @@ TEST_P(PrefetchURLLoaderInterceptorBecomeNotServableTest, DISABLE_ASAN(Basic)) {
EXPECT_TRUE(was_intercepted(kTestUrl).has_value());
switch (std::get<2>(GetParam())) {
switch (std::get<1>(GetParam())) {
case NotServableReason::kOnCompleteFailure:
EXPECT_FALSE(was_intercepted(kTestUrl).value());
ExpectCorrectUkmLogs({.is_accurate = true}, kTestUrl);
@ -1283,7 +1263,6 @@ INSTANTIATE_TEST_SUITE_P(
PrefetchURLLoaderInterceptorBecomeNotServableTest,
testing::Combine(
testing::ValuesIn(PrefetchReusableValuesForTests()),
testing::Bool(),
testing::Values(NotServableReason::kOnCompleteFailure,
NotServableReason::kAnotherRequest,
NotServableReason::kAnotherRequestCompleted)));

@ -17854,26 +17854,6 @@
]
}
],
"PrefetchNewWaitLoop": [
{
"platforms": [
"android",
"android_webview",
"chromeos",
"linux",
"mac",
"windows"
],
"experiments": [
{
"name": "Enabled_20240909",
"enable_features": [
"PrefetchNewWaitLoop"
]
}
]
}
],
"PrefetchProxyDesktop": [
{
"platforms": [
@ -17906,7 +17886,6 @@
{
"name": "Enabled_20250129",
"params": {
"PrefetchReusableUseNewWaitLoop": "true",
"prefetch_reusable_body_size_limit": "4194304"
},
"enable_features": [

@ -3004,7 +3004,6 @@ crbug.com/376770788 [ Mac13 ] external/wpt/webcodecs/per-frame-qp-encoding.https
crbug.com/377072733 [ Win11-arm64 ] external/wpt/webrtc/RTCDataChannel-send-close.html [ Skip Timeout ]
crbug.com/376770788 [ Win11-arm64 ] virtual/shared-storage-fenced-frame-mparch/external/wpt/shared-storage/shared-storage-writable-service-worker-iframe.tentative.https.sub.html [ Timeout ]
[ Win11-arm64 ] virtual/fenced-frame-mparch-internal/wpt_internal/fenced_frame/unpartitioned-storage-permissions-policy-self.tentative.https.sub.html [ Timeout ]
crbug.com/40263108 [ Win11-arm64 ] virtual/prefetch-new-wait-loop/external/wpt/speculation-rules/prefetch/out-of-document-rule-set.https.html?include=InvalidUrlForSpeculationRulesSet [ Timeout ]
[ Win11-arm64 ] virtual/fenced-frame-mparch-internal/wpt_internal/fenced_frame/unpartitioned-storage-permissions-policy-none.tentative.https.sub.html [ Timeout ]
crbug.com/376515525 external/wpt/css/css-text/line-breaking/segment-break-transformation-ignorable-1.html [ Failure ]
crbug.com/376126805 [ Mac13 ] external/wpt/webcodecs/per-frame-qp-encoding.https.any.worker.html?vp9_p0 [ Timeout ]
@ -3253,7 +3252,6 @@ crbug.com/345868498 [ Mac14 ] external/wpt/xhr/event-loadstart.any.html [ Timeou
crbug.com/345868498 [ Mac14 ] external/wpt/xhr/send-data-blob.htm [ Timeout ]
crbug.com/345868498 [ Mac14 ] external/wpt/xhr/send-usp.any.worker.html [ Timeout ]
crbug.com/358041221 [ Mac14 ] virtual/prefetch-reusable/external/wpt/speculation-rules/prefetch/no-vary-search/prefetch-single-with-hint.https.html?22-22 [ Timeout ]
crbug.com/358041221 [ Mac14 ] virtual/prefetch-new-wait-loop/external/wpt/speculation-rules/prefetch/no-vary-search/prefetch-single-with-hint.https.html?22-22 [ Timeout ]
crbug.com/345868499 [ Mac14 ] virtual/scalefactor200/external/wpt/css/filter-effects/effect-reference-lighting-no-light.tentative.html [ Failure Timeout ]
crbug.com/345585682 external/wpt/html/rendering/widgets/input-number-text-size.tentative.html [ Failure ]
crbug.com/343886935 external/wpt/webrtc/RTCPeerConnection-addTcpIceCandidate.html [ Skip Timeout ]
@ -4678,8 +4676,6 @@ crbug.com/40854799 virtual/prefetch/http/tests/inspector-protocol/prefetch/reque
crbug.com/40854799 virtual/prefetch/http/tests/inspector-protocol/prefetch/request-will-be-sent-redirect.https.js [ Failure Pass ]
crbug.com/40854799 virtual/prefetch-reusable/http/tests/inspector-protocol/prefetch/request-will-be-sent.https.js [ Failure Pass ]
crbug.com/40854799 virtual/prefetch-reusable/http/tests/inspector-protocol/prefetch/request-will-be-sent-redirect.https.js [ Failure Pass ]
crbug.com/40854799 virtual/prefetch-new-wait-loop/http/tests/inspector-protocol/prefetch/request-will-be-sent.https.js [ Failure Pass ]
crbug.com/40854799 virtual/prefetch-new-wait-loop/http/tests/inspector-protocol/prefetch/request-will-be-sent-redirect.https.js [ Failure Pass ]
crbug.com/40854799 virtual/prerender2-fallback-prefetch-spec-rules-prefetch/http/tests/inspector-protocol/prefetch/request-will-be-sent.https.js [ Failure Pass ]
crbug.com/40854799 virtual/prerender2-fallback-prefetch-spec-rules-prefetch/http/tests/inspector-protocol/prefetch/request-will-be-sent-redirect.https.js [ Failure Pass ]
@ -7663,7 +7659,6 @@ crbug.com/326065972 [ Win11-arm64 ] external/wpt/webrtc-encoded-transform/tentat
crbug.com/326067001 [ Win11-arm64 ] external/wpt/fedcm/fedcm-authz/fedcm-userinfo-after-resolve.https.html [ Failure Pass Timeout ] # Flaky
crbug.com/326067598 [ Win11-arm64 ] virtual/fenced-frame-mparch/external/wpt/fenced-frame/set-automatic-beacon.https.html [ Failure Pass Timeout ] # Flaky
crbug.com/326066872 [ Win11-arm64 ] virtual/prefetch-reusable/external/wpt/speculation-rules/prefetch/navigation-timing-requestStart-responseStart.https.html?prefetch=true [ Failure Pass Timeout ] # Flaky
crbug.com/326066872 [ Win11-arm64 ] virtual/prefetch-new-wait-loop/external/wpt/speculation-rules/prefetch/navigation-timing-requestStart-responseStart.https.html?prefetch=true [ Failure Pass Timeout ] # Flaky
crbug.com/40943541 [ Win11-arm64 ] external/wpt/webtransport/echo-large-bidirectional-streams.https.any.html [ Failure Pass Timeout ] # Flaky
crbug.com/326123298 virtual/third-party-cookie-phaseout-enabled/external/wpt/cookies/third-party-cookies/third-party-cookie-heuristics.tentative.https.html [ Failure Pass Timeout ]

@ -1658,21 +1658,6 @@
],
"expires": "Oct 1, 2025"
},
{
"prefix": "prefetch-new-wait-loop",
"owners": ["kenoss@chromium.org"],
"platforms": ["Linux", "Mac", "Win"],
"bases": [
"external/wpt/speculation-rules/prefetch",
"http/tests/inspector-protocol/prefetch"
],
"exclusive_tests": "ALL",
"args": [
"--enable-features=PrefetchUseContentRefactor:block_until_head_eager_prefetch/true/block_until_head_timeout_eager_prefetch/0,PrefetchCookieIndices,CookieIndicesHeader,PrefetchNewWaitLoop,ExemptSpeculationRulesHeaderFromCSP",
"--bypass-prefetch-proxy-for-host=not-web-platform.test"
],
"expires": "March 9, 2025"
},
{
"prefix": "prefetch-no-vary-search",
"owners": ["jbroman@chromium.org", "liviutinta@chromium.org"],

@ -1 +0,0 @@
This directory is for testing kPrefetchNewWaitLoop feature of speculation-rule based prefetch. crbug.com/365467850

@ -38,31 +38,6 @@ chromium-metrics-reviews@google.com.
<variant name="Served" summary="served"/>
</variants>
<histogram
name="PrefetchProxy.AfterClick.BlockUntilHeadDuration.{WasServed}.{SpeculationEagerness}"
units="ms" expires_after="2025-07-13">
<owner>kouhei@chromium.org</owner>
<owner>chrome-loading@chromium.org</owner>
<summary>
If a prefetch request has started but the head of the prefetch response has
not been received yet when a navigation to a URL that matches the prefetch,
then the prefetch service will block until the head of the prefetch response
is received and then decide to serve or not serve the prefetch.
This histogram records the amount of time that the prefetch service blocked
until the head of the prefetch response was received. This histogram is only
recorded for prefetches that are {WasServed} and with an Eagerness of
{SpeculationEagerness}.
Only recorded if `kPrefetchNewWaitLoop` is disabled.
`PrefetchProxy.AfterClick.BlockUntilHeadDuration2.{WasServed}.{SpeculationEagerness}`
is the corresponding metric for the enabled case. This metric will be
removed once `kPrefetchNewWaitLoop` is launched.
</summary>
<token key="WasServed" variants="WasServed"/>
<token key="SpeculationEagerness" variants="SpeculationEagerness"/>
</histogram>
<histogram
name="PrefetchProxy.AfterClick.BlockUntilHeadDuration2.{WasServed}.{SpeculationEagerness}"
units="ms" expires_after="2025-08-10">
@ -83,8 +58,6 @@ chromium-metrics-reviews@google.com.
This histogram is only recorded for prefetches that are {WasServed} and with
an Eagerness of {SpeculationEagerness}.
Only recorded if `kPrefetchNewWaitLoop` is enabled.
</summary>
<token key="WasServed" variants="WasServed"/>
<token key="SpeculationEagerness" variants="SpeculationEagerness"/>
@ -114,8 +87,6 @@ chromium-metrics-reviews@google.com.
PrefetchProxy.AfterClick.BlockUntilHeadDuration2.{WasServed}.{SpeculationEagerness}
is that this is also recorded for non-blocked case (i.e. the blocked
duration is zero).
Only recorded if `kPrefetchNewWaitLoop` is enabled.
</summary>
<token key="WasServed" variants="WasServed"/>
<token key="SpeculationEagerness" variants="SpeculationEagerness"/>
@ -230,8 +201,6 @@ chromium-metrics-reviews@google.com.
This histogram is only for prefetches with an eagerness of
{SpeculationEagerness}.
Only recorded if `kPrefetchNewWaitLoop` is enabled.
</summary>
<token key="SpeculationEagerness" variants="SpeculationEagerness"/>
</histogram>
@ -250,30 +219,6 @@ chromium-metrics-reviews@google.com.
</summary>
</histogram>
<histogram
name="PrefetchProxy.AfterClick.WasBlockedUntilHeadWhenServing.{SpeculationEagerness}"
enum="Boolean" expires_after="2025-07-13">
<owner>kouhei@chromium.org</owner>
<owner>chrome-loading@chromium.org</owner>
<summary>
If a prefetch request has started but the non-redirect header of the
prefetch response has not been received yet when a navigation to a URL that
is expected to matche the prefetch, then the prefetch service will block
until the non-redirect header of the prefetch response is received and then
decide to serve or not serve the prefetch.
This histogram records whether or not prefetch service will block or not for
a prefetch. This histogram is only for prefetches with an Eagerness of
{SpeculationEagerness}.
Only recorded if `kPrefetchNewWaitLoop` is disabled.
`PrefetchProxy.AfterClick.PrefetchMatchingBlockedNavigationWithPrefetch.{SpeculationEagerness}`
is the corresponding metric for the enabled case. This metric will be
removed once `kPrefetchNewWaitLoop` is launched.
</summary>
<token key="SpeculationEagerness" variants="SpeculationEagerness"/>
</histogram>
<histogram name="PrefetchProxy.AfterClick.WasFullRedirectChainServed"
enum="Boolean" expires_after="2025-07-13">
<owner>kouhei@chromium.org</owner>