Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fixed #21242 -- Allowed more IANA schemes in URLValidator

Thanks Sascha Peilicke for the report and initial patch, and
Tim Graham for the review.
  • Loading branch information...
commit 6d66ba59488bbd0d4f0c2f32b2921f1512301143 1 parent 9f13c33
Claude Paroz claudep authored
16 django/core/validators.py
View
@@ -44,7 +44,7 @@ def __call__(self, value):
@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
18 docs/ref/validators.txt
View
@@ -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``
------------------
7 docs/releases/1.7.txt
View
@@ -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
=====================================
7 tests/validators/tests.py
View
@@ -18,6 +18,7 @@
NOW = datetime.now()
+EXTENDED_SCHEMES = ['http', 'https', 'ftp', 'ftps', 'git', 'file']
TEST_DATA = (
# (validator, value, expected),
@@ -141,6 +142,7 @@
(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 @@
(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 @@
(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),
Please sign in to comment.
Something went wrong with that request. Please try again.