Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(58)

Side by Side Diff: components/subresource_filter/core/browser/subresource_filter_features.cc

Issue 2844063002: Add support for multiple simultaneous subresource_filter::Configurations. (Closed)
Patch Set: Rebase. Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/subresource_filter/core/browser/subresource_filter_features .h" 5 #include "components/subresource_filter/core/browser/subresource_filter_features .h"
6 6
7 #include <map>
8 #include <ostream>
9 #include <sstream>
7 #include <string> 10 #include <string>
11 #include <tuple>
8 #include <utility> 12 #include <utility>
9 13
14 #include "base/json/json_writer.h"
10 #include "base/lazy_instance.h" 15 #include "base/lazy_instance.h"
11 #include "base/metrics/field_trial_params.h" 16 #include "base/metrics/field_trial_params.h"
12 #include "base/strings/string_number_conversions.h" 17 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_piece.h"
14 #include "base/strings/string_split.h" 18 #include "base/strings/string_split.h"
15 #include "base/strings/string_util.h" 19 #include "base/strings/string_util.h"
16 #include "base/synchronization/lock.h" 20 #include "base/synchronization/lock.h"
21 #include "base/values.h"
17 #include "components/variations/variations_associated_data.h" 22 #include "components/variations/variations_associated_data.h"
18 23
19 namespace subresource_filter { 24 namespace subresource_filter {
20 25
21 namespace { 26 namespace {
22 27
28 // Helpers --------------------------------------------------------------------
29
30 class CommaSeparatedStrings {
31 public:
32 CommaSeparatedStrings(std::string comma_separated_strings)
33 : backing_string_(comma_separated_strings),
34 pieces_(base::SplitStringPiece(backing_string_,
35 ",",
36 base::TRIM_WHITESPACE,
37 base::SPLIT_WANT_NONEMPTY)) {}
38
39 bool CaseInsensitiveContains(base::StringPiece lowercase_key) const {
40 const auto predicate = [lowercase_key](base::StringPiece element) {
41 return base::LowerCaseEqualsASCII(element, lowercase_key);
42 };
43 return std::find_if(pieces_.begin(), pieces_.end(), predicate) !=
44 pieces_.end();
45 }
46
47 private:
48 const std::string backing_string_;
49 const std::vector<base::StringPiece> pieces_;
50
51 DISALLOW_COPY_AND_ASSIGN(CommaSeparatedStrings);
52 };
53
23 std::string TakeVariationParamOrReturnEmpty( 54 std::string TakeVariationParamOrReturnEmpty(
24 std::map<std::string, std::string>* params, 55 std::map<std::string, std::string>* params,
25 const std::string& key) { 56 const std::string& key) {
26 auto it = params->find(key); 57 auto it = params->find(key);
27 if (it == params->end()) 58 if (it == params->end())
28 return std::string(); 59 return std::string();
29 std::string value = std::move(it->second); 60 std::string value = std::move(it->second);
30 params->erase(it); 61 params->erase(it);
31 return value; 62 return value;
32 } 63 }
33 64
34 ActivationLevel ParseActivationLevel(const base::StringPiece activation_level) { 65 ActivationLevel ParseActivationLevel(const base::StringPiece activation_level) {
35 if (base::LowerCaseEqualsASCII(activation_level, kActivationLevelEnabled)) 66 if (base::LowerCaseEqualsASCII(activation_level, kActivationLevelEnabled))
36 return ActivationLevel::ENABLED; 67 return ActivationLevel::ENABLED;
37 else if (base::LowerCaseEqualsASCII(activation_level, kActivationLevelDryRun)) 68 else if (base::LowerCaseEqualsASCII(activation_level, kActivationLevelDryRun))
38 return ActivationLevel::DRYRUN; 69 return ActivationLevel::DRYRUN;
39 return ActivationLevel::DISABLED; 70 return ActivationLevel::DISABLED;
40 } 71 }
41 72
42 ActivationScope ParseActivationScope(const base::StringPiece activation_scope) { 73 ActivationScope ParseActivationScope(const base::StringPiece activation_scope) {
43 if (base::LowerCaseEqualsASCII(activation_scope, kActivationScopeAllSites)) 74 if (base::LowerCaseEqualsASCII(activation_scope, kActivationScopeAllSites))
44 return ActivationScope::ALL_SITES; 75 return ActivationScope::ALL_SITES;
45 else if (base::LowerCaseEqualsASCII(activation_scope, 76 else if (base::LowerCaseEqualsASCII(activation_scope,
46 kActivationScopeActivationList)) 77 kActivationScopeActivationList))
47 return ActivationScope::ACTIVATION_LIST; 78 return ActivationScope::ACTIVATION_LIST;
48 return ActivationScope::NO_SITES; 79 return ActivationScope::NO_SITES;
49 } 80 }
50 81
51 ActivationList ParseActivationList(const base::StringPiece activation_lists) { 82 ActivationList ParseActivationList(std::string activation_lists_string) {
52 ActivationList activation_list_type = ActivationList::NONE; 83 ActivationList activation_list_type = ActivationList::NONE;
53 for (const base::StringPiece& activation_list : 84 CommaSeparatedStrings activation_lists(std::move(activation_lists_string));
54 base::SplitStringPiece(activation_lists, ",", base::TRIM_WHITESPACE, 85 if (activation_lists.CaseInsensitiveContains(
55 base::SPLIT_WANT_NONEMPTY)) { 86 kActivationListPhishingInterstitial)) {
56 if (base::LowerCaseEqualsASCII(activation_list, 87 return ActivationList::PHISHING_INTERSTITIAL;
57 kActivationListPhishingInterstitial)) { 88 } else if (activation_lists.CaseInsensitiveContains(
58 return ActivationList::PHISHING_INTERSTITIAL; 89 kActivationListSocialEngineeringAdsInterstitial)) {
59 } else if (base::LowerCaseEqualsASCII( 90 activation_list_type = ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL;
60 activation_list, 91 } else if (activation_lists.CaseInsensitiveContains(
61 kActivationListSocialEngineeringAdsInterstitial)) { 92 kActivationListSubresourceFilter)) {
62 activation_list_type = ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL; 93 activation_list_type = ActivationList::SUBRESOURCE_FILTER;
63 } else if (base::LowerCaseEqualsASCII(activation_list,
64 kActivationListSubresourceFilter)) {
65 activation_list_type = ActivationList::SUBRESOURCE_FILTER;
66 }
67 } 94 }
68 return activation_list_type; 95 return activation_list_type;
69 } 96 }
70 97
71 double ParsePerformanceMeasurementRate(const std::string& rate) { 98 double ParsePerformanceMeasurementRate(const std::string& rate) {
72 double value = 0; 99 double value = 0.0;
73 if (!base::StringToDouble(rate, &value) || value < 0) 100 if (!base::StringToDouble(rate, &value) || value < 0)
74 return 0; 101 return 0.0;
75 return value < 1 ? value : 1; 102 return value < 1 ? value : 1;
76 } 103 }
77 104
78 bool ParseBool(const base::StringPiece value) { 105 bool ParseBool(const base::StringPiece value) {
79 return base::LowerCaseEqualsASCII(value, "true"); 106 return base::LowerCaseEqualsASCII(value, "true");
80 } 107 }
81 108
82 Configuration ParseFieldTrialConfiguration() { 109 int ParseInt(const base::StringPiece value) {
110 int result = 0;
111 base::StringToInt(value, &result);
112 return result;
113 }
114
115 std::vector<Configuration> FillEnabledPresetConfigurations(
116 std::map<std::string, std::string>* params) {
117 const struct {
118 const char* name;
119 bool enabled_by_default;
120 Configuration (*factory_method)();
121 } kAvailablePresetConfigurations[] = {
122 {kPresetLiveRunOnPhishingSites, false,
123 &Configuration::MakePresetForLiveRunOnPhishingSites},
124 {kPresetPerformanceTestingDryRunOnAllSites, false,
125 &Configuration::MakePresetForPerformanceTestingDryRunOnAllSites}};
126
127 CommaSeparatedStrings enabled_presets(
128 TakeVariationParamOrReturnEmpty(params, kEnablePresetsParameterName));
129 CommaSeparatedStrings disabled_presets(
130 TakeVariationParamOrReturnEmpty(params, kDisablePresetsParameterName));
131
132 std::vector<Configuration> enabled_configurations;
133 for (const auto& available_preset : kAvailablePresetConfigurations) {
134 if ((enabled_presets.CaseInsensitiveContains(available_preset.name) ||
135 available_preset.enabled_by_default) &&
136 !disabled_presets.CaseInsensitiveContains(available_preset.name)) {
137 enabled_configurations.push_back(available_preset.factory_method());
138 }
139 }
140
141 return enabled_configurations;
142 }
143
144 Configuration ParseExperimentalConfiguration(
145 std::map<std::string, std::string>* params) {
83 Configuration configuration; 146 Configuration configuration;
84 147
85 std::map<std::string, std::string> params; 148 // ActivationConditions:
86 base::GetFieldTrialParamsByFeature(kSafeBrowsingSubresourceFilter, &params); 149 configuration.activation_conditions.activation_scope = ParseActivationScope(
150 TakeVariationParamOrReturnEmpty(params, kActivationScopeParameterName));
87 151
88 configuration.activation_level = ParseActivationLevel( 152 configuration.activation_conditions.activation_list = ParseActivationList(
89 TakeVariationParamOrReturnEmpty(&params, kActivationLevelParameterName)); 153 TakeVariationParamOrReturnEmpty(params, kActivationListsParameterName));
90 154
91 configuration.activation_scope = ParseActivationScope( 155 configuration.activation_conditions.priority =
92 TakeVariationParamOrReturnEmpty(&params, kActivationScopeParameterName)); 156 ParseInt(TakeVariationParamOrReturnEmpty(
157 params, kActivationPriorityParameterName));
93 158
94 configuration.activation_list = ParseActivationList( 159 // ActivationOptions:
95 TakeVariationParamOrReturnEmpty(&params, kActivationListsParameterName)); 160 configuration.activation_options.activation_level = ParseActivationLevel(
161 TakeVariationParamOrReturnEmpty(params, kActivationLevelParameterName));
96 162
97 configuration.performance_measurement_rate = 163 configuration.activation_options.performance_measurement_rate =
98 ParsePerformanceMeasurementRate(TakeVariationParamOrReturnEmpty( 164 ParsePerformanceMeasurementRate(TakeVariationParamOrReturnEmpty(
99 &params, kPerformanceMeasurementRateParameterName)); 165 params, kPerformanceMeasurementRateParameterName));
100 166
101 configuration.should_suppress_notifications = 167 configuration.activation_options.should_suppress_notifications =
102 ParseBool(TakeVariationParamOrReturnEmpty( 168 ParseBool(TakeVariationParamOrReturnEmpty(
103 &params, kSuppressNotificationsParameterName)); 169 params, kSuppressNotificationsParameterName));
104 170
105 configuration.ruleset_flavor = 171 configuration.activation_options.should_whitelist_site_on_reload =
106 TakeVariationParamOrReturnEmpty(&params, kRulesetFlavorParameterName); 172 ParseBool(TakeVariationParamOrReturnEmpty(
173 params, kWhitelistSiteOnReloadParameterName));
107 174
108 configuration.should_whitelist_site_on_reload = 175 // GeneralSettings:
109 ParseBool(TakeVariationParamOrReturnEmpty( 176 configuration.general_settings.ruleset_flavor =
110 &params, kWhitelistSiteOnReloadParameterName)); 177 TakeVariationParamOrReturnEmpty(params, kRulesetFlavorParameterName);
111 178
112 return configuration; 179 return configuration;
113 } 180 }
114 181
182 std::vector<Configuration> ParseEnabledConfigurations() {
183 std::map<std::string, std::string> params;
184 base::GetFieldTrialParamsByFeature(kSafeBrowsingSubresourceFilter, &params);
185
186 std::vector<Configuration> configs = FillEnabledPresetConfigurations(&params);
187
188 Configuration experimental_config = ParseExperimentalConfiguration(&params);
189 configs.push_back(std::move(experimental_config));
190
191 return configs;
192 }
193
194 template <class T>
195 std::string StreamToString(const T& value) {
196 std::ostringstream oss;
197 oss << value;
198 return oss.str();
199 }
200
201 std::vector<Configuration> SortConfigsByDecreasingPriority(
202 std::vector<Configuration> configs) {
203 auto comp = [](const Configuration& a, const Configuration& b) {
204 return a.activation_conditions.priority > b.activation_conditions.priority;
205 };
206 std::sort(configs.begin(), configs.end(), comp);
207 return configs;
208 }
209
210 base::StringPiece GetLexicographicallyGreatestRulesetFlavor(
211 const std::vector<Configuration>& configs) {
212 base::StringPiece greatest_flavor;
213 for (const auto& config : configs) {
214 base::StringPiece flavor = config.general_settings.ruleset_flavor;
215 if (flavor > greatest_flavor)
216 greatest_flavor = flavor;
217 }
218 return greatest_flavor;
219 }
220
221 // Globals --------------------------------------------------------------------
222
115 base::LazyInstance<base::Lock>::Leaky g_active_configurations_lock = 223 base::LazyInstance<base::Lock>::Leaky g_active_configurations_lock =
116 LAZY_INSTANCE_INITIALIZER; 224 LAZY_INSTANCE_INITIALIZER;
117 225
118 base::LazyInstance<scoped_refptr<ConfigurationList>>::Leaky 226 base::LazyInstance<scoped_refptr<ConfigurationList>>::Leaky
119 g_active_configurations = LAZY_INSTANCE_INITIALIZER; 227 g_active_configurations = LAZY_INSTANCE_INITIALIZER;
120 228
121 } // namespace 229 } // namespace
122 230
231 // Constant definitions -------------------------------------------------------
232
123 const base::Feature kSafeBrowsingSubresourceFilter{ 233 const base::Feature kSafeBrowsingSubresourceFilter{
124 "SubresourceFilter", base::FEATURE_DISABLED_BY_DEFAULT}; 234 "SubresourceFilter", base::FEATURE_DISABLED_BY_DEFAULT};
125 235
126 const base::Feature kSafeBrowsingSubresourceFilterExperimentalUI{ 236 const base::Feature kSafeBrowsingSubresourceFilterExperimentalUI{
127 "SubresourceFilterExperimentalUI", base::FEATURE_DISABLED_BY_DEFAULT}; 237 "SubresourceFilterExperimentalUI", base::FEATURE_DISABLED_BY_DEFAULT};
128 238
129 // Legacy name `activation_state` is used in variation parameters. 239 // Legacy name `activation_state` is used in variation parameters.
130 const char kActivationLevelParameterName[] = "activation_state"; 240 const char kActivationLevelParameterName[] = "activation_state";
131 const char kActivationLevelDryRun[] = "dryrun"; 241 const char kActivationLevelDryRun[] = "dryrun";
132 const char kActivationLevelEnabled[] = "enabled"; 242 const char kActivationLevelEnabled[] = "enabled";
133 const char kActivationLevelDisabled[] = "disabled"; 243 const char kActivationLevelDisabled[] = "disabled";
134 244
135 const char kActivationScopeParameterName[] = "activation_scope"; 245 const char kActivationScopeParameterName[] = "activation_scope";
136 const char kActivationScopeAllSites[] = "all_sites"; 246 const char kActivationScopeAllSites[] = "all_sites";
137 const char kActivationScopeActivationList[] = "activation_list"; 247 const char kActivationScopeActivationList[] = "activation_list";
138 const char kActivationScopeNoSites[] = "no_sites"; 248 const char kActivationScopeNoSites[] = "no_sites";
139 249
140 const char kActivationListsParameterName[] = "activation_lists"; 250 const char kActivationListsParameterName[] = "activation_lists";
141 const char kActivationListSocialEngineeringAdsInterstitial[] = 251 const char kActivationListSocialEngineeringAdsInterstitial[] =
142 "social_engineering_ads_interstitial"; 252 "social_engineering_ads_interstitial";
143 const char kActivationListPhishingInterstitial[] = "phishing_interstitial"; 253 const char kActivationListPhishingInterstitial[] = "phishing_interstitial";
144 const char kActivationListSubresourceFilter[] = "subresource_filter"; 254 const char kActivationListSubresourceFilter[] = "subresource_filter";
145 255
146 const char kRulesetFlavorParameterName[] = "ruleset_flavor"; 256 const char kActivationPriorityParameterName[] = "activation_priority";
147 257
148 const char kPerformanceMeasurementRateParameterName[] = 258 const char kPerformanceMeasurementRateParameterName[] =
149 "performance_measurement_rate"; 259 "performance_measurement_rate";
260 const char kSuppressNotificationsParameterName[] = "suppress_notifications";
261 const char kWhitelistSiteOnReloadParameterName[] = "whitelist_site_on_reload";
150 262
151 const char kSuppressNotificationsParameterName[] = "suppress_notifications"; 263 const char kRulesetFlavorParameterName[] = "ruleset_flavor";
152 264
153 const char kWhitelistSiteOnReloadParameterName[] = "whitelist_site_on_reload"; 265 const char kEnablePresetsParameterName[] = "enable_presets";
266 const char kDisablePresetsParameterName[] = "disable_presets";
267 const char kPresetLiveRunOnPhishingSites[] = "liverun_on_phishing_sites";
268 const char kPresetPerformanceTestingDryRunOnAllSites[] =
269 "performance_testing_dryrun_on_all_sites";
270
271 // Configuration --------------------------------------------------------------
272
273 // static
274 Configuration Configuration::MakePresetForLiveRunOnPhishingSites() {
275 Configuration config(ActivationLevel::ENABLED,
276 ActivationScope::ACTIVATION_LIST,
277 ActivationList::PHISHING_INTERSTITIAL);
278 config.activation_conditions.priority = 1000;
279 return config;
280 }
281
282 // static
283 Configuration Configuration::MakePresetForPerformanceTestingDryRunOnAllSites() {
284 Configuration config(ActivationLevel::DRYRUN, ActivationScope::ALL_SITES);
285 config.activation_options.performance_measurement_rate = 1.0;
286 config.activation_conditions.priority = 500;
287 return config;
288 }
154 289
155 Configuration::Configuration() = default; 290 Configuration::Configuration() = default;
156 Configuration::Configuration(ActivationLevel activation_level, 291 Configuration::Configuration(ActivationLevel activation_level,
157 ActivationScope activation_scope, 292 ActivationScope activation_scope,
158 ActivationList activation_list) 293 ActivationList activation_list) {
159 : activation_level(activation_level), 294 activation_options.activation_level = activation_level;
160 activation_scope(activation_scope), 295 activation_conditions.activation_scope = activation_scope;
161 activation_list(activation_list) {} 296 activation_conditions.activation_list = activation_list;
297 }
298 Configuration::Configuration(const Configuration&) = default;
162 Configuration::Configuration(Configuration&&) = default; 299 Configuration::Configuration(Configuration&&) = default;
163 Configuration::~Configuration() = default; 300 Configuration::~Configuration() = default;
301 Configuration& Configuration::operator=(const Configuration&) = default;
164 Configuration& Configuration::operator=(Configuration&&) = default; 302 Configuration& Configuration::operator=(Configuration&&) = default;
165 303
166 ConfigurationList::ConfigurationList(Configuration config) 304 bool Configuration::operator==(const Configuration& rhs) const {
167 : config_(std::move(config)) {} 305 const auto tie = [](const Configuration& config) {
306 return std::tie(config.activation_conditions.activation_scope,
307 config.activation_conditions.activation_list,
308 config.activation_conditions.priority,
309 config.activation_options.activation_level,
310 config.activation_options.performance_measurement_rate,
311 config.activation_options.should_whitelist_site_on_reload,
312 config.activation_options.should_suppress_notifications,
313 config.general_settings.ruleset_flavor);
314 };
315 return tie(*this) == tie(rhs);
316 }
317
318 bool Configuration::operator!=(const Configuration& rhs) const {
319 return !(*this == rhs);
320 }
321
322 std::ostream& operator<<(std::ostream& os, const Configuration& config) {
323 base::DictionaryValue dict;
324 dict.SetString("activation_scope",
325 StreamToString(config.activation_conditions.activation_scope));
326 dict.SetString("activation_list",
327 StreamToString(config.activation_conditions.activation_list));
328 dict.SetInteger("priority", config.activation_conditions.priority);
329 dict.SetString("activation_level",
330 StreamToString(config.activation_options.activation_level));
331 dict.SetDouble("performance_measurement_rate",
332 config.activation_options.performance_measurement_rate);
333 dict.SetBoolean("should_suppress_notifications",
334 config.activation_options.should_suppress_notifications);
335 dict.SetBoolean("should_whitelist_site_on_reload",
336 config.activation_options.should_whitelist_site_on_reload);
337 dict.SetString("ruleset_flavor",
338 StreamToString(config.general_settings.ruleset_flavor));
339 std::string json;
340 base::JSONWriter::WriteWithOptions(
341 dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
342 return os << json;
343 }
344
345 // ConfigurationList ----------------------------------------------------------
346
347 ConfigurationList::ConfigurationList(std::vector<Configuration> configs)
348 : configs_by_decreasing_priority_(
349 SortConfigsByDecreasingPriority(std::move(configs))),
350 lexicographically_greatest_ruleset_flavor_(
351 GetLexicographicallyGreatestRulesetFlavor(
352 configs_by_decreasing_priority_)) {}
168 ConfigurationList::~ConfigurationList() = default; 353 ConfigurationList::~ConfigurationList() = default;
169 354
170 scoped_refptr<ConfigurationList> GetActiveConfigurations() { 355 scoped_refptr<ConfigurationList> GetEnabledConfigurations() {
171 base::AutoLock lock(g_active_configurations_lock.Get()); 356 base::AutoLock lock(g_active_configurations_lock.Get());
172 if (!g_active_configurations.Get()) { 357 if (!g_active_configurations.Get()) {
173 g_active_configurations.Get() = 358 g_active_configurations.Get() =
174 base::MakeShared<ConfigurationList>(ParseFieldTrialConfiguration()); 359 base::MakeShared<ConfigurationList>(ParseEnabledConfigurations());
175 } 360 }
176 return g_active_configurations.Get(); 361 return g_active_configurations.Get();
177 } 362 }
178 363
179 namespace testing { 364 namespace testing {
180 365
181 scoped_refptr<ConfigurationList> GetAndSetActivateConfigurations( 366 scoped_refptr<ConfigurationList> GetAndSetActivateConfigurations(
182 scoped_refptr<ConfigurationList> new_configs) { 367 scoped_refptr<ConfigurationList> new_configs) {
183 base::AutoLock lock(g_active_configurations_lock.Get()); 368 base::AutoLock lock(g_active_configurations_lock.Get());
184 auto old_configs = std::move(g_active_configurations.Get()); 369 auto old_configs = std::move(g_active_configurations.Get());
185 g_active_configurations.Get() = std::move(new_configs); 370 g_active_configurations.Get() = std::move(new_configs);
186 return old_configs; 371 return old_configs;
187 } 372 }
188 373
189 } // namespace testing 374 } // namespace testing
190 375
191 } // namespace subresource_filter 376 } // namespace subresource_filter
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698