Skip to content

Commit 319b562

Browse files
committed
Allow multiple capture groups for debounce regex action
1 parent ae4bba2 commit 319b562

File tree

2 files changed

+94
-5
lines changed

2 files changed

+94
-5
lines changed

components/debounce/browser/debounce_rule.cc

+26-5
Original file line numberDiff line numberDiff line change
@@ -187,17 +187,36 @@ bool DebounceRule::ValidateAndParsePatternRegex(
187187
<< " which is an invalid regex pattern";
188188
return false;
189189
}
190-
if (pattern_regex.NumberOfCapturingGroups() != 1) {
190+
if (pattern_regex.NumberOfCapturingGroups() < 1) {
191191
VLOG(1) << "Debounce rule has param: " << pattern
192-
<< " which captures != 1 groups";
192+
<< " which captures < 1 groups";
193193
return false;
194194
}
195195

196-
if (!RE2::PartialMatch(path, pattern_regex, parsed_value)) {
196+
// Get matching capture groups by applying regex to the path
197+
size_t number_of_capturing_groups =
198+
pattern_regex.NumberOfCapturingGroups() + 1;
199+
std::vector<re2::StringPiece> match_results(number_of_capturing_groups);
200+
201+
if (!pattern_regex.Match(path, 0, path.size(), RE2::UNANCHORED,
202+
match_results.data(), match_results.size())) {
197203
VLOG(1) << "Debounce rule with param: " << param_
198204
<< " was unable to capture string";
199205
return false;
200206
}
207+
208+
// This will always be at least 2: the first one is the full match
209+
DCHECK_GT(match_results.size(), 1u);
210+
211+
// Build parsed_value string by appending matches, ignoring the first match
212+
// which will be the whole match
213+
std::for_each(std::begin(match_results) + 1, std::end(match_results),
214+
[parsed_value](re2::StringPiece matched_string) {
215+
if (!matched_string.empty()) {
216+
matched_string.AppendToString(parsed_value);
217+
}
218+
});
219+
201220
return true;
202221
}
203222

@@ -212,12 +231,14 @@ bool DebounceRule::Apply(const GURL& original_url,
212231
action_ != kDebounceRegexPath)
213232
return false;
214233
// If URL matches an explicitly excluded pattern, this rule does not apply.
215-
if (exclude_pattern_set_.MatchesURL(original_url))
234+
if (exclude_pattern_set_.MatchesURL(original_url)) {
216235
return false;
236+
}
217237
// If URL does not match an explicitly included pattern, this rule does not
218238
// apply.
219-
if (!include_pattern_set_.MatchesURL(original_url))
239+
if (!include_pattern_set_.MatchesURL(original_url)) {
220240
return false;
241+
}
221242

222243
if (!DebounceRule::CheckPrefForRule(prefs)) {
223244
return false;

components/debounce/browser/test/debounce_rule_unittest.cc

+68
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,74 @@ TEST(DebounceRuleUnitTest, ParamCapturesNonURLWithPrependScheme) {
183183
}
184184
}
185185

186+
TEST(DebounceRuleUnitTest, TwoCaptureGroups) {
187+
const std::string contents = R"json(
188+
189+
[{
190+
"include": [
191+
"*://test.com/*"
192+
],
193+
"exclude": [
194+
],
195+
"action": "regex-path",
196+
"prepend_scheme": "https",
197+
"param": "^/([^/]+)/xyz(/.*)$"
198+
}]
199+
200+
)json";
201+
std::vector<std::unique_ptr<DebounceRule>> rules = StringToRules(contents);
202+
203+
for (const std::unique_ptr<DebounceRule>& rule : rules) {
204+
CheckApplyResult(rule.get(), GURL("https://test.com/brave.com/xyz/abc.jpg"),
205+
"https://brave.com/abc.jpg", false);
206+
}
207+
}
208+
209+
TEST(DebounceRuleUnitTest, CurlyBracesInRegexGetParseError) {
210+
const std::string contents = R"json(
211+
212+
[{
213+
"include": [
214+
"*://test.com/*"
215+
],
216+
"exclude": [
217+
],
218+
"action": "regex-path",
219+
"prepend_scheme": "https",
220+
"param": "^/turbo/([^/]+)/xyz(/\d{4})/xyzzy(/.*)$"
221+
}]
222+
223+
)json";
224+
225+
auto parsed = DebounceRule::ParseRules(contents);
226+
EXPECT_FALSE(parsed.has_value());
227+
}
228+
229+
TEST(DebounceRuleUnitTest, ThreeCaptureGroups) {
230+
const std::string contents = R"json(
231+
232+
[{
233+
"include": [
234+
"*://test.com/*"
235+
],
236+
"exclude": [
237+
],
238+
"action": "regex-path",
239+
"prepend_scheme": "https",
240+
"param": "^/turbo/([^/]+)/xyz(/[0-9]+)/xyzzy(/.*)$"
241+
}]
242+
243+
)json";
244+
std::vector<std::unique_ptr<DebounceRule>> rules = StringToRules(contents);
245+
246+
for (const std::unique_ptr<DebounceRule>& rule : rules) {
247+
CheckApplyResult(
248+
rule.get(),
249+
GURL("https://test.com/turbo/brave.com/xyz/2022/xyzzy/abc.jpg"),
250+
"https://brave.com/2022/abc.jpg", false);
251+
}
252+
}
253+
186254
TEST(DebounceRuleUnitTest, ParamCapturesURLWithPrependScheme) {
187255
const std::string contents = R"json(
188256

0 commit comments

Comments
 (0)