From 21f333bcefccc151d6439246f8203d609ab6ca79 Mon Sep 17 00:00:00 2001
From: Erik Romijn <eromijn@solidlinks.nl>
Date: Sat, 23 Feb 2013 14:44:57 +0100
Subject: [PATCH] Fix #17751: Added stripping of whitespace for
 IPAddressField/GenericIPAddressField

---
 django/core/validators.py                  |  2 +-
 django/forms/fields.py                     |  8 ++++++
 tests/modeltests/validation/tests.py       | 18 +++++++++++--
 tests/regressiontests/forms/tests/extra.py | 30 +++++++++++-----------
 4 files changed, 40 insertions(+), 18 deletions(-)

diff --git a/django/core/validators.py b/django/core/validators.py
index 948ae286732..322741be39f 100644
--- a/django/core/validators.py
+++ b/django/core/validators.py
@@ -129,7 +129,7 @@ validate_email = EmailValidator()
 slug_re = re.compile(r'^[-a-zA-Z0-9_]+$')
 validate_slug = RegexValidator(slug_re, _("Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."), 'invalid')
 
-ipv4_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}$')
+ipv4_re = re.compile(r'^\s*(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\s*$')
 validate_ipv4_address = RegexValidator(ipv4_re, _('Enter a valid IPv4 address.'), 'invalid')
 
 
diff --git a/django/forms/fields.py b/django/forms/fields.py
index 621d3801f28..aa909a8aa5f 100644
--- a/django/forms/fields.py
+++ b/django/forms/fields.py
@@ -1096,6 +1096,10 @@ class IPAddressField(CharField):
     }
     default_validators = [validators.validate_ipv4_address]
 
+    def clean(self, value):
+        value = self.to_python(value).strip()
+        return super(IPAddressField, self).clean(value)
+
 
 class GenericIPAddressField(CharField):
     default_error_messages = {}
@@ -1107,6 +1111,10 @@ class GenericIPAddressField(CharField):
         self.default_error_messages['invalid'] = invalid_error_message
         super(GenericIPAddressField, self).__init__(*args, **kwargs)
 
+    def clean(self, value):
+        value = self.to_python(value).strip()
+        return super(GenericIPAddressField, self).clean(value)
+
     def to_python(self, value):
         if value in validators.EMPTY_VALUES:
             return ''
diff --git a/tests/modeltests/validation/tests.py b/tests/modeltests/validation/tests.py
index 58b7b94e7fe..dca99052e56 100644
--- a/tests/modeltests/validation/tests.py
+++ b/tests/modeltests/validation/tests.py
@@ -116,40 +116,54 @@ class GenericIPAddressFieldTests(ValidationTestCase):
     def test_correct_generic_ip_passes(self):
         giptm = GenericIPAddressTestModel(generic_ip="1.2.3.4")
         self.assertEqual(None, giptm.full_clean())
+        giptm = GenericIPAddressTestModel(generic_ip=" 1.2.3.4 ")
+        self.assertEqual(None, giptm.full_clean())
         giptm = GenericIPAddressTestModel(generic_ip="2001::2")
         self.assertEqual(None, giptm.full_clean())
+        giptm = GenericIPAddressTestModel(generic_ip=" 2001::2 ")
+        self.assertEqual(None, giptm.full_clean())
 
     def test_invalid_generic_ip_raises_error(self):
         giptm = GenericIPAddressTestModel(generic_ip="294.4.2.1")
         self.assertFailsValidation(giptm.full_clean, ['generic_ip',])
+        giptm = GenericIPAddressTestModel(generic_ip="1.2.3 .4")
+        self.assertFailsValidation(giptm.full_clean, ['generic_ip',])
         giptm = GenericIPAddressTestModel(generic_ip="1:2")
         self.assertFailsValidation(giptm.full_clean, ['generic_ip',])
 
     def test_correct_v4_ip_passes(self):
         giptm = GenericIPAddressTestModel(v4_ip="1.2.3.4")
         self.assertEqual(None, giptm.full_clean())
+        giptm = GenericIPAddressTestModel(v4_ip=" 1.2.3.4 ")
+        self.assertEqual(None, giptm.full_clean())
 
     def test_invalid_v4_ip_raises_error(self):
         giptm = GenericIPAddressTestModel(v4_ip="294.4.2.1")
         self.assertFailsValidation(giptm.full_clean, ['v4_ip',])
+        giptm = GenericIPAddressTestModel(v4_ip="294.4 .2.1")
+        self.assertFailsValidation(giptm.full_clean, ['v4_ip',])
         giptm = GenericIPAddressTestModel(v4_ip="2001::2")
         self.assertFailsValidation(giptm.full_clean, ['v4_ip',])
 
     def test_correct_v6_ip_passes(self):
         giptm = GenericIPAddressTestModel(v6_ip="2001::2")
         self.assertEqual(None, giptm.full_clean())
