Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 17 additions & 9 deletions src/blocker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ pub struct Blocker {
pub(crate) filter_data_context: FilterDataContextRef,
}

#[cfg(feature = "single-thread")]
pub(crate) type RegexManagerRef<'a> = std::cell::RefMut<'a, RegexManager>;
#[cfg(not(feature = "single-thread"))]
pub(crate) type RegexManagerRef<'a> = std::sync::MutexGuard<'a, RegexManager>;

impl Blocker {
/// Decide if a network request (usually from WebRequest API) should be
/// blocked, redirected or allowed.
Expand Down Expand Up @@ -130,31 +135,34 @@ impl Blocker {
self.get_list(NetworkFilterListId::TaggedFiltersAll)
}

#[cfg(feature = "single-thread")]
fn borrow_regex_manager(&self) -> std::cell::RefMut<'_, RegexManager> {
pub(crate) fn borrow_regex_manager(&self) -> RegexManagerRef<'_> {
#[cfg(feature = "single-thread")]
#[allow(unused_mut)]
let mut manager = self.regex_manager.borrow_mut();
#[cfg(not(feature = "single-thread"))]
let mut manager = self.regex_manager.lock().unwrap();

#[cfg(not(target_arch = "wasm32"))]
manager.update_time();

manager
}

#[cfg(not(feature = "single-thread"))]
fn borrow_regex_manager(&self) -> std::sync::MutexGuard<'_, RegexManager> {
let mut manager = self.regex_manager.lock().unwrap();
manager.update_time();
manager
}

pub fn check_generic_hide(&self, hostname_request: &Request) -> bool {
let mut regex_manager = self.borrow_regex_manager();
self.generic_hide()
.check(hostname_request, &HashSet::new(), &mut regex_manager)
.is_some()
}

#[doc(hidden)]
pub(crate) fn check_exceptions(&self, request: &Request) -> bool {
Comment on lines +158 to +159
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to include #[doc(hidden)] on pub(crate) items

let mut regex_manager = self.borrow_regex_manager();
self.exceptions()
.check(request, &HashSet::new(), &mut regex_manager)
.is_some()
}

