OLD | NEW |
---|---|
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" | 18 #include "base/strings/string_piece.h" |
14 #include "base/strings/string_split.h" | 19 #include "base/strings/string_split.h" |
15 #include "base/strings/string_util.h" | 20 #include "base/strings/string_util.h" |
16 #include "base/synchronization/lock.h" | 21 #include "base/synchronization/lock.h" |
22 #include "base/values.h" | |
17 #include "components/variations/variations_associated_data.h" | 23 #include "components/variations/variations_associated_data.h" |
18 | 24 |
19 namespace subresource_filter { | 25 namespace subresource_filter { |
20 | 26 |
21 namespace { | 27 namespace { |
22 | 28 |
29 // Helpers for parsing the experimental configuration ------------------------- | |
30 | |
23 std::string TakeVariationParamOrReturnEmpty( | 31 std::string TakeVariationParamOrReturnEmpty( |
24 std::map<std::string, std::string>* params, | 32 std::map<std::string, std::string>* params, |
25 const std::string& key) { | 33 const std::string& key) { |
26 auto it = params->find(key); | 34 auto it = params->find(key); |
27 if (it == params->end()) | 35 if (it == params->end()) |
28 return std::string(); | 36 return std::string(); |
29 std::string value = std::move(it->second); | 37 std::string value = std::move(it->second); |
30 params->erase(it); | 38 params->erase(it); |
31 return value; | 39 return value; |
32 } | 40 } |
(...skipping 29 matching lines...) Expand all Loading... | |
62 activation_list_type = ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL; | 70 activation_list_type = ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL; |
63 } else if (base::LowerCaseEqualsASCII(activation_list, | 71 } else if (base::LowerCaseEqualsASCII(activation_list, |
64 kActivationListSubresourceFilter)) { | 72 kActivationListSubresourceFilter)) { |
65 activation_list_type = ActivationList::SUBRESOURCE_FILTER; | 73 activation_list_type = ActivationList::SUBRESOURCE_FILTER; |
66 } | 74 } |
67 } | 75 } |
68 return activation_list_type; | 76 return activation_list_type; |
69 } | 77 } |
70 | 78 |
71 double ParsePerformanceMeasurementRate(const std::string& rate) { | 79 double ParsePerformanceMeasurementRate(const std::string& rate) { |
72 double value = 0; | 80 double value = 0.0; |
73 if (!base::StringToDouble(rate, &value) || value < 0) | 81 if (!base::StringToDouble(rate, &value) || value < 0) |
74 return 0; | 82 return 0.0; |
75 return value < 1 ? value : 1; | 83 return value < 1 ? value : 1; |
76 } | 84 } |
77 | 85 |
78 bool ParseBool(const base::StringPiece value) { | 86 bool ParseBool(const base::StringPiece value) { |
79 return base::LowerCaseEqualsASCII(value, "true"); | 87 return base::LowerCaseEqualsASCII(value, "true"); |
80 } | 88 } |
81 | 89 |
82 Configuration ParseFieldTrialConfiguration() { | 90 std::vector<Configuration> FillEnabledPresetConfigurations( |
91 std::map<std::string, std::string>* params) { | |
92 const struct { | |
93 const char* name; | |
94 Configuration (*factory_method)(); | |
95 } kAvailablePresetConfigurations[] = { | |
96 {kPresetLiveRunOnPhishingSites, | |
97 &Configuration::MakePresetForLiveRunOnPhishingSites}, | |
98 {kPresetPerformanceTestingDryRunOnAllSites, | |
99 &Configuration::MakePresetForPerformanceTestingDryRunOnAllSites}}; | |
100 | |
101 std::vector<Configuration> enabled_configurations; | |
102 const std::string enabled_presets_list = | |
103 TakeVariationParamOrReturnEmpty(params, kEnablePresetsParameterName); | |
104 for (const base::StringPiece enabled_preset : | |
105 base::SplitStringPiece(enabled_presets_list, ",", base::TRIM_WHITESPACE, | |
106 base::SPLIT_WANT_NONEMPTY)) { | |
107 for (const auto& available_preset : kAvailablePresetConfigurations) { | |
108 if (base::LowerCaseEqualsASCII(enabled_preset, available_preset.name)) { | |
109 enabled_configurations.push_back(available_preset.factory_method()); | |
110 break; | |
111 } | |
112 } | |
113 } | |
114 return enabled_configurations; | |
115 } | |
116 | |
117 Configuration ParseExperimentalConfiguration( | |
118 std::map<std::string, std::string>* params) { | |
83 Configuration configuration; | 119 Configuration configuration; |
84 | 120 |
85 std::map<std::string, std::string> params; | 121 // ActivationConditions: |
86 base::GetFieldTrialParamsByFeature(kSafeBrowsingSubresourceFilter, ¶ms); | 122 configuration.activation_conditions.activation_scope = ParseActivationScope( |
123 TakeVariationParamOrReturnEmpty(params, kActivationScopeParameterName)); | |
87 | 124 |
88 configuration.activation_level = ParseActivationLevel( | 125 configuration.activation_conditions.activation_list = ParseActivationList( |
89 TakeVariationParamOrReturnEmpty(¶ms, kActivationLevelParameterName)); | 126 TakeVariationParamOrReturnEmpty(params, kActivationListsParameterName)); |
90 | 127 |
91 configuration.activation_scope = ParseActivationScope( | 128 // ActivationOptions: |
92 TakeVariationParamOrReturnEmpty(¶ms, kActivationScopeParameterName)); | 129 configuration.activation_options.activation_level = ParseActivationLevel( |
130 TakeVariationParamOrReturnEmpty(params, kActivationLevelParameterName)); | |
93 | 131 |
94 configuration.activation_list = ParseActivationList( | 132 configuration.activation_options.performance_measurement_rate = |
95 TakeVariationParamOrReturnEmpty(¶ms, kActivationListsParameterName)); | 133 ParsePerformanceMeasurementRate(TakeVariationParamOrReturnEmpty( |
134 params, kPerformanceMeasurementRateParameterName)); | |
96 | 135 |
97 configuration.performance_measurement_rate = | 136 configuration.activation_options.should_suppress_notifications = |
98 ParsePerformanceMeasurementRate(TakeVariationParamOrReturnEmpty( | 137 ParseBool(TakeVariationParamOrReturnEmpty( |
99 ¶ms, kPerformanceMeasurementRateParameterName)); | 138 params, kSuppressNotificationsParameterName)); |
100 | 139 |
101 configuration.should_suppress_notifications = | 140 configuration.activation_options.should_whitelist_site_on_reload = |
102 ParseBool(TakeVariationParamOrReturnEmpty( | 141 ParseBool(TakeVariationParamOrReturnEmpty( |
103 ¶ms, kSuppressNotificationsParameterName)); | 142 params, kWhitelistSiteOnReloadParameterName)); |
104 | 143 |
105 configuration.ruleset_flavor = | 144 // GeneralSettings: |
106 TakeVariationParamOrReturnEmpty(¶ms, kRulesetFlavorParameterName); | 145 configuration.general_settings.ruleset_flavor = |
107 | 146 TakeVariationParamOrReturnEmpty(params, kRulesetFlavorParameterName); |
108 configuration.should_whitelist_site_on_reload = | |
109 ParseBool(TakeVariationParamOrReturnEmpty( | |
110 ¶ms, kWhitelistSiteOnReloadParameterName)); | |
111 | 147 |
112 return configuration; | 148 return configuration; |
113 } | 149 } |
114 | 150 |
151 std::vector<Configuration> ParseEnabledConfigurations() { | |
152 std::map<std::string, std::string> params; | |
153 base::GetFieldTrialParamsByFeature(kSafeBrowsingSubresourceFilter, ¶ms); | |
154 | |
155 std::vector<Configuration> configs = FillEnabledPresetConfigurations(¶ms); | |
156 | |
157 Configuration experimental_config = ParseExperimentalConfiguration(¶ms); | |
158 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
| |
159 | |
160 return configs; | |
161 } | |
162 | |
163 std::vector<Configuration> MakeConfigVector(Configuration config) { | |
164 std::vector<Configuration> configs; | |
165 configs.push_back(std::move(config)); | |
166 return configs; | |
167 } | |
168 | |
169 template <class T> | |
170 std::string StreamToString(const T& value) { | |
171 std::ostringstream oss; | |
172 oss << value; | |
173 return oss.str(); | |
174 } | |
175 | |
176 // Helpers for calculating configuration priorities --------------------------- | |
177 | |
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.
| |
178 size_t GetActivationLevelPriority(ActivationLevel activation_level) { | |
179 switch (activation_level) { | |
180 case ActivationLevel::DISABLED: | |
181 return 1; | |
182 case ActivationLevel::DRYRUN: | |
183 return 2; | |
184 case ActivationLevel::ENABLED: | |
185 return 3; | |
186 } | |
187 NOTREACHED(); | |
188 return 0; | |
189 } | |
190 | |
191 size_t GetActivationScopePriority(ActivationScope activation_scope) { | |
192 // The more specific ACTIVATION_LIST trumps the blanket scopes. | |
193 switch (activation_scope) { | |
194 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.
| |
195 return 1; | |
196 case ActivationScope::ALL_SITES: | |
197 return 2; | |
198 case ActivationScope::ACTIVATION_LIST: | |
199 return 3; | |
200 } | |
201 NOTREACHED(); | |
202 return 0; | |
203 } | |
204 | |
205 // Returns an opaque value that represents the priority of the given |config|, | |
206 // where a greater value indicates higher priority. If it falls onto the | |
207 // |activation_list| to break a tie, the more recently implemented list has a | |
208 // higher priority. | |
209 std::tuple<size_t, size_t, size_t> GetConfigurationPriority( | |
210 const Configuration& config) { | |
211 // std::tuple implements lexicographical compare. | |
212 return std::make_tuple( | |
213 GetActivationLevelPriority(config.activation_options.activation_level), | |
214 GetActivationScopePriority(config.activation_conditions.activation_scope), | |
215 static_cast<size_t>(config.activation_conditions.activation_list)); | |
216 } | |
217 | |
218 std::vector<Configuration> SortConfigsByDecreasingPriority( | |
219 std::vector<Configuration> configs) { | |
220 auto comp = [](const Configuration& a, const Configuration& b) { | |
221 return GetConfigurationPriority(a) > GetConfigurationPriority(b); | |
222 }; | |
223 std::sort(configs.begin(), configs.end(), comp); | |
224 return configs; | |
225 } | |
226 | |
227 // Globals -------------------------------------------------------------------- | |
228 | |
115 base::LazyInstance<base::Lock>::Leaky g_active_configurations_lock = | 229 base::LazyInstance<base::Lock>::Leaky g_active_configurations_lock = |
116 LAZY_INSTANCE_INITIALIZER; | 230 LAZY_INSTANCE_INITIALIZER; |
117 | 231 |
118 base::LazyInstance<scoped_refptr<ConfigurationList>>::Leaky | 232 base::LazyInstance<scoped_refptr<ConfigurationList>>::Leaky |
119 g_active_configurations = LAZY_INSTANCE_INITIALIZER; | 233 g_active_configurations = LAZY_INSTANCE_INITIALIZER; |
120 | 234 |
121 } // namespace | 235 } // namespace |
122 | 236 |
237 // Constant definitions ------------------------------------------------------- | |
238 | |
123 const base::Feature kSafeBrowsingSubresourceFilter{ | 239 const base::Feature kSafeBrowsingSubresourceFilter{ |
124 "SubresourceFilter", base::FEATURE_DISABLED_BY_DEFAULT}; | 240 "SubresourceFilter", base::FEATURE_DISABLED_BY_DEFAULT}; |
125 | 241 |
126 const base::Feature kSafeBrowsingSubresourceFilterExperimentalUI{ | 242 const base::Feature kSafeBrowsingSubresourceFilterExperimentalUI{ |
127 "SubresourceFilterExperimentalUI", base::FEATURE_DISABLED_BY_DEFAULT}; | 243 "SubresourceFilterExperimentalUI", base::FEATURE_DISABLED_BY_DEFAULT}; |
128 | 244 |
129 // Legacy name `activation_state` is used in variation parameters. | 245 // Legacy name `activation_state` is used in variation parameters. |
130 const char kActivationLevelParameterName[] = "activation_state"; | 246 const char kActivationLevelParameterName[] = "activation_state"; |
131 const char kActivationLevelDryRun[] = "dryrun"; | 247 const char kActivationLevelDryRun[] = "dryrun"; |
132 const char kActivationLevelEnabled[] = "enabled"; | 248 const char kActivationLevelEnabled[] = "enabled"; |
133 const char kActivationLevelDisabled[] = "disabled"; | 249 const char kActivationLevelDisabled[] = "disabled"; |
134 | 250 |
135 const char kActivationScopeParameterName[] = "activation_scope"; | 251 const char kActivationScopeParameterName[] = "activation_scope"; |
136 const char kActivationScopeAllSites[] = "all_sites"; | 252 const char kActivationScopeAllSites[] = "all_sites"; |
137 const char kActivationScopeActivationList[] = "activation_list"; | 253 const char kActivationScopeActivationList[] = "activation_list"; |
138 const char kActivationScopeNoSites[] = "no_sites"; | 254 const char kActivationScopeNoSites[] = "no_sites"; |
139 | 255 |
140 const char kActivationListsParameterName[] = "activation_lists"; | 256 const char kActivationListsParameterName[] = "activation_lists"; |
141 const char kActivationListSocialEngineeringAdsInterstitial[] = | 257 const char kActivationListSocialEngineeringAdsInterstitial[] = |
142 "social_engineering_ads_interstitial"; | 258 "social_engineering_ads_interstitial"; |
143 const char kActivationListPhishingInterstitial[] = "phishing_interstitial"; | 259 const char kActivationListPhishingInterstitial[] = "phishing_interstitial"; |
144 const char kActivationListSubresourceFilter[] = "subresource_filter"; | 260 const char kActivationListSubresourceFilter[] = "subresource_filter"; |
145 | 261 |
262 const char kPerformanceMeasurementRateParameterName[] = | |
263 "performance_measurement_rate"; | |
264 const char kSuppressNotificationsParameterName[] = "suppress_notifications"; | |
265 const char kWhitelistSiteOnReloadParameterName[] = "whitelist_site_on_reload"; | |
266 | |
146 const char kRulesetFlavorParameterName[] = "ruleset_flavor"; | 267 const char kRulesetFlavorParameterName[] = "ruleset_flavor"; |
147 | 268 |
148 const char kPerformanceMeasurementRateParameterName[] = | 269 const char kEnablePresetsParameterName[] = "enable_presets"; |
149 "performance_measurement_rate"; | 270 const char kPresetLiveRunOnPhishingSites[] = "liverun_on_phishing_sites"; |
271 const char kPresetPerformanceTestingDryRunOnAllSites[] = | |
272 "performance_testing_dryrun_on_all_sites"; | |
150 | 273 |
151 const char kSuppressNotificationsParameterName[] = "suppress_notifications"; | 274 // Configuration -------------------------------------------------------------- |
152 | 275 |
153 const char kWhitelistSiteOnReloadParameterName[] = "whitelist_site_on_reload"; | 276 // static |
277 Configuration Configuration::MakePresetForLiveRunOnPhishingSites() { | |
278 return Configuration(ActivationLevel::ENABLED, | |
279 ActivationScope::ACTIVATION_LIST, | |
280 ActivationList::PHISHING_INTERSTITIAL); | |
281 } | |
282 | |
283 // static | |
284 Configuration Configuration::MakePresetForPerformanceTestingDryRunOnAllSites() { | |
285 Configuration config(ActivationLevel::DRYRUN, ActivationScope::ALL_SITES); | |
286 config.activation_options.performance_measurement_rate = 1.0; | |
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 |
304 bool Configuration::operator==(const Configuration& rhs) const { | |
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_options.activation_level, | |
309 config.activation_options.performance_measurement_rate, | |
310 config.activation_options.should_whitelist_site_on_reload, | |
311 config.activation_options.should_suppress_notifications, | |
312 config.general_settings.ruleset_flavor); | |
313 }; | |
314 return tie(*this) == tie(rhs); | |
315 } | |
316 | |
317 bool Configuration::operator!=(const Configuration& rhs) const { | |
318 return !(*this == rhs); | |
319 } | |
320 | |
321 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
| |
322 base::DictionaryValue dict; | |
323 dict.SetString("activation_scope", | |
324 StreamToString(config.activation_conditions.activation_scope)); | |
325 dict.SetString("activation_list", | |
326 StreamToString(config.activation_conditions.activation_list)); | |
327 dict.SetString("activation_level", | |
328 StreamToString(config.activation_options.activation_level)); | |
329 dict.SetDouble("performance_measurement_rate", | |
330 config.activation_options.performance_measurement_rate); | |
331 dict.SetBoolean("should_suppress_notifications", | |
332 config.activation_options.should_suppress_notifications); | |
333 dict.SetBoolean("should_whitelist_site_on_reload", | |
334 config.activation_options.should_whitelist_site_on_reload); | |
335 dict.SetString("ruleset_flavor", | |
336 StreamToString(config.general_settings.ruleset_flavor)); | |
337 std::string json; | |
338 base::JSONWriter::WriteWithOptions( | |
339 dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json); | |
340 return os << json; | |
341 } | |
342 | |
343 // ConfigurationList ---------------------------------------------------------- | |
344 | |
345 ConfigurationList::ConfigurationList(std::vector<Configuration> configs) | |
346 : configs_by_decreasing_priority_( | |
347 SortConfigsByDecreasingPriority(std::move(configs))) {} | |
166 ConfigurationList::ConfigurationList(Configuration config) | 348 ConfigurationList::ConfigurationList(Configuration config) |
167 : config_(std::move(config)) {} | 349 : 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
| |
168 ConfigurationList::~ConfigurationList() = default; | 350 ConfigurationList::~ConfigurationList() = default; |
169 | 351 |
170 scoped_refptr<ConfigurationList> GetActiveConfigurations() { | 352 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.
| |
353 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
| |
354 for (const auto& config : configs_by_decreasing_priority_) { | |
355 const std::string& flavor = config.general_settings.ruleset_flavor; | |
356 if (flavor.size() > most_specific_flavor.size() || | |
357 (flavor.size() == most_specific_flavor.size() && | |
358 flavor > most_specific_flavor)) { | |
359 most_specific_flavor = flavor; | |
360 } | |
361 } | |
362 return most_specific_flavor; | |
363 } | |
364 | |
365 scoped_refptr<ConfigurationList> GetEnabledConfigurations() { | |
171 base::AutoLock lock(g_active_configurations_lock.Get()); | 366 base::AutoLock lock(g_active_configurations_lock.Get()); |
172 if (!g_active_configurations.Get()) { | 367 if (!g_active_configurations.Get()) { |
173 g_active_configurations.Get() = | 368 g_active_configurations.Get() = |
174 base::MakeShared<ConfigurationList>(ParseFieldTrialConfiguration()); | 369 base::MakeShared<ConfigurationList>(ParseEnabledConfigurations()); |
175 } | 370 } |
176 return g_active_configurations.Get(); | 371 return g_active_configurations.Get(); |
177 } | 372 } |
178 | 373 |
179 namespace testing { | 374 namespace testing { |
180 | 375 |
181 scoped_refptr<ConfigurationList> GetAndSetActivateConfigurations( | 376 scoped_refptr<ConfigurationList> GetAndSetActivateConfigurations( |
182 scoped_refptr<ConfigurationList> new_configs) { | 377 scoped_refptr<ConfigurationList> new_configs) { |
183 base::AutoLock lock(g_active_configurations_lock.Get()); | 378 base::AutoLock lock(g_active_configurations_lock.Get()); |
184 auto old_configs = std::move(g_active_configurations.Get()); | 379 auto old_configs = std::move(g_active_configurations.Get()); |
185 g_active_configurations.Get() = std::move(new_configs); | 380 g_active_configurations.Get() = std::move(new_configs); |
186 return old_configs; | 381 return old_configs; |
187 } | 382 } |
188 | 383 |
189 } // namespace testing | 384 } // namespace testing |
190 | 385 |
191 } // namespace subresource_filter | 386 } // namespace subresource_filter |
OLD | NEW |