Detect group matches in replacements more robustly
The Python re module uses '\n' for group backreference substitution, whereas mod_alias uses '$n', and thus we must translate between them when processing RedirectMatch directives. Previously this was done by substituting backslashes for any dollar signs in the replacement string. However, group substitution only occurs when the $ is not escaped with a backslash and is followed by a decimal digit. Follow the same rules here. Change-Id: Ib33534b40e0b126c769ec17f76e1ecc83d790ebc
This commit is contained in:
parent
7e37a20c79
commit
006ffc075c
3
releasenotes/notes/group-subst-16dce373ccd24118.yaml
Normal file
3
releasenotes/notes/group-subst-16dce373ccd24118.yaml
Normal file
@ -0,0 +1,3 @@
|
||||
fixes:
|
||||
- Literal '$' characters are now handled correctly when they appear in
|
||||
substitution strings for RedirectMatch directives.
|
@ -70,14 +70,19 @@ class Redirect(Rule):
|
||||
class RedirectMatch(Rule):
|
||||
"A RedirectMatch rule with a regular expression."
|
||||
|
||||
_group_subst = re.compile(r'(?<!\\)\$([0-9])')
|
||||
|
||||
def __init__(self, linenum, *params):
|
||||
super(RedirectMatch, self).__init__(linenum, *params)
|
||||
self.regex = re.compile(self.pattern)
|
||||
if self.target:
|
||||
self.target_repl = self.target.replace('$', '\\')
|
||||
self.target_repl = self._get_target_repl()
|
||||
else:
|
||||
self.target_repl = None
|
||||
|
||||
def _get_target_repl(self):
|
||||
return self._group_subst.sub(r'\\1', self.target).replace(r'\$', '$')
|
||||
|
||||
def match(self, path):
|
||||
m = self.regex.search(path)
|
||||
if m:
|
||||
|
@ -106,6 +106,26 @@ class TestRedirectMatch(base.TestCase):
|
||||
rule.match('/user/foo'),
|
||||
)
|
||||
|
||||
def test_match_with_no_group_dollar(self):
|
||||
rule = rules.RedirectMatch(
|
||||
1,
|
||||
'redirectmatch', '301', '^/user/(.*)$', '/pike/user/$a',
|
||||
)
|
||||
self.assertEqual(
|
||||
('301', '/pike/user/$a'),
|
||||
rule.match('/user/foo'),
|
||||
)
|
||||
|
||||
def test_match_with_group_escape(self):
|
||||
rule = rules.RedirectMatch(
|
||||
1,
|
||||
'redirectmatch', '301', '^/user/(.*)$', '/pike/user/\\$1',
|
||||
)
|
||||
self.assertEqual(
|
||||
('301', '/pike/user/$1'),
|
||||
rule.match('/user/foo'),
|
||||
)
|
||||
|
||||
def test_no_match(self):
|
||||
rule = rules.RedirectMatch(
|
||||
1,
|
||||
|
Loading…
Reference in New Issue
Block a user