Support gzip encoding if available
This commit is contained in:
parent
4280c448cf
commit
59880107a7
93
speedtest.py
93
speedtest.py
|
@ -29,6 +29,13 @@ import platform
|
||||||
import threading
|
import threading
|
||||||
import xml.parsers.expat
|
import xml.parsers.expat
|
||||||
|
|
||||||
|
try:
|
||||||
|
import gzip
|
||||||
|
GZIP_BASE = gzip.GzipFile
|
||||||
|
except ImportError:
|
||||||
|
gzip = None
|
||||||
|
GZIP_BASE = object
|
||||||
|
|
||||||
__version__ = '1.0.0'
|
__version__ = '1.0.0'
|
||||||
|
|
||||||
|
|
||||||
|
@ -125,11 +132,13 @@ except ImportError:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
|
BytesIO = None
|
||||||
except ImportError:
|
except ImportError:
|
||||||
try:
|
try:
|
||||||
from io import StringIO
|
from io import StringIO, BytesIO
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from StringIO import StringIO
|
from StringIO import StringIO
|
||||||
|
BytesIO = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import builtins
|
import builtins
|
||||||
|
@ -216,15 +225,19 @@ class SpeedtestException(Exception):
|
||||||
"""Base exception for this module"""
|
"""Base exception for this module"""
|
||||||
|
|
||||||
|
|
||||||
|
class SpeedtestHTTPError(SpeedtestException):
|
||||||
|
"""Base HTTP exception for this module"""
|
||||||
|
|
||||||
|
|
||||||
class SpeedtestConfigError(SpeedtestException):
|
class SpeedtestConfigError(SpeedtestException):
|
||||||
"""Configuration provided is invalid"""
|
"""Configuration provided is invalid"""
|
||||||
|
|
||||||
|
|
||||||
class ConfigRetrievalError(SpeedtestException):
|
class ConfigRetrievalError(SpeedtestHTTPError):
|
||||||
"""Could not retrieve config.php"""
|
"""Could not retrieve config.php"""
|
||||||
|
|
||||||
|
|
||||||
class ServersRetrievalError(SpeedtestException):
|
class ServersRetrievalError(SpeedtestHTTPError):
|
||||||
"""Could not retrieve speedtest-servers.php"""
|
"""Could not retrieve speedtest-servers.php"""
|
||||||
|
|
||||||
|
|
||||||
|
@ -266,6 +279,30 @@ class SpeedtestBestServerFailure(SpeedtestException):
|
||||||
"""Unable to determine best server"""
|
"""Unable to determine best server"""
|
||||||
|
|
||||||
|
|
||||||
|
class GzipDecodedResponse(GZIP_BASE):
|
||||||
|
"""A file-like object to decode a response encoded with the gzip
|
||||||
|
method, as described in RFC 1952.
|
||||||
|
|
||||||
|
Largely copied from ``xmlrpclib``/``xmlrpc.client`` and modified
|
||||||
|
to work for py2.4-py3
|
||||||
|
"""
|
||||||
|
def __init__(self, response):
|
||||||
|
# response doesn't support tell() and read(), required by
|
||||||
|
# GzipFile
|
||||||
|
if not gzip:
|
||||||
|
raise SpeedtestHTTPError('HTTP response body is gzip encoded, '
|
||||||
|
'but gzip support is not available')
|
||||||
|
IO = BytesIO or StringIO
|
||||||
|
self.io = IO(response.read())
|
||||||
|
gzip.GzipFile.__init__(self, mode='rb', fileobj=self.io)
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
try:
|
||||||
|
gzip.GzipFile.close(self)
|
||||||
|
finally:
|
||||||
|
self.io.close()
|
||||||
|
|
||||||
|
|
||||||
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"""
|
||||||
|
|
||||||
|
@ -365,6 +402,23 @@ def catch_request(request):
|
||||||
return None, e
|
return None, e
|
||||||
|
|
||||||
|
|
||||||
|
def get_response_stream(response):
|
||||||
|
"""Helper function to return either a Gzip reader if
|
||||||
|
``Content-Encoding`` is ``gzip`` otherwise the response itself
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
getheader = response.headers.getheader
|
||||||
|
except AttributeError:
|
||||||
|
getheader = response.getheader
|
||||||
|
|
||||||
|
if getheader('content-encoding') == 'gzip':
|
||||||
|
return GzipDecodedResponse(response)
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
def get_attributes_by_tag_name(dom, tag_name):
|
def get_attributes_by_tag_name(dom, tag_name):
|
||||||
"""Retrieve an attribute from an XML document and return it in a
|
"""Retrieve an attribute from an XML document and return it in a
|
||||||
consistent format
|
consistent format
|
||||||
|
@ -639,21 +693,28 @@ class Speedtest(object):
|
||||||
we are interested in
|
we are interested in
|
||||||
"""
|
"""
|
||||||
|
|
||||||
request = build_request('://www.speedtest.net/speedtest-config.php')
|
headers = {}
|
||||||
|
if gzip:
|
||||||
|
headers['Accept-Encoding'] = 'gzip'
|
||||||
|
request = build_request('://www.speedtest.net/speedtest-config.php',
|
||||||
|
headers=headers)
|
||||||
uh, e = catch_request(request)
|
uh, e = catch_request(request)
|
||||||
if e:
|
if e:
|
||||||
raise ConfigRetrievalError(e)
|
raise ConfigRetrievalError(e)
|
||||||
configxml = []
|
configxml = []
|
||||||
|
|
||||||
|
stream = get_response_stream(uh)
|
||||||
|
|
||||||
while 1:
|
while 1:
|
||||||
configxml.append(uh.read(10240))
|
configxml.append(stream.read(10240))
|
||||||
if len(configxml[-1]) == 0:
|
if len(configxml[-1]) == 0:
|
||||||
break
|
break
|
||||||
|
stream.close()
|
||||||
|
uh.close()
|
||||||
|
|
||||||
if int(uh.code) != 200:
|
if int(uh.code) != 200:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
uh.close()
|
|
||||||
|
|
||||||
printer(''.encode().join(configxml), debug=True)
|
printer(''.encode().join(configxml), debug=True)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -734,28 +795,36 @@ class Speedtest(object):
|
||||||
'http://c.speedtest.net/speedtest-servers.php',
|
'http://c.speedtest.net/speedtest-servers.php',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
headers = {}
|
||||||
|
if gzip:
|
||||||
|
headers['Accept-Encoding'] = 'gzip'
|
||||||
|
|
||||||
errors = []
|
errors = []
|
||||||
for url in urls:
|
for url in urls:
|
||||||
try:
|
try:
|
||||||
request = build_request('%s?threads=%s' %
|
request = build_request('%s?threads=%s' %
|
||||||
(url,
|
(url,
|
||||||
self.config['threads']['download']))
|
self.config['threads']['download']),
|
||||||
|
headers=headers)
|
||||||
uh, e = catch_request(request)
|
uh, e = catch_request(request)
|
||||||
if e:
|
if e:
|
||||||
errors.append('%s' % e)
|
errors.append('%s' % e)
|
||||||
raise ServersRetrievalError
|
raise ServersRetrievalError
|
||||||
|
|
||||||
|
stream = get_response_stream(uh)
|
||||||
|
|
||||||
serversxml = []
|
serversxml = []
|
||||||
while 1:
|
while 1:
|
||||||
serversxml.append(uh.read(10240))
|
serversxml.append(stream.read(10240))
|
||||||
if len(serversxml[-1]) == 0:
|
if len(serversxml[-1]) == 0:
|
||||||
break
|
break
|
||||||
if int(uh.code) != 200:
|
|
||||||
uh.close()
|
|
||||||
raise ServersRetrievalError
|
|
||||||
|
|
||||||
|
stream.close()
|
||||||
uh.close()
|
uh.close()
|
||||||
|
|
||||||
|
if int(uh.code) != 200:
|
||||||
|
raise ServersRetrievalError
|
||||||
|
|
||||||
printer(''.encode().join(serversxml), debug=True)
|
printer(''.encode().join(serversxml), debug=True)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
Loading…
Reference in New Issue