Commit 61c4f2cb authored by Robert Ogden's avatar Robert Ogden Committed by Commit Bot

Add support of max number of fetches during Isolated Prerender NSP

Every NSP has its own URLLoaderFactory, so this CL adds a simple
counter to that class and when the max is reached, sends
ERR_FAILED to all further requests.

Bug: 1127120
Change-Id: I14b8509bdd2c3a0de371675bfe37520c26fc8064
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2404157Reviewed-by: default avatarRyan Sturm <ryansturm@chromium.org>
Commit-Queue: Robert Ogden <robertogden@chromium.org>
Cr-Commit-Position: refs/heads/master@{#806246}
parent bde814dc
......@@ -29,6 +29,7 @@
#include "chrome/browser/net/profile_network_context_service_factory.h"
#include "chrome/browser/prerender/isolated/isolated_prerender_features.h"
#include "chrome/browser/prerender/isolated/isolated_prerender_origin_prober.h"
#include "chrome/browser/prerender/isolated/isolated_prerender_params.h"
#include "chrome/browser/prerender/isolated/isolated_prerender_proxy_configurator.h"
#include "chrome/browser/prerender/isolated/isolated_prerender_service.h"
#include "chrome/browser/prerender/isolated/isolated_prerender_service_factory.h"
......@@ -2816,6 +2817,60 @@ IN_PROC_BROWSER_TEST_F(IsolatedPrerenderWithNSPBrowserTest,
origin_requests_after_prerender.size());
}
IN_PROC_BROWSER_TEST_F(IsolatedPrerenderWithNSPBrowserTest,
DISABLE_ON_WIN_MAC_CHROMEOS(LimitSubresourceCount)) {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
"isolated-prerender-unlimited-prefetches");
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
kIsolatedPrerenderLimitNSPSubresourcesCmdLineFlag, "1");
SetDataSaverEnabled(true);
GURL starting_page = GetOriginServerURL("/simple.html");
ui_test_utils::NavigateToURL(browser(), starting_page);
WaitForUpdatedCustomProxyConfig();
IsolatedPrerenderTabHelper* tab_helper =
IsolatedPrerenderTabHelper::FromWebContents(GetWebContents());
GURL eligible_link =
GetOriginServerURL("/prerender/isolated/prefetch_page.html");
TestTabHelperObserver tab_helper_observer(tab_helper);
tab_helper_observer.SetExpectedSuccessfulURLs({eligible_link});
base::RunLoop prefetch_run_loop;
base::RunLoop nsp_run_loop;
tab_helper_observer.SetOnPrefetchSuccessfulClosure(
prefetch_run_loop.QuitClosure());
tab_helper_observer.SetOnNSPFinishedClosure(nsp_run_loop.QuitClosure());
GURL doc_url("https://www.google.com/search?q=test");
MakeNavigationPrediction(doc_url, {eligible_link});
// This run loop will quit when a NSP finishes.
nsp_run_loop.Run();
base::HistogramTester histogram_tester;
// Navigate to the predicted site.
ui_test_utils::NavigateToURL(browser(), eligible_link);
// Checks that only one resource was used from cache.
histogram_tester.ExpectUniqueSample(
"IsolatedPrerender.AfterClick.Subresources.UsedCache", true, 1);
// Navigate again to trigger UKM recording.
ui_test_utils::NavigateToURL(browser(), GURL("about:blank"));
// 16 = |PrefetchStatus::kPrefetchUsedNoProbeWithNSP|.
EXPECT_EQ(base::Optional<int64_t>(16),
GetUKMMetric(eligible_link,
ukm::builders::PrefetchProxy_AfterSRPClick::kEntryName,
ukm::builders::PrefetchProxy_AfterSRPClick::
kSRPClickPrefetchStatusName));
}
class ProbingAndNSPEnabledIsolatedPrerenderBrowserTest
: public IsolatedPrerenderBrowserTest {
public:
......
......@@ -9,10 +9,14 @@
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/metrics/field_trial_params.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/prerender/isolated/isolated_prerender_features.h"
#include "chrome/common/chrome_features.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
const char kIsolatedPrerenderLimitNSPSubresourcesCmdLineFlag[] =
"isolated-prerender-max-subresource-per-prerender";
const char kIsolatedPrerenderEnableNSPCmdLineFlag[] =
"isolated-prerender-nsp-enabled";
......@@ -138,3 +142,17 @@ bool IsolatedPrerenderMustHTTPProbeInsteadOfTLS() {
features::kIsolatePrerendersMustProbeOrigin, "replace_tls_with_http",
false);
}
size_t IsolatedPrerenderMaxSubresourcesPerPrerender() {
std::string cmd_line_value =
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
kIsolatedPrerenderLimitNSPSubresourcesCmdLineFlag);
size_t cmd_line_parsed;
if (!cmd_line_value.empty() &&
base::StringToSizeT(cmd_line_value, &cmd_line_parsed)) {
return cmd_line_parsed;
}
return base::GetFieldTrialParamByFeatureAsInt(
features::kIsolatePrerenders, "max_subresource_count_per_prerender", 50);
}
......@@ -14,6 +14,10 @@
// This command line flag enables NoStatePrefetch on Isolated Prerenders.
extern const char kIsolatedPrerenderEnableNSPCmdLineFlag[];
// Overrides the value returned by
// |IsolatedPrerenderMaxSubresourcesPerPrerender| when a valid long is given.
extern const char kIsolatedPrerenderLimitNSPSubresourcesCmdLineFlag[];
// Returns true if the Isolated Prerender feature is enabled.
bool IsolatedPrerenderIsEnabled();
......@@ -66,4 +70,7 @@ base::TimeDelta IsolatedPrerenderCanaryCheckCacheLifetime();
// Experimental control to replace TLS probing with HTTP.
bool IsolatedPrerenderMustHTTPProbeInsteadOfTLS();
// The maximum number of subresources that will be fetched per prefetched page.
size_t IsolatedPrerenderMaxSubresourcesPerPrerender();
#endif // CHROME_BROWSER_PRERENDER_ISOLATED_ISOLATED_PRERENDER_PARAMS_H_
......@@ -10,9 +10,12 @@
#include "base/metrics/histogram.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "chrome/browser/prerender/isolated/isolated_prerender_params.h"
#include "chrome/browser/prerender/isolated/isolated_prerender_tab_helper.h"
#include "chrome/browser/profiles/profile.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_constants.h"
#include "mojo/public/cpp/bindings/receiver.h"
......@@ -271,6 +274,49 @@ void IsolatedPrerenderProxyingURLLoaderFactory::InProgressRequest::
profile_, redirect_chain_, on_resource_load_successful_);
}
IsolatedPrerenderProxyingURLLoaderFactory::AbortRequest::~AbortRequest() =
default;
IsolatedPrerenderProxyingURLLoaderFactory::AbortRequest::AbortRequest(
mojo::PendingReceiver<network::mojom::URLLoader> loader_receiver,
mojo::PendingRemote<network::mojom::URLLoaderClient> client)
: target_client_(std::move(client)),
loader_receiver_(this, std::move(loader_receiver)) {
loader_receiver_.set_disconnect_handler(base::BindOnce(
&IsolatedPrerenderProxyingURLLoaderFactory::AbortRequest::OnBindingClosed,
base::Unretained(this)));
// PostTask the failure to get it out of this message loop, allowing the mojo
// pipes to settle in.
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(
&IsolatedPrerenderProxyingURLLoaderFactory::AbortRequest::Abort,
weak_factory_.GetWeakPtr()));
}
void IsolatedPrerenderProxyingURLLoaderFactory::AbortRequest::Abort() {
target_client_->OnComplete(
network::URLLoaderCompletionStatus(net::ERR_FAILED));
}
void IsolatedPrerenderProxyingURLLoaderFactory::AbortRequest::FollowRedirect(
const std::vector<std::string>& removed_headers,
const net::HttpRequestHeaders& modified_headers,
const net::HttpRequestHeaders& modified_cors_exempt_headers,
const base::Optional<GURL>& new_url) {}
void IsolatedPrerenderProxyingURLLoaderFactory::AbortRequest::SetPriority(
net::RequestPriority priority,
int32_t intra_priority_value) {}
void IsolatedPrerenderProxyingURLLoaderFactory::AbortRequest::
PauseReadingBodyFromNet() {}
void IsolatedPrerenderProxyingURLLoaderFactory::AbortRequest::
ResumeReadingBodyFromNet() {}
void IsolatedPrerenderProxyingURLLoaderFactory::AbortRequest::
OnBindingClosed() {
delete this;
}
IsolatedPrerenderProxyingURLLoaderFactory::
IsolatedPrerenderProxyingURLLoaderFactory(
int frame_tree_node_id,
......@@ -332,9 +378,18 @@ void IsolatedPrerenderProxyingURLLoaderFactory::CreateLoaderAndStart(
// If this request is happening during a prerender then check if it is
// eligible for caching before putting it on the network.
if (ShouldHandleRequestForPrerender()) {
// Check if this prerender has exceeded its max number of subresources.
request_count_++;
if (request_count_ > IsolatedPrerenderMaxSubresourcesPerPrerender()) {
std::unique_ptr<AbortRequest> request = std::make_unique<AbortRequest>(
std::move(loader_receiver), std::move(client));
// The request will manage its own lifecycle based on the mojo pipes.
request.release();
return;
}
// We must check if the request can be cached and set the appropriate load
// flag if so.
IsolatedPrerenderTabHelper::CheckEligibilityOfURL(
profile, request.url,
base::BindOnce(
......
......@@ -153,18 +153,50 @@ class IsolatedPrerenderProxyingURLLoaderFactory
// There are the mojo pipe endpoints between this proxy and the renderer.
// Messages received by |client_receiver_| are forwarded to
// |target_client_|.
mojo::Receiver<network::mojom::URLLoaderClient> client_receiver_{this};
mojo::Remote<network::mojom::URLLoaderClient> target_client_;
mojo::Receiver<network::mojom::URLLoader> loader_receiver_;
// These are the mojo pipe endpoints between this proxy and the network
// process. Messages received by |loader_receiver_| are forwarded to
// |target_loader_|.
mojo::Receiver<network::mojom::URLLoader> loader_receiver_;
mojo::Remote<network::mojom::URLLoader> target_loader_;
mojo::Receiver<network::mojom::URLLoaderClient> client_receiver_{this};
DISALLOW_COPY_AND_ASSIGN(InProgressRequest);
};
// Terminates the request when constructed.
class AbortRequest : public network::mojom::URLLoader {
public:
AbortRequest(
mojo::PendingReceiver<network::mojom::URLLoader> loader_receiver,
mojo::PendingRemote<network::mojom::URLLoaderClient> client);
~AbortRequest() override;
// network::mojom::URLLoader:
void FollowRedirect(
const std::vector<std::string>& removed_headers,
const net::HttpRequestHeaders& modified_headers,
const net::HttpRequestHeaders& modified_cors_exempt_headers,
const base::Optional<GURL>& new_url) override;
void SetPriority(net::RequestPriority priority,
int32_t intra_priority_value) override;
void PauseReadingBodyFromNet() override;
void ResumeReadingBodyFromNet() override;
private:
void OnBindingClosed();
void Abort();
// There are the mojo pipe endpoints between this proxy and the renderer.
mojo::Remote<network::mojom::URLLoaderClient> target_client_;
mojo::Receiver<network::mojom::URLLoader> loader_receiver_;
base::WeakPtrFactory<AbortRequest> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(AbortRequest);
};
// Used as a callback for determining the eligibility of a resource to be
// cached during prerender.
void OnEligibilityResult(
......@@ -208,6 +240,10 @@ class IsolatedPrerenderProxyingURLLoaderFactory
std::set<std::unique_ptr<InProgressRequest>, base::UniquePtrComparator>
requests_;
// Tracks how many requests the prerender has made in order to limit the
// number of subresources that can be prefetched by one page.
size_t request_count_ = 0;
// The network process URLLoaderFactory.
mojo::Remote<network::mojom::URLLoaderFactory> network_process_factory_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment