summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorClaude Paroz <claude@2xlibre.net>2014-06-26 16:55:36 +0200
committerClaude Paroz <claude@2xlibre.net>2014-07-09 09:54:34 +0200
commite167e96cfea670422ca75d0b35fe7c4195f25b63 (patch)
tree5d4e868390c8afefd43026b0710d72f7c1785c82 /django
parent8780849da06f866720284d2c61d0aae5890e92ae (diff)
Fixed #22223 -- Prevented over-escaping URLs in reverse()
And follow more closely the class of characters defined in the RFC 3986. Thanks Erik van Zijst for the report and the initial patch, and Tim Graham for the review.
Diffstat (limited to 'django')
-rw-r--r--django/contrib/admin/utils.py2
-rw-r--r--django/core/urlresolvers.py6
-rw-r--r--django/utils/html.py3
-rw-r--r--django/utils/http.py3
4 files changed, 10 insertions, 4 deletions
diff --git a/django/contrib/admin/utils.py b/django/contrib/admin/utils.py
index 0c8ac1c6fc..3c3ef3bbd9 100644
--- a/django/contrib/admin/utils.py
+++ b/django/contrib/admin/utils.py
@@ -57,7 +57,7 @@ def quote(s):
res = list(s)
for i in range(len(res)):
c = res[i]
- if c in """:/_#?;@&=+$,"<>%\\""":
+ if c in """:/_#?;@&=+$,"[]<>%\\""":
res[i] = '_%02X' % ord(c)
return ''.join(res)
diff --git a/django/core/urlresolvers.py b/django/core/urlresolvers.py
index e8564ecc76..d3bfef423b 100644
--- a/django/core/urlresolvers.py
+++ b/django/core/urlresolvers.py
@@ -20,7 +20,7 @@ from django.utils.datastructures import MultiValueDict
from django.utils.deprecation import RemovedInDjango20Warning
from django.utils.encoding import force_str, force_text, iri_to_uri
from django.utils.functional import lazy
-from django.utils.http import urlquote
+from django.utils.http import RFC3986_SUBDELIMS, urlquote
from django.utils.module_loading import module_has_submodule
from django.utils.regex_helper import normalize
from django.utils import six, lru_cache
@@ -453,7 +453,9 @@ class RegexURLResolver(LocaleRegexProvider):
# arguments in order to return a properly encoded URL.
candidate_pat = prefix_norm.replace('%', '%%') + result
if re.search('^%s%s' % (prefix_norm, pattern), candidate_pat % candidate_subs, re.UNICODE):
- candidate_subs = dict((k, urlquote(v)) for (k, v) in candidate_subs.items())
+ # safe characters from `pchar` definition of RFC 3986
+ candidate_subs = dict((k, urlquote(v, safe=RFC3986_SUBDELIMS + str('/~:@')))
+ for (k, v) in candidate_subs.items())
return candidate_pat % candidate_subs
# 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
diff --git a/django/utils/html.py b/django/utils/html.py
index 38fe90d1a9..d5fe2f4a6b 100644
--- a/django/utils/html.py
+++ b/django/utils/html.py
@@ -7,6 +7,7 @@ import sys
from django.utils.encoding import force_text, force_str
from django.utils.functional import allow_lazy
+from django.utils.http import RFC3986_GENDELIMS, RFC3986_SUBDELIMS
from django.utils.safestring import SafeData, mark_safe
from django.utils import six
from django.utils.six.moves.urllib.parse import quote, unquote, urlsplit, urlunsplit
@@ -215,7 +216,7 @@ def smart_urlquote(url):
url = unquote(force_str(url))
# See http://bugs.python.org/issue2637
- url = quote(url, safe=b'!*\'();:@&=+$,/?#[]~')
+ url = quote(url, safe=RFC3986_SUBDELIMS + RFC3986_GENDELIMS + str('~'))
return force_text(url)
diff --git a/django/utils/http.py b/django/utils/http.py
index 27d445d46f..2375f95b5b 100644
--- a/django/utils/http.py
+++ b/django/utils/http.py
@@ -30,6 +30,9 @@ RFC1123_DATE = re.compile(r'^\w{3}, %s %s %s %s GMT$' % (__D, __M, __Y, __T))
RFC850_DATE = re.compile(r'^\w{6,9}, %s-%s-%s %s GMT$' % (__D, __M, __Y2, __T))
ASCTIME_DATE = re.compile(r'^\w{3} %s %s %s %s$' % (__M, __D2, __T, __Y))
+RFC3986_GENDELIMS = str(":/?#[]@")
+RFC3986_SUBDELIMS = str("!$&'()*+,;=")
+
def urlquote(url, safe='/'):
"""