pub fn check_parameterised(
&self,
request: &Request,
Expand Down
10 changes: 10 additions & 0 deletions src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ impl Engine {
self.blocker.check(request, &self.resources)
}

#[doc(hidden)]
pub(crate) fn check_network_request_exceptions(&self, request: &Request) -> bool {
self.blocker.check_exceptions(request)
}

pub fn check_network_request_subset(
&self,
request: &Request,
Expand Down Expand Up @@ -266,6 +271,11 @@ impl Engine {
self.blocker.set_regex_discard_policy(new_discard_policy);
}

#[cfg(test)]
pub fn borrow_regex_manager(&self) -> crate::blocker::RegexManagerRef<'_> {
Comment on lines +274 to +275
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment describing why this is necessary would be helpful

(I can tell from the diffs below, but later it won't be as obvious)

self.blocker.borrow_regex_manager()
}

#[cfg(feature = "debug-info")]
pub fn discard_regex(&mut self, regex_id: u64) {
self.blocker.discard_regex(regex_id);
Expand Down
36 changes: 12 additions & 24 deletions src/filters/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -969,6 +969,18 @@ impl NetworkFilter {
FilterTokens::Other(t)
}
}

#[doc(hidden)]
pub fn matches_test(&self, request: &request::Request) -> bool {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#[cfg(test)]?

let filter_set = crate::FilterSet::new_with_rules(vec![self.clone()], vec![], true);
let engine = crate::Engine::from_filter_set(filter_set, true);

if self.is_exception() {
engine.check_network_request_exceptions(request)
} else {
engine.check_network_request(request).matched
}
}
}

impl NetworkFilterMaskHelper for NetworkFilter {
Expand All @@ -993,30 +1005,6 @@ pub trait NetworkMatchable {
fn matches_test(&self, request: &request::Request) -> bool;
}

impl NetworkMatchable for NetworkFilter {
fn matches(&self, request: &request::Request, regex_manager: &mut RegexManager) -> bool {
Comment on lines -996 to -997
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fwiw, this is a breaking API change and will require another bump up to 0.12.x

use crate::filters::network_matchers::{
check_excluded_domains, check_included_domains, check_options, check_pattern,
};
check_options(self.mask, request)
&& check_included_domains(self.opt_domains.as_deref(), request)
&& check_excluded_domains(self.opt_not_domains.as_deref(), request)
&& check_pattern(
self.mask,
self.filter.iter(),
self.hostname.as_deref(),
(self as *const NetworkFilter) as u64,
request,
regex_manager,
)
}

#[cfg(test)]
fn matches_test(&self, request: &request::Request) -> bool {
self.matches(request, &mut RegexManager::default())
}
}

// ---------------------------------------------------------------------------
// Filter parsing
// ---------------------------------------------------------------------------
Expand Down
35 changes: 0 additions & 35 deletions src/filters/network_matchers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,22 +414,6 @@ pub fn check_options(mask: NetworkFilterMask, request: &request::Request) -> boo
true
}

#[inline]
pub fn check_included_domains(opt_domains: Option<&[Hash]>, request: &request::Request) -> bool {
// Source URL must be among these domains to match
if let Some(included_domains) = opt_domains.as_ref() {
if let Some(source_hashes) = request.source_hostname_hashes.as_ref() {
if source_hashes
.iter()
.all(|h| !utils::bin_lookup(included_domains, *h))
{
return false;
}
}
}
true
}

#[inline]
pub fn check_included_domains_mapped(
opt_domains: Option<&[u32]>,
Expand All @@ -451,25 +435,6 @@ pub fn check_included_domains_mapped(
true
}

#[inline]
pub fn check_excluded_domains(
opt_not_domains: Option<&[Hash]>,
request: &request::Request,
) -> bool {
if let Some(excluded_domains) = opt_not_domains.as_ref() {
if let Some(source_hashes) = request.source_hostname_hashes.as_ref() {
if source_hashes
.iter()
.any(|h| utils::bin_lookup(excluded_domains, *h))
{
return false;
}
}
}

true
}

#[inline]
pub fn check_excluded_domains_mapped(
opt_not_domains: Option<&[u32]>,
Expand Down
2 changes: 1 addition & 1 deletion src/regex_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use std::time::Duration;

#[cfg(test)]
#[cfg(not(target_arch = "wasm32"))]
use mock_instant::global::Instant;
use mock_instant::thread_local::Instant;
#[cfg(not(test))]
#[cfg(not(target_arch = "wasm32"))]
use std::time::Instant;
Expand Down
35 changes: 18 additions & 17 deletions tests/legacy_harness.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
mod legacy_test_filters {
use adblock::filters::network::NetworkFilter;
use adblock::filters::network::NetworkFilterMask;
use adblock::filters::network::NetworkMatchable;
use adblock::regex_manager::RegexManager;
use adblock::request::Request;
use adblock::Engine;

fn test_filter<'a>(
raw_filter: &str,
Expand Down Expand Up @@ -35,12 +34,15 @@ mod legacy_test_filters {
filter.filter
);

let engine = Engine::from_rules_debug([raw_filter], Default::default());

for to_block in blocked {
assert!(
filter.matches(
&Request::new(to_block, "https://example.com", "other").unwrap(),
&mut RegexManager::default()
),
engine
.check_network_request(
&Request::new(to_block, "https://example.com", "other").unwrap(),
)
.matched,
"Expected filter {} to match {}",
raw_filter,
&to_block
Expand All @@ -49,10 +51,11 @@ mod legacy_test_filters {

for to_pass in not_blocked {
assert!(
!filter.matches(
&Request::new(to_pass, "https://example.com", "other").unwrap(),
&mut RegexManager::default()
),
!engine
.check_network_request(
&Request::new(to_pass, "https://example.com", "other").unwrap(),
)
.matched,
"Expected filter {} to pass {}",
raw_filter,
&to_pass
Expand Down Expand Up @@ -302,14 +305,12 @@ mod legacy_test_filters {
);

// explicit, separate testcase construction of the "script" option as it is not the deafult
let filter = NetworkFilter::parse(
"||googlesyndication.com/safeframe/$third-party,script",
true,
Default::default(),
)
.unwrap();
let request = Request::new("http://tpc.googlesyndication.com/safeframe/1-0-2/html/container.html#xpc=sf-gdn-exp-2&p=http%3A//slashdot.org;", "https://this-is-always-third-party.com", "script").unwrap();
assert!(filter.matches(&request, &mut RegexManager::default()));
let engine = Engine::from_rules_debug(
["||googlesyndication.com/safeframe/$third-party,script"],
Default::default(),
);
assert!(engine.check_network_request(&request).matched);
}
}

Expand Down
5 changes: 2 additions & 3 deletions tests/matching.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use adblock::filters::network::{NetworkFilter, NetworkFilterMaskHelper, NetworkMatchable};
use adblock::regex_manager::RegexManager;
use adblock::filters::network::{NetworkFilter, NetworkFilterMaskHelper};
use adblock::request::Request;
use adblock::resources::{MimeType, Resource, ResourceType};
use adblock::Engine;
Expand Down Expand Up @@ -75,7 +74,7 @@ fn check_filter_matching() {
// The dataset has cases where URL is set to just "http://" or "https://", which we do not support
if let Ok(request) = request_res {
assert!(
network_filter.matches(&request, &mut RegexManager::default()),
network_filter.matches_test(&request),
"Expected {} to match {} at {}, typed {}",
filter,
req.url,
Expand Down
63 changes: 52 additions & 11 deletions tests/unit/filters/network_matchers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,9 +350,38 @@ mod match_tests {
}

fn check_options(filter: &NetworkFilter, request: &request::Request) -> bool {
let mut mapping = HashMap::new();
let opt_domains = filter.opt_domains.clone().map(|domains| {
domains
.iter()
.map(|domain| {
mapping.insert(*domain, *domain as u32);
*domain as u32
})
.collect::<Vec<u32>>()
});

let opt_not_domains = filter.opt_not_domains.clone().map(|domains| {
domains
.iter()
.map(|domain| {
mapping.insert(*domain, *domain as u32);
*domain as u32
})
.collect::<Vec<u32>>()
});

super::super::check_options(filter.mask, request)
&& super::super::check_included_domains(filter.opt_domains.as_deref(), request)
&& super::super::check_excluded_domains(filter.opt_not_domains.as_deref(), request)
&& super::super::check_included_domains_mapped(
opt_domains.as_deref(),
request,
&mapping,
)
&& super::super::check_excluded_domains_mapped(
opt_not_domains.as_deref(),
request,
&mapping,
)
}

#[test]
Expand Down Expand Up @@ -659,22 +688,34 @@ mod match_tests {
}

#[test]
#[ignore] // Not going to handle lookaround regexes
#[cfg(feature = "debug-info")]
fn check_lookaround_regex_handled() {
{
use crate::Engine;
let filter = r#"/^https?:\/\/([0-9a-z\-]+\.)?(9anime|animeland|animenova|animeplus|animetoon|animewow|gamestorrent|goodanime|gogoanime|igg-games|kimcartoon|memecenter|readcomiconline|toonget|toonova|watchcartoononline)\.[a-z]{2,4}\/(?!([Ee]xternal|[Ii]mages|[Ss]cripts|[Uu]ploads|ac|ajax|assets|combined|content|cov|cover|(img\/bg)|(img\/icon)|inc|jwplayer|player|playlist-cat-rss|static|thumbs|wp-content|wp-includes)\/)(.*)/$image,other,script,~third-party,xmlhttprequest,domain=~animeland.hu"#;
let network_filter = NetworkFilter::parse(filter, true, Default::default()).unwrap();
let url = "https://data.foo.com/9VjjrjU9Or2aqkb8PDiqTBnULPgeI48WmYEHkYer";
let source = "http://123movies.com";
let engine = Engine::from_rules(vec![filter], Default::default());
let url = "https://9anime.to/watch/episode-1";
let source = "https://9anime.to";
let request = request::Request::new(url, source, "script").unwrap();
let mut regex_manager = RegexManager::default();
assert!(regex_manager.get_compiled_regex_count() == 0);
assert_eq!(
engine
.get_debug_info()
.regex_debug_info
.compiled_regex_count,
0
);
// Regex can't be compiled, so no match.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the test case added here (already in the disabled state):
40b7815

regex crate can't parse such regex, so I changed the test to verify it doesn't match

assert!(
network_filter.matches(&request, &mut regex_manager),
"Expected match for {filter} on {url}"
!engine.check_network_request(&request).matched,
"Expected no match for {filter} on {url}"
);
assert_eq!(
engine
.get_debug_info()
.regex_debug_info
.compiled_regex_count,
1
);
assert!(regex_manager.get_compiled_regex_count() == 1);
}
}

Expand Down
Loading