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
2 changes: 2 additions & 0 deletions src/blocker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ impl Blocker {
#[allow(unused_mut)]
let mut manager = self.regex_manager.borrow_mut();
#[cfg(not(feature = "single-thread"))]
// A poisoned mutex means a panic occurred while the lock was held, which is
// unrecoverable; propagating it here would not add value.
let mut manager = self.regex_manager.lock().unwrap();

#[cfg(not(target_arch = "wasm32"))]
Expand Down
1 change: 1 addition & 0 deletions src/cosmetic_filter_cache_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ impl<'a> CosmeticFilterCacheBuilder<'a> {
(false, Some(selector), None) => Hide(selector),
(true, Some(selector), None) => InjectScript((selector, rule.permission)),
(false, selector, action) => ProceduralOrAction(
// ProceduralOrActionFilter only contains JSON-serializable fields
serde_json::to_string(&ProceduralOrActionFilter {
selector: selector
.map(|selector| vec![CosmeticFilterOperator::CssSelector(selector)])
Expand Down
1 change: 1 addition & 0 deletions src/filters/abstract_network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ fn parse_filter_options(raw_options: &str) -> Result<Vec<NetworkFilterOption>, N
// Check for options: option=value1|value2
let mut option_and_values = maybe_negated_option.splitn(2, '=');
let (option, value) = (
// splitn always yields at least one element, even for an empty string
option_and_values.next().unwrap(),
option_and_values.next().unwrap_or_default(),
);
Expand Down
69 changes: 35 additions & 34 deletions src/lists.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,46 +305,47 @@ impl FilterSet {

let mut filters_used = vec![];

self.network_filters.into_iter().for_each(|filter| {
// Don't process bad filter rules or matching bad filter rules.
if bad_filter_ids.contains(&filter.get_id()) || filter.is_badfilter() {
return;
}
let original_rule = *filter
.raw_line
.clone()
.expect("All rules should be in debug mode");
if let Ok(equivalent) = TryInto::<content_blocking::CbRuleEquivalent>::try_into(filter)
{
filters_used.push(original_rule);
equivalent
.into_iter()
.for_each(|cb_rule| match &cb_rule.action.typ {
self.network_filters
.into_iter()
.try_for_each(|filter| -> Result<(), ()> {
// Don't process bad filter rules or matching bad filter rules.
if bad_filter_ids.contains(&filter.get_id()) || filter.is_badfilter() {
return Ok(());
}
let original_rule = *filter.raw_line.clone().ok_or(())?;
if let Ok(equivalent) =
TryInto::<content_blocking::CbRuleEquivalent>::try_into(filter)
{
filters_used.push(original_rule);
equivalent
.into_iter()
.for_each(|cb_rule| match &cb_rule.action.typ {
content_blocking::CbType::IgnorePreviousRules => {
ignore_previous_rules.push(cb_rule)
}
_ => other_rules.push(cb_rule),
});
}
Ok(())
})?;

let add_fp_document_exception = !filters_used.is_empty();

self.cosmetic_filters
.into_iter()
.try_for_each(|filter| -> Result<(), ()> {
let original_rule = *filter.raw_line.clone().ok_or(())?;
if let Ok(cb_rule) = TryInto::<content_blocking::CbRule>::try_into(filter) {
filters_used.push(original_rule);
match &cb_rule.action.typ {
content_blocking::CbType::IgnorePreviousRules => {
ignore_previous_rules.push(cb_rule)
}
_ => other_rules.push(cb_rule),
});
}
});

let add_fp_document_exception = !filters_used.is_empty();

self.cosmetic_filters.into_iter().for_each(|filter| {
let original_rule = *filter
.raw_line
.clone()
.expect("All rules should be in debug mode");
if let Ok(cb_rule) = TryInto::<content_blocking::CbRule>::try_into(filter) {
filters_used.push(original_rule);
match &cb_rule.action.typ {
content_blocking::CbType::IgnorePreviousRules => {
ignore_previous_rules.push(cb_rule)
}
_ => other_rules.push(cb_rule),
}
}
});
Ok(())
})?;

other_rules.extend(ignore_previous_rules);

Expand Down
2 changes: 2 additions & 0 deletions src/regex_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ impl RegexManager {
v.regex = Some(make_regexp(mask, filters));
self.compiled_regex_count += 1;
}
// Always Some: set to Some above if it was None
v.regex.as_ref().unwrap().is_match(pattern)
}
Entry::Vacant(e) => {
Expand All @@ -272,6 +273,7 @@ impl RegexManager {
last_used: self.now,
usage_count: 1,
};
// Always Some: the entry was just constructed with Some(...)
e.insert(new_entry)
.regex
.as_ref()
Expand Down
6 changes: 4 additions & 2 deletions src/resources/resource_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,8 +336,8 @@ impl ResourceStorage {
filter_permission: PermissionMask,
required_deps: &mut Vec<ResourceImpl>,
) -> Result<String, ScriptletResourceError> {
// `unwrap` is safe because these are guaranteed valid at filter parsing.
let scriptlet_args = parse_scriptlet_args(scriptlet_args).unwrap();
let scriptlet_args = parse_scriptlet_args(scriptlet_args)
.ok_or(ScriptletResourceError::InvalidScriptletArgs)?;

if scriptlet_args.is_empty() {
return Err(ScriptletResourceError::MissingScriptletName);
Expand Down Expand Up @@ -472,6 +472,8 @@ pub enum ScriptletResourceError {
ContentTypeNotInjectable,
#[error("filter rule is not authorized to inject the intended scriptlet")]
InsufficientPermissions,
#[error("scriptlet arguments could not be parsed")]
InvalidScriptletArgs,
}

impl From<base64::DecodeError> for ScriptletResourceError {
Expand Down
2 changes: 2 additions & 0 deletions src/url_parser/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -529,9 +529,11 @@ impl Parser {
}

if host_str.is_ascii() {
// write! to a String is infallible
write!(&mut self.serialization, "{host_str}").unwrap();
} else {
let encoded = idna::domain_to_ascii(host_str)?;
// write! to a String is infallible
write!(&mut self.serialization, "{encoded}").unwrap();
}

Expand Down
9 changes: 9 additions & 0 deletions tests/unit/resources/resource_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,15 @@ mod scriptlet_storage_tests {
resources.get_scriptlet_resource("", Default::default(), &mut vec![]),
Err(ScriptletResourceError::MissingScriptletName),
);
// Unclosed quote → parse_scriptlet_args returns None → InvalidScriptletArgs
assert_eq!(
resources.get_scriptlet_resource(
r#"greet, "unclosed"#,
Default::default(),
&mut vec![]
),
Err(ScriptletResourceError::InvalidScriptletArgs),
);

assert_eq!(
resources.get_scriptlet_resources([(
Expand Down