Fixed #21242 -- Allowed more IANA schemes in URLValidator
Thanks Sascha Peilicke for the report and initial patch, and Tim Graham for the review.
This commit is contained in:
parent
9f13c33281
commit
6d66ba5948
|
@ -44,7 +44,7 @@ class RegexValidator(object):
|
|||
@deconstructible
|
||||
class URLValidator(RegexValidator):
|
||||
regex = re.compile(
|
||||
r'^(?:http|ftp)s?://' # http:// or https://
|
||||
r'^(?:[a-z0-9\.\-]*)://' # scheme is validated separately
|
||||
r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' # domain...
|
||||
r'localhost|' # localhost...
|
||||
r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|' # ...or ipv4
|
||||
|
@ -52,14 +52,26 @@ class URLValidator(RegexValidator):
|
|||
r'(?::\d+)?' # optional port
|
||||
r'(?:/?|[/?]\S+)$', re.IGNORECASE)
|
||||
message = _('Enter a valid URL.')
|
||||
schemes = ['http', 'https', 'ftp', 'ftps']
|
||||
|
||||
def __init__(self, schemes=None, **kwargs):
|
||||
super(URLValidator, self).__init__(**kwargs)
|
||||
if schemes is not None:
|
||||
self.schemes = schemes
|
||||
|
||||
def __call__(self, value):
|
||||
value = force_text(value)
|
||||
# Check first if the scheme is valid
|
||||
scheme = value.split('://')[0].lower()
|
||||
if scheme not in self.schemes:
|
||||
raise ValidationError(self.message, code=self.code)
|
||||
|
||||
# Then check full URL
|
||||
try:
|
||||
super(URLValidator, self).__call__(value)
|
||||
except ValidationError as e:
|
||||
# Trivial case failed. Try for possible IDN domain
|
||||
if value:
|
||||
value = force_text(value)
|
||||
scheme, netloc, path, query, fragment = urlsplit(value)
|
||||
try:
|
||||
netloc = netloc.encode('idna').decode('ascii') # IDN -> ACE
|
||||
|
|
|
@ -87,10 +87,24 @@ to, or in lieu of custom ``field.clean()`` methods.
|
|||
|
||||
``URLValidator``
|
||||
----------------
|
||||
.. class:: URLValidator()
|
||||
.. class:: URLValidator([schemes=None, regex=None, message=None, code=None])
|
||||
|
||||
A :class:`RegexValidator` that ensures a value looks like a URL, and raises
|
||||
an error code of ``'invalid'`` if it doesn't.
|
||||
an error code of ``'invalid'`` if it doesn't. In addition to the optional
|
||||
arguments of its parent :class:`RegexValidator` class, ``URLValidator``
|
||||
accepts an extra optional attribute:
|
||||
|
||||
.. attribute:: schemes
|
||||
|
||||
URL/URI scheme list to validate against. If not provided, the default
|
||||
list is ``['http', 'https', 'ftp', 'ftps']``. As a reference, the IANA
|
||||
Web site provides a full list of `valid URI schemes`_.
|
||||
|
||||
.. _valid URI schemes: https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml
|
||||
|
||||
.. versionchanged:: 1.7
|
||||
|
||||
The optional ``schemes`` attribute was added.
|
||||
|
||||
``validate_email``
|
||||
------------------
|
||||
|
|
|
@ -567,6 +567,13 @@ Tests
|
|||
* :meth:`~django.test.TransactionTestCase.assertNumQueries` now prints
|
||||
out the list of executed queries if the assertion fails.
|
||||
|
||||
Validators
|
||||
^^^^^^^^^^
|
||||
|
||||
* :class:`~django.core.validators.URLValidator` now accepts an optional
|
||||
``schemes`` argument which allows customization of the accepted URI schemes
|
||||
(instead of the defaults ``http(s)`` and ``ftp(s)``).
|
||||
|
||||
Backwards incompatible changes in 1.7
|
||||
=====================================
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ from django.test.utils import str_prefix
|
|||
|
||||
|
||||
NOW = datetime.now()
|
||||
EXTENDED_SCHEMES = ['http', 'https', 'ftp', 'ftps', 'git', 'file']
|
||||
|
||||
TEST_DATA = (
|
||||
# (validator, value, expected),
|
||||
|
@ -141,6 +142,7 @@ TEST_DATA = (
|
|||
(MinLengthValidator(10), '', ValidationError),
|
||||
|
||||
(URLValidator(), 'http://www.djangoproject.com/', None),
|
||||
(URLValidator(), 'HTTP://WWW.DJANGOPROJECT.COM/', None),
|
||||
(URLValidator(), 'http://localhost/', None),
|
||||
(URLValidator(), 'http://example.com/', None),
|
||||
(URLValidator(), 'http://www.example.com/', None),
|
||||
|
@ -155,6 +157,8 @@ TEST_DATA = (
|
|||
(URLValidator(), 'https://example.com/', None),
|
||||
(URLValidator(), 'ftp://example.com/', None),
|
||||
(URLValidator(), 'ftps://example.com/', None),
|
||||
(URLValidator(EXTENDED_SCHEMES), 'file://localhost/path', None),
|
||||
(URLValidator(EXTENDED_SCHEMES), 'git://example.com/', None),
|
||||
|
||||
(URLValidator(), 'foo', ValidationError),
|
||||
(URLValidator(), 'http://', ValidationError),
|
||||
|
@ -165,6 +169,9 @@ TEST_DATA = (
|
|||
(URLValidator(), 'http://-invalid.com', ValidationError),
|
||||
(URLValidator(), 'http://inv-.alid-.com', ValidationError),
|
||||
(URLValidator(), 'http://inv-.-alid.com', ValidationError),
|
||||
(URLValidator(), 'file://localhost/path', ValidationError),
|
||||
(URLValidator(), 'git://example.com/', ValidationError),
|
||||
(URLValidator(EXTENDED_SCHEMES), 'git://-invalid.com', ValidationError),
|
||||
|
||||
(BaseValidator(True), True, None),
|
||||
(BaseValidator(True), False, ValidationError),
|
||||
|
|
Loading…
Reference in New Issue