summaryrefslogtreecommitdiff
path: root/django/core/validators.py
diff options
context:
space:
mode:
authorRussell Keith-Magee <russell@keith-magee.com>2011-09-10 01:08:24 +0000
committerRussell Keith-Magee <russell@keith-magee.com>2011-09-10 01:08:24 +0000
commit1a76dbefdfc60e2d5954c0ba614c3d054ba9c3f0 (patch)
tree053c60d65b333df990de1250af0085ec75baf953 /django/core/validators.py
parentfbe2eead2fa9d808658ca582241bcacb02618840 (diff)
[1.3.X] Altered the behavior of URLField to avoid a potential DOS vector, and to avoid potential leakage of local filesystem data. A security announcement will be made shortly.
Backport of r16760 from trunk. git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.3.X@16763 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django/core/validators.py')
-rw-r--r--django/core/validators.py50
1 files changed, 32 insertions, 18 deletions
diff --git a/django/core/validators.py b/django/core/validators.py
index a40af0c8dd..a93c6ac975 100644
--- a/django/core/validators.py
+++ b/django/core/validators.py
@@ -1,3 +1,4 @@
+import platform
import re
import urllib2
import urlparse
@@ -39,10 +40,6 @@ class RegexValidator(object):
if not self.regex.search(smart_unicode(value)):
raise ValidationError(self.message, code=self.code)
-class HeadRequest(urllib2.Request):
- def get_method(self):
- return "HEAD"
-
class URLValidator(RegexValidator):
regex = re.compile(
r'^(?:http|ftp)s?://' # http:// or https://
@@ -52,7 +49,8 @@ class URLValidator(RegexValidator):
r'(?::\d+)?' # optional port
r'(?:/?|[/?]\S+)$', re.IGNORECASE)
- def __init__(self, verify_exists=False, validator_user_agent=URL_VALIDATOR_USER_AGENT):
+ def __init__(self, verify_exists=False,
+ validator_user_agent=URL_VALIDATOR_USER_AGENT):
super(URLValidator, self).__init__()
self.verify_exists = verify_exists
self.user_agent = validator_user_agent
@@ -76,6 +74,7 @@ class URLValidator(RegexValidator):
else:
url = value
+ #This is deprecated and will be removed in a future release.
if self.verify_exists:
headers = {
"Accept": "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5",
@@ -88,21 +87,36 @@ class URLValidator(RegexValidator):
broken_error = ValidationError(
_(u'This URL appears to be a broken link.'), code='invalid_link')
try:
- req = HeadRequest(url, None, headers)
- u = urllib2.urlopen(req)
+ req = urllib2.Request(url, None, headers)
+ req.get_method = lambda: 'HEAD'
+ #Create an opener that does not support local file access
+ opener = urllib2.OpenerDirector()
+
+ #Don't follow redirects, but don't treat them as errors either
+ error_nop = lambda *args, **kwargs: True
+ http_error_processor = urllib2.HTTPErrorProcessor()
+ http_error_processor.http_error_301 = error_nop
+ http_error_processor.http_error_302 = error_nop
+ http_error_processor.http_error_307 = error_nop
+
+ handlers = [urllib2.UnknownHandler(),
+ urllib2.HTTPHandler(),
+ urllib2.HTTPDefaultErrorHandler(),
+ urllib2.FTPHandler(),
+ http_error_processor]
+ try:
+ import ssl
+ handlers.append(urllib2.HTTPSHandler())
+ except:
+ #Python isn't compiled with SSL support
+ pass
+ map(opener.add_handler, handlers)
+ if platform.python_version_tuple() >= (2, 6):
+ opener.open(req, timeout=10)
+ else:
+ opener.open(req)
except ValueError:
raise ValidationError(_(u'Enter a valid URL.'), code='invalid')
- except urllib2.HTTPError, e:
- if e.code in (405, 501):
- # Try a GET request (HEAD refused)
- # See also: http://www.w3.org/Protocols/rfc2616/rfc2616.html
- try:
- req = urllib2.Request(url, None, headers)
- u = urllib2.urlopen(req)
- except:
- raise broken_error
- else:
- raise broken_error
except: # urllib2.URLError, httplib.InvalidURL, etc.
raise broken_error