Skip to content

Commit 2e8522e

Browse files
authored
Fix processing bad_filter in into_content_blocking (#559)
1 parent fb302a1 commit 2e8522e

File tree

3 files changed

+61
-3
lines changed

3 files changed

+61
-3
lines changed

src/content_blocking.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -316,9 +316,10 @@ impl TryFrom<NetworkFilter> for CbRuleEquivalent {
316316
if v.mask.contains(NetworkFilterMask::GENERIC_HIDE) {
317317
return Err(CbRuleCreationFailure::NetworkGenerichideUnsupported);
318318
}
319-
if v.mask.contains(NetworkFilterMask::BAD_FILTER) {
320-
return Err(CbRuleCreationFailure::NetworkBadFilterUnsupported);
321-
}
319+
debug_assert!(
320+
!v.mask.contains(NetworkFilterMask::BAD_FILTER),
321+
"BAD_FILTER should be filtered out"
322+
);
322323
if v.is_csp() {
323324
return Err(CbRuleCreationFailure::NetworkCspUnsupported);
324325
}

src/lists.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,17 +285,31 @@ impl FilterSet {
285285
self,
286286
) -> Result<(Vec<crate::content_blocking::CbRule>, Vec<String>), ()> {
287287
use crate::content_blocking;
288+
use crate::filters::network::NetworkFilterMaskHelper;
289+
use std::collections::HashSet;
288290

289291
if !self.debug {
290292
return Err(());
291293
}
292294

295+
// Store bad filter id to skip them later.
296+
let mut bad_filter_ids = HashSet::new();
297+
for filter in self.network_filters.iter() {
298+
if filter.is_badfilter() {
299+
bad_filter_ids.insert(filter.get_id_without_badfilter());
300+
}
301+
}
302+
293303
let mut ignore_previous_rules = vec![];
294304
let mut other_rules = vec![];
295305

296306
let mut filters_used = vec![];
297307

298308
self.network_filters.into_iter().for_each(|filter| {
309+
// Don't process bad filter rules or matching bad filter rules.
310+
if bad_filter_ids.contains(&filter.get_id()) || filter.is_badfilter() {
311+
return;
312+
}
299313
let original_rule = *filter
300314
.raw_line
301315
.clone()

tests/unit/content_blocking.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,17 @@ mod ab2cb_tests {
1515
);
1616
}
1717

18+
fn test_from_abp_multi(abp_rules: &[&str], cb: &str) {
19+
let mut filter_set = crate::lists::FilterSet::new(true);
20+
filter_set.add_filters(abp_rules, Default::default());
21+
let (cb_rules, _) = filter_set.into_content_blocking().unwrap();
22+
assert_eq!(
23+
cb_rules,
24+
serde_json::from_str::<Vec<CbRule>>(cb)
25+
.expect("content blocking rules under test could not be deserialized")
26+
);
27+
}
28+
1829
#[test]
1930
fn ad_tests() {
2031
test_from_abp(
@@ -653,6 +664,38 @@ mod ab2cb_tests {
653664
}]"####,
654665
);
655666
}
667+
668+
#[test]
669+
fn badfilter_cancels_matching_rules() {
670+
// Test that BAD_FILTER rules cancel out matching rules
671+
// Input: regular rule, BAD_FILTER rule, and differently modified rule
672+
// Output: only the differently modified rule should remain (BAD_FILTER cancels the exact match)
673+
test_from_abp_multi(
674+
&[
675+
"||example.com^",
676+
"||example.com^$badfilter",
677+
"||example.com^$third-party",
678+
],
679+
r####"[{
680+
"action": {
681+
"type": "block"
682+
},
683+
"trigger": {
684+
"url-filter": "^[^:]+:(//)?([^/]+\\.)?example\\.com",
685+
"load-type": ["third-party"]
686+
}
687+
}, {
688+
"action": {
689+
"type": "ignore-previous-rules"
690+
},
691+
"trigger": {
692+
"url-filter": ".*",
693+
"resource-type": ["document"],
694+
"load-type": ["first-party"]
695+
}
696+
}]"####,
697+
);
698+
}
656699
}
657700

658701
#[cfg(test)]

0 commit comments

Comments
 (0)