Merge ad57c7cf2e into 795bc51da4
This commit is contained in:
commit
ba142a723c
@ -89,6 +89,7 @@ Usage
|
|||||||
--server SERVER Specify a server ID to test against
|
--server SERVER Specify a server ID to test against
|
||||||
--mini MINI URL of the Speedtest Mini server
|
--mini MINI URL of the Speedtest Mini server
|
||||||
--source SOURCE Source IP address to bind to
|
--source SOURCE Source IP address to bind to
|
||||||
|
--timeout TIMEOUT HTTP timeout in seconds. Default 10
|
||||||
--version Show the version number and exit
|
--version Show the version number and exit
|
||||||
|
|
||||||
Inconsistency
|
Inconsistency
|
||||||
|
|||||||
190
speedtest_cli.py
190
speedtest_cli.py
@ -18,6 +18,7 @@
|
|||||||
__version__ = '0.3.1'
|
__version__ = '0.3.1'
|
||||||
|
|
||||||
# Some global variables we use
|
# Some global variables we use
|
||||||
|
user_agent = 'speedtest-cli/%s' % __version__
|
||||||
source = None
|
source = None
|
||||||
shutdown_event = None
|
shutdown_event = None
|
||||||
|
|
||||||
@ -165,6 +166,17 @@ def distance(origin, destination):
|
|||||||
return d
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def build_request(url, data=None, headers={}):
|
||||||
|
"""Build a urllib2 request object
|
||||||
|
|
||||||
|
This function automatically adds a User-Agent header to all requests
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
headers['User-Agent'] = user_agent
|
||||||
|
return Request(url, data=data, headers=headers)
|
||||||
|
|
||||||
|
|
||||||
class FileGetter(threading.Thread):
|
class FileGetter(threading.Thread):
|
||||||
"""Thread class for retrieving a URL"""
|
"""Thread class for retrieving a URL"""
|
||||||
|
|
||||||
@ -178,7 +190,8 @@ class FileGetter(threading.Thread):
|
|||||||
self.result = [0]
|
self.result = [0]
|
||||||
try:
|
try:
|
||||||
if (timeit.default_timer() - self.starttime) <= 10:
|
if (timeit.default_timer() - self.starttime) <= 10:
|
||||||
f = urlopen(self.url)
|
request = build_request(self.url)
|
||||||
|
f = urlopen(request)
|
||||||
while 1 and not shutdown_event.isSet():
|
while 1 and not shutdown_event.isSet():
|
||||||
self.result.append(len(f.read(10240)))
|
self.result.append(len(f.read(10240)))
|
||||||
if self.result[-1] == 0:
|
if self.result[-1] == 0:
|
||||||
@ -242,7 +255,8 @@ class FilePutter(threading.Thread):
|
|||||||
try:
|
try:
|
||||||
if ((timeit.default_timer() - self.starttime) <= 10 and
|
if ((timeit.default_timer() - self.starttime) <= 10 and
|
||||||
not shutdown_event.isSet()):
|
not shutdown_event.isSet()):
|
||||||
f = urlopen(self.url, self.data)
|
request = build_request(self.url, data=self.data)
|
||||||
|
f = urlopen(request)
|
||||||
f.read(11)
|
f.read(11)
|
||||||
f.close()
|
f.close()
|
||||||
self.result = len(self.data)
|
self.result = len(self.data)
|
||||||
@ -305,7 +319,8 @@ def getConfig():
|
|||||||
we are interested in
|
we are interested in
|
||||||
"""
|
"""
|
||||||
|
|
||||||
uh = urlopen('http://www.speedtest.net/speedtest-config.php')
|
request = build_request('http://www.speedtest.net/speedtest-config.php')
|
||||||
|
uh = urlopen(request)
|
||||||
configxml = []
|
configxml = []
|
||||||
while 1:
|
while 1:
|
||||||
configxml.append(uh.read(10240))
|
configxml.append(uh.read(10240))
|
||||||
@ -337,12 +352,15 @@ def getConfig():
|
|||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
def closestServers(client, all=False):
|
def closestServers(client, numServers=5):
|
||||||
"""Determine the 5 closest speedtest.net servers based on geographic
|
"""Determine the closest speedtest.net servers based on geographic
|
||||||
distance
|
distance. The default number of servers to return is 5. If the
|
||||||
|
number of servers is specified as 0 then all servers are returned.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
uh = urlopen('http://www.speedtest.net/speedtest-servers-static.php')
|
url = 'http://www.speedtest.net/speedtest-servers-static.php'
|
||||||
|
request = build_request(url)
|
||||||
|
uh = urlopen(request)
|
||||||
serversxml = []
|
serversxml = []
|
||||||
while 1:
|
while 1:
|
||||||
serversxml.append(uh.read(10240))
|
serversxml.append(uh.read(10240))
|
||||||
@ -382,7 +400,7 @@ def closestServers(client, all=False):
|
|||||||
for d in sorted(servers.keys()):
|
for d in sorted(servers.keys()):
|
||||||
for s in servers[d]:
|
for s in servers[d]:
|
||||||
closest.append(s)
|
closest.append(s)
|
||||||
if len(closest) == 5 and not all:
|
if len(closest) == numServers and numServers != 0:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
@ -408,8 +426,9 @@ def getBestServer(servers):
|
|||||||
h = HTTPSConnection(urlparts[1])
|
h = HTTPSConnection(urlparts[1])
|
||||||
else:
|
else:
|
||||||
h = HTTPConnection(urlparts[1])
|
h = HTTPConnection(urlparts[1])
|
||||||
|
headers = {'User-Agent': user_agent}
|
||||||
start = timeit.default_timer()
|
start = timeit.default_timer()
|
||||||
h.request("GET", urlparts[2])
|
h.request("GET", urlparts[2], headers=headers)
|
||||||
r = h.getresponse()
|
r = h.getresponse()
|
||||||
total = (timeit.default_timer() - start)
|
total = (timeit.default_timer() - start)
|
||||||
except (HTTPError, URLError, socket.error):
|
except (HTTPError, URLError, socket.error):
|
||||||
@ -469,7 +488,7 @@ def speedtest():
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
parser.add_argument('--bytes', dest='units', action='store_const',
|
parser.add_argument('--bytes', dest='units', action='store_const',
|
||||||
const=('bytes', 1), default=('bits', 8),
|
const=('byte', 1), default=('bit', 8),
|
||||||
help='Display values in bytes instead of bits. Does '
|
help='Display values in bytes instead of bits. Does '
|
||||||
'not affect the image generated by --share')
|
'not affect the image generated by --share')
|
||||||
parser.add_argument('--share', action='store_true',
|
parser.add_argument('--share', action='store_true',
|
||||||
@ -478,12 +497,29 @@ def speedtest():
|
|||||||
parser.add_argument('--simple', action='store_true',
|
parser.add_argument('--simple', action='store_true',
|
||||||
help='Suppress verbose output, only show basic '
|
help='Suppress verbose output, only show basic '
|
||||||
'information')
|
'information')
|
||||||
|
parser.add_argument('--showconfig', action='store_true',
|
||||||
|
help='Display the client configuration')
|
||||||
|
parser.add_argument('--saveconfig', help='Specify a file to save the '
|
||||||
|
'speedtest.net configuration')
|
||||||
|
parser.add_argument('--loadconfig', help='Specify a file to load the '
|
||||||
|
'speedtest.net configuration')
|
||||||
parser.add_argument('--list', action='store_true',
|
parser.add_argument('--list', action='store_true',
|
||||||
help='Display a list of speedtest.net servers '
|
help='Display a list of speedtest.net servers '
|
||||||
'sorted by distance')
|
'sorted by distance')
|
||||||
|
parser.add_argument('--listservers', action='store_true',
|
||||||
|
help='Display a list of speedtest.net servers '
|
||||||
|
'sorted by distance. Synonym for --list')
|
||||||
|
parser.add_argument('--saveservers', help='Specify a file to save the '
|
||||||
|
'speedtest.net servers list')
|
||||||
|
parser.add_argument('--loadservers', help='Specify a file of speedtest.net'
|
||||||
|
' servers to use instead of downloading the list')
|
||||||
parser.add_argument('--server', help='Specify a server ID to test against')
|
parser.add_argument('--server', help='Specify a server ID to test against')
|
||||||
|
parser.add_argument('--saveresults', help='Specify a file to save the '
|
||||||
|
'speedtest.net results')
|
||||||
parser.add_argument('--mini', help='URL of the Speedtest Mini server')
|
parser.add_argument('--mini', help='URL of the Speedtest Mini server')
|
||||||
parser.add_argument('--source', help='Source IP address to bind to')
|
parser.add_argument('--source', help='Source IP address to bind to')
|
||||||
|
parser.add_argument('--timeout', default=10, type=int,
|
||||||
|
help='HTTP timeout in seconds. Default 10')
|
||||||
parser.add_argument('--version', action='store_true',
|
parser.add_argument('--version', action='store_true',
|
||||||
help='Show the version number and exit')
|
help='Show the version number and exit')
|
||||||
|
|
||||||
@ -498,24 +534,62 @@ def speedtest():
|
|||||||
if args.version:
|
if args.version:
|
||||||
version()
|
version()
|
||||||
|
|
||||||
|
socket.setdefaulttimeout(args.timeout)
|
||||||
|
|
||||||
# If specified bind to a specific IP address
|
# If specified bind to a specific IP address
|
||||||
if args.source:
|
if args.source:
|
||||||
source = args.source
|
source = args.source
|
||||||
socket.socket = bound_socket
|
socket.socket = bound_socket
|
||||||
|
|
||||||
if not args.simple:
|
# Retrieve speedtest configuration
|
||||||
print_('Retrieving speedtest.net configuration...')
|
if args.loadconfig is None:
|
||||||
try:
|
if not args.simple:
|
||||||
config = getConfig()
|
print_('Retrieving speedtest.net configuration...')
|
||||||
except URLError:
|
try:
|
||||||
print_('Cannot retrieve speedtest configuration')
|
config = getConfig()
|
||||||
sys.exit(1)
|
except URLError:
|
||||||
|
print_('Cannot retrieve speedtest configuration')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
if not args.simple:
|
if args.saveconfig is not None:
|
||||||
print_('Retrieving speedtest.net server list...')
|
if not args.simple:
|
||||||
if args.list or args.server:
|
print_('Saving speedtest.net configuration to %s'
|
||||||
servers = closestServers(config['client'], True)
|
% args.saveconfig)
|
||||||
if args.list:
|
try:
|
||||||
|
configfile = open(args.saveconfig, 'w')
|
||||||
|
except:
|
||||||
|
print_('Unable to open configuration file %s'
|
||||||
|
% args.saveconfig)
|
||||||
|
sys.exit(1)
|
||||||
|
configfile.write(str(config))
|
||||||
|
configfile.close()
|
||||||
|
else:
|
||||||
|
if not args.simple:
|
||||||
|
print_('Loading speedtest.net configuration from %s'
|
||||||
|
% args.loadconfig)
|
||||||
|
try:
|
||||||
|
confFile = open(args.loadconfig, 'r')
|
||||||
|
except:
|
||||||
|
print_('Unable to open configuration file %s' % args.loadconfig)
|
||||||
|
sys.exit(1)
|
||||||
|
config = eval(confFile.read())
|
||||||
|
confFile.close()
|
||||||
|
|
||||||
|
if args.showconfig:
|
||||||
|
print_('Speedtest.net configuration:')
|
||||||
|
for configitem in config:
|
||||||
|
print_(' %s: %s' % (configitem, config[configitem]))
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
# Retrieve speedtest server list
|
||||||
|
if (args.list or args.listservers or args.saveservers is not None
|
||||||
|
or (args.server and args.loadservers is None)):
|
||||||
|
if not args.simple:
|
||||||
|
print_('Retrieving speedtest.net server list...')
|
||||||
|
servers = closestServers(config['client'], 0) # return all servers
|
||||||
|
|
||||||
|
# Display the server list and exit
|
||||||
|
if args.list or args.listservers:
|
||||||
serverList = []
|
serverList = []
|
||||||
for server in servers:
|
for server in servers:
|
||||||
line = ('%(id)4s) %(sponsor)s (%(name)s, %(country)s) '
|
line = ('%(id)4s) %(sponsor)s (%(name)s, %(country)s) '
|
||||||
@ -532,8 +606,38 @@ def speedtest():
|
|||||||
except IOError:
|
except IOError:
|
||||||
pass
|
pass
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
elif args.saveservers is not None:
|
||||||
|
if not args.simple:
|
||||||
|
print_('Saving speedtest.net server list to %s...'
|
||||||
|
% args.saveservers)
|
||||||
|
try:
|
||||||
|
svrFile = open(args.saveservers, 'w')
|
||||||
|
except:
|
||||||
|
print_('Unable to open server file')
|
||||||
|
sys.exit(1)
|
||||||
|
svrFile.write(str(servers))
|
||||||
|
svrFile.close()
|
||||||
|
print_('Done')
|
||||||
|
sys.exit(0)
|
||||||
|
elif args.loadservers is not None:
|
||||||
|
if not args.simple:
|
||||||
|
print_('Loading speedtest.net server list from %s'
|
||||||
|
% args.loadservers)
|
||||||
|
try:
|
||||||
|
svrFile = open(args.loadservers, 'r')
|
||||||
|
except:
|
||||||
|
print_('Unable to open server file')
|
||||||
|
sys.exit(1)
|
||||||
|
allServers = eval(svrFile.read())
|
||||||
|
svrFile.close()
|
||||||
|
if len(allServers) > 10:
|
||||||
|
servers = allServers[:5]
|
||||||
|
else:
|
||||||
|
servers = allServers
|
||||||
else:
|
else:
|
||||||
servers = closestServers(config['client'])
|
if not args.simple:
|
||||||
|
print_('Retrieving speedtest.net server list...')
|
||||||
|
servers = closestServers(config['client']) # return closest 5 servers
|
||||||
|
|
||||||
if not args.simple:
|
if not args.simple:
|
||||||
print_('Testing from %(isp)s (%(ip)s)...' % config['client'])
|
print_('Testing from %(isp)s (%(ip)s)...' % config['client'])
|
||||||
@ -553,7 +657,8 @@ def speedtest():
|
|||||||
url = args.mini
|
url = args.mini
|
||||||
urlparts = urlparse(url)
|
urlparts = urlparse(url)
|
||||||
try:
|
try:
|
||||||
f = urlopen(args.mini)
|
request = build_request(args.mini)
|
||||||
|
f = urlopen(request)
|
||||||
except:
|
except:
|
||||||
print_('Invalid Speedtest Mini URL')
|
print_('Invalid Speedtest Mini URL')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@ -564,7 +669,9 @@ def speedtest():
|
|||||||
if not extension:
|
if not extension:
|
||||||
for ext in ['php', 'asp', 'aspx', 'jsp']:
|
for ext in ['php', 'asp', 'aspx', 'jsp']:
|
||||||
try:
|
try:
|
||||||
f = urlopen('%s/speedtest/upload.%s' % (args.mini, ext))
|
request = build_request('%s/speedtest/upload.%s' %
|
||||||
|
(args.mini, ext))
|
||||||
|
f = urlopen(request)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
@ -617,10 +724,11 @@ def speedtest():
|
|||||||
if not args.simple:
|
if not args.simple:
|
||||||
print_('Testing download speed', end='')
|
print_('Testing download speed', end='')
|
||||||
dlspeed = downloadSpeed(urls, args.simple)
|
dlspeed = downloadSpeed(urls, args.simple)
|
||||||
|
dlspdstr = '%0.2f M%s/s' % ((dlspeed / 1000 / 1000)
|
||||||
|
* args.units[1], args.units[0])
|
||||||
if not args.simple:
|
if not args.simple:
|
||||||
print_()
|
print_()
|
||||||
print_('Download: %0.2f M%s/s' %
|
print_('Download: %s' % dlspdstr)
|
||||||
((dlspeed / 1000 / 1000) * args.units[1], args.units[0]))
|
|
||||||
|
|
||||||
sizesizes = [int(.25 * 1000 * 1000), int(.5 * 1000 * 1000)]
|
sizesizes = [int(.25 * 1000 * 1000), int(.5 * 1000 * 1000)]
|
||||||
sizes = []
|
sizes = []
|
||||||
@ -630,10 +738,25 @@ def speedtest():
|
|||||||
if not args.simple:
|
if not args.simple:
|
||||||
print_('Testing upload speed', end='')
|
print_('Testing upload speed', end='')
|
||||||
ulspeed = uploadSpeed(best['url'], sizes, args.simple)
|
ulspeed = uploadSpeed(best['url'], sizes, args.simple)
|
||||||
|
ulspdstr = '%0.2f M%s/s' % ((ulspeed / 1000 / 1000)
|
||||||
|
* args.units[1], args.units[0])
|
||||||
if not args.simple:
|
if not args.simple:
|
||||||
print_()
|
print_()
|
||||||
print_('Upload: %0.2f M%s/s' %
|
print_('Upload: %s' % ulspdstr)
|
||||||
((ulspeed / 1000 / 1000) * args.units[1], args.units[0]))
|
|
||||||
|
# Save test results
|
||||||
|
if args.saveresults is not None:
|
||||||
|
if not args.simple:
|
||||||
|
print_('Saving test results to %s' % args.saveresults)
|
||||||
|
try:
|
||||||
|
resfile = open(args.saveresults, 'a')
|
||||||
|
except:
|
||||||
|
print_('Unable to open results file')
|
||||||
|
sys.exit(1)
|
||||||
|
resfile.write(('%(id)s,%(sponsor)s,%(name)s,%(country)s,'
|
||||||
|
'%(latency)s ms,' % best) + ('%s,%s\n'
|
||||||
|
% (dlspdstr, ulspdstr)))
|
||||||
|
resfile.close()
|
||||||
|
|
||||||
if args.share and args.mini:
|
if args.share and args.mini:
|
||||||
print_('Cannot generate a speedtest.net share results image while '
|
print_('Cannot generate a speedtest.net share results image while '
|
||||||
@ -659,10 +782,11 @@ def speedtest():
|
|||||||
(ping, ulspeedk, dlspeedk, '297aae72'))
|
(ping, ulspeedk, dlspeedk, '297aae72'))
|
||||||
.encode()).hexdigest()]
|
.encode()).hexdigest()]
|
||||||
|
|
||||||
req = Request('http://www.speedtest.net/api/api.php',
|
headers = {'Referer': 'http://c.speedtest.net/flash/speedtest.swf'}
|
||||||
data='&'.join(apiData).encode())
|
request = build_request('http://www.speedtest.net/api/api.php',
|
||||||
req.add_header('Referer', 'http://c.speedtest.net/flash/speedtest.swf')
|
data='&'.join(apiData).encode(),
|
||||||
f = urlopen(req)
|
headers=headers)
|
||||||
|
f = urlopen(request)
|
||||||
response = f.read()
|
response = f.read()
|
||||||
code = f.code
|
code = f.code
|
||||||
f.close()
|
f.close()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user