Skip to content

Commit 827af35

Browse files
committed
support generichide rules
1 parent be0ba3b commit 827af35

File tree

4 files changed

+179
-44
lines changed

4 files changed

+179
-44
lines changed

src/blocker.rs

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ pub struct Blocker {
9898
#[cfg(feature = "object-pooling")]
9999
#[serde(skip_serializing, skip_deserializing)]
100100
pool: TokenPool,
101+
102+
#[serde(default)]
103+
generic_hide: NetworkFilterList,
101104
}
102105

103106
impl Blocker {
@@ -109,6 +112,21 @@ impl Blocker {
109112
self.check_parameterised(request, false, false)
110113
}
111114

115+
pub fn check_generic_hide(&self, hostname_request: &Request) -> bool {
116+
let mut request_tokens;
117+
#[cfg(feature = "object-pooling")]
118+
{
119+
request_tokens = self.pool.pool.new();
120+
}
121+
#[cfg(not(feature = "object-pooling"))]
122+
{
123+
request_tokens = Vec::with_capacity(utils::TOKENS_BUFFER_SIZE);
124+
}
125+
hostname_request.get_tokens(&mut request_tokens);
126+
127+
self.generic_hide.check(hostname_request, &request_tokens, &HashSet::new()).is_some()
128+
}
129+
112130
pub fn check_parameterised(&self, request: &Request, matched_rule: bool, force_check_exceptions: bool) -> BlockerResult {
113131
if !request.is_supported {
114132
return BlockerResult::default();
@@ -247,6 +265,8 @@ impl Blocker {
247265
let mut tagged_filters_all = Vec::with_capacity(200);
248266
// $badfilter
249267
let mut badfilters = Vec::with_capacity(100);
268+
// $generichide
269+
let mut generic_hide = Vec::with_capacity(4000);
250270
// All other filters
251271
let mut filters = Vec::with_capacity(network_filters.len());
252272

@@ -268,6 +288,8 @@ impl Blocker {
268288
}
269289
if filter.is_csp() {
270290
csp.push(filter);
291+
} else if filter.is_generic_hide() {
292+
generic_hide.push(filter);
271293
} else if filter.is_exception() {
272294
exceptions.push(filter);
273295
} else if filter.is_important() {
@@ -283,6 +305,7 @@ impl Blocker {
283305
}
284306

285307
csp.shrink_to_fit();
308+
generic_hide.shrink_to_fit();
286309
exceptions.shrink_to_fit();
287310
importants.shrink_to_fit();
288311
redirects.shrink_to_fit();
@@ -296,6 +319,7 @@ impl Blocker {
296319
redirects: NetworkFilterList::new(redirects, options.enable_optimizations),
297320
filters_tagged: NetworkFilterList::new(Vec::new(), options.enable_optimizations),
298321
filters: NetworkFilterList::new(filters, options.enable_optimizations),
322+
generic_hide: NetworkFilterList::new(generic_hide, options.enable_optimizations),
299323
// Tags special case for enabling/disabling them dynamically
300324
tags_enabled: HashSet::new(),
301325
tagged_filters_all,
@@ -315,6 +339,8 @@ impl Blocker {
315339
pub fn filter_exists(&self, filter: &NetworkFilter) -> bool {
316340
if filter.is_csp() {
317341
self.csp.filter_exists(filter)
342+
} else if filter.is_generic_hide() {
343+
self.generic_hide.filter_exists(filter)
318344
} else if filter.is_exception() {
319345
self.exceptions.filter_exists(filter)
320346
} else if filter.is_important() {
@@ -336,6 +362,9 @@ impl Blocker {
336362
} else if filter.is_csp() {
337363
self.csp.filter_add(filter);
338364
Ok(self)
365+
} else if filter.is_generic_hide() {
366+
self.generic_hide.filter_add(filter);
367+
Ok(self)
339368
} else if filter.is_exception() {
340369
self.exceptions.filter_add(filter);
341370
Ok(self)
@@ -1327,6 +1356,20 @@ mod blocker_tests {
13271356
assert!(!matched_rule.matched);
13281357
assert!(matched_rule.exception.is_some());
13291358
}
1359+
1360+
#[test]
1361+
fn generichide() {
1362+
let blocker_options: BlockerOptions = BlockerOptions {
1363+
debug: true,
1364+
enable_optimizations: true,
1365+
};
1366+
1367+
let mut blocker = Blocker::new(Vec::new(), &blocker_options);
1368+
1369+
blocker.filter_add(NetworkFilter::parse("@@||example.com$generichide", true).unwrap()).unwrap();
1370+
1371+
assert!(blocker.check_generic_hide(&Request::from_url("https://example.com").unwrap()));
1372+
}
13301373
}
13311374

13321375
#[cfg(test)]
@@ -1346,14 +1389,13 @@ mod legacy_rule_parsing_tests {
13461389
// easyList = { 24478, 31144, 0, 5589 };
13471390
// not handling (and not including) filters with the following options:
13481391
// - $popup
1349-
// - $generichide
13501392
// - $subdocument
13511393
// - $document
13521394
// - $elemhide
13531395
// difference from original counts caused by not handling document/subdocument options and possibly miscounting on the blocker side.
13541396
// Printing all non-cosmetic, non-html, non-comment/-empty rules and ones with no unsupported options yields 29142 items
13551397
// This engine also handles 3 rules that old one does not
1356-
const EASY_LIST: ListCounts = ListCounts { filters: 24062+3, cosmetic_filters: 31163, exceptions: 5080 };
1398+
const EASY_LIST: ListCounts = ListCounts { filters: 24062+3, cosmetic_filters: 31163, exceptions: 5800 };
13571399
// easyPrivacy = { 11817, 0, 0, 1020 };
13581400
// differences in counts explained by hashset size underreporting as detailed in the next two cases
13591401
const EASY_PRIVACY: ListCounts = ListCounts { filters: 11889, cosmetic_filters: 0, exceptions: 1021 };
@@ -1391,7 +1433,8 @@ mod legacy_rule_parsing_tests {
13911433
let blocker = Blocker::new(network_filters, &blocker_options);
13921434

13931435
// Some filters in the filter_map are pointed at by multiple tokens, increasing the total number of items
1394-
assert!(vec_hashmap_len(&blocker.exceptions.filter_map) >= expectation.exceptions, "Number of collected exceptions does not match expectation");
1436+
assert!(vec_hashmap_len(&blocker.exceptions.filter_map) + vec_hashmap_len(&blocker.generic_hide.filter_map)
1437+
>= expectation.exceptions, "Number of collected exceptions does not match expectation");
13951438

13961439
assert!(vec_hashmap_len(&blocker.filters.filter_map) +
13971440
vec_hashmap_len(&blocker.importants.filter_map) +

src/cosmetic_filter_cache.rs

Lines changed: 46 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ lazy_static! {
1212
static ref PUBLIC_SUFFIXES: psl::List = psl::List::new();
1313
}
1414

15-
/// Contains cosmetic filter information intended to be injected into a particular hostname.
15+
/// Contains cosmetic filter information intended to be used on a particular URL.
1616
///
1717
/// `hide_selectors` is a set of any CSS selector on the page that should be hidden, i.e. styled as
1818
/// `{ display: none !important; }`.
@@ -25,21 +25,27 @@ lazy_static! {
2525
///
2626
/// `injected_script` is the Javascript code for any scriptlets that should be injected into the
2727
/// page.
28+
///
29+
/// `generichide` is set to true if there is a corresponding `$generichide` exception network
30+
/// filter. If so, the page should not query for additional generic rules using
31+
/// `hidden_class_id_selectors`.
2832
#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
29-
pub struct HostnameSpecificResources {
33+
pub struct UrlSpecificResources {
3034
pub hide_selectors: HashSet<String>,
3135
pub style_selectors: HashMap<String, Vec<String>>,
3236
pub exceptions: HashSet<String>,
3337
pub injected_script: String,
38+
pub generichide: bool,
3439
}
3540

36-
impl HostnameSpecificResources {
41+
impl UrlSpecificResources {
3742
pub fn empty() -> Self {
3843
Self {
3944
hide_selectors: HashSet::new(),
4045
style_selectors: HashMap::new(),
4146
exceptions: HashSet::new(),
4247
injected_script: String::new(),
48+
generichide: false,
4349
}
4450
}
4551
}
@@ -197,10 +203,10 @@ impl CosmeticFilterCache {
197203
.collect::<Vec<_>>()
198204
}
199205

200-
pub fn hostname_cosmetic_resources(&self, hostname: &str) -> HostnameSpecificResources {
206+
pub fn hostname_cosmetic_resources(&self, hostname: &str, generichide: bool) -> UrlSpecificResources {
201207
let domain = match PUBLIC_SUFFIXES.domain(hostname) {
202208
Some(domain) => domain,
203-
None => return HostnameSpecificResources::empty(),
209+
None => return UrlSpecificResources::empty(),
204210
};
205211
let domain_str = domain.to_str();
206212

@@ -225,8 +231,13 @@ impl CosmeticFilterCache {
225231

226232
let (hostname_hide_selectors, style_selectors, script_injections) = hostname_specific_rules(&rules_that_apply[..]);
227233

228-
let mut hide_selectors = self.misc_generic_selectors.difference(&exceptions.hide_exceptions).cloned().collect::<HashSet<_>>();
229-
hostname_hide_selectors.into_iter().for_each(|sel| { hide_selectors.insert(sel); });
234+
let hide_selectors = if generichide {
235+
hostname_hide_selectors
236+
} else {
237+
let mut hide_selectors = self.misc_generic_selectors.difference(&exceptions.hide_exceptions).cloned().collect::<HashSet<_>>();
238+
hostname_hide_selectors.into_iter().for_each(|sel| { hide_selectors.insert(sel); });
239+
hide_selectors
240+
};
230241

231242
let mut injected_script = String::new();
232243
script_injections.iter().for_each(|s| {
@@ -236,11 +247,12 @@ impl CosmeticFilterCache {
236247
}
237248
});
238249

239-
HostnameSpecificResources {
250+
UrlSpecificResources {
240251
hide_selectors,
241252
style_selectors,
242253
exceptions: exceptions.hide_exceptions,
243254
injected_script,
255+
generichide,
244256
}
245257
}
246258

@@ -446,15 +458,15 @@ mod cosmetic_cache_tests {
446458
"sub.example.com#@#.item2",
447459
]);
448460

449-
let out = cfcache.hostname_cosmetic_resources("test.com");
450-
let mut expected = HostnameSpecificResources::empty();
461+
let out = cfcache.hostname_cosmetic_resources("test.com", false);
462+
let mut expected = UrlSpecificResources::empty();
451463
assert_eq!(out, expected);
452464

453-
let out = cfcache.hostname_cosmetic_resources("example.com");
465+
let out = cfcache.hostname_cosmetic_resources("example.com", false);
454466
expected.exceptions.insert(".item".into());
455467
assert_eq!(out, expected);
456468

457-
let out = cfcache.hostname_cosmetic_resources("sub.example.com");
469+
let out = cfcache.hostname_cosmetic_resources("sub.example.com", false);
458470
expected.exceptions.insert(".item2".into());
459471
assert_eq!(out, expected);
460472
}
@@ -465,16 +477,16 @@ mod cosmetic_cache_tests {
465477
"example.com,~sub.example.com##.item",
466478
]);
467479

468-
let out = cfcache.hostname_cosmetic_resources("test.com");
469-
let mut expected = HostnameSpecificResources::empty();
480+
let out = cfcache.hostname_cosmetic_resources("test.com", false);
481+
let mut expected = UrlSpecificResources::empty();
470482
assert_eq!(out, expected);
471483

472-
let out = cfcache.hostname_cosmetic_resources("example.com");
484+
let out = cfcache.hostname_cosmetic_resources("example.com", false);
473485
expected.hide_selectors.insert(".item".to_owned());
474486
assert_eq!(out, expected);
475487

476-
let out = cfcache.hostname_cosmetic_resources("sub.example.com");
477-
let mut expected = HostnameSpecificResources::empty();
488+
let out = cfcache.hostname_cosmetic_resources("sub.example.com", false);
489+
let mut expected = UrlSpecificResources::empty();
478490
expected.exceptions.insert(".item".into());
479491
assert_eq!(out, expected);
480492
}
@@ -488,23 +500,23 @@ mod cosmetic_cache_tests {
488500
"a2.sub.example.com##.element:style(background: #000)",
489501
]);
490502

491-
let out = cfcache.hostname_cosmetic_resources("sub.example.com");
492-
let mut expected = HostnameSpecificResources::empty();
503+
let out = cfcache.hostname_cosmetic_resources("sub.example.com", false);
504+
let mut expected = UrlSpecificResources::empty();
493505
assert_eq!(out, expected);
494506

495-
let out = cfcache.hostname_cosmetic_resources("sub.test.example.com");
507+
let out = cfcache.hostname_cosmetic_resources("sub.test.example.com", false);
496508
assert_eq!(out, expected);
497509

498-
let out = cfcache.hostname_cosmetic_resources("a1.sub.example.com");
510+
let out = cfcache.hostname_cosmetic_resources("a1.sub.example.com", false);
499511
expected.hide_selectors.insert(".element".to_owned());
500512
assert_eq!(out, expected);
501513

502-
let out = cfcache.hostname_cosmetic_resources("test.example.com");
514+
let out = cfcache.hostname_cosmetic_resources("test.example.com", false);
503515
expected.hide_selectors.clear();
504516
expected.style_selectors.insert(".element".to_owned(), vec!["background: #fff".to_owned()]);
505517
assert_eq!(out, expected);
506518

507-
let out = cfcache.hostname_cosmetic_resources("a2.sub.example.com");
519+
let out = cfcache.hostname_cosmetic_resources("a2.sub.example.com", false);
508520
expected.style_selectors.clear();
509521
expected.style_selectors.insert(".element".to_owned(), vec!["background: #000".to_owned()]);
510522
assert_eq!(out, expected);
@@ -547,26 +559,26 @@ mod cosmetic_cache_tests {
547559
},
548560
]);
549561

550-
let out = cfcache.hostname_cosmetic_resources("sub.example.com");
551-
let mut expected = HostnameSpecificResources::empty();
562+
let out = cfcache.hostname_cosmetic_resources("sub.example.com", false);
563+
let mut expected = UrlSpecificResources::empty();
552564
assert_eq!(out, expected);
553565

554-
let out = cfcache.hostname_cosmetic_resources("sub.test.example.com");
566+
let out = cfcache.hostname_cosmetic_resources("sub.test.example.com", false);
555567
assert_eq!(out, expected);
556568

557-
let out = cfcache.hostname_cosmetic_resources("test.example.com");
569+
let out = cfcache.hostname_cosmetic_resources("test.example.com", false);
558570
expected.injected_script = "set-constant.js, atob, trueFunc\n".to_owned();
559571
assert_eq!(out, expected);
560572

561-
let out = cfcache.hostname_cosmetic_resources("cosmetic.net");
573+
let out = cfcache.hostname_cosmetic_resources("cosmetic.net", false);
562574
expected.injected_script = "nowebrtc.js\n".to_owned();
563575
assert_eq!(out, expected);
564576

565-
let out = cfcache.hostname_cosmetic_resources("g.cosmetic.net");
577+
let out = cfcache.hostname_cosmetic_resources("g.cosmetic.net", false);
566578
expected.injected_script = "nowebrtc.js\nwindow.open-defuser.js\n".to_owned();
567579
assert_eq!(out, expected);
568580

569-
let out = cfcache.hostname_cosmetic_resources("c.g.cosmetic.net");
581+
let out = cfcache.hostname_cosmetic_resources("c.g.cosmetic.net", false);
570582
expected.injected_script = "window.open-defuser.js\n".to_owned();
571583
assert_eq!(out, expected);
572584
}
@@ -619,7 +631,7 @@ mod cosmetic_cache_tests {
619631
"~test.com###test-element",
620632
];
621633
let cfcache = CosmeticFilterCache::new(rules.iter().map(|r| CosmeticFilter::parse(r, false).unwrap()).collect::<Vec<_>>());
622-
let exceptions = cfcache.hostname_cosmetic_resources("example.co.uk").exceptions;
634+
let exceptions = cfcache.hostname_cosmetic_resources("example.co.uk", false).exceptions;
623635

624636
let out = cfcache.hidden_class_id_selectors(&["a-class".into()], &[], &exceptions);
625637
assert_eq!(out, [".a-class .with .children"]);
@@ -630,7 +642,7 @@ mod cosmetic_cache_tests {
630642
let out = cfcache.hidden_class_id_selectors(&[], &["test-element".into()], &exceptions);
631643
assert_eq!(out, ["#test-element"]);
632644

633-
let exceptions = cfcache.hostname_cosmetic_resources("a1.test.com").exceptions;
645+
let exceptions = cfcache.hostname_cosmetic_resources("a1.test.com", false).exceptions;
634646

635647
let out = cfcache.hidden_class_id_selectors(&["a-class".into()], &[], &exceptions);
636648
assert_eq!(out, [".a-class", ".a-class .with .children"]);
@@ -653,14 +665,14 @@ mod cosmetic_cache_tests {
653665
];
654666
let cfcache = CosmeticFilterCache::new(rules.iter().map(|r| CosmeticFilter::parse(r, false).unwrap()).collect::<Vec<_>>());
655667

656-
let hide_selectors = cfcache.hostname_cosmetic_resources("test.com").hide_selectors;
668+
let hide_selectors = cfcache.hostname_cosmetic_resources("test.com", false).hide_selectors;
657669
let mut expected_hides = HashSet::new();
658670
expected_hides.insert("a[href=\"bad.com\"]".to_owned());
659671
expected_hides.insert("div > p".to_owned());
660672
expected_hides.insert("a[href=\"notbad.com\"]".to_owned());
661673
assert_eq!(hide_selectors, expected_hides);
662674

663-
let hide_selectors = cfcache.hostname_cosmetic_resources("example.com").hide_selectors;
675+
let hide_selectors = cfcache.hostname_cosmetic_resources("example.com", false).hide_selectors;
664676
let mut expected_hides = HashSet::new();
665677
expected_hides.insert("a[href=\"bad.com\"]".to_owned());
666678
assert_eq!(hide_selectors, expected_hides);

0 commit comments

Comments
 (0)