blob: df686ed45c7bf6ebbaca63b48e4e349b89025e3a [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/previews/core/previews_experiments.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/logging.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/field_trial_params.h"
#include "base/optional.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "components/previews/core/previews_features.h"
#include "components/previews/core/previews_switches.h"
#include "google_apis/google_api_keys.h"
namespace previews {
namespace {
// The group of client-side previews experiments. This controls paramters of the
// client side blacklist.
const char kClientSidePreviewsFieldTrial[] = "ClientSidePreviews";
// Name for the version parameter of a field trial. Version changes will
// result in older blacklist entries being removed.
const char kVersion[] = "version";
// The threshold of EffectiveConnectionType above which previews will not be
// served.
// See net/nqe/effective_connection_type.h for mapping from string to value.
const char kEffectiveConnectionTypeThreshold[] =
"max_allowed_effective_connection_type";
// The session maximum threshold of EffectiveConnectionType above which previews
// will not be served. This is maximum limit on top of any per-preview-type
// threshold or per-page-pattern slow page trigger threshold. It is intended
// to be Finch configured on a session basis to limit slow page triggering to
// be a proportion of all eligible page loads.
// See net/nqe/effective_connection_type.h for mapping from string to value.
const char kSessionMaxECTTrigger[] = "session_max_ect_trigger";
// Inflation parameters for estimating NoScript data savings.
const char kNoScriptInflationPercent[] = "NoScriptInflationPercent";
const char kNoScriptInflationBytes[] = "NoScriptInflationBytes";
const char kOptimizationGuideServiceURL[] = "";
// Inflation parameters for estimating ResourceLoadingHints data savings.
const char kResourceLoadingHintsInflationPercent[] =
"ResourceLoadingHintsInflationPercent";
const char kResourceLoadingHintsInflationBytes[] =
"ResourceLoadingHintsInflationBytes";
size_t GetParamValueAsSizeT(const std::string& trial_name,
const std::string& param_name,
size_t default_value) {
size_t value;
if (!base::StringToSizeT(
base::GetFieldTrialParamValue(trial_name, param_name), &value)) {
return default_value;
}
return value;
}
int GetParamValueAsInt(const std::string& trial_name,
const std::string& param_name,
int default_value) {
int value;
if (!base::StringToInt(base::GetFieldTrialParamValue(trial_name, param_name),
&value)) {
return default_value;
}
return value;
}
net::EffectiveConnectionType GetParamValueAsECT(
const std::string& trial_name,
const std::string& param_name,
net::EffectiveConnectionType default_value) {
return net::GetEffectiveConnectionTypeForName(
base::GetFieldTrialParamValue(trial_name, param_name))
.value_or(default_value);
}
net::EffectiveConnectionType GetParamValueAsECTByFeature(
const base::Feature& feature,
const std::string& param_name,
net::EffectiveConnectionType default_value) {
return net::GetEffectiveConnectionTypeForName(
base::GetFieldTrialParamValueByFeature(feature, param_name))
.value_or(default_value);
}
} // namespace
namespace params {
size_t MaxStoredHistoryLengthForPerHostBlackList() {
return GetParamValueAsSizeT(kClientSidePreviewsFieldTrial,
"per_host_max_stored_history_length", 4);
}
size_t MaxStoredHistoryLengthForHostIndifferentBlackList() {
return GetParamValueAsSizeT(kClientSidePreviewsFieldTrial,
"host_indifferent_max_stored_history_length", 10);
}
size_t MaxInMemoryHostsInBlackList() {
return GetParamValueAsSizeT(kClientSidePreviewsFieldTrial,
"max_hosts_in_blacklist", 100);
}
size_t MaxHostsForOptimizationGuideServiceHintsFetch() {
return GetFieldTrialParamByFeatureAsInt(
features::kOptimizationHintsFetching,
"max_hosts_for_optimization_guide_service_hints_fetch", 30);
}
int PerHostBlackListOptOutThreshold() {
return GetParamValueAsInt(kClientSidePreviewsFieldTrial,
"per_host_opt_out_threshold", 2);
}
int HostIndifferentBlackListOptOutThreshold() {
return GetParamValueAsInt(kClientSidePreviewsFieldTrial,
"host_indifferent_opt_out_threshold", 6);
}
base::TimeDelta PerHostBlackListDuration() {
return base::TimeDelta::FromDays(
GetParamValueAsInt(kClientSidePreviewsFieldTrial,
"per_host_black_list_duration_in_days", 30));
}
base::TimeDelta HostIndifferentBlackListPerHostDuration() {
return base::TimeDelta::FromDays(
GetParamValueAsInt(kClientSidePreviewsFieldTrial,
"host_indifferent_black_list_duration_in_days", 30));
}
base::TimeDelta SingleOptOutDuration() {
return base::TimeDelta::FromSeconds(
GetParamValueAsInt(kClientSidePreviewsFieldTrial,
"single_opt_out_duration_in_seconds", 60 * 5));
}
base::TimeDelta OfflinePreviewFreshnessDuration() {
return base::TimeDelta::FromDays(
GetParamValueAsInt(kClientSidePreviewsFieldTrial,
"offline_preview_freshness_duration_in_days", 7));
}
base::TimeDelta LitePagePreviewsSingleBypassDuration() {
return base::TimeDelta::FromSeconds(base::GetFieldTrialParamByFeatureAsInt(
features::kLitePageServerPreviews, "single_bypass_duration_in_seconds",
60 * 5));
}
base::TimeDelta LitePagePreviewsNavigationTimeoutDuration() {
return base::TimeDelta::FromMilliseconds(
base::GetFieldTrialParamByFeatureAsInt(features::kLitePageServerPreviews,
"navigation_timeout_milliseconds",
30 * 1000));
}
std::vector<std::string> LitePagePreviewsBlacklistedPathSuffixes() {
const std::string csv = base::GetFieldTrialParamValueByFeature(
features::kLitePageServerPreviews, "blacklisted_path_suffixes");
if (csv == "")
return {};
return base::SplitString(csv, ",", base::TRIM_WHITESPACE,
base::SPLIT_WANT_NONEMPTY);
}
int LitePageRedirectPreviewMaxServerBlacklistByteSize() {
return base::GetFieldTrialParamByFeatureAsInt(
features::kLitePageServerPreviews, "max_blacklist_byte_size",
250 * 1024 /* 250KB */);
}
size_t LitePageRedirectPreviewMaxNavigationRestarts() {
return base::GetFieldTrialParamByFeatureAsInt(
features::kLitePageServerPreviews, "max_navigation_restart", 5);
}
int PreviewServerLoadshedMaxSeconds() {
return base::GetFieldTrialParamByFeatureAsInt(
features::kLitePageServerPreviews, "loadshed_max_seconds",
5 * 60 /* 5 minutes */);
}
bool LitePagePreviewsTriggerOnLocalhost() {
return base::GetFieldTrialParamByFeatureAsBool(
features::kLitePageServerPreviews, "trigger_on_localhost", false);
}
bool LitePagePreviewsOverridePageHints() {
return base::GetFieldTrialParamByFeatureAsBool(
features::kLitePageServerPreviews, "override_pagehints", false);
}
GURL GetLitePagePreviewsDomainURL() {
// Command line override takes priority.
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kLitePageServerPreviewHost)) {
const std::string switch_value =
command_line->GetSwitchValueASCII(switches::kLitePageServerPreviewHost);
const GURL url(switch_value);
if (url.is_valid())
return url;
LOG(WARNING)
<< "The following litepages previews host URL specified at the "
<< "command-line is invalid: " << switch_value;
}
std::string variable_host_str = GetFieldTrialParamValueByFeature(
features::kLitePageServerPreviews, "previews_host");
if (!variable_host_str.empty()) {
GURL variable_host(variable_host_str);
DCHECK(variable_host.is_valid());
DCHECK(variable_host.has_scheme());
return variable_host;
}
return GURL("https://litepages.googlezip.net/");
}
std::string GetOptimizationGuideServiceAPIKey() {
// Command line override takes priority.
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kOptimizationGuideServiceAPIKey)) {
return command_line->GetSwitchValueASCII(
switches::kOptimizationGuideServiceAPIKey);
}
return google_apis::GetAPIKey();
}
GURL GetOptimizationGuideServiceURL() {
// Command line override takes priority.
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kOptimizationGuideServiceURL)) {
// Assume the command line switch is correct and return it.
return GURL(command_line->GetSwitchValueASCII(
switches::kOptimizationGuideServiceURL));
}
std::string url = base::GetFieldTrialParamValueByFeature(
features::kOptimizationHintsFetching, "optimization_guide_service_url");
if (url.empty())
return GURL(kOptimizationGuideServiceURL);
return GURL(url);
}
std::string LitePageRedirectPreviewExperiment() {
return GetFieldTrialParamValueByFeature(features::kLitePageServerPreviews,
"lite_page_preview_experiment");
}
bool IsInLitePageRedirectControl() {
return base::GetFieldTrialParamByFeatureAsBool(
features::kLitePageServerPreviews, "control_group", false);
}
net::EffectiveConnectionType GetECTThresholdForPreview(
previews::PreviewsType type) {
switch (type) {
case PreviewsType::OFFLINE:
case PreviewsType::NOSCRIPT:
case PreviewsType::LITE_PAGE_REDIRECT:
return GetParamValueAsECT(kClientSidePreviewsFieldTrial,
kEffectiveConnectionTypeThreshold,
net::EFFECTIVE_CONNECTION_TYPE_2G);
case PreviewsType::LOFI:
return GetParamValueAsECTByFeature(features::kClientLoFi,
kEffectiveConnectionTypeThreshold,
net::EFFECTIVE_CONNECTION_TYPE_2G);
case PreviewsType::LITE_PAGE:
NOTREACHED();
break;
case PreviewsType::NONE:
case PreviewsType::UNSPECIFIED:
case PreviewsType::RESOURCE_LOADING_HINTS:
return GetParamValueAsECTByFeature(features::kResourceLoadingHints,
kEffectiveConnectionTypeThreshold,
net::EFFECTIVE_CONNECTION_TYPE_2G);
case PreviewsType::DEPRECATED_AMP_REDIRECTION:
case PreviewsType::LAST:
break;
}
NOTREACHED();
return net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
}
net::EffectiveConnectionType GetSessionMaxECTThreshold() {
return GetParamValueAsECTByFeature(features::kSlowPageTriggering,
kSessionMaxECTTrigger,
net::EFFECTIVE_CONNECTION_TYPE_2G);
}
bool ArePreviewsAllowed() {
return base::FeatureList::IsEnabled(features::kPreviews);
}
bool IsPreviewsOmniboxUiEnabled() {
return base::FeatureList::IsEnabled(features::kAndroidOmniboxPreviewsBadge);
}
bool IsOfflinePreviewsEnabled() {
return base::FeatureList::IsEnabled(features::kOfflinePreviews);
}
bool IsClientLoFiEnabled() {
return base::FeatureList::IsEnabled(features::kClientLoFi);
}
bool IsNoScriptPreviewsEnabled() {
return base::FeatureList::IsEnabled(features::kNoScriptPreviews);
}
bool IsResourceLoadingHintsEnabled() {
return base::FeatureList::IsEnabled(features::kResourceLoadingHints);
}
bool IsLitePageServerPreviewsEnabled() {
return base::FeatureList::IsEnabled(features::kLitePageServerPreviews);
}
int OfflinePreviewsVersion() {
return GetParamValueAsInt(kClientSidePreviewsFieldTrial, kVersion, 0);
}
int ClientLoFiVersion() {
return base::GetFieldTrialParamByFeatureAsInt(features::kClientLoFi, kVersion,
0);
}
int LitePageServerPreviewsVersion() {
return base::GetFieldTrialParamByFeatureAsInt(
features::kLitePageServerPreviews, kVersion, 0);
}
int NoScriptPreviewsVersion() {
return GetFieldTrialParamByFeatureAsInt(features::kNoScriptPreviews, kVersion,
0);
}
int ResourceLoadingHintsVersion() {
return GetFieldTrialParamByFeatureAsInt(features::kResourceLoadingHints,
kVersion, 0);
}
size_t GetMaxPageHintsInMemoryThreshhold() {
return GetFieldTrialParamByFeatureAsInt(features::kResourceLoadingHints,
"max_page_hints_in_memory_threshold",
500);
}
bool IsOptimizationHintsEnabled() {
return base::FeatureList::IsEnabled(features::kOptimizationHints);
}
bool IsHintsFetchingEnabled() {
return base::FeatureList::IsEnabled(features::kOptimizationHintsFetching);
}
int NoScriptPreviewsInflationPercent() {
// The default value was determined from lab experiment data of whitelisted
// URLs. It may be improved once there is enough UKM live experiment data
// via the field trial param.
return GetFieldTrialParamByFeatureAsInt(features::kNoScriptPreviews,
kNoScriptInflationPercent, 80);
}
int NoScriptPreviewsInflationBytes() {
return GetFieldTrialParamByFeatureAsInt(features::kNoScriptPreviews,
kNoScriptInflationBytes, 0);
}
int ResourceLoadingHintsPreviewsInflationPercent() {
return GetFieldTrialParamByFeatureAsInt(features::kResourceLoadingHints,
kResourceLoadingHintsInflationPercent,
20);
}
int ResourceLoadingHintsPreviewsInflationBytes() {
return GetFieldTrialParamByFeatureAsInt(
features::kResourceLoadingHints, kResourceLoadingHintsInflationBytes, 0);
}
} // namespace params
std::string GetStringNameForType(PreviewsType type) {
// The returned string is used to record histograms for the new preview type.
// Also add the string to Previews.Types histogram suffix in histograms.xml.
switch (type) {
case PreviewsType::NONE:
return "None";
case PreviewsType::OFFLINE:
return "Offline";
case PreviewsType::LOFI:
return "LoFi";
case PreviewsType::LITE_PAGE:
return "LitePage";
case PreviewsType::LITE_PAGE_REDIRECT:
return "LitePageRedirect";
case PreviewsType::NOSCRIPT:
return "NoScript";
case PreviewsType::UNSPECIFIED:
return "Unspecified";
case PreviewsType::RESOURCE_LOADING_HINTS:
return "ResourceLoadingHints";
case PreviewsType::DEPRECATED_AMP_REDIRECTION:
case PreviewsType::LAST:
break;
}
NOTREACHED();
return std::string();
}
} // namespace previews