mirror of
				https://github.com/django/django.git
				synced 2025-10-28 08:06:09 +00:00 
			
		
		
		
	Fixed #18210 -- Escaped special characters in reverse prefixes.
Ensured that special characters passed in to reverse via the prefix argument are properly escaped so that calls to django.utils.regex_helpers.normalize and/or string formatting operations don't result in exceptions. Thanks to toofishes for the error report.
This commit is contained in:
		| @@ -16,6 +16,7 @@ from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist | ||||
| from django.utils.datastructures import MultiValueDict | ||||
| from django.utils.encoding import force_str, force_text, iri_to_uri | ||||
| from django.utils.functional import memoize, lazy | ||||
| from django.utils.http import urlquote | ||||
| from django.utils.importlib import import_module | ||||
| from django.utils.module_loading import module_has_submodule | ||||
| from django.utils.regex_helper import normalize | ||||
| @@ -379,14 +380,15 @@ class RegexURLResolver(LocaleRegexProvider): | ||||
|         except (ImportError, AttributeError) as e: | ||||
|             raise NoReverseMatch("Error importing '%s': %s." % (lookup_view, e)) | ||||
|         possibilities = self.reverse_dict.getlist(lookup_view) | ||||
|         prefix_norm, prefix_args = normalize(_prefix)[0] | ||||
|  | ||||
|         prefix_norm, prefix_args = normalize(urlquote(_prefix))[0] | ||||
|         for possibility, pattern, defaults in possibilities: | ||||
|             for result, params in possibility: | ||||
|                 if args: | ||||
|                     if len(args) != len(params) + len(prefix_args): | ||||
|                         continue | ||||
|                     unicode_args = [force_text(val) for val in args] | ||||
|                     candidate =  (prefix_norm + result) % dict(zip(prefix_args + params, unicode_args)) | ||||
|                     candidate = (prefix_norm + result) % dict(zip(prefix_args + params, unicode_args)) | ||||
|                 else: | ||||
|                     if set(kwargs.keys()) | set(defaults.keys()) != set(params) | set(defaults.keys()) | set(prefix_args): | ||||
|                         continue | ||||
| @@ -398,8 +400,8 @@ class RegexURLResolver(LocaleRegexProvider): | ||||
|                     if not matches: | ||||
|                         continue | ||||
|                     unicode_kwargs = dict([(k, force_text(v)) for (k, v) in kwargs.items()]) | ||||
|                     candidate = (prefix_norm + result) % unicode_kwargs | ||||
|                 if re.search('^%s%s' % (_prefix, pattern), candidate, re.UNICODE): | ||||
|                     candidate = (prefix_norm.replace('%', '%%') + result) % unicode_kwargs | ||||
|                 if re.search('^%s%s' % (prefix_norm, pattern), candidate, re.UNICODE): | ||||
|                     return candidate | ||||
|         # lookup_view can be URL label, or dotted path, or callable, Any of | ||||
|         # these can be passed in at the top, but callables are not friendly in | ||||
|   | ||||
| @@ -171,6 +171,18 @@ class URLPatternReverse(TestCase): | ||||
|         # Reversing None should raise an error, not return the last un-named view. | ||||
|         self.assertRaises(NoReverseMatch, reverse, None) | ||||
|  | ||||
|     def test_prefix_braces(self): | ||||
|         self.assertEqual('/%7B%7Binvalid%7D%7D/includes/non_path_include/', | ||||
|                reverse('non_path_include', prefix='/{{invalid}}/')) | ||||
|  | ||||
|     def test_prefix_parenthesis(self): | ||||
|         self.assertEqual('/bogus%29/includes/non_path_include/', | ||||
|                reverse('non_path_include', prefix='/bogus)/')) | ||||
|  | ||||
|     def test_prefix_format_char(self): | ||||
|         self.assertEqual('/bump%2520map/includes/non_path_include/', | ||||
|                reverse('non_path_include', prefix='/bump%20map/')) | ||||
|  | ||||
| class ResolverTests(unittest.TestCase): | ||||
|     def test_resolver_repr(self): | ||||
|         """ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user