Skip to content

Commit d8a5c21

Browse files
JulianKahnertkvesteri
authored andcommitted
add IPv6 address parsing (#83)
* add IPv6 address parsing * add tests with urls from https://www.ietf.org/rfc/rfc2732.txt
1 parent dc5f17b commit d8a5c21

File tree

2 files changed

+44
-0
lines changed

2 files changed

+44
-0
lines changed

tests/test_url.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@
5252
u'http://127.0.10.150',
5353
u'http://localhost',
5454
u'http://localhost:8000',
55+
u'http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html',
56+
u'http://[1080:0:0:0:8:800:200C:417A]/index.html',
57+
u'http://[3ffe:2a00:100:7031::1]',
58+
u'http://[1080::8:800:200C:417A]/foo',
59+
u'http://[::192.9.5.5]/ipng',
60+
u'http://[::FFFF:129.144.52.38]:80/index.html',
61+
u'http://[2010:836B:4179::836B:4179]',
5562
])
5663
def test_returns_true_on_valid_url(address):
5764
assert url(address)
@@ -118,6 +125,9 @@ def test_returns_true_on_valid_public_url(address, public):
118125
'http://.www.foo.bar./',
119126
'http://127.12.0.260',
120127
'http://example.com/">user@example.com',
128+
'http://[2010:836B:4179::836B:4179',
129+
'http://2010:836B:4179::836B:4179',
130+
'http://2010:836B:4179::836B:4179:80/index.html',
121131
])
122132
def test_returns_failed_validation_on_invalid_url(address):
123133
assert isinstance(url(address), ValidationFailure)

validators/url.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,40 @@
3434
u"" + ip_middle_octet + u"{2}"
3535
u"" + ip_last_octet + u")"
3636
u"|"
37+
# IPv6 RegEx from https://stackoverflow.com/a/17871737
38+
u"\[("
39+
# 1:2:3:4:5:6:7:8
40+
u"([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|"
41+
# 1:: 1:2:3:4:5:6:7::
42+
u"([0-9a-fA-F]{1,4}:){1,7}:|"
43+
# 1::8 1:2:3:4:5:6::8 1:2:3:4:5:6::8
44+
u"([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|"
45+
# 1::7:8 1:2:3:4:5::7:8 1:2:3:4:5::8
46+
u"([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|"
47+
# 1::6:7:8 1:2:3:4::6:7:8 1:2:3:4::8
48+
u"([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|"
49+
# 1::5:6:7:8 1:2:3::5:6:7:8 1:2:3::8
50+
u"([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|"
51+
# 1::4:5:6:7:8 1:2::4:5:6:7:8 1:2::8
52+
u"([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|"
53+
# 1::3:4:5:6:7:8 1::3:4:5:6:7:8 1::8
54+
u"[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|"
55+
# ::2:3:4:5:6:7:8 ::2:3:4:5:6:7:8 ::8 ::
56+
u":((:[0-9a-fA-F]{1,4}){1,7}|:)|"
57+
# fe80::7:8%eth0 fe80::7:8%1
58+
# (link-local IPv6 addresses with zone index)
59+
u"fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|"
60+
u"::(ffff(:0{1,4}){0,1}:){0,1}"
61+
u"((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}"
62+
# ::255.255.255.255 ::ffff:255.255.255.255 ::ffff:0:255.255.255.255
63+
# (IPv4-mapped IPv6 addresses and IPv4-translated addresses)
64+
u"(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|"
65+
u"([0-9a-fA-F]{1,4}:){1,4}:"
66+
u"((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}"
67+
# 2001:db8:3:4::192.0.2.33 64:ff9b::192.0.2.33
68+
# (IPv4-Embedded IPv6 Address)
69+
u"(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])"
70+
u")\]|"
3771
# host name
3872
u"(?:(?:[a-z\u00a1-\uffff0-9]-?)*[a-z\u00a1-\uffff0-9]+)"
3973
# domain name

0 commit comments

Comments
 (0)