PageRenderTime 74ms CodeModel.GetById 60ms app.highlight 11ms RepoModel.GetById 1ms app.codeStats 0ms

/Django-1.4.3/django/core/validators.py

https://bitbucket.org/ducopdep/tiny_blog
Python | 252 lines | 219 code | 22 blank | 11 comment | 8 complexity | 1a00e3f938e504e8fa39170746ec21b0 MD5 | raw file
Possible License(s): BSD-3-Clause
  1import platform
  2import re
  3import urllib
  4import urllib2
  5import urlparse
  6
  7from django.core.exceptions import ValidationError
  8from django.utils.translation import ugettext_lazy as _
  9from django.utils.encoding import smart_unicode
 10from django.utils.ipv6 import is_valid_ipv6_address
 11
 12# These values, if given to validate(), will trigger the self.required check.
 13EMPTY_VALUES = (None, '', [], (), {})
 14
 15try:
 16    from django.conf import settings
 17    URL_VALIDATOR_USER_AGENT = settings.URL_VALIDATOR_USER_AGENT
 18except ImportError:
 19    # It's OK if Django settings aren't configured.
 20    URL_VALIDATOR_USER_AGENT = 'Django (http://www.djangoproject.com/)'
 21
 22class RegexValidator(object):
 23    regex = ''
 24    message = _(u'Enter a valid value.')
 25    code = 'invalid'
 26
 27    def __init__(self, regex=None, message=None, code=None):
 28        if regex is not None:
 29            self.regex = regex
 30        if message is not None:
 31            self.message = message
 32        if code is not None:
 33            self.code = code
 34
 35        # Compile the regex if it was not passed pre-compiled.
 36        if isinstance(self.regex, basestring):
 37            self.regex = re.compile(self.regex)
 38
 39    def __call__(self, value):
 40        """
 41        Validates that the input matches the regular expression.
 42        """
 43        if not self.regex.search(smart_unicode(value)):
 44            raise ValidationError(self.message, code=self.code)
 45
 46class URLValidator(RegexValidator):
 47    regex = re.compile(
 48        r'^(?:http|ftp)s?://' # http:// or https://
 49        r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' #domain...
 50        r'localhost|' #localhost...
 51        r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip
 52        r'(?::\d+)?' # optional port
 53        r'(?:/?|[/?]\S+)$', re.IGNORECASE)
 54
 55    def __init__(self, verify_exists=False,
 56                 validator_user_agent=URL_VALIDATOR_USER_AGENT):
 57        super(URLValidator, self).__init__()
 58        self.verify_exists = verify_exists
 59        self.user_agent = validator_user_agent
 60
 61    def __call__(self, value):
 62        try:
 63            super(URLValidator, self).__call__(value)
 64        except ValidationError, e:
 65            # Trivial case failed. Try for possible IDN domain
 66            if value:
 67                value = smart_unicode(value)
 68                scheme, netloc, path, query, fragment = urlparse.urlsplit(value)
 69                try:
 70                    netloc = netloc.encode('idna') # IDN -> ACE
 71                except UnicodeError: # invalid domain part
 72                    raise e
 73                url = urlparse.urlunsplit((scheme, netloc, path, query, fragment))
 74                super(URLValidator, self).__call__(url)
 75            else:
 76                raise
 77        else:
 78            url = value
 79
 80        if self.verify_exists:
 81            import warnings
 82            warnings.warn(
 83                "The URLField verify_exists argument has intractable security "
 84                "and performance issues. Accordingly, it has been deprecated.",
 85                DeprecationWarning
 86                )
 87
 88            headers = {
 89                "Accept": "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5",
 90                "Accept-Language": "en-us,en;q=0.5",
 91                "Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
 92                "Connection": "close",
 93                "User-Agent": self.user_agent,
 94            }
 95            url = url.encode('utf-8')
 96            # Quote characters from the unreserved set, refs #16812
 97            url = urllib.quote(url, "!*'();:@&=+$,/?#[]")
 98            broken_error = ValidationError(
 99                _(u'This URL appears to be a broken link.'), code='invalid_link')
