0

This is my second python project (I'm not experienced) and I seem to be struggling with a problem regarding encoding. I believe the problem to be existing within an array. I have tried pre-encoding the inputs as well as the '297aae72' that I took using a similar resolution that I found here .encode('utf-8') but I experience the same error.

I believe this is a hashing problem due to an encoding conflict within the array that is being constructed.

This file is speed test.py, where I believe the error to be found.

import hashlib
from hashlib import md5
import urllib.request, urllib.error, urllib.parse
import sys
from urllib.parse import parse_qs
import functions


ping = 16
accuracy = 8
server = functions.setup()


def speed_test(up, down):
    get_data = [
        'download=%s' % down,
        'ping=%s' % ping,
        'upload=%s' % up,
        'promo=',
        'startmode=%s' % 'pingselect',
        'recommendedserverid=%s' % server,
        'accuracy=%s' % 8,
        'serverid=%s' % server,
        'hash=%s' % md5('%s-%s-%s-%s' %
                        (ping, up, down, '297aae72') 
                        ).hexdigest()]
    request = urllib.request.Request('http://www.speedtest.net/api/api.php',
                              data='&'.join(get_data))
    request.add_header('Referer', 'http://c.speedtest.net/flash/speedtest.swf')
    connection = urllib.request.urlopen(request)
    response = connection.read()
    response_code = connection.code
    connection.close()

    if int(response_code) != 200:
        print('There was an issue submitting data')
        sys.exit(1)

    qs_args = parse_qs(response)
    result_id = qs_args.get('resultid')
    if not result_id or len(result_id) != 1:
        print('No speedtest image found?')
        sys.exit(1)

    print(('Speedtest Results: http://www.speedtest.net/result/%s.png' % result_id[0]))


down_input = input("Please enter your download speed (EX: 375.520): ")
down_input = down_input.replace(".", "")

up_input = input("Please enter your upload speed (EX: 375.520): ")
up_input = up_input.replace(".", "")

speed_test(up_input, down_input)

This file is funcitons.py

import math
import urllib.request, urllib.error, urllib.parse
import os
import time
from xml.dom import minidom as DOM


def calculate_distance(origin, destination):
    lat1, lon1 = origin
    lat2, lon2 = destination
    radius = 6371  # km

    latitude = math.radians(lat2 - lat1)
    longitude = math.radians(lon2 - lon1)
    a = (math.sin(latitude / 2) * math.sin(latitude / 2) + math.cos(math.radians(lat1)) * math.cos(math.radians(lat2)) * math.sin(longitude / 2)
         * math.sin(longitude / 2))
    c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
    destination = radius * c

    return destination


def get_closest_servers(client, complete=False):
    connection = urllib.request.urlopen('http://speedtest.net/speedtest-servers.php')
    server_xml = connection.read()
    if int(connection.code) != 200:
        return None
    connection.close()
    root = DOM.parseString(server_xml)
    servers = {}
    for server in root.getElementsByTagName('server'):
        attrib = dict(list(server.attributes.items()))
        d = calculate_distance([float(client['lat']), float(client['lon'])],
                               [float(attrib.get('lat')), float(attrib.get('lon'))])
        attrib['d'] = d
        if d not in servers:
            servers[d] = [attrib]
        else:
            servers[d].append(attrib)

    closest = []
    for d in sorted(servers.keys()):
        for s in servers[d]:
            closest.append(s)
            if len(closest) == 5 and not complete:
                break
        else:
            continue
        break

    del servers
    del root
    return closest


def get_best_server(servers):
    results = {}
    for server in servers:
        cum = 0
        url = os.path.dirname(server['url'])
        for i in range(0, 3):
            uh = urllib.request.urlopen('%s/latency.txt' % url)
            start = time.time()
            text = uh.read().strip()
            total = time.time() - start
            if int(uh.code) == 200 and text == 'test=test':
                cum += total
            else:
                cum += 3600
            uh.close()
        avg = round((cum / 3) * 1000000, 3)
        results[avg] = server

    fastest = sorted(results.keys())[0]
    best = results[fastest]
    best['latency'] = fastest

    return best


def get_config():
    uh = urllib.request.urlopen('http://www.speedtest.net/speedtest-config.php')
    config_xml = uh.read()
    if int(uh.code) != 200:
        return None
    uh.close()
    root = DOM.parseString(config_xml)
    config = {
        'client': extract_tag_name(root, 'client'),
        'times': extract_tag_name(root, 'times'),
        'download': extract_tag_name(root, 'download'),
        'upload': extract_tag_name(root, 'upload')}

    del root
    return config


def extract_tag_name(dom, tag_name):
    elem = dom.getElementsByTagName(tag_name)[0]
    return dict(list(elem.attributes.items()))


def setup():
    print('Configuring server, one moment.')
    configs = get_config()
    closest_server = get_closest_servers(configs['client'])
    best = get_best_server(closest_server)
    return best['id']

This is the error I receive when the application is executed.

Traceback (most recent call last):
  File "speedtest.py", line 54, in <module>
    speed_test(up_input, down_input)
  File "speedtest.py", line 25, in speed_test
    (ping, up, down, '297aae72')
TypeError: Unicode-objects must be encoded before hashing

Am I missing something here? After encoding the variables there is no change to the error in my instance.

Thanks for any help that can be provided.

1 Answer 1

3

This doesn't have anything to do with "arrays"; you are being confused by the fact that you're trying to do everything inline when you define get_data. Actually, the problem is your call to md5(); as the error says, you can't pass a unicode string to that, you need to pass bytes. So, just encode the string:

hash = md5(('%s-%s-%s-%s' % (ping, up, down, '297aae72')).encode('utf-8')).hexdigest()
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.