Ticket #9764: idn_support.diff

File idn_support.diff, 3.6 KB (added by UloPe, 6 years ago)

EmailField, URLField IDN support

  • django/forms/fields.py

     
    432432        RegexField.__init__(self, email_re, max_length, min_length, *args,
    433433                            **kwargs)
    434434
     435    def clean(self, value):
     436        try:
     437            value = super(EmailField, self).clean(value)
     438        except ValidationError:
     439            # Trivial case failed. Try for possible IDN domain-part
     440            if value and u'@' in value:
     441                parts = value.split(u'@')
     442                domain_part = parts[-1]
     443                try:
     444                    parts[-1] = parts[-1].encode('idna')
     445                except UnicodeError:
     446                    pass # invalid domain part
     447                # After validation revert ACE encoded domain-part to
     448                # original (IDN) value as suggested by RFC 3490
     449                value = super(EmailField, self).clean(u'@'.join(parts)
     450                    ).replace(parts[-1], domain_part)
     451            else:
     452                raise
     453        return value
     454
    435455try:
    436456    from django.conf import settings
    437457    URL_VALIDATOR_USER_AGENT = settings.URL_VALIDATOR_USER_AGENT
     
    547567        self.user_agent = validator_user_agent
    548568
    549569    def clean(self, value):
     570        if value:
     571            value = smart_unicode(value)
    550572        # If no URL scheme given, assume http://
    551573        if value and '://' not in value:
    552574            value = u'http://%s' % value
    553         # If no URL path given, assume /
    554         if value and not urlparse.urlsplit(value)[2]:
    555             value += '/'
     575        if value:
     576            splitted = urlparse.urlsplit(value)
     577            # IDN -> ACE
     578            try:
     579                netloc_ace = splitted[1].encode('idna')
     580            except UnicodeError: # invalid domain part
     581                netloc_ace = splitted[1]
     582            value = value.replace(splitted[1], netloc_ace)
     583            # If no URL path given, assume /
     584            if not splitted[2]:
     585                value += u'/'
    556586        value = super(URLField, self).clean(value)
    557587        if value == u'':
    558588            return value
     589        # ACE -> IDN
     590        value = value.replace(netloc_ace, splitted[1])
    559591        if self.verify_exists:
    560592            import urllib2
    561593            headers = {
  • tests/regressiontests/forms/fields.py

     
    733733ValidationError: [u'This field is required.']
    734734>>> f.clean('person@example.com')
    735735u'person@example.com'
     736
     737Address with IDN domain-part:
     738>>> f.clean('local@domain.with.idn.xyzäöüßabc.part.com')
     739u'local@domain.with.idn.xyz\xe4\xf6\xfc\xdfabc.part.com'
     740
    736741>>> f.clean('foo')
    737742Traceback (most recent call last):
    738743...
     
    765770Traceback (most recent call last):
    766771...
    767772ValidationError: [u'Enter a valid e-mail address.']
     773>>> f.clean('foo@.com')
     774Traceback (most recent call last):
     775...
     776ValidationError: [u'Enter a valid e-mail address.']
    768777
    769778EmailField also access min_length and max_length parameters, for convenience.
    770779>>> f = EmailField(min_length=10, max_length=15)
     
    868877u'http://200.8.9.10/'
    869878>>> f.clean('http://200.8.9.10:8000/test')
    870879u'http://200.8.9.10:8000/test'
     880
     881IDN domain
     882>>> f.clean('http://some.idn.xyzäöüßabc.domain.com:123/blah')
     883u'http://some.idn.xyz\xe4\xf6\xfc\xdfabc.domain.com:123/blah'
     884
    871885>>> f.clean('foo')
    872886Traceback (most recent call last):
    873887...
Back to Top