+        giptm = GenericIPAddressTestModel(v6_ip=" 2001::2 ")
+        self.assertEqual(None, giptm.full_clean())
 
     def test_invalid_v6_ip_raises_error(self):
         giptm = GenericIPAddressTestModel(v6_ip="1.2.3.4")
         self.assertFailsValidation(giptm.full_clean, ['v6_ip',])
+        giptm = GenericIPAddressTestModel(v6_ip="2001:: 2")
+        self.assertFailsValidation(giptm.full_clean, ['v6_ip',])
         giptm = GenericIPAddressTestModel(v6_ip="1:2")
         self.assertFailsValidation(giptm.full_clean, ['v6_ip',])
 
     def test_v6_uniqueness_detection(self):
         # These two addresses are the same with different syntax
-        giptm = GenericIPAddressTestModel(generic_ip="2001::1:0:0:0:0:2")
+        giptm = GenericIPAddressTestModel(generic_ip=" 2001::1:0:0:0:0:2")
         giptm.save()
-        giptm = GenericIPAddressTestModel(generic_ip="2001:0:1:2")
+        giptm = GenericIPAddressTestModel(generic_ip="2001:0:1:2 ")
         self.assertFailsValidation(giptm.full_clean, ['generic_ip',])
 
     def test_v4_unpack_uniqueness_detection(self):
diff --git a/tests/regressiontests/forms/tests/extra.py b/tests/regressiontests/forms/tests/extra.py
index b5f36dc9819..359ad442bc4 100644
--- a/tests/regressiontests/forms/tests/extra.py
+++ b/tests/regressiontests/forms/tests/extra.py
@@ -474,7 +474,7 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin):
         f = IPAddressField()
         self.assertFormErrors(['This field is required.'], f.clean, '')
         self.assertFormErrors(['This field is required.'], f.clean, None)
-        self.assertEqual(f.clean('127.0.0.1'), '127.0.0.1')
+        self.assertEqual(f.clean(' 127.0.0.1'), '127.0.0.1')
         self.assertFormErrors(['Enter a valid IPv4 address.'], f.clean, 'foo')
         self.assertFormErrors(['Enter a valid IPv4 address.'], f.clean, '127.0.0.')
         self.assertFormErrors(['Enter a valid IPv4 address.'], f.clean, '1.2.3.4.5')
@@ -483,7 +483,7 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin):
         f = IPAddressField(required=False)
         self.assertEqual(f.clean(''), '')
         self.assertEqual(f.clean(None), '')
-        self.assertEqual(f.clean('127.0.0.1'), '127.0.0.1')
+        self.assertEqual(f.clean(' 127.0.0.1'), '127.0.0.1')
         self.assertFormErrors(['Enter a valid IPv4 address.'], f.clean, 'foo')
         self.assertFormErrors(['Enter a valid IPv4 address.'], f.clean, '127.0.0.')
         self.assertFormErrors(['Enter a valid IPv4 address.'], f.clean, '1.2.3.4.5')
@@ -499,13 +499,13 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin):
         f = GenericIPAddressField()
         self.assertFormErrors(['This field is required.'], f.clean, '')
         self.assertFormErrors(['This field is required.'], f.clean, None)
-        self.assertEqual(f.clean('127.0.0.1'), '127.0.0.1')
+        self.assertEqual(f.clean(' 127.0.0.1 '), '127.0.0.1')
         self.assertFormErrors(['Enter a valid IPv4 or IPv6 address.'], f.clean, 'foo')
         self.assertFormErrors(['Enter a valid IPv4 or IPv6 address.'], f.clean, '127.0.0.')
         self.assertFormErrors(['Enter a valid IPv4 or IPv6 address.'], f.clean, '1.2.3.4.5')
         self.assertFormErrors(['Enter a valid IPv4 or IPv6 address.'], f.clean, '256.125.1.5')
-        self.assertEqual(f.clean('fe80::223:6cff:fe8a:2e8a'), 'fe80::223:6cff:fe8a:2e8a')
-        self.assertEqual(f.clean('2a02::223:6cff:fe8a:2e8a'), '2a02::223:6cff:fe8a:2e8a')
+        self.assertEqual(f.clean(' fe80::223:6cff:fe8a:2e8a '), 'fe80::223:6cff:fe8a:2e8a')
+        self.assertEqual(f.clean(' 2a02::223:6cff:fe8a:2e8a '), '2a02::223:6cff:fe8a:2e8a')
         self.assertFormErrors(['Enter a valid IPv4 or IPv6 address.'], f.clean, '12345:2:3:4')
         self.assertFormErrors(['Enter a valid IPv4 or IPv6 address.'], f.clean, '1::2:3::4')
         self.assertFormErrors(['Enter a valid IPv4 or IPv6 address.'], f.clean, 'foo::223:6cff:fe8a:2e8a')
