From e02196f2dc9d80e16a6e021a828ed5cee69eeab1 Mon Sep 17 00:00:00 2001 From: KirtiRamchandani Date: Tue, 2 Jun 2026 11:38:46 +0530 Subject: [PATCH] Ignore invalid regexes in full-regex sets --- src/regex_manager.rs | 42 ++++++++++++++++++++++++++++++------- tests/unit/regex_manager.rs | 17 +++++++++++++++ 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/regex_manager.rs b/src/regex_manager.rs index c0c9a924..0358a545 100644 --- a/src/regex_manager.rs +++ b/src/regex_manager.rs @@ -161,6 +161,38 @@ where ) } +fn compile_regex_pattern(pattern: &str) -> Result { + BytesRegexBuilder::new(pattern).unicode(false).build() +} + +fn compile_regex_set(patterns: Vec, discard_invalid_patterns: bool) -> CompiledRegex { + match BytesRegexSetBuilder::new(&patterns).unicode(false).build() { + Ok(compiled) => CompiledRegex::CompiledSet(compiled), + Err(e) if discard_invalid_patterns => { + let valid_patterns: Vec<_> = patterns + .into_iter() + .filter(|pattern| compile_regex_pattern(pattern).is_ok()) + .collect(); + + match valid_patterns.len() { + 0 => CompiledRegex::RegexParsingError(e), + 1 => match compile_regex_pattern(&valid_patterns[0]) { + Ok(compiled) => CompiledRegex::Compiled(compiled), + Err(e) => CompiledRegex::RegexParsingError(e), + }, + _ => match BytesRegexSetBuilder::new(valid_patterns) + .unicode(false) + .build() + { + Ok(compiled) => CompiledRegex::CompiledSet(compiled), + Err(e) => CompiledRegex::RegexParsingError(e), + }, + } + } + Err(e) => CompiledRegex::RegexParsingError(e), + } +} + /// Compiles a filter pattern to a regex. This is only performed *lazily* for /// filters containing at least a * or ^ symbol. Because Regexes are expansive, /// we try to convert some patterns to plain filters. @@ -218,7 +250,7 @@ where CompiledRegex::MatchAll } else if escaped_patterns.len() == 1 { let pattern = &escaped_patterns[0]; - match BytesRegexBuilder::new(pattern).unicode(false).build() { + match compile_regex_pattern(pattern) { Ok(compiled) => CompiledRegex::Compiled(compiled), Err(e) => { // println!("Regex parsing failed ({:?})", e); @@ -226,13 +258,7 @@ where } } } else { - match BytesRegexSetBuilder::new(escaped_patterns) - .unicode(false) - .build() - { - Ok(compiled) => CompiledRegex::CompiledSet(compiled), - Err(e) => CompiledRegex::RegexParsingError(e), - } + compile_regex_set(escaped_patterns, is_complete_regex) } } diff --git a/tests/unit/regex_manager.rs b/tests/unit/regex_manager.rs index 739781dd..fc854305 100644 --- a/tests/unit/regex_manager.rs +++ b/tests/unit/regex_manager.rs @@ -1,3 +1,20 @@ +#[cfg(test)] +mod compile_tests { + use crate::regex_manager::compile_regex; + + #[test] + fn invalid_complete_regex_does_not_disable_valid_pattern_in_set() { + let compiled = compile_regex( + [r#"/^https:\/\/b\.com/"#, r#"/(?=a)/"#].into_iter(), + false, + false, + true, + ); + + assert!(compiled.is_match("https://b.com")); + } +} + #[cfg(all(test, feature = "debug-info"))] mod tests { use super::super::*;