use crate::blocker::{Blocker, BlockerResult};
use crate::cosmetic_filter_cache::{CosmeticFilterCache, UrlSpecificResources};
use crate::cosmetic_filter_cache_builder::CosmeticFilterCacheBuilder;
use crate::data_format::{deserialize_dat_file, serialize_dat_file, DeserializationError};
use crate::filters::cosmetic::CosmeticFilter;
use crate::filters::fb_builder::EngineFlatBuilder;
use crate::filters::fb_network_builder::NetworkRulesBuilder;
use crate::filters::filter_data_context::{FilterDataContext, FilterDataContextRef};
use crate::filters::network::NetworkFilter;
use crate::flatbuffers::containers::flat_serialize::FlatSerialize;
use crate::flatbuffers::unsafe_tools::VerifiedFlatbufferMemory;
use crate::lists::{FilterSet, ParseOptions};
use crate::regex_manager::RegexManagerDiscardPolicy;
use crate::request::Request;
use crate::resources::{Resource, ResourceStorage, ResourceStorageBackend};
use std::collections::HashSet;
pub struct Engine {
blocker: Blocker,
cosmetic_cache: CosmeticFilterCache,
resources: ResourceStorage,
filter_data_context: FilterDataContextRef,
}
#[cfg(feature = "debug-info")]
pub struct EngineDebugInfo {
pub regex_debug_info: crate::regex_manager::RegexDebugInfo,
pub flatbuffer_size: usize,
}
impl Default for Engine {
fn default() -> Self {
Self::from_filter_set(FilterSet::new(false), false)
}
}
impl Engine {
pub fn from_rules(
rules: impl IntoIterator<Item = impl AsRef<str>>,
opts: ParseOptions,
) -> Self {
let mut filter_set = FilterSet::new(false);
filter_set.add_filters(rules, opts);
Self::from_filter_set(filter_set, true)
}
pub fn from_rules_debug(
rules: impl IntoIterator<Item = impl AsRef<str>>,
opts: ParseOptions,
) -> Self {
Self::from_rules_parametrised(rules, opts, true, true)
}
pub fn from_rules_parametrised(
filter_rules: impl IntoIterator<Item = impl AsRef<str>>,
opts: ParseOptions,
debug: bool,
optimize: bool,
) -> Self {
let mut filter_set = FilterSet::new(debug);
filter_set.add_filters(filter_rules, opts);
Self::from_filter_set(filter_set, optimize)
}
#[cfg(test)]
pub(crate) fn cosmetic_cache(self) -> CosmeticFilterCache {
self.cosmetic_cache
}
#[cfg(test)]
pub(crate) fn filter_data_context(self) -> FilterDataContextRef {
self.filter_data_context
}
pub fn from_filter_set(set: FilterSet, optimize: bool) -> Self {
let FilterSet {
network_filters,
cosmetic_filters,
..
} = set;
let memory = make_flatbuffer(network_filters, cosmetic_filters, optimize);
let filter_data_context = FilterDataContext::new(memory);
Self {
blocker: Blocker::from_context(FilterDataContextRef::clone(&filter_data_context)),
cosmetic_cache: CosmeticFilterCache::from_context(FilterDataContextRef::clone(
&filter_data_context,
)),
resources: ResourceStorage::default(),
filter_data_context,
}
}
pub fn check_network_request(&self, request: &Request) -> BlockerResult {
self.blocker.check(request, &self.resources)
}
#[cfg(test)]
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,
previously_matched_rule: bool,
force_check_exceptions: bool,
) -> BlockerResult {
self.blocker.check_parameterised(
request,
&self.resources,
previously_matched_rule,
force_check_exceptions,
)
}
pub fn get_csp_directives(&self, request: &Request) -> Option<String> {
self.blocker.get_csp_directives(request)
}
pub fn use_tags(&mut self, tags: &[&str]) {
self.blocker.use_tags(tags);
}
pub fn enable_tags(&mut self, tags: &[&str]) {
self.blocker.enable_tags(tags);
}
pub fn disable_tags(&mut self, tags: &[&str]) {
self.blocker.disable_tags(tags);
}
pub fn tag_exists(&self, tag: &str) -> bool {
self.blocker.tags_enabled().contains(&tag.to_owned())
}
pub fn use_resources(&mut self, resources: impl IntoIterator<Item = Resource>) {
let storage = crate::resources::InMemoryResourceStorage::from_resources(resources);
self.use_resource_storage(storage);
}
#[cfg(not(feature = "single-thread"))]
pub fn use_resource_storage<R: ResourceStorageBackend + 'static + Sync + Send>(
&mut self,
resources: R,
) {
self.resources = ResourceStorage::from_backend(resources);
}
#[cfg(feature = "single-thread")]
pub fn use_resource_storage<R: ResourceStorageBackend + 'static>(&mut self, resources: R) {
self.resources = ResourceStorage::from_backend(resources);
}
pub fn hidden_class_id_selectors(
&self,
classes: impl IntoIterator<Item = impl AsRef<str>>,
ids: impl IntoIterator<Item = impl AsRef<str>>,
exceptions: &HashSet<String>,
) -> Vec<String> {
self.cosmetic_cache
.hidden_class_id_selectors(classes, ids, exceptions)
}
pub fn url_cosmetic_resources(&self, url: &str) -> UrlSpecificResources {
let request = if let Ok(request) = Request::new(url, url, "document") {
request
} else {
return UrlSpecificResources::empty();
};
let generichide = self.blocker.check_generic_hide(&request);
self.cosmetic_cache.hostname_cosmetic_resources(
&self.resources,
&request.hostname,
generichide,
)
}
pub fn set_regex_discard_policy(&mut self, new_discard_policy: RegexManagerDiscardPolicy) {
self.blocker.set_regex_discard_policy(new_discard_policy);
}
#[cfg(test)]
pub fn borrow_regex_manager(&self) -> crate::blocker::RegexManagerRef<'_> {
self.blocker.borrow_regex_manager()
}
#[cfg(feature = "debug-info")]
pub fn discard_regex(&mut self, regex_id: u64) {
self.blocker.discard_regex(regex_id);
}
#[cfg(feature = "debug-info")]
pub fn get_debug_info(&self) -> EngineDebugInfo {
EngineDebugInfo {
regex_debug_info: self.blocker.get_regex_debug_info(),
flatbuffer_size: self.filter_data_context.memory.data().len(),
}
}
pub fn serialize(&self) -> Vec<u8> {
let data = self.filter_data_context.memory.data();
serialize_dat_file(data)
}
pub fn deserialize(&mut self, serialized: &[u8]) -> Result<(), DeserializationError> {
let current_tags = self.blocker.tags_enabled();
let data = deserialize_dat_file(serialized)?;
let memory = VerifiedFlatbufferMemory::from_raw(data)
.map_err(DeserializationError::FlatBufferParsingError)?;
let context = FilterDataContext::new(memory);
self.filter_data_context = context;
self.blocker =
Blocker::from_context(FilterDataContextRef::clone(&self.filter_data_context));
self.blocker
.use_tags(¤t_tags.iter().map(|s| &**s).collect::<Vec<_>>());
self.cosmetic_cache = CosmeticFilterCache::from_context(FilterDataContextRef::clone(
&self.filter_data_context,
));
Ok(())
}
}
#[cfg(not(feature = "single-thread"))]
fn _assertions() {
fn _assert_send<T: Send>() {}
fn _assert_sync<T: Sync>() {}
_assert_send::<Engine>();
_assert_sync::<Engine>();
}
fn make_flatbuffer(
network_filters: Vec<NetworkFilter>,
cosmetic_filters: Vec<CosmeticFilter>,
optimize: bool,
) -> VerifiedFlatbufferMemory {
let mut builder = EngineFlatBuilder::default();
let network_rules_builder = NetworkRulesBuilder::from_rules(network_filters, optimize);
let network_rules = FlatSerialize::serialize(network_rules_builder, &mut builder);
let cosmetic_rules = CosmeticFilterCacheBuilder::from_rules(cosmetic_filters, &mut builder);
let cosmetic_rules = FlatSerialize::serialize(cosmetic_rules, &mut builder);
builder.finish(network_rules, cosmetic_rules)
}
#[cfg(test)]
#[path = "../tests/unit/engine.rs"]
mod unit_tests;