1use crate::blocker::{Blocker, BlockerResult};
4use crate::cosmetic_filter_cache::{CosmeticFilterCache, UrlSpecificResources};
5use crate::cosmetic_filter_cache_builder::CosmeticFilterCacheBuilder;
6use crate::data_format::{deserialize_dat_file, serialize_dat_file, DeserializationError};
7use crate::filters::cosmetic::CosmeticFilter;
8use crate::filters::fb_builder::EngineFlatBuilder;
9use crate::filters::fb_network_builder::NetworkRulesBuilder;
10use crate::filters::filter_data_context::{FilterDataContext, FilterDataContextRef};
11use crate::filters::network::NetworkFilter;
12use crate::flatbuffers::containers::flat_serialize::FlatSerialize;
13use crate::flatbuffers::unsafe_tools::VerifiedFlatbufferMemory;
14use crate::lists::{FilterSet, ParseOptions};
15use crate::regex_manager::RegexManagerDiscardPolicy;
16use crate::request::Request;
17use crate::resources::{Resource, ResourceStorage, ResourceStorageBackend};
18
19use std::collections::HashSet;
20
21pub struct Engine {
55 blocker: Blocker,
56 cosmetic_cache: CosmeticFilterCache,
57 resources: ResourceStorage,
58 filter_data_context: FilterDataContextRef,
59}
60
61#[cfg(feature = "debug-info")]
62pub struct EngineDebugInfo {
63 pub regex_debug_info: crate::regex_manager::RegexDebugInfo,
64 pub flatbuffer_size: usize,
65}
66
67impl Default for Engine {
68 fn default() -> Self {
69 Self::from_filter_set(FilterSet::new(false), false)
70 }
71}
72
73impl Engine {
74 pub fn from_rules(
76 rules: impl IntoIterator<Item = impl AsRef<str>>,
77 opts: ParseOptions,
78 ) -> Self {
79 let mut filter_set = FilterSet::new(false);
80 filter_set.add_filters(rules, opts);
81 Self::from_filter_set(filter_set, true)
82 }
83
84 pub fn from_rules_debug(
86 rules: impl IntoIterator<Item = impl AsRef<str>>,
87 opts: ParseOptions,
88 ) -> Self {
89 Self::from_rules_parametrised(rules, opts, true, true)
90 }
91
92 pub fn from_rules_parametrised(
93 filter_rules: impl IntoIterator<Item = impl AsRef<str>>,
94 opts: ParseOptions,
95 debug: bool,
96 optimize: bool,
97 ) -> Self {
98 let mut filter_set = FilterSet::new(debug);
99 filter_set.add_filters(filter_rules, opts);
100 Self::from_filter_set(filter_set, optimize)
101 }
102
103 #[cfg(test)]
104 pub(crate) fn cosmetic_cache(self) -> CosmeticFilterCache {
105 self.cosmetic_cache
106 }
107
108 #[cfg(test)]
109 pub(crate) fn filter_data_context(self) -> FilterDataContextRef {
110 self.filter_data_context
111 }
112
113 pub fn from_filter_set(set: FilterSet, optimize: bool) -> Self {
116 let FilterSet {
117 network_filters,
118 cosmetic_filters,
119 ..
120 } = set;
121
122 let memory = make_flatbuffer(network_filters, cosmetic_filters, optimize);
123
124 let filter_data_context = FilterDataContext::new(memory);
125
126 Self {
127 blocker: Blocker::from_context(FilterDataContextRef::clone(&filter_data_context)),
128 cosmetic_cache: CosmeticFilterCache::from_context(FilterDataContextRef::clone(
129 &filter_data_context,
130 )),
131 resources: ResourceStorage::default(),
132 filter_data_context,
133 }
134 }
135
136 pub fn check_network_request(&self, request: &Request) -> BlockerResult {
139 self.blocker.check(request, &self.resources)
140 }
141
142 #[cfg(test)]
143 pub(crate) fn check_network_request_exceptions(&self, request: &Request) -> bool {
144 self.blocker.check_exceptions(request)
145 }
146
147 pub fn check_network_request_subset(
148 &self,
149 request: &Request,
150 previously_matched_rule: bool,
151 force_check_exceptions: bool,
152 ) -> BlockerResult {
153 self.blocker.check_parameterised(
154 request,
155 &self.resources,
156 previously_matched_rule,
157 force_check_exceptions,
158 )
159 }
160
161 pub fn get_csp_directives(&self, request: &Request) -> Option<String> {
166 self.blocker.get_csp_directives(request)
167 }
168
169 pub fn use_tags(&mut self, tags: &[&str]) {
174 self.blocker.use_tags(tags);
175 }
176
177 pub fn enable_tags(&mut self, tags: &[&str]) {
182 self.blocker.enable_tags(tags);
183 }
184
185 pub fn disable_tags(&mut self, tags: &[&str]) {
190 self.blocker.disable_tags(tags);
191 }
192
193 pub fn tag_exists(&self, tag: &str) -> bool {
198 self.blocker.tags_enabled().contains(&tag.to_owned())
199 }
200
201 pub fn use_resources(&mut self, resources: impl IntoIterator<Item = Resource>) {
206 let storage = crate::resources::InMemoryResourceStorage::from_resources(resources);
207 self.use_resource_storage(storage);
208 }
209
210 #[cfg(not(feature = "single-thread"))]
216 pub fn use_resource_storage<R: ResourceStorageBackend + 'static + Sync + Send>(
217 &mut self,
218 resources: R,
219 ) {
220 self.resources = ResourceStorage::from_backend(resources);
221 }
222
223 #[cfg(feature = "single-thread")]
229 pub fn use_resource_storage<R: ResourceStorageBackend + 'static>(&mut self, resources: R) {
230 self.resources = ResourceStorage::from_backend(resources);
231 }
232
233 pub fn hidden_class_id_selectors(
242 &self,
243 classes: impl IntoIterator<Item = impl AsRef<str>>,
244 ids: impl IntoIterator<Item = impl AsRef<str>>,
245 exceptions: &HashSet<String>,
246 ) -> Vec<String> {
247 self.cosmetic_cache
248 .hidden_class_id_selectors(classes, ids, exceptions)
249 }
250
251 pub fn url_cosmetic_resources(&self, url: &str) -> UrlSpecificResources {
256 let request = if let Ok(request) = Request::new(url, url, "document") {
257 request
258 } else {
259 return UrlSpecificResources::empty();
260 };
261
262 let generichide = self.blocker.check_generic_hide(&request);
263 self.cosmetic_cache.hostname_cosmetic_resources(
264 &self.resources,
265 &request.hostname,
266 generichide,
267 )
268 }
269
270 pub fn set_regex_discard_policy(&mut self, new_discard_policy: RegexManagerDiscardPolicy) {
271 self.blocker.set_regex_discard_policy(new_discard_policy);
272 }
273
274 #[cfg(test)]
275 pub fn borrow_regex_manager(&self) -> crate::blocker::RegexManagerRef<'_> {
276 self.blocker.borrow_regex_manager()
277 }
278
279 #[cfg(feature = "debug-info")]
280 pub fn discard_regex(&mut self, regex_id: u64) {
281 self.blocker.discard_regex(regex_id);
282 }
283
284 #[cfg(feature = "debug-info")]
285 pub fn get_debug_info(&self) -> EngineDebugInfo {
286 EngineDebugInfo {
287 regex_debug_info: self.blocker.get_regex_debug_info(),
288 flatbuffer_size: self.filter_data_context.memory.data().len(),
289 }
290 }
291
292 pub fn serialize(&self) -> Vec<u8> {
294 let data = self.filter_data_context.memory.data();
295 serialize_dat_file(data)
296 }
297
298 pub fn deserialize(&mut self, serialized: &[u8]) -> Result<(), DeserializationError> {
304 let current_tags = self.blocker.tags_enabled();
305
306 let data = deserialize_dat_file(serialized)?;
307 let memory = VerifiedFlatbufferMemory::from_raw(data)
308 .map_err(DeserializationError::FlatBufferParsingError)?;
309
310 let context = FilterDataContext::new(memory);
311 self.filter_data_context = context;
312 self.blocker =
313 Blocker::from_context(FilterDataContextRef::clone(&self.filter_data_context));
314 self.blocker
315 .use_tags(¤t_tags.iter().map(|s| &**s).collect::<Vec<_>>());
316 self.cosmetic_cache = CosmeticFilterCache::from_context(FilterDataContextRef::clone(
317 &self.filter_data_context,
318 ));
319 Ok(())
320 }
321}
322
323#[cfg(not(feature = "single-thread"))]
325fn _assertions() {
326 fn _assert_send<T: Send>() {}
327 fn _assert_sync<T: Sync>() {}
328
329 _assert_send::<Engine>();
330 _assert_sync::<Engine>();
331}
332
333fn make_flatbuffer(
334 network_filters: Vec<NetworkFilter>,
335 cosmetic_filters: Vec<CosmeticFilter>,
336 optimize: bool,
337) -> VerifiedFlatbufferMemory {
338 let mut builder = EngineFlatBuilder::default();
339 let network_rules_builder = NetworkRulesBuilder::from_rules(network_filters, optimize);
340 let network_rules = FlatSerialize::serialize(network_rules_builder, &mut builder);
341 let cosmetic_rules = CosmeticFilterCacheBuilder::from_rules(cosmetic_filters, &mut builder);
342 let cosmetic_rules = FlatSerialize::serialize(cosmetic_rules, &mut builder);
343 builder.finish(network_rules, cosmetic_rules)
344}
345
346#[cfg(test)]
347#[path = "../tests/unit/engine.rs"]
348mod unit_tests;