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..140256adf39f0fbd85887381bf1cb5f6245e23bd 100644 |
--- a/components/subresource_filter/core/browser/subresource_filter_features.cc |
+++ b/components/subresource_filter/core/browser/subresource_filter_features.cc |
@@ -4,9 +4,14 @@ |
#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" |
@@ -14,12 +19,15 @@ |
#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 for parsing the experimental configuration ------------------------- |
+ |
std::string TakeVariationParamOrReturnEmpty( |
std::map<std::string, std::string>* params, |
const std::string& key) { |
@@ -69,9 +77,9 @@ ActivationList ParseActivationList(const base::StringPiece activation_lists) { |
} |
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 +87,145 @@ bool ParseBool(const base::StringPiece value) { |
return base::LowerCaseEqualsASCII(value, "true"); |
} |
-Configuration ParseFieldTrialConfiguration() { |
- Configuration configuration; |
+std::vector<Configuration> FillEnabledPresetConfigurations( |
+ std::map<std::string, std::string>* params) { |
+ const struct { |
+ const char* name; |
+ Configuration (*factory_method)(); |
+ } kAvailablePresetConfigurations[] = { |
+ {kPresetLiveRunOnPhishingSites, |
+ &Configuration::MakePresetForLiveRunOnPhishingSites}, |
+ {kPresetPerformanceTestingDryRunOnAllSites, |
+ &Configuration::MakePresetForPerformanceTestingDryRunOnAllSites}}; |
+ |
+ std::vector<Configuration> enabled_configurations; |
+ const std::string enabled_presets_list = |
+ TakeVariationParamOrReturnEmpty(params, kEnablePresetsParameterName); |
+ for (const base::StringPiece enabled_preset : |
+ base::SplitStringPiece(enabled_presets_list, ",", base::TRIM_WHITESPACE, |
+ base::SPLIT_WANT_NONEMPTY)) { |
+ for (const auto& available_preset : kAvailablePresetConfigurations) { |
+ if (base::LowerCaseEqualsASCII(enabled_preset, available_preset.name)) { |
+ enabled_configurations.push_back(available_preset.factory_method()); |
+ break; |
+ } |
+ } |
+ } |
+ return enabled_configurations; |
+} |
- std::map<std::string, std::string> params; |
- base::GetFieldTrialParamsByFeature(kSafeBrowsingSubresourceFilter, ¶ms); |
+Configuration ParseExperimentalConfiguration( |
+ std::map<std::string, std::string>* params) { |
+ Configuration configuration; |
- configuration.activation_level = ParseActivationLevel( |
- TakeVariationParamOrReturnEmpty(¶ms, kActivationLevelParameterName)); |
+ // ActivationConditions: |
+ configuration.activation_conditions.activation_scope = ParseActivationScope( |
+ TakeVariationParamOrReturnEmpty(params, kActivationScopeParameterName)); |
- configuration.activation_scope = ParseActivationScope( |
- TakeVariationParamOrReturnEmpty(¶ms, kActivationScopeParameterName)); |
+ configuration.activation_conditions.activation_list = ParseActivationList( |
+ TakeVariationParamOrReturnEmpty(params, kActivationListsParameterName)); |
- 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)); |
pkalinnikov
2017/05/04 12:04:22
So, we add an experimental config regardless of wh
engedy
2017/05/05 12:25:42
Yes, but it is mostly only needed because otherwis
|
+ |
+ return configs; |
+} |
+ |
+std::vector<Configuration> MakeConfigVector(Configuration config) { |
+ std::vector<Configuration> configs; |
+ configs.push_back(std::move(config)); |
+ return configs; |
+} |
+ |
+template <class T> |
+std::string StreamToString(const T& value) { |
+ std::ostringstream oss; |
+ oss << value; |
+ return oss.str(); |
+} |
+ |
+// Helpers for calculating configuration priorities --------------------------- |
+ |
Charlie Harrison
2017/05/03 14:52:17
A comment here about what the priority levels mean
engedy
2017/05/05 12:25:42
Done.
|
+size_t GetActivationLevelPriority(ActivationLevel activation_level) { |
+ switch (activation_level) { |
+ case ActivationLevel::DISABLED: |
+ return 1; |
+ case ActivationLevel::DRYRUN: |
+ return 2; |
+ case ActivationLevel::ENABLED: |
+ return 3; |
+ } |
+ NOTREACHED(); |
+ return 0; |
+} |
+ |
+size_t GetActivationScopePriority(ActivationScope activation_scope) { |
+ // The more specific ACTIVATION_LIST trumps the blanket scopes. |
+ switch (activation_scope) { |
+ case ActivationScope::NO_SITES: |
pkalinnikov
2017/05/04 12:04:22
Hm, I am confused by the term "more specific". My
engedy
2017/05/05 12:25:42
Removed this, N/A anymore.
|
+ return 1; |
+ case ActivationScope::ALL_SITES: |
+ return 2; |
+ case ActivationScope::ACTIVATION_LIST: |
+ return 3; |
+ } |
+ NOTREACHED(); |
+ return 0; |
+} |
+ |
+// Returns an opaque value that represents the priority of the given |config|, |
+// where a greater value indicates higher priority. If it falls onto the |
+// |activation_list| to break a tie, the more recently implemented list has a |
+// higher priority. |
+std::tuple<size_t, size_t, size_t> GetConfigurationPriority( |
+ const Configuration& config) { |
+ // std::tuple implements lexicographical compare. |
+ return std::make_tuple( |
+ GetActivationLevelPriority(config.activation_options.activation_level), |
+ GetActivationScopePriority(config.activation_conditions.activation_scope), |
+ static_cast<size_t>(config.activation_conditions.activation_list)); |
+} |
+ |
+std::vector<Configuration> SortConfigsByDecreasingPriority( |
+ std::vector<Configuration> configs) { |
+ auto comp = [](const Configuration& a, const Configuration& b) { |
+ return GetConfigurationPriority(a) > GetConfigurationPriority(b); |
+ }; |
+ std::sort(configs.begin(), configs.end(), comp); |
+ return configs; |
+} |
+ |
+// Globals -------------------------------------------------------------------- |
+ |
base::LazyInstance<base::Lock>::Leaky g_active_configurations_lock = |
LAZY_INSTANCE_INITIALIZER; |
@@ -120,6 +234,8 @@ base::LazyInstance<scoped_refptr<ConfigurationList>>::Leaky |
} // namespace |
+// Constant definitions ------------------------------------------------------- |
+ |
const base::Feature kSafeBrowsingSubresourceFilter{ |
"SubresourceFilter", base::FEATURE_DISABLED_BY_DEFAULT}; |
@@ -143,35 +259,114 @@ const char kActivationListSocialEngineeringAdsInterstitial[] = |
const char kActivationListPhishingInterstitial[] = "phishing_interstitial"; |
const char kActivationListSubresourceFilter[] = "subresource_filter"; |
-const char kRulesetFlavorParameterName[] = "ruleset_flavor"; |
- |
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 kPresetLiveRunOnPhishingSites[] = "liverun_on_phishing_sites"; |
+const char kPresetPerformanceTestingDryRunOnAllSites[] = |
+ "performance_testing_dryrun_on_all_sites"; |
+ |
+// Configuration -------------------------------------------------------------- |
+ |
+// static |
+Configuration Configuration::MakePresetForLiveRunOnPhishingSites() { |
+ return Configuration(ActivationLevel::ENABLED, |
+ ActivationScope::ACTIVATION_LIST, |
+ ActivationList::PHISHING_INTERSTITIAL); |
+} |
+ |
+// static |
+Configuration Configuration::MakePresetForPerformanceTestingDryRunOnAllSites() { |
+ Configuration config(ActivationLevel::DRYRUN, ActivationScope::ALL_SITES); |
+ config.activation_options.performance_measurement_rate = 1.0; |
+ 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; |
+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_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) { |
Charlie Harrison
2017/05/03 14:52:18
This reminds me, with all these configurations I t
pkalinnikov
2017/05/04 12:04:23
+1
Does trace work well with multi-line strings?
engedy
2017/05/05 12:25:42
As clarified in our offline discussion, we are tal
engedy
2017/05/05 12:25:42
To clarify, are we talking about SCOPED_TRACE's he
|
+ base::DictionaryValue dict; |
+ dict.SetString("activation_scope", |
+ StreamToString(config.activation_conditions.activation_scope)); |
+ dict.SetString("activation_list", |
+ StreamToString(config.activation_conditions.activation_list)); |
+ 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))) {} |
ConfigurationList::ConfigurationList(Configuration config) |
- : config_(std::move(config)) {} |
+ : ConfigurationList(MakeConfigVector(std::move(config))) {} |
pkalinnikov
2017/05/04 12:04:22
nit1: Can this be just {std::move(config)} instead
engedy
2017/05/05 12:25:42
Initializer lists don't take rvalues, so there wil
|
ConfigurationList::~ConfigurationList() = default; |
-scoped_refptr<ConfigurationList> GetActiveConfigurations() { |
+std::string ConfigurationList::GetMostSpecificRulesetFlavor() const { |
pkalinnikov
2017/05/04 12:04:22
Since the ConfigurationList is immutable, could we
engedy
2017/05/05 12:25:42
Done. It's more consistent either way.
|
+ std::string most_specific_flavor; |
Charlie Harrison
2017/05/03 14:52:17
Can it be const ref so we don't copy the underlyin
pkalinnikov
2017/05/04 12:04:22
+1, const ptr.
engedy
2017/05/05 12:25:42
Done.
engedy
2017/05/05 12:25:42
Well we cannot re-assign a const&, but StringPiece
|
+ for (const auto& config : configs_by_decreasing_priority_) { |
+ const std::string& flavor = config.general_settings.ruleset_flavor; |
+ if (flavor.size() > most_specific_flavor.size() || |
+ (flavor.size() == most_specific_flavor.size() && |
+ flavor > most_specific_flavor)) { |
+ most_specific_flavor = flavor; |
+ } |
+ } |
+ return most_specific_flavor; |
+} |
+ |
+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(); |
} |