#include "content/browser/preloading/prefetch/prefetch_params.h"
#include <string>
#include "base/command_line.h"
#include "base/metrics/field_trial_params.h"
#include "base/no_destructor.h"
#include "base/rand_util.h"
#include "base/strings/strcat.h"
#include "content/browser/preloading/prefetch/prefetch_features.h"
#include "content/browser/preloading/prefetch/prefetch_type.h"
#include "content/browser/preloading/preloading_trigger_type_impl.h"
#include "content/browser/preloading/prerender/prerender_features.h"
#include "content/public/common/content_features.h"
namespace content {
GURL PrefetchProxyHost(const GURL& default_proxy_url) {
std::string cmd_line_value =
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
"isolated-prerender-tunnel-proxy");
if (!cmd_line_value.empty()) {
GURL cmd_line_url(cmd_line_value);
if (cmd_line_url.is_valid()) {
return cmd_line_url;
}
LOG(ERROR) << "--isolated-prerender-tunnel-proxy value is invalid";
}
return default_proxy_url;
}
std::string PrefetchProxyServerExperimentGroup() {
return base::GetFieldTrialParamValueByFeature(
features::kPrefetchUseContentRefactor, "server_experiment_group");
}
bool PrefetchAllowAllDomains() {
return base::GetFieldTrialParamByFeatureAsBool(
features::kPrefetchUseContentRefactor, "allow_all_domains",
false) ||
base::CommandLine::ForCurrentProcess()->HasSwitch(
"isolated-prerender-allow-all-domains");
}
bool PrefetchAllowAllDomainsForExtendedPreloading() {
return base::GetFieldTrialParamByFeatureAsBool(
features::kPrefetchUseContentRefactor,
"allow_all_domains_for_extended_preloading", true);
}
bool PrefetchServiceSendDecoyRequestForIneligblePrefetch(
bool disabled_based_on_user_settings) {
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
"prefetch-proxy-never-send-decoy-requests-for-testing")) {
return false;
}
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
"prefetch-proxy-always-send-decoy-requests-for-testing")) {
return true;
}
if (base::GetFieldTrialParamByFeatureAsBool(
features::kPrefetchUseContentRefactor,
"disable_decoys_based_on_user_settings", true) &&
disabled_based_on_user_settings) {
return false;
}
double probability = base::GetFieldTrialParamByFeatureAsDouble(
features::kPrefetchUseContentRefactor,
"ineligible_decoy_request_probability", 1.0);
probability = std::max(0.0, probability);
probability = std::min(1.0, probability);
return base::RandDouble() < probability;
}
base::TimeDelta PrefetchTimeoutDuration() {
return base::Milliseconds(base::GetFieldTrialParamByFeatureAsInt(
features::kPrefetchUseContentRefactor, "prefetch_timeout_ms",
10 * 1000 ));
}
size_t PrefetchMainframeBodyLengthLimit() {
return 1024 * base::GetFieldTrialParamByFeatureAsInt(
features::kPrefetchUseContentRefactor,
"max_mainframe_body_length_kb", 5 * 1024);
}
bool PrefetchStartsSpareRenderer() {
return base::CommandLine::ForCurrentProcess()->HasSwitch(
"isolated-prerender-start-spare-renderer") ||
base::GetFieldTrialParamByFeatureAsBool(
features::kPrefetchUseContentRefactor, "start_spare_renderer",
true);
}
base::TimeDelta PrefetchContainerDefaultTtlInPrefetchService() {
return base::Seconds(base::GetFieldTrialParamByFeatureAsInt(
features::kPrefetchUseContentRefactor, "prefetch_container_lifetime_s",
10 * 60 ));
}
bool PrefetchServiceHTMLOnly() {
return base::GetFieldTrialParamByFeatureAsBool(
features::kPrefetchUseContentRefactor, "html_only", false);
}
bool ShouldPrefetchBypassProxyForTestHost(std::string_view host) {
static const base::NoDestructor<std::string> bypass(
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
"bypass-prefetch-proxy-for-host"));
if (bypass->empty()) {
return false;
}
return host == *bypass;
}
base::TimeDelta PrefetchCacheableDuration() {
return base::Seconds(base::GetFieldTrialParamByFeatureAsInt(
features::kPrefetchUseContentRefactor, "cacheable_duration", 300));
}
bool PrefetchProbingEnabled() {
return base::GetFieldTrialParamByFeatureAsBool(
features::kPrefetchCanaryCheckerParams, "must_probe_origin", true);
}
bool PrefetchCanaryCheckEnabled() {
return base::GetFieldTrialParamByFeatureAsBool(
features::kPrefetchCanaryCheckerParams, "do_canary", true);
}
bool PrefetchTLSCanaryCheckEnabled() {
return base::GetFieldTrialParamByFeatureAsBool(
features::kPrefetchCanaryCheckerParams, "do_tls_canary", false);
}
GURL PrefetchTLSCanaryCheckURL(const GURL& default_tls_canary_check_url) {
GURL url(base::GetFieldTrialParamValueByFeature(
features::kPrefetchCanaryCheckerParams, "tls_canary_url"));
if (url.is_valid())
return url;
return default_tls_canary_check_url;
}
GURL PrefetchDNSCanaryCheckURL(const GURL& default_dns_canary_check_url) {
GURL url(base::GetFieldTrialParamValueByFeature(
features::kPrefetchCanaryCheckerParams, "dns_canary_url"));
if (url.is_valid())
return url;
return default_dns_canary_check_url;
}
base::TimeDelta PrefetchCanaryCheckCacheLifetime() {
return base::Hours(base::GetFieldTrialParamByFeatureAsInt(
features::kPrefetchCanaryCheckerParams, "canary_cache_hours", 24));
}
base::TimeDelta PrefetchCanaryCheckTimeout() {
return base::Milliseconds(base::GetFieldTrialParamByFeatureAsInt(
features::kPrefetchCanaryCheckerParams, "canary_check_timeout_ms",
5 * 1000 ));
}
int PrefetchCanaryCheckRetries() {
return base::GetFieldTrialParamByFeatureAsInt(
features::kPrefetchCanaryCheckerParams, "canary_check_retries", 1);
}
base::TimeDelta PrefetchBlockUntilHeadTimeout(
const PrefetchType& prefetch_type,
bool should_disable_block_until_head_timeout,
bool is_nav_prerender) {
if (should_disable_block_until_head_timeout) {
return base::Seconds(0);
}
if (!features::kPrerender2FallbackPrefetchUseBlockUntilHeadTimetout.Get() &&
is_nav_prerender) {
return base::Seconds(0);
}
int timeout_in_milliseconds = 0;
if (IsSpeculationRuleType(prefetch_type.trigger_type())) {
switch (prefetch_type.GetEagerness()) {
case blink::mojom::SpeculationEagerness::kImmediate:
timeout_in_milliseconds = base::GetFieldTrialParamByFeatureAsInt(
features::kPrefetchUseContentRefactor,
"block_until_head_timeout_immediate_prefetch", 1000);
break;
case blink::mojom::SpeculationEagerness::kEager:
timeout_in_milliseconds = base::GetFieldTrialParamByFeatureAsInt(
features::kPrefetchUseContentRefactor,
"block_until_head_timeout_eager_prefetch", 1000);
break;
case blink::mojom::SpeculationEagerness::kModerate:
timeout_in_milliseconds = base::GetFieldTrialParamByFeatureAsInt(
features::kPrefetchUseContentRefactor,
"block_until_head_timeout_moderate_prefetch", 0);
break;
case blink::mojom::SpeculationEagerness::kConservative:
timeout_in_milliseconds = base::GetFieldTrialParamByFeatureAsInt(
features::kPrefetchUseContentRefactor,
"block_until_head_timeout_conservative_prefetch", 0);
break;
}
} else {
timeout_in_milliseconds = base::GetFieldTrialParamByFeatureAsInt(
features::kPrefetchUseContentRefactor,
"block_until_head_timeout_embedder_prefetch", 1000);
}
return base::Milliseconds(timeout_in_milliseconds);
}
std::string GetMetricsSuffixTriggerTypeAndEagerness(
const PrefetchType prefetch_type,
const std::optional<std::string>& embedder_histogram_suffix) {
switch (prefetch_type.trigger_type()) {
case PreloadingTriggerType::kSpeculationRule:
switch (prefetch_type.GetEagerness()) {
case blink::mojom::SpeculationEagerness::kImmediate:
return "SpeculationRule_Immediate2";
case blink::mojom::SpeculationEagerness::kEager:
return "SpeculationRule_Eager2";
case blink::mojom::SpeculationEagerness::kModerate:
return "SpeculationRule_Moderate";
case blink::mojom::SpeculationEagerness::kConservative:
return "SpeculationRule_Conservative";
}
case PreloadingTriggerType::kSpeculationRuleFromIsolatedWorld:
switch (prefetch_type.GetEagerness()) {
case blink::mojom::SpeculationEagerness::kImmediate:
return "SpeculationRule_Immediate2";
case blink::mojom::SpeculationEagerness::kEager:
return "SpeculationRule_Eager2";
case blink::mojom::SpeculationEagerness::kModerate:
return "SpeculationRuleFromIsolatedWorld_Moderate";
case blink::mojom::SpeculationEagerness::kConservative:
return "SpeculationRuleFromIsolatedWorld_Conservative";
}
case PreloadingTriggerType::kSpeculationRuleFromAutoSpeculationRules:
switch (prefetch_type.GetEagerness()) {
case blink::mojom::SpeculationEagerness::kImmediate:
return "SpeculationRule_Immediate2";
case blink::mojom::SpeculationEagerness::kEager:
return "SpeculationRule_Eager2";
case blink::mojom::SpeculationEagerness::kModerate:
return "SpeculationRuleFromAutoSpeculationRules_Moderate";
case blink::mojom::SpeculationEagerness::kConservative:
return "SpeculationRuleFromAutoSpeculationRules_Conservative";
}
case PreloadingTriggerType::kEmbedder:
CHECK(!embedder_histogram_suffix.value().empty());
return base::StrCat({"Embedder_", embedder_histogram_suffix.value()});
}
}
bool PrefetchNIKScopeEnabled() {
return base::FeatureList::IsEnabled(features::kPrefetchNIKScope);
}
size_t GetPrefetchDataPipeTeeBodySizeLimit() {
return static_cast<size_t>(features::kPrefetchReusableBodySizeLimit.Get());
}
bool UsePrefetchScheduler() {
return base::FeatureList::IsEnabled(features::kPrefetchScheduler) ||
features::kPrerender2FallbackPrefetchSchedulerPolicy.Get() !=
features::Prerender2FallbackPrefetchSchedulerPolicy::kNotUse ||
base::FeatureList::IsEnabled(
features::kWebViewPrefetchHighestPrefetchPriority) ||
base::FeatureList::IsEnabled(
features::kPrefetchMultipleActiveSetSizeLimitForBase);
}
}