100            try:
101                req = urllib2.Request(url, None, headers)
102                req.get_method = lambda: 'HEAD'
103                #Create an opener that does not support local file access
104                opener = urllib2.OpenerDirector()
105
106                #Don't follow redirects, but don't treat them as errors either
107                error_nop = lambda *args, **kwargs: True
108                http_error_processor = urllib2.HTTPErrorProcessor()
109                http_error_processor.http_error_301 = error_nop
110                http_error_processor.http_error_302 = error_nop
111                http_error_processor.http_error_307 = error_nop
112
113                handlers = [urllib2.UnknownHandler(),
114                            urllib2.HTTPHandler(),
115                            urllib2.HTTPDefaultErrorHandler(),
116                            urllib2.FTPHandler(),
117                            http_error_processor]
118                try:
119                    import ssl
120                except ImportError:
121                    # Python isn't compiled with SSL support
122                    pass
123                else:
124                    handlers.append(urllib2.HTTPSHandler())
125                map(opener.add_handler, handlers)
126                if platform.python_version_tuple() >= (2, 6):
127                    opener.open(req, timeout=10)
128                else:
129                    opener.open(req)
130            except ValueError:
131                raise ValidationError(_(u'Enter a valid URL.'), code='invalid')
132            except: # urllib2.URLError, httplib.InvalidURL, etc.
133                raise broken_error
134
135
136def validate_integer(value):
137    try:
138        int(value)
139    except (ValueError, TypeError):
140        raise ValidationError('')
141
142class EmailValidator(RegexValidator):
143
144    def __call__(self, value):
145        try:
146            super(EmailValidator, self).__call__(value)
147        except ValidationError, e:
148            # Trivial case failed. Try for possible IDN domain-part
149            if value and u'@' in value:
150                parts = value.split(u'@')
151                try:
152                    parts[-1] = parts[-1].encode('idna')
153                except UnicodeError:
154                    raise e
155                super(EmailValidator, self).__call__(u'@'.join(parts))
156            else:
157                raise
158
159email_re = re.compile(
160    r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*"  # dot-atom
161    # quoted-string, see also http://tools.ietf.org/html/rfc2822#section-3.2.5
162    r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"'
163    r')@((?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?$)'  # domain
164    r'|\[(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\]$', re.IGNORECASE)  # literal form, ipv4 address (SMTP 4.1.3)
165validate_email = EmailValidator(email_re, _(u'Enter a valid e-mail address.'), 'invalid')
166
167slug_re = re.compile(r'^[-\w]+$')
168validate_slug = RegexValidator(slug_re, _(u"Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."), 'invalid')
169
170ipv4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$')
171validate_ipv4_address = RegexValidator(ipv4_re, _(u'Enter a valid IPv4 address.'), 'invalid')
172
173def validate_ipv6_address(value):
174    if not is_valid_ipv6_address(value):
175        raise ValidationError(_(u'Enter a valid IPv6 address.'), code='invalid')
176
177def validate_ipv46_address(value):
178    try:
179        validate_ipv4_address(value)
180    except ValidationError:
181        try:
182            validate_ipv6_address(value)
183        except ValidationError:
184            raise ValidationError(_(u'Enter a valid IPv4 or IPv6 address.'), code='invalid')
185
186ip_address_validator_map = {
187    'both': ([validate_ipv46_address], _('Enter a valid IPv4 or IPv6 address.')),
188    'ipv4': ([validate_ipv4_address], _('Enter a valid IPv4 address.')),
189    'ipv6': ([validate_ipv6_address], _('Enter a valid IPv6 address.')),
190}
191
192def ip_address_validators(protocol, unpack_ipv4):
193    """
194    Depending on the given parameters returns the appropriate validators for
195    the GenericIPAddressField.
196
197    This code is here, because it is exactly the same for the model and the form field.
198    """
199    if protocol != 'both' and unpack_ipv4:
200        raise ValueError(
201            "You can only use `unpack_ipv4` if `protocol` is set to 'both'")
202    try:
203        return ip_address_validator_map[protocol.lower()]
204    except KeyError:
205        raise ValueError("The protocol '%s' is unknown. Supported: %s"
206                         % (protocol, ip_address_validator_map.keys()))
207
208comma_separated_int_list_re = re.compile('^[\d,]+$')
209validate_comma_separated_integer_list = RegexValidator(comma_separated_int_list_re, _(u'Enter only digits separated by commas.'), 'invalid')
210
211
212class BaseValidator(object):
213    compare = lambda self, a, b: a is not b
214    clean   = lambda self, x: x
215    message = _(u'Ensure this value is %(limit_value)s (it is %(show_value)s).')
216    code = 'limit_value'
217
218    def __init__(self, limit_value):
219        self.limit_value = limit_value
220
221    def __call__(self, value):
222        cleaned = self.clean(value)
223        params = {'limit_value': self.limit_value, 'show_value': cleaned}
224        if self.compare(cleaned, self.limit_value):
225            raise ValidationError(
226                self.message % params,
227                code=self.code,
228                params=params,
229            )
230
231class MaxValueValidator(BaseValidator):
232    compare = lambda self, a, b: a > b
233    message = _(u'Ensure this value is less than or equal to %(limit_value)s.')
234    code = 'max_value'
235
236class MinValueValidator(BaseValidator):
237    compare = lambda self, a, b: a < b
238    message = _(u'Ensure this value is greater than or equal to %(limit_value)s.')
239    code = 'min_value'
240
241class MinLengthValidator(BaseValidator):
242    compare = lambda self, a, b: a < b
243    clean   = lambda self, x: len(x)
244    message = _(u'Ensure this value has at least %(limit_value)d characters (it has %(show_value)d).')
245    code = 'min_length'
246
247class MaxLengthValidator(BaseValidator):
248    compare = lambda self, a, b: a > b
249    clean   = lambda self, x: len(x)
250    message = _(u'Ensure this value has at most %(limit_value)d characters (it has %(show_value)d).')
251    code = 'max_length'
252