@@ -516,7 +516,7 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin):
         f = GenericIPAddressField(protocol="IPv4")
         self.assertFormErrors(['This field is required.'], f.clean, '')
         self.assertFormErrors(['This field is required.'], f.clean, None)
-        self.assertEqual(f.clean('127.0.0.1'), '127.0.0.1')
+        self.assertEqual(f.clean(' 127.0.0.1 '), '127.0.0.1')
         self.assertFormErrors(['Enter a valid IPv4 address.'], f.clean, 'foo')
         self.assertFormErrors(['Enter a valid IPv4 address.'], f.clean, '127.0.0.')
         self.assertFormErrors(['Enter a valid IPv4 address.'], f.clean, '1.2.3.4.5')
@@ -533,8 +533,8 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin):
         self.assertFormErrors(['Enter a valid IPv6 address.'], f.clean, '127.0.0.')
         self.assertFormErrors(['Enter a valid IPv6 address.'], f.clean, '1.2.3.4.5')
         self.assertFormErrors(['Enter a valid IPv6 address.'], f.clean, '256.125.1.5')
-        self.assertEqual(f.clean('fe80::223:6cff:fe8a:2e8a'), 'fe80::223:6cff:fe8a:2e8a')
-        self.assertEqual(f.clean('2a02::223:6cff:fe8a:2e8a'), '2a02::223:6cff:fe8a:2e8a')
+        self.assertEqual(f.clean(' fe80::223:6cff:fe8a:2e8a '), 'fe80::223:6cff:fe8a:2e8a')
+        self.assertEqual(f.clean(' 2a02::223:6cff:fe8a:2e8a '), '2a02::223:6cff:fe8a:2e8a')
         self.assertFormErrors(['Enter a valid IPv6 address.'], f.clean, '12345:2:3:4')
         self.assertFormErrors(['Enter a valid IPv6 address.'], f.clean, '1::2:3::4')
         self.assertFormErrors(['Enter a valid IPv6 address.'], f.clean, 'foo::223:6cff:fe8a:2e8a')
@@ -550,8 +550,8 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin):
         self.assertFormErrors(['Enter a valid IPv4 or IPv6 address.'], f.clean, '127.0.0.')
         self.assertFormErrors(['Enter a valid IPv4 or IPv6 address.'], f.clean, '1.2.3.4.5')
         self.assertFormErrors(['Enter a valid IPv4 or IPv6 address.'], f.clean, '256.125.1.5')
-        self.assertEqual(f.clean('fe80::223:6cff:fe8a:2e8a'), 'fe80::223:6cff:fe8a:2e8a')
-        self.assertEqual(f.clean('2a02::223:6cff:fe8a:2e8a'), '2a02::223:6cff:fe8a:2e8a')
+        self.assertEqual(f.clean(' fe80::223:6cff:fe8a:2e8a '), 'fe80::223:6cff:fe8a:2e8a')
+        self.assertEqual(f.clean(' 2a02::223:6cff:fe8a:2e8a '), '2a02::223:6cff:fe8a:2e8a')
         self.assertFormErrors(['Enter a valid IPv4 or IPv6 address.'], f.clean, '12345:2:3:4')
         self.assertFormErrors(['Enter a valid IPv4 or IPv6 address.'], f.clean, '1::2:3::4')
         self.assertFormErrors(['Enter a valid IPv4 or IPv6 address.'], f.clean, 'foo::223:6cff:fe8a:2e8a')
@@ -561,13 +561,13 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin):
     def test_generic_ipaddress_normalization(self):
         # Test the normalising code
         f = GenericIPAddressField()
-        self.assertEqual(f.clean('::ffff:0a0a:0a0a'), '::ffff:10.10.10.10')
-        self.assertEqual(f.clean('::ffff:10.10.10.10'), '::ffff:10.10.10.10')
-        self.assertEqual(f.clean('2001:000:a:0000:0:fe:fe:beef'), '2001:0:a::fe:fe:beef')
-        self.assertEqual(f.clean('2001::a:0000:0:fe:fe:beef'), '2001:0:a::fe:fe:beef')
+        self.assertEqual(f.clean(' ::ffff:0a0a:0a0a  '), '::ffff:10.10.10.10')
+        self.assertEqual(f.clean(' ::ffff:10.10.10.10  '), '::ffff:10.10.10.10')
+        self.assertEqual(f.clean(' 2001:000:a:0000:0:fe:fe:beef  '), '2001:0:a::fe:fe:beef')
+        self.assertEqual(f.clean(' 2001::a:0000:0:fe:fe:beef  '), '2001:0:a::fe:fe:beef')
 
         f = GenericIPAddressField(unpack_ipv4=True)
-        self.assertEqual(f.clean('::ffff:0a0a:0a0a'), '10.10.10.10')
+        self.assertEqual(f.clean(' ::ffff:0a0a:0a0a'), '10.10.10.10')
 
     def test_smart_text(self):
         class Test: