245 lines
6.1 KiB
Python
245 lines
6.1 KiB
Python
"""
|
|
Network Utilities
|
|
(from web.py)
|
|
"""
|
|
|
|
__all__ = [
|
|
"validipaddr", "validip6addr", "validipport", "validip", "validaddr",
|
|
"urlquote",
|
|
"httpdate", "parsehttpdate",
|
|
"htmlquote", "htmlunquote", "websafe",
|
|
]
|
|
|
|
import urllib, time
|
|
try: import datetime
|
|
except ImportError: pass
|
|
import re
|
|
import socket
|
|
|
|
def validip6addr(address):
|
|
"""
|
|
Returns True if `address` is a valid IPv6 address.
|
|
|
|
>>> validip6addr('::')
|
|
True
|
|
>>> validip6addr('aaaa:bbbb:cccc:dddd::1')
|
|
True
|
|
>>> validip6addr('1:2:3:4:5:6:7:8:9:10')
|
|
False
|
|
>>> validip6addr('12:10')
|
|
False
|
|
"""
|
|
try:
|
|
socket.inet_pton(socket.AF_INET6, address)
|
|
except (socket.error, AttributeError):
|
|
return False
|
|
|
|
return True
|
|
|
|
def validipaddr(address):
|
|
"""
|
|
Returns True if `address` is a valid IPv4 address.
|
|
|
|
>>> validipaddr('192.168.1.1')
|
|
True
|
|
>>> validipaddr('192.168.1.800')
|
|
False
|
|
>>> validipaddr('192.168.1')
|
|
False
|
|
"""
|
|
try:
|
|
octets = address.split('.')
|
|
if len(octets) != 4:
|
|
return False
|
|
for x in octets:
|
|
if not (0 <= int(x) <= 255):
|
|
return False
|
|
except ValueError:
|
|
return False
|
|
return True
|
|
|
|
def validipport(port):
|
|
"""
|
|
Returns True if `port` is a valid IPv4 port.
|
|
|
|
>>> validipport('9000')
|
|
True
|
|
>>> validipport('foo')
|
|
False
|
|
>>> validipport('1000000')
|
|
False
|
|
"""
|
|
try:
|
|
if not (0 <= int(port) <= 65535):
|
|
return False
|
|
except ValueError:
|
|
return False
|
|
return True
|
|
|
|
def validip(ip, defaultaddr="0.0.0.0", defaultport=8080):
|
|
"""
|
|
Returns `(ip_address, port)` from string `ip_addr_port`
|
|
>>> validip('1.2.3.4')
|
|
('1.2.3.4', 8080)
|
|
>>> validip('80')
|
|
('0.0.0.0', 80)
|
|
>>> validip('192.168.0.1:85')
|
|
('192.168.0.1', 85)
|
|
>>> validip('::')
|
|
('::', 8080)
|
|
>>> validip('[::]:88')
|
|
('::', 88)
|
|
>>> validip('[::1]:80')
|
|
('::1', 80)
|
|
|
|
"""
|
|
addr = defaultaddr
|
|
port = defaultport
|
|
|
|
#Matt Boswell's code to check for ipv6 first
|
|
match = re.search(r'^\[([^]]+)\](?::(\d+))?$',ip) #check for [ipv6]:port
|
|
if match:
|
|
if validip6addr(match.group(1)):
|
|
if match.group(2):
|
|
if validipport(match.group(2)): return (match.group(1),int(match.group(2)))
|
|
else:
|
|
return (match.group(1),port)
|
|
else:
|
|
if validip6addr(ip): return (ip,port)
|
|
#end ipv6 code
|
|
|
|
ip = ip.split(":", 1)
|
|
if len(ip) == 1:
|
|
if not ip[0]:
|
|
pass
|
|
elif validipaddr(ip[0]):
|
|
addr = ip[0]
|
|
elif validipport(ip[0]):
|
|
port = int(ip[0])
|
|
else:
|
|
raise ValueError, ':'.join(ip) + ' is not a valid IP address/port'
|
|
elif len(ip) == 2:
|
|
addr, port = ip
|
|
if not validipaddr(addr) and validipport(port):
|
|
raise ValueError, ':'.join(ip) + ' is not a valid IP address/port'
|
|
port = int(port)
|
|
else:
|
|
raise ValueError, ':'.join(ip) + ' is not a valid IP address/port'
|
|
return (addr, port)
|
|
|
|
def validaddr(string_):
|
|
"""
|
|
Returns either (ip_address, port) or "/path/to/socket" from string_
|
|
|
|
>>> validaddr('/path/to/socket')
|
|
'/path/to/socket'
|
|
>>> validaddr('8000')
|
|
('0.0.0.0', 8000)
|
|
>>> validaddr('127.0.0.1')
|
|
('127.0.0.1', 8080)
|
|
>>> validaddr('127.0.0.1:8000')
|
|
('127.0.0.1', 8000)
|
|
>>> validip('[::1]:80')
|
|
('::1', 80)
|
|
>>> validaddr('fff')
|
|
Traceback (most recent call last):
|
|
...
|
|
ValueError: fff is not a valid IP address/port
|
|
"""
|
|
if '/' in string_:
|
|
return string_
|
|
else:
|
|
return validip(string_)
|
|
|
|
def urlquote(val):
|
|
"""
|
|
Quotes a string for use in a URL.
|
|
|
|
>>> urlquote('://?f=1&j=1')
|
|
'%3A//%3Ff%3D1%26j%3D1'
|
|
>>> urlquote(None)
|
|
''
|
|
>>> urlquote(u'\u203d')
|
|
'%E2%80%BD'
|
|
"""
|
|
if val is None: return ''
|
|
if not isinstance(val, unicode): val = str(val)
|
|
else: val = val.encode('utf-8')
|
|
return urllib.quote(val)
|
|
|
|
def httpdate(date_obj):
|
|
"""
|
|
Formats a datetime object for use in HTTP headers.
|
|
|
|
>>> import datetime
|
|
>>> httpdate(datetime.datetime(1970, 1, 1, 1, 1, 1))
|
|
'Thu, 01 Jan 1970 01:01:01 GMT'
|
|
"""
|
|
return date_obj.strftime("%a, %d %b %Y %H:%M:%S GMT")
|
|
|
|
def parsehttpdate(string_):
|
|
"""
|
|
Parses an HTTP date into a datetime object.
|
|
|
|
>>> parsehttpdate('Thu, 01 Jan 1970 01:01:01 GMT')
|
|
datetime.datetime(1970, 1, 1, 1, 1, 1)
|
|
"""
|
|
try:
|
|
t = time.strptime(string_, "%a, %d %b %Y %H:%M:%S %Z")
|
|
except ValueError:
|
|
return None
|
|
return datetime.datetime(*t[:6])
|
|
|
|
def htmlquote(text):
|
|
r"""
|
|
Encodes `text` for raw use in HTML.
|
|
|
|
>>> htmlquote(u"<'&\">")
|
|
u'<'&">'
|
|
"""
|
|
text = text.replace(u"&", u"&") # Must be done first!
|
|
text = text.replace(u"<", u"<")
|
|
text = text.replace(u">", u">")
|
|
text = text.replace(u"'", u"'")
|
|
text = text.replace(u'"', u""")
|
|
return text
|
|
|
|
def htmlunquote(text):
|
|
r"""
|
|
Decodes `text` that's HTML quoted.
|
|
|
|
>>> htmlunquote(u'<'&">')
|
|
u'<\'&">'
|
|
"""
|
|
text = text.replace(u""", u'"')
|
|
text = text.replace(u"'", u"'")
|
|
text = text.replace(u">", u">")
|
|
text = text.replace(u"<", u"<")
|
|
text = text.replace(u"&", u"&") # Must be done last!
|
|
return text
|
|
|
|
def websafe(val):
|
|
r"""Converts `val` so that it is safe for use in Unicode HTML.
|
|
|
|
>>> websafe("<'&\">")
|
|
u'<'&">'
|
|
>>> websafe(None)
|
|
u''
|
|
>>> websafe(u'\u203d')
|
|
u'\u203d'
|
|
>>> websafe('\xe2\x80\xbd')
|
|
u'\u203d'
|
|
"""
|
|
if val is None:
|
|
return u''
|
|
elif isinstance(val, str):
|
|
val = val.decode('utf-8')
|
|
elif not isinstance(val, unicode):
|
|
val = unicode(val)
|
|
|
|
return htmlquote(val)
|
|
|
|
if __name__ == "__main__":
|
|
import doctest
|
|
doctest.testmod()
|