Better handling of HTTP exceptions, and loop through server list URLs. See #86

This commit is contained in:
Matt Martz 2015-01-16 16:04:07 -06:00
parent b0e1e58a0b
commit 3ee45cace8
1 changed files with 79 additions and 38 deletions

View File

@ -139,6 +139,13 @@ else:
del builtins del builtins
class SpeedtestCliServerListError(Exception):
"""Internal Exception class used to indicate to move on to the next
URL for retrieving speedtest.net server details
"""
def bound_socket(*args, **kwargs): def bound_socket(*args, **kwargs):
"""Bind socket to a specified source IP address""" """Bind socket to a specified source IP address"""
@ -177,6 +184,19 @@ def build_request(url, data=None, headers={}):
return Request(url, data=data, headers=headers) return Request(url, data=data, headers=headers)
def catch_request(request):
"""Helper function to catch common exceptions encountered when
establishing a connection with a HTTP/HTTPS request
"""
try:
uh = urlopen(request)
return uh
except (HTTPError, URLError, socket.error):
return False
class FileGetter(threading.Thread): class FileGetter(threading.Thread):
"""Thread class for retrieving a URL""" """Thread class for retrieving a URL"""
@ -320,7 +340,10 @@ def getConfig():
""" """
request = build_request('http://www.speedtest.net/speedtest-config.php') request = build_request('http://www.speedtest.net/speedtest-config.php')
uh = urlopen(request) uh = catch_request(request)
if uh is False:
print_('Could not retrieve speedtest.net configuration')
sys.exit(1)
configxml = [] configxml = []
while 1: while 1:
configxml.append(uh.read(10240)) configxml.append(uh.read(10240))
@ -337,7 +360,7 @@ def getConfig():
'times': root.find('times').attrib, 'times': root.find('times').attrib,
'download': root.find('download').attrib, 'download': root.find('download').attrib,
'upload': root.find('upload').attrib} 'upload': root.find('upload').attrib}
except AttributeError: except AttributeError: # Python3 branch
root = DOM.parseString(''.join(configxml)) root = DOM.parseString(''.join(configxml))
config = { config = {
'client': getAttributesByTagName(root, 'client'), 'client': getAttributesByTagName(root, 'client'),
@ -357,35 +380,44 @@ def closestServers(client, all=False):
distance distance
""" """
url = 'http://www.speedtest.net/speedtest-servers-static.php' urls = [
'http://c.speedtest.net/speedtest-servers-static.php',
'http://www.speedtest.net/speedtest-servers-static.php',
]
servers = {}
for url in urls:
try:
request = build_request(url) request = build_request(url)
uh = urlopen(request) uh = catch_request(request)
if uh is False:
raise SpeedtestCliServerListError
serversxml = [] serversxml = []
while 1: while 1:
serversxml.append(uh.read(10240)) serversxml.append(uh.read(10240))
if len(serversxml[-1]) == 0: if len(serversxml[-1]) == 0:
break break
if int(uh.code) != 200: if int(uh.code) != 200:
return None uh.close()
raise SpeedtestCliServerListError
uh.close() uh.close()
try: try:
try: try:
root = ET.fromstring(''.encode().join(serversxml)) root = ET.fromstring(''.encode().join(serversxml))
elements = root.getiterator('server') elements = root.getiterator('server')
except AttributeError: except AttributeError: # Python3 branch
root = DOM.parseString(''.join(serversxml)) root = DOM.parseString(''.join(serversxml))
elements = root.getElementsByTagName('server') elements = root.getElementsByTagName('server')
except SyntaxError: except SyntaxError:
print_('Failed to parse list of speedtest.net servers') raise SpeedtestCliServerListError
sys.exit(1)
servers = {}
for server in elements: for server in elements:
try: try:
attrib = server.attrib attrib = server.attrib
except AttributeError: except AttributeError:
attrib = dict(list(server.attributes.items())) attrib = dict(list(server.attributes.items()))
d = distance([float(client['lat']), float(client['lon'])], d = distance([float(client['lat']),
[float(attrib.get('lat')), float(attrib.get('lon'))]) float(client['lon'])],
[float(attrib.get('lat')),
float(attrib.get('lon'))])
attrib['d'] = d attrib['d'] = d
if d not in servers: if d not in servers:
servers[d] = [attrib] servers[d] = [attrib]
@ -394,6 +426,12 @@ def closestServers(client, all=False):
del root del root
del serversxml del serversxml
del elements del elements
except SpeedtestCliServerListError:
continue
if not servers:
print_('Failed to retrieve list of speedtest.net servers')
sys.exit(1)
closest = [] closest = []
for d in sorted(servers.keys()): for d in sorted(servers.keys()):
@ -688,7 +726,10 @@ def speedtest():
request = build_request('http://www.speedtest.net/api/api.php', request = build_request('http://www.speedtest.net/api/api.php',
data='&'.join(apiData).encode(), data='&'.join(apiData).encode(),
headers=headers) headers=headers)
f = urlopen(request) f = catch_request(request)
if f is False:
print_('Could not submit results to speedtest.net')
sys.exit(1)
response = f.read() response = f.read()
code = f.code code = f.code
f.close() f.close()