Index: components/subresource_filter/core/browser/subresource_filter_features.cc |
diff --git a/components/subresource_filter/core/browser/subresource_filter_features.cc b/components/subresource_filter/core/browser/subresource_filter_features.cc |
index 06b06f1b3a6f2be15c0e3ddf5aa1321fe1380e7e..5ce505d10bf931e2536b9ee84c3ce012ceb22adf 100644 |
--- a/components/subresource_filter/core/browser/subresource_filter_features.cc |
+++ b/components/subresource_filter/core/browser/subresource_filter_features.cc |
@@ -4,22 +4,53 @@ |
#include "components/subresource_filter/core/browser/subresource_filter_features.h" |
+#include <map> |
+#include <ostream> |
+#include <sstream> |
#include <string> |
+#include <tuple> |
#include <utility> |
+#include "base/json/json_writer.h" |
#include "base/lazy_instance.h" |
#include "base/metrics/field_trial_params.h" |
#include "base/strings/string_number_conversions.h" |
-#include "base/strings/string_piece.h" |
#include "base/strings/string_split.h" |
#include "base/strings/string_util.h" |
#include "base/synchronization/lock.h" |
+#include "base/values.h" |
#include "components/variations/variations_associated_data.h" |
namespace subresource_filter { |
namespace { |
+// Helpers -------------------------------------------------------------------- |
+ |
+class CommaSeparatedStrings { |
+ public: |
+ CommaSeparatedStrings(std::string comma_separated_strings) |
+ : backing_string_(comma_separated_strings), |
+ pieces_(base::SplitStringPiece(backing_string_, |
+ ",", |
+ base::TRIM_WHITESPACE, |
+ base::SPLIT_WANT_NONEMPTY)) {} |
+ |
+ bool CaseInsensitiveContains(base::StringPiece lowercase_key) const { |
+ const auto predicate = [lowercase_key](base::StringPiece element) { |
+ return base::LowerCaseEqualsASCII(element, lowercase_key); |
+ }; |
+ return std::find_if(pieces_.begin(), pieces_.end(), predicate) != |
+ pieces_.end(); |
+ } |
+ |
+ private: |
+ const std::string backing_string_; |
+ const std::vector<base::StringPiece> pieces_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(CommaSeparatedStrings); |
+}; |
+ |
std::string TakeVariationParamOrReturnEmpty( |
std::map<std::string, std::string>* params, |
const std::string& key) { |
@@ -48,30 +79,26 @@ ActivationScope ParseActivationScope(const base::StringPiece activation_scope) { |
return ActivationScope::NO_SITES; |
} |
-ActivationList ParseActivationList(const base::StringPiece activation_lists) { |
+ActivationList ParseActivationList(std::string activation_lists_string) { |
ActivationList activation_list_type = ActivationList::NONE; |
- for (const base::StringPiece& activation_list : |
- base::SplitStringPiece(activation_lists, ",", base::TRIM_WHITESPACE, |
- base::SPLIT_WANT_NONEMPTY)) { |
- if (base::LowerCaseEqualsASCII(activation_list, |
- kActivationListPhishingInterstitial)) { |
- return ActivationList::PHISHING_INTERSTITIAL; |
- } else if (base::LowerCaseEqualsASCII( |
- activation_list, |
- kActivationListSocialEngineeringAdsInterstitial)) { |
- activation_list_type = ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL; |
- } else if (base::LowerCaseEqualsASCII(activation_list, |
- kActivationListSubresourceFilter)) { |
- activation_list_type = ActivationList::SUBRESOURCE_FILTER; |
- } |
+ CommaSeparatedStrings activation_lists(std::move(activation_lists_string)); |
+ if (activation_lists.CaseInsensitiveContains( |
+ kActivationListPhishingInterstitial)) { |
+ return ActivationList::PHISHING_INTERSTITIAL; |
+ } else if (activation_lists.CaseInsensitiveContains( |
+ kActivationListSocialEngineeringAdsInterstitial)) { |
+ activation_list_type = ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL; |
+ } else if (activation_lists.CaseInsensitiveContains( |
+ kActivationListSubresourceFilter)) { |
+ activation_list_type = ActivationList::SUBRESOURCE_FILTER; |
} |
return activation_list_type; |
} |
double ParsePerformanceMeasurementRate(const std::string& rate) { |
- double value = 0; |
+ double value = 0.0; |
if (!base::StringToDouble(rate, &value) || value < 0) |
- return 0; |
+ return 0.0; |
return value < 1 ? value : 1; |
} |
@@ -79,39 +106,120 @@ bool ParseBool(const base::StringPiece value) { |
return base::LowerCaseEqualsASCII(value, "true"); |
} |
-Configuration ParseFieldTrialConfiguration() { |
+int ParseInt(const base::StringPiece value) { |
+ int result = 0; |
+ base::StringToInt(value, &result); |
+ return result; |
+} |
+ |
+std::vector<Configuration> FillEnabledPresetConfigurations( |
+ std::map<std::string, std::string>* params) { |
+ const struct { |
+ const char* name; |
+ bool enabled_by_default; |
+ Configuration (*factory_method)(); |
+ } kAvailablePresetConfigurations[] = { |
+ {kPresetLiveRunOnPhishingSites, false, |
+ &Configuration::MakePresetForLiveRunOnPhishingSites}, |
+ {kPresetPerformanceTestingDryRunOnAllSites, false, |
+ &Configuration::MakePresetForPerformanceTestingDryRunOnAllSites}}; |
+ |
+ CommaSeparatedStrings enabled_presets( |
+ TakeVariationParamOrReturnEmpty(params, kEnablePresetsParameterName)); |
+ CommaSeparatedStrings disabled_presets( |
+ TakeVariationParamOrReturnEmpty(params, kDisablePresetsParameterName)); |
+ |
+ std::vector<Configuration> enabled_configurations; |
+ for (const auto& available_preset : kAvailablePresetConfigurations) { |
+ if ((enabled_presets.CaseInsensitiveContains(available_preset.name) || |
+ available_preset.enabled_by_default) && |
+ !disabled_presets.CaseInsensitiveContains(available_preset.name)) { |
+ enabled_configurations.push_back(available_preset.factory_method()); |
+ } |
+ } |
+ |
+ return enabled_configurations; |
+} |
+ |
+Configuration ParseExperimentalConfiguration( |
+ std::map<std::string, std::string>* params) { |
Configuration configuration; |
- std::map<std::string, std::string> params; |
- base::GetFieldTrialParamsByFeature(kSafeBrowsingSubresourceFilter, ¶ms); |
+ // ActivationConditions: |
+ configuration.activation_conditions.activation_scope = ParseActivationScope( |
+ TakeVariationParamOrReturnEmpty(params, kActivationScopeParameterName)); |
- configuration.activation_level = ParseActivationLevel( |
- TakeVariationParamOrReturnEmpty(¶ms, kActivationLevelParameterName)); |
+ configuration.activation_conditions.activation_list = ParseActivationList( |
+ TakeVariationParamOrReturnEmpty(params, kActivationListsParameterName)); |
- configuration.activation_scope = ParseActivationScope( |
- TakeVariationParamOrReturnEmpty(¶ms, kActivationScopeParameterName)); |
+ configuration.activation_conditions.priority = |
+ ParseInt(TakeVariationParamOrReturnEmpty( |
+ params, kActivationPriorityParameterName)); |
- configuration.activation_list = ParseActivationList( |
- TakeVariationParamOrReturnEmpty(¶ms, kActivationListsParameterName)); |
+ // ActivationOptions: |
+ configuration.activation_options.activation_level = ParseActivationLevel( |
+ TakeVariationParamOrReturnEmpty(params, kActivationLevelParameterName)); |
- configuration.performance_measurement_rate = |
+ configuration.activation_options.performance_measurement_rate = |
ParsePerformanceMeasurementRate(TakeVariationParamOrReturnEmpty( |
- ¶ms, kPerformanceMeasurementRateParameterName)); |
+ params, kPerformanceMeasurementRateParameterName)); |
- configuration.should_suppress_notifications = |
+ configuration.activation_options.should_suppress_notifications = |
ParseBool(TakeVariationParamOrReturnEmpty( |
- ¶ms, kSuppressNotificationsParameterName)); |
- |
- configuration.ruleset_flavor = |
- TakeVariationParamOrReturnEmpty(¶ms, kRulesetFlavorParameterName); |
+ params, kSuppressNotificationsParameterName)); |
- configuration.should_whitelist_site_on_reload = |
+ configuration.activation_options.should_whitelist_site_on_reload = |
ParseBool(TakeVariationParamOrReturnEmpty( |
- ¶ms, kWhitelistSiteOnReloadParameterName)); |
+ params, kWhitelistSiteOnReloadParameterName)); |
+ |
+ // GeneralSettings: |
+ configuration.general_settings.ruleset_flavor = |
+ TakeVariationParamOrReturnEmpty(params, kRulesetFlavorParameterName); |
return configuration; |
} |
+std::vector<Configuration> ParseEnabledConfigurations() { |
+ std::map<std::string, std::string> params; |
+ base::GetFieldTrialParamsByFeature(kSafeBrowsingSubresourceFilter, ¶ms); |
+ |
+ std::vector<Configuration> configs = FillEnabledPresetConfigurations(¶ms); |
+ |
+ Configuration experimental_config = ParseExperimentalConfiguration(¶ms); |
+ configs.push_back(std::move(experimental_config)); |
+ |
+ return configs; |
+} |
+ |
+template <class T> |
+std::string StreamToString(const T& value) { |
+ std::ostringstream oss; |
+ oss << value; |
+ return oss.str(); |
+} |
+ |
+std::vector<Configuration> SortConfigsByDecreasingPriority( |
+ std::vector<Configuration> configs) { |
+ auto comp = [](const Configuration& a, const Configuration& b) { |
+ return a.activation_conditions.priority > b.activation_conditions.priority; |
+ }; |
+ std::sort(configs.begin(), configs.end(), comp); |
+ return configs; |
+} |
+ |
+base::StringPiece GetLexicographicallyGreatestRulesetFlavor( |
+ const std::vector<Configuration>& configs) { |
+ base::StringPiece greatest_flavor; |
+ for (const auto& config : configs) { |
+ base::StringPiece flavor = config.general_settings.ruleset_flavor; |
+ if (flavor > greatest_flavor) |
+ greatest_flavor = flavor; |
+ } |
+ return greatest_flavor; |
+} |
+ |
+// Globals -------------------------------------------------------------------- |
+ |
base::LazyInstance<base::Lock>::Leaky g_active_configurations_lock = |
LAZY_INSTANCE_INITIALIZER; |
@@ -120,6 +228,8 @@ base::LazyInstance<scoped_refptr<ConfigurationList>>::Leaky |
} // namespace |
+// Constant definitions ------------------------------------------------------- |
+ |
const base::Feature kSafeBrowsingSubresourceFilter{ |
"SubresourceFilter", base::FEATURE_DISABLED_BY_DEFAULT}; |
@@ -143,35 +253,110 @@ const char kActivationListSocialEngineeringAdsInterstitial[] = |
const char kActivationListPhishingInterstitial[] = "phishing_interstitial"; |
const char kActivationListSubresourceFilter[] = "subresource_filter"; |
-const char kRulesetFlavorParameterName[] = "ruleset_flavor"; |
+const char kActivationPriorityParameterName[] = "activation_priority"; |
const char kPerformanceMeasurementRateParameterName[] = |
"performance_measurement_rate"; |
- |
const char kSuppressNotificationsParameterName[] = "suppress_notifications"; |
- |
const char kWhitelistSiteOnReloadParameterName[] = "whitelist_site_on_reload"; |
+const char kRulesetFlavorParameterName[] = "ruleset_flavor"; |
+ |
+const char kEnablePresetsParameterName[] = "enable_presets"; |
+const char kDisablePresetsParameterName[] = "disable_presets"; |
+const char kPresetLiveRunOnPhishingSites[] = "liverun_on_phishing_sites"; |
+const char kPresetPerformanceTestingDryRunOnAllSites[] = |
+ "performance_testing_dryrun_on_all_sites"; |
+ |
+// Configuration -------------------------------------------------------------- |
+ |
+// static |
+Configuration Configuration::MakePresetForLiveRunOnPhishingSites() { |
+ Configuration config(ActivationLevel::ENABLED, |
+ ActivationScope::ACTIVATION_LIST, |
+ ActivationList::PHISHING_INTERSTITIAL); |
+ config.activation_conditions.priority = 1000; |
+ return config; |
+} |
+ |
+// static |
+Configuration Configuration::MakePresetForPerformanceTestingDryRunOnAllSites() { |
+ Configuration config(ActivationLevel::DRYRUN, ActivationScope::ALL_SITES); |
+ config.activation_options.performance_measurement_rate = 1.0; |
+ config.activation_conditions.priority = 500; |
+ return config; |
+} |
+ |
Configuration::Configuration() = default; |
Configuration::Configuration(ActivationLevel activation_level, |
ActivationScope activation_scope, |
- ActivationList activation_list) |
- : activation_level(activation_level), |
- activation_scope(activation_scope), |
- activation_list(activation_list) {} |
+ ActivationList activation_list) { |
+ activation_options.activation_level = activation_level; |
+ activation_conditions.activation_scope = activation_scope; |
+ activation_conditions.activation_list = activation_list; |
+} |
+Configuration::Configuration(const Configuration&) = default; |
Configuration::Configuration(Configuration&&) = default; |
Configuration::~Configuration() = default; |
+Configuration& Configuration::operator=(const Configuration&) = default; |
Configuration& Configuration::operator=(Configuration&&) = default; |
-ConfigurationList::ConfigurationList(Configuration config) |
- : config_(std::move(config)) {} |
+bool Configuration::operator==(const Configuration& rhs) const { |
+ const auto tie = [](const Configuration& config) { |
+ return std::tie(config.activation_conditions.activation_scope, |
+ config.activation_conditions.activation_list, |
+ config.activation_conditions.priority, |
+ config.activation_options.activation_level, |
+ config.activation_options.performance_measurement_rate, |
+ config.activation_options.should_whitelist_site_on_reload, |
+ config.activation_options.should_suppress_notifications, |
+ config.general_settings.ruleset_flavor); |
+ }; |
+ return tie(*this) == tie(rhs); |
+} |
+ |
+bool Configuration::operator!=(const Configuration& rhs) const { |
+ return !(*this == rhs); |
+} |
+ |
+std::ostream& operator<<(std::ostream& os, const Configuration& config) { |
+ base::DictionaryValue dict; |
+ dict.SetString("activation_scope", |
+ StreamToString(config.activation_conditions.activation_scope)); |
+ dict.SetString("activation_list", |
+ StreamToString(config.activation_conditions.activation_list)); |
+ dict.SetInteger("priority", config.activation_conditions.priority); |
+ dict.SetString("activation_level", |
+ StreamToString(config.activation_options.activation_level)); |
+ dict.SetDouble("performance_measurement_rate", |
+ config.activation_options.performance_measurement_rate); |
+ dict.SetBoolean("should_suppress_notifications", |
+ config.activation_options.should_suppress_notifications); |
+ dict.SetBoolean("should_whitelist_site_on_reload", |
+ config.activation_options.should_whitelist_site_on_reload); |
+ dict.SetString("ruleset_flavor", |
+ StreamToString(config.general_settings.ruleset_flavor)); |
+ std::string json; |
+ base::JSONWriter::WriteWithOptions( |
+ dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json); |
+ return os << json; |
+} |
+ |
+// ConfigurationList ---------------------------------------------------------- |
+ |
+ConfigurationList::ConfigurationList(std::vector<Configuration> configs) |
+ : configs_by_decreasing_priority_( |
+ SortConfigsByDecreasingPriority(std::move(configs))), |
+ lexicographically_greatest_ruleset_flavor_( |
+ GetLexicographicallyGreatestRulesetFlavor( |
+ configs_by_decreasing_priority_)) {} |
ConfigurationList::~ConfigurationList() = default; |
-scoped_refptr<ConfigurationList> GetActiveConfigurations() { |
+scoped_refptr<ConfigurationList> GetEnabledConfigurations() { |
base::AutoLock lock(g_active_configurations_lock.Get()); |
if (!g_active_configurations.Get()) { |
g_active_configurations.Get() = |
- base::MakeShared<ConfigurationList>(ParseFieldTrialConfiguration()); |
+ base::MakeShared<ConfigurationList>(ParseEnabledConfigurations()); |
} |
return g_active_configurations.Get(); |
} |