From 077ecf696ce2f2f11bb928e00256dd61d1a09f97 Mon Sep 17 00:00:00 2001 From: Ferry Boender Date: Mon, 7 Sep 2020 17:14:18 +0200 Subject: [PATCH] Port to python 3 --- src/scriptform.py | 18 ++++++------------ src/webapp.py | 27 ++++++++++++--------------- src/webserver.py | 19 +++++++++++-------- 3 files changed, 29 insertions(+), 35 deletions(-) diff --git a/src/scriptform.py b/src/scriptform.py index 6c637ee..a60c305 100755 --- a/src/scriptform.py +++ b/src/scriptform.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ @@ -10,7 +10,7 @@ import optparse import os import json import logging -import thread +import threading import hashlib import socket @@ -51,7 +51,8 @@ class ScriptForm(object): if self.cache and self.form_config_singleton is not None: return self.form_config_singleton - file_contents = file(self.config_file, 'r').read() + with open(self.config_file, "r") as fh: + file_contents = fh.read() try: config = json.loads(file_contents) except ValueError as err: @@ -138,7 +139,7 @@ class ScriptForm(object): # We need to spawn a new thread in which the server is shut down, # because doing it from the main thread blocks, since the server is # waiting for connections.. - thread.start_new_thread(t_shutdown, (self, )) + threading.Thread(target=t_shutdown, args=(1,)) def main(): # pragma: no cover @@ -181,7 +182,7 @@ def main(): # pragma: no cover if plain_pw != getpass.getpass('Repeat password: '): sys.stderr.write("Passwords do not match.\n") sys.exit(1) - sys.stdout.write(hashlib.sha256(plain_pw).hexdigest() + '\n') + sys.stdout.write(hashlib.sha256(plain_pw.encode('utf8')).hexdigest() + '\n') sys.exit(0) else: if not options.action_stop and len(args) < 1: @@ -210,13 +211,6 @@ def main(): # pragma: no cover elif options.action_stop: daemon.stop() sys.exit(0) - except socket.error as err: - log.exception(err) - sys.stderr.write("Cannot bind to port {0}: {1}\n".format( - options.port, - str(err) - )) - sys.exit(2) except Exception as err: log.exception(err) raise diff --git a/src/webapp.py b/src/webapp.py index edf7c55..f915eec 100644 --- a/src/webapp.py +++ b/src/webapp.py @@ -209,14 +209,12 @@ class ScriptFormWebApp(RequestHandler): # If a 'users' element was present in the form configuration file, the # user must be authenticated. if form_config.users: - auth_header = self.headers.getheader("Authorization") + auth_header = self.headers.get("Authorization") if auth_header is not None: # Validate the username and password - auth_unpw = auth_header.split(' ', 1)[1] - username, password = base64.decodestring(auth_unpw).split(":", - 1) - pw_hash = hashlib.sha256(password).hexdigest() - + auth_unpw = auth_header.split(' ', 1)[1].encode('utf-8') + username, password = base64.b64decode(auth_unpw).decode('utf-8').split(":", 1) + pw_hash = hashlib.sha256(password.encode('utf-8')).hexdigest() if username in form_config.users and \ pw_hash == form_config.users[username]: # Valid username and password. Return the username. @@ -414,13 +412,12 @@ class ScriptFormWebApp(RequestHandler): if field.filename == '': continue tmp_fname = tempfile.mktemp(prefix="scriptform_") - tmp_file = file(tmp_fname, 'w') - while True: - buf = field.file.read(1024 * 16) - if not buf: - break - tmp_file.write(buf) - tmp_file.close() + with open(tmp_fname, "wb") as tmp_file: + while True: + buf = field.file.read(1024 * 16) + if not buf: + break + tmp_file.write(buf) field.file.close() tmp_files.append(tmp_fname) # For later cleanup @@ -509,7 +506,7 @@ class ScriptFormWebApp(RequestHandler): if not os.path.exists(path): raise HTTPError(404, "Not found") - static_file = file(path, 'r') self.send_response(200) self.end_headers() - self.wfile.write(static_file.read()) + with open(path, "r") as static_file: + self.wfile.write(static_file.read()) diff --git a/src/webserver.py b/src/webserver.py index 7880b3b..276efb1 100644 --- a/src/webserver.py +++ b/src/webserver.py @@ -2,9 +2,9 @@ Basic web server / framework. """ -from SocketServer import ThreadingMixIn -import BaseHTTPServer -import urlparse +from socketserver import ThreadingMixIn +from http.server import HTTPServer, BaseHTTPRequestHandler +import urllib.parse import cgi @@ -14,6 +14,9 @@ class HTTPError(Exception): etc. They are caught by the 'framework' and sent to the client's browser. """ def __init__(self, status_code, msg, headers=None): + assert isinstance(status_code, int) + assert isinstance(msg, str) + if headers is None: headers = {} self.status_code = status_code @@ -22,14 +25,14 @@ class HTTPError(Exception): Exception.__init__(self, status_code, msg, headers) -class ThreadedHTTPServer(ThreadingMixIn, BaseHTTPServer.HTTPServer): +class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): """ Base class for multithreaded HTTP servers. """ pass -class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): +class RequestHandler(BaseHTTPRequestHandler): """ Basic web server request handler. Handles GET and POST requests. You should inherit from this class and implement h_ methods for handling requests. @@ -61,9 +64,9 @@ class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): """ Parse information from a request. """ - url_comp = urlparse.urlsplit(reqinfo) + url_comp = urllib.parse.urlsplit(reqinfo) path = url_comp.path - query_vars = urlparse.parse_qs(url_comp.query) + query_vars = urllib.parse.parse_qs(url_comp.query) # Only return the first value of each query var. E.g. for # "?foo=1&foo=2" return '1'. var_values = dict([(k, v[0]) for k, v in query_vars.items()]) @@ -104,7 +107,7 @@ class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): self.send_header(header_k, header_v) self.end_headers() self.wfile.write("Error {0}: {1}".format(err.status_code, - err.msg)) + err.msg).encode('utf-8')) self.wfile.flush() return False except Exception as err: