From fb3aec03f48ef89c1eb28a225e30df8d92cea882 Mon Sep 17 00:00:00 2001 From: vin Date: Sat, 15 Nov 2025 19:10:20 -0500 Subject: update dependencies --- src/lib.rs | 251 ++++++++++++++++++++++--------------------------------------- 1 file changed, 88 insertions(+), 163 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index e8797d2..7aa2ade 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,21 +12,18 @@ )] use adblock::blocker::BlockerResult as RustBlockerResult; -use adblock::blocker::{BlockerError as RustBlockerError, Redirection}; use adblock::cosmetic_filter_cache::UrlSpecificResources as RustUrlSpecificResources; use adblock::engine::Engine as RustEngine; use adblock::lists::FilterSet as RustFilterSet; use adblock::lists::{FilterFormat, ParseOptions, RuleTypes}; +use adblock::request::Request; use pyo3::create_exception; use pyo3::exceptions::PyException; use pyo3::prelude::*; use pyo3::types::PyBytes; use pyo3::PyErr; -use adblock::resources::{ - AddResourceError as RustAddResourceError, MimeType, Resource, ResourceType, -}; -use std::collections::HashMap; +use adblock::resources::{MimeType, PermissionMask, Resource, ResourceType}; use std::collections::HashSet; use std::error::Error; use std::fmt::{self, Display}; @@ -35,39 +32,39 @@ use std::io::{Read, Write}; /// Brave's adblocking library in Python! #[pymodule] -fn adblock(py: Python<'_>, m: &PyModule) -> PyResult<()> { +fn adblock_py(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add("__version__", env!("CARGO_PKG_VERSION"))?; m.add_class::()?; m.add_class::()?; m.add_class::()?; m.add_class::()?; - m.add("AdblockException", py.get_type::())?; - m.add("BlockerException", py.get_type::())?; - m.add("SerializationError", py.get_type::())?; + m.add("AdblockException", m.py().get_type_bound::())?; + m.add("BlockerException", m.py().get_type_bound::())?; + m.add("SerializationError", m.py().get_type_bound::())?; m.add( "DeserializationError", - py.get_type::(), + m.py().get_type_bound::(), )?; m.add( "OptimizedFilterExistence", - py.get_type::(), + m.py().get_type_bound::(), )?; m.add( "BadFilterAddUnsupported", - py.get_type::(), + m.py().get_type_bound::(), )?; - m.add("FilterExists", py.get_type::())?; + m.add("FilterExists", m.py().get_type_bound::())?; m.add( "AddResourceException", - py.get_type::(), + m.py().get_type_bound::(), )?; m.add( "InvalidBase64ContentError", - py.get_type::(), + m.py().get_type_bound::(), )?; m.add( "InvalidUtf8ContentError", - py.get_type::(), + m.py().get_type_bound::(), )?; Ok(()) } @@ -94,14 +91,11 @@ pub struct BlockerResult { /// /// [1]: https://github.com/gorhill/uBlock/wiki/Static-filter-syntax#redirect #[pyo3(get)] - pub redirect_type: Option, - /// Exception is not `None` when the blocker matched on an exception rule. - /// Effectively this means that there was a match, but the request should - /// not be blocked. It is a non-empty string if the blocker was initialized - /// from a list of rules with debugging enabled, otherwise the original - /// string representation is discarded to reduce memory use. - #[pyo3(get)] pub redirect: Option, + /// `removeparam` may remove URL parameters. If the original request URL was + /// modified at all, the new version will be here. + #[pyo3(get)] + pub rewritten_url: Option, /// Exception is not `None` when the blocker matched on an exception rule. /// Effectively this means that there was a match, but the request should /// not be blocked. It is a non-empty string if the blocker was initialized @@ -114,32 +108,17 @@ pub struct BlockerResult { /// a match, it is not `None`. #[pyo3(get)] pub filter: Option, - /// The `error` field is only used to signal that there was an error in - /// parsing the provided URLs when using the simpler - /// `check_network_urls` method. - #[pyo3(get)] - pub error: Option, } impl From for BlockerResult { fn from(br: RustBlockerResult) -> Self { - let (redirect, redirect_type) = if let Some(resource) = br.redirect { - match resource { - Redirection::Resource(resource) => (Some(resource), Some("resource".to_string())), - Redirection::Url(url) => (Some(url), Some("url".to_string())), - } - } else { - (None, None) - }; - Self { matched: br.matched, important: br.important, + redirect: br.redirect, + rewritten_url: br.rewritten_url, exception: br.exception, filter: br.filter, - error: br.error, - redirect_type, - redirect, } } } @@ -148,13 +127,13 @@ impl From for BlockerResult { impl BlockerResult { fn __repr__(&self) -> PyResult { Ok(format!( - "BlockerResult(matched={}, important={}, redirect={}, exception={}, filter={}, error={})", + "BlockerResult(matched={}, important={}, redirect={}, rewritten_url={}, exception={}, filter={})", self.matched.diy_python_repr(), self.important.diy_python_repr(), self.redirect.diy_python_repr(), + self.rewritten_url.diy_python_repr(), self.exception.diy_python_repr(), self.filter.diy_python_repr(), - self.error.diy_python_repr(), )) } } @@ -214,17 +193,6 @@ impl From for PyErr { } } -impl From for BlockerError { - fn from(err: RustBlockerError) -> Self { - match err { - RustBlockerError::SerializationError => Self::SerializationError, - RustBlockerError::DeserializationError => Self::DeserializationError, - RustBlockerError::OptimizedFilterExistence => Self::OptimizedFilterExistence, - RustBlockerError::BadFilterAddUnsupported => Self::BadFilterAddUnsupported, - RustBlockerError::FilterExists => Self::FilterExists, - } - } -} fn filter_format_from_string(filter_format: &str) -> PyResult { match filter_format { @@ -252,7 +220,6 @@ fn rule_types_from_string(rule_types: &str) -> PyResult { /// created. FilterSet allows assembling a compound list from multiple /// different sources before compiling the rules into an Engine. #[pyclass] -#[pyo3(text_signature = "($self, debug)")] #[derive(Clone)] pub struct FilterSet { filter_set: RustFilterSet, @@ -266,7 +233,7 @@ impl FilterSet { /// the more compact internal representation. If enabled, this information /// will be passed to the corresponding Engine. #[new] - #[args(debug = false)] + #[pyo3(signature = (debug = false))] pub fn new(debug: bool) -> Self { Self { filter_set: RustFilterSet::new(debug), @@ -279,18 +246,11 @@ impl FilterSet { /// /// The format is a string containing either "standard" (ABP/uBO-style) /// or "hosts". - #[pyo3(text_signature = "($self, filter_list, format, include_redirect_urls, rule_types)")] - #[args( - filter_list, - format = "\"standard\"", - include_redirect_urls = "false", - rule_types = "\"all\"" - )] + #[pyo3(signature = (filter_list, format = "standard", rule_types = "all"))] pub fn add_filter_list( &mut self, filter_list: &str, format: &str, - include_redirect_urls: bool, rule_types: &str, ) -> PyResult<()> { let filter_format = filter_format_from_string(format)?; @@ -299,8 +259,8 @@ impl FilterSet { filter_list, ParseOptions { format: filter_format, - include_redirect_urls, rule_types, + permissions: PermissionMask::default(), }, ); Ok(()) @@ -311,18 +271,11 @@ impl FilterSet { /// /// The format is a string containing either "standard" (ABP/uBO-style) /// or "hosts". - #[pyo3(text_signature = "($self, filters, format, include_redirect_urls, rule_types)")] - #[args( - filters, - format = "\"standard\"", - include_redirect_urls = "false", - rule_types = "\"all\"" - )] + #[pyo3(signature = (filters, format = "standard", rule_types = "all"))] pub fn add_filters( &mut self, filters: Vec, format: &str, - include_redirect_urls: bool, rule_types: &str, ) -> PyResult<()> { let filter_format = filter_format_from_string(format)?; @@ -331,8 +284,8 @@ impl FilterSet { &filters, ParseOptions { format: filter_format, - include_redirect_urls, rule_types, + permissions: PermissionMask::default(), }, ); Ok(()) @@ -351,10 +304,9 @@ pub struct UrlSpecificResources { /// styled as `{ display: none !important; }`. #[pyo3(get)] pub hide_selectors: HashSet, - /// A map of CSS selectors on the page to respective non-hide style rules, - /// i.e. any required styles other than `display: none`. + /// Set of JSON-encoded procedural filters or filters with an action. #[pyo3(get)] - pub style_selectors: HashMap>, + pub procedural_actions: HashSet, /// A set of any class or id CSS selectors that should not have generic /// rules applied. // In practice, these should be passed to `class_id_stylesheet` and not @@ -376,7 +328,7 @@ impl From for UrlSpecificResources { fn from(r: RustUrlSpecificResources) -> Self { Self { hide_selectors: r.hide_selectors, - style_selectors: r.style_selectors, + procedural_actions: r.procedural_actions, exceptions: r.exceptions, injected_script: r.injected_script, generichide: r.generichide, @@ -388,9 +340,9 @@ impl From for UrlSpecificResources { impl UrlSpecificResources { fn __repr__(&self) -> PyResult { Ok(format!( - "UrlSpecificResources<{} hide selectors, {} style selectors, {} exceptions, injected_javascript={}, generichide={}>", + "UrlSpecificResources<{} hide selectors, {} procedural actions, {} exceptions, injected_javascript={}, generichide={}>", self.hide_selectors.len(), - self.style_selectors.len(), + self.procedural_actions.len(), self.exceptions.len(), self.injected_script.diy_python_repr(), self.generichide.diy_python_repr(), @@ -418,7 +370,6 @@ impl UrlSpecificResources { /// /// [1]: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/webRequest/ResourceType #[pyclass] -#[pyo3(text_signature = "($self, filter_set, optimize)")] pub struct Engine { engine: RustEngine, optimize: bool, @@ -428,7 +379,7 @@ pub struct Engine { impl Engine { /// Create a new adblocking engine #[new] - #[args(filter_set, optimize = true)] + #[pyo3(signature = (filter_set, optimize = true))] pub fn new(filter_set: FilterSet, optimize: bool) -> Self { let engine = RustEngine::from_filter_set(filter_set.filter_set, optimize); Self { engine, optimize } @@ -442,17 +393,26 @@ impl Engine { /// * `url` - The URL of the request to check /// * `source_url` - The URL from where the request is made /// * `request_type` - The resource type that the request points to - #[pyo3(text_signature = "($self, url, source_url, request_type)")] pub fn check_network_urls( &self, url: &str, source_url: &str, request_type: &str, ) -> BlockerResult { - let blocker_result = self - .engine - .check_network_urls(url, source_url, request_type); - blocker_result.into() + match Request::new(url, source_url, request_type) { + Ok(request) => { + let blocker_result = self.engine.check_network_request(&request); + blocker_result.into() + } + Err(_) => BlockerResult { + matched: false, + important: false, + redirect: None, + rewritten_url: None, + exception: None, + filter: None, + } + } } /// Check if a request should be blocked based on the given parameters. @@ -465,9 +425,7 @@ impl Engine { /// * `third_party_request` - Is the given request to a third-party? Here, /// `None` can be given and the engine will figure it out based on the /// `hostname` and `source_hostname`. - #[pyo3( - text_signature = "($self, url, hostname, source_hostname, requsest_type, third_party_request)" - )] + #[pyo3(signature = (url, hostname, source_hostname, request_type, third_party_request = None))] pub fn check_network_urls_with_hostnames( &self, url: &str, @@ -476,13 +434,11 @@ impl Engine { request_type: &str, third_party_request: Option, ) -> BlockerResult { - let blocker_result = self.engine.check_network_urls_with_hostnames( - url, - hostname, - source_hostname, - request_type, - third_party_request, - ); + let third_party = third_party_request.unwrap_or_else(|| { + hostname != source_hostname + }); + let request = Request::preparsed(url, hostname, source_hostname, request_type, third_party); + let blocker_result = self.engine.check_network_request(&request); blocker_result.into() } @@ -499,10 +455,7 @@ impl Engine { /// * `previously_matched_rule` - Return a match as long as there are no /// exceptions /// * `force_check_exceptions` - Check exceptions even if no other rule matches - #[pyo3( - text_signature = "($self, url, hostname, source_hostname, request_type, \ - third_party_request, previously_matched_rule, force_check_exceptions)" - )] + #[pyo3(signature = (url, hostname, source_hostname, request_type, third_party_request = None, previously_matched_rule = false, force_check_exceptions = false))] #[allow(clippy::too_many_arguments)] pub fn check_network_urls_with_hostnames_subset( &self, @@ -514,12 +467,12 @@ impl Engine { previously_matched_rule: bool, force_check_exceptions: bool, ) -> BlockerResult { - let blocker_result = self.engine.check_network_urls_with_hostnames_subset( - url, - hostname, - source_hostname, - request_type, - third_party_request, + let third_party = third_party_request.unwrap_or_else(|| { + hostname != source_hostname + }); + let request = Request::preparsed(url, hostname, source_hostname, request_type, third_party); + let blocker_result = self.engine.check_network_request_subset( + &request, previously_matched_rule, force_check_exceptions, ); @@ -534,7 +487,7 @@ impl Engine { /// Use `"template"` if wanting to specify a template resource type. /// * `content`: The resource data, encoded using standard base64 configuration /// * `aliases`: List of aliases for the resource - #[pyo3(text_signature = "($self, name, content_type, content, aliases)")] + #[pyo3(signature = (name, content_type, content, aliases = None))] pub fn add_resource( &mut self, name: &str, @@ -542,7 +495,7 @@ impl Engine { content: &str, aliases: Option>, ) -> PyResult<()> { - let result = self.engine.add_resource(Resource { + let resource = Resource { name: name.to_string(), aliases: aliases.unwrap_or_default(), kind: match content_type { @@ -552,47 +505,27 @@ impl Engine { ))), }, content: content.to_string(), - }); + dependencies: Vec::new(), + permission: PermissionMask::default(), + }; - match result { - Ok(_) => Ok(()), - Err(err) => match err { - RustAddResourceError::InvalidBase64Content => Err( - InvalidBase64ContentError::new_err("invalid base64 content".to_string()), - ), - RustAddResourceError::InvalidUtf8Content => Err(InvalidUtf8ContentError::new_err( - "invalid utf content".to_string(), - )), - }, - } + self.engine.use_resources(std::iter::once(resource)); + Ok(()) } /// Serialize this blocking engine to bytes. They can then be deserialized /// using `deserialize()` to get the same engine again. - #[pyo3(text_signature = "($self)")] - pub fn serialize<'p>(&mut self, py: Python<'p>) -> PyResult<&'p PyBytes> { - let bytes = self.serialize_inner()?; - let py_bytes = PyBytes::new(py, &bytes); + pub fn serialize<'p>(&self, py: Python<'p>) -> PyResult> { + let bytes = self.engine.serialize(); + let py_bytes = PyBytes::new_bound(py, &bytes); Ok(py_bytes) } - fn serialize_inner(&mut self) -> PyResult> { - let result = self.engine.serialize_raw(); - match result { - Ok(x) => Ok(x), - Err(error) => { - let my_blocker_error: BlockerError = error.into(); - Err(my_blocker_error.into()) - } - } - } - /// Serialize this blocking engine to a file. The file can then be /// deserialized using `deserialize_from_file()` to get the same engine /// again. - #[pyo3(text_signature = "($self, file)")] - pub fn serialize_to_file(&mut self, file: &str) -> PyResult<()> { - let data = self.serialize_inner()?; + pub fn serialize_to_file(&self, file: &str) -> PyResult<()> { + let data = self.engine.serialize(); let mut fd = fs::OpenOptions::new() .create(true) .truncate(true) @@ -603,21 +536,14 @@ impl Engine { } /// Deserialize a blocking engine from bytes produced with `serialize()`. - #[pyo3(text_signature = "($self, serialized)")] pub fn deserialize(&mut self, serialized: &[u8]) -> PyResult<()> { - let result = self.engine.deserialize(serialized); - match result { - Ok(_) => Ok(()), - Err(error) => { - let my_blocker_error: BlockerError = error.into(); - Err(my_blocker_error.into()) - } - } + self.engine.deserialize(serialized).map_err(|_| { + DeserializationError::new_err("Failed to deserialize engine data") + }) } /// Deserialize a blocking engine from file produced with /// `serialize_to_file()`. - #[pyo3(text_signature = "($self, file)")] pub fn deserialize_from_file(&mut self, file: &str) -> PyResult<()> { let mut fd = fs::File::open(file)?; let mut data: Vec = Vec::new(); @@ -626,18 +552,20 @@ impl Engine { } /// Checks if the given filter exists in the blocking engine. - #[pyo3(text_signature = "($self, filter)")] - pub fn filter_exists(&self, filter: &str) -> bool { - self.engine.filter_exists(filter) + /// Note: This method has been removed in the latest version of adblock-rust. + /// It will always return false. + pub fn filter_exists(&self, _filter: &str) -> bool { + // This method no longer exists in the adblock-rust API + false } /// Sets this engine's tags to be _only_ the ones provided in tags. /// /// Tags can be used to cheaply enable or disable network rules with a /// corresponding $tag option. - #[pyo3(text_signature = "($self, tags)")] - pub fn use_tags(&mut self, tags: Vec<&str>) { - self.engine.use_tags(&tags); + pub fn use_tags(&mut self, tags: Vec) { + let tag_refs: Vec<&str> = tags.iter().map(|s| s.as_str()).collect(); + self.engine.use_tags(&tag_refs); } /// Sets this engine's tags to additionally include the ones provided in @@ -645,9 +573,9 @@ impl Engine { /// /// Tags can be used to cheaply enable or disable network rules with a /// corresponding $tag option. - #[pyo3(text_signature = "($self, tags)")] - pub fn enable_tags(&mut self, tags: Vec<&str>) { - self.engine.enable_tags(&tags); + pub fn enable_tags(&mut self, tags: Vec) { + let tag_refs: Vec<&str> = tags.iter().map(|s| s.as_str()).collect(); + self.engine.enable_tags(&tag_refs); } /// Sets this engine's tags to no longer include the ones provided in @@ -655,16 +583,15 @@ impl Engine { /// /// Tags can be used to cheaply enable or disable network rules with a /// corresponding $tag option. - #[pyo3(text_signature = "($self, tags)")] - pub fn disable_tags(&mut self, tags: Vec<&str>) { - self.engine.disable_tags(&tags); + pub fn disable_tags(&mut self, tags: Vec) { + let tag_refs: Vec<&str> = tags.iter().map(|s| s.as_str()).collect(); + self.engine.disable_tags(&tag_refs); } /// Checks if a given tag exists in this engine. /// /// Tags can be used to cheaply enable or disable network rules with a /// corresponding $tag option. - #[pyo3(text_signature = "($self, tag)")] pub fn tag_exists(&self, tag: &str) -> bool { self.engine.tag_exists(tag) } @@ -673,7 +600,6 @@ impl Engine { /// url. Once this has been called, all CSS ids and classes on a /// page should be passed to hidden_class_id_selectors to obtain any /// stylesheets consisting of generic rules. - #[pyo3(text_signature = "($self, url)")] pub fn url_cosmetic_resources(&self, url: &str) -> UrlSpecificResources { self.engine.url_cosmetic_resources(url).into() } @@ -685,7 +611,6 @@ impl Engine { /// are not excepted. /// /// Exceptions should be passed directly from UrlSpecificResources. - #[pyo3(text_signature = "($self, classes, ids, exceptions)")] pub fn hidden_class_id_selectors( &self, classes: Vec, -- cgit v1.2.3