From 5498e1de87f90ec0ae0ee097d2efe06bfd293f51 Mon Sep 17 00:00:00 2001 From: rnhmjoj Date: Fri, 23 Aug 2019 01:31:58 +0200 Subject: [PATCH] better error reporting * use a template based on the Privoxy one * print a stack of the exceptions * link the documentation and issue tracker --- cert.py | 4 +- data/error.html | 107 ++++++++++++++++++++++++++++++++++++++++++++++++ main.py | 49 ++++++++++++---------- proxy.py | 60 ++++++++++++++++++--------- 4 files changed, 176 insertions(+), 44 deletions(-) create mode 100644 data/error.html diff --git a/cert.py b/cert.py index 6d2688d..78aa00a 100755 --- a/cert.py +++ b/cert.py @@ -56,9 +56,9 @@ def get_cert(name, config): cafile: the CA file to create dummpy cert files certdir: the path where cert files are looked for or created ''' - certfile = os.path.join(config.CERTDIR, name + '.crt') + certfile = os.path.join(config.certdir, name + '.crt') if not os.path.exists(certfile): - dummy_cert(config.CA, certfile, name) + dummy_cert(config.ca, certfile, name) return certfile diff --git a/data/error.html b/data/error.html new file mode 100644 index 0000000..de02eae --- /dev/null +++ b/data/error.html @@ -0,0 +1,107 @@ + + + + + + $server: Error $code + + + +
+
$code
+ +
+

+ This is $server + on $hostname ($address), port $port +

+
+
+ +
+

$message:

+

+ Your request for $url could not be fulfilled + because an error occured. +

+
+ +
+

More information:

+ $explain +

Error generated on $now.

+
+ + + + diff --git a/main.py b/main.py index c73f02d..81786f4 100755 --- a/main.py +++ b/main.py @@ -29,16 +29,19 @@ _name = 'privoxy-tls' class LoadConfig: def __init__(self, configfile): - self.config = configparser.ConfigParser(allow_no_value=True, - inline_comment_prefixes=('#',)) + self.config = configparser.ConfigParser( + allow_no_value=True, delimiters=('=',), + inline_comment_prefixes=('#',)) self.config.read(configfile) - self.PROXADDR = self.config['General'].get('ProxAddr') - self.FRONTPORT = int(self.config['General'].get('FrontPort')) - self.REARPORT = int(self.config['General'].get('RearPort')) - self.GeneralPROXY = self.config['General'].get('DefaultProxy') - self.LOGLEVEL = self.config['General'].get('LogLevel') - self.CA = self.config['General'].get('CACert') - self.CERTDIR = self.config['General'].get('CertDir') + self.proxy_name = self.config['General'].get('ProxAddr') + self.front_name = self.config['General'].get('FrontAddr', 'localhost') + self.rear_name = self.config['General'].get('RearAddr', 'localhost') + self.front_port = int(self.config['General'].get('FrontPort')) + self.rear_port = int(self.config['General'].get('RearPort')) + self.proxy = self.config['General'].get('DefaultProxy') + self.loglevel = self.config['General'].get('LogLevel') + self.ca = self.config['General'].get('CACert') + self.certdir = self.config['General'].get('CertDir') class ConnectionPools: @@ -307,7 +310,7 @@ class FrontRequestHandler(ProxyRequestHandler): logger.warning(f'{self.reqNum:03d} [F] {e} on ' f'"{self.command} {url}"') except (urllib3.exceptions.HTTPError,) as e: - self.sendout_error(url, 502, message="HTTPError", explain=e) + self.sendout_error(url, 502, message="HTTP Error", explain=e) logger.warning(f'{self.reqNum:03d} [F] {e} on ' f'"{self.command} {url}"') finally: @@ -323,7 +326,7 @@ class RearRequestHandler(ProxyRequestHandler): Supposed to be the parent proxy for Privoxy for tagged requests Convert http request to https """ - server_version = f'{_name} front/{__version__}' + server_version = f'{_name} rear/{__version__}' def do_METHOD(self): "Convert http request to https" @@ -409,7 +412,7 @@ class RearRequestHandler(ProxyRequestHandler): logger.warning(f'{self.reqNum:03d} [R]{prefix} ' f'"{self.command} {url}" {e}') except (urllib3.exceptions.HTTPError,) as e: - self.sendout_error(url, 502, message="HTTPError", explain=e) + self.sendout_error(url, 502, message="HTTP Error", explain=e) logger.warning(f'{self.reqNum:03d} [R]{prefix} ' f'"{self.command} {url}" {e}') @@ -423,16 +426,18 @@ class RearRequestHandler(ProxyRequestHandler): def main(): urllib3.disable_warnings() - logger.setLevel(getattr(logging, config.LOGLEVEL, logging.INFO)) + logger.setLevel(getattr(logging, config.loglevel, logging.INFO)) handler = logging.StreamHandler() formatter = logging.Formatter('%(asctime)s %(message)s', datefmt='[%H:%M]') handler.setFormatter(formatter) logger.addHandler(handler) - frontserver = FrontServer(('', config.FRONTPORT), FrontRequestHandler) - rearserver = RearServer(('', config.REARPORT), RearRequestHandler) - frontserver.config = config - for worker in (frontserver.serve_forever, rearserver.serve_forever, + frontserver = FrontServer((config.front_name, config.front_port), + FrontRequestHandler) + rearserver = RearServer((config.rear_name, config.rear_port), + RearRequestHandler) + for worker in (frontserver.serve_forever, + rearserver.serve_forever, pools.reloadConfig): thread = threading.Thread(target=worker) thread.daemon = True @@ -440,10 +445,10 @@ def main(): print('=' * 40) print(f'{_name} {__version__} (urllib3/{urllib3.__version__})') - print(f'Front : localhost:{config.FRONTPORT}') - print(f'Privoxy : {config.PROXADDR}') - print(f'Rear : localhost:{config.REARPORT}') - print(f'Parent : {config.GeneralPROXY}') + print(f'Front : {config.front_name}:{config.front_port}') + print(f'Privoxy : {config.proxy_name}') + print(f'Rear : {config.rear_name}:{config.rear_port}') + print(f'Proxy : {config.proxy}') print('=' * 40) while True: time.sleep(1) @@ -461,7 +466,7 @@ if __name__ == '__main__': logger = logging.getLogger(__name__) config = LoadConfig(CONFIG) proxpool = urllib3.ProxyManager( - config.PROXADDR, num_pools=10, maxsize=8, + config.proxy_name, num_pools=10, maxsize=8, timeout=urllib3.util.timeout.Timeout( connect=90.0, read=310.0)) pools = ConnectionPools(CONFIG) diff --git a/proxy.py b/proxy.py index e912420..623b994 100755 --- a/proxy.py +++ b/proxy.py @@ -12,6 +12,8 @@ import cgi import socket import select import ssl +import string +import pathlib from http.server import HTTPServer, BaseHTTPRequestHandler from socketserver import ThreadingMixIn @@ -20,23 +22,36 @@ from cert import get_cert _name = 'proxy' logger = logging.getLogger('__main__') -message_format = '''\ - - - - - Proxy Error: {code} - - -

{code}: {message}

-

The following error occurred while - trying to access {url} -

-

{explain}

-
Generated on {now} by {server}. - - -''' +data = pathlib.Path(__file__).parent / 'data' +error_template = string.Template(open(data / 'error.html').read()) + + +def walk_traceback(e, n=0): + ''' + Produce an HTML formatted stack trace + given an exception. + ''' + partial = [] + ul = lambda xs: ('') + + for i, arg in enumerate(e.args): + name = (('' + + type(e).__name__ + + '') if i == 0 else '') + if isinstance(arg, str): + partial.append( + name + ' - ' + + arg.replace('<', '<').replace('>', '>')) + else: + partial.append(name) + + if isinstance(arg, Exception): + partial.append(walk_traceback(arg, n+1)) + if n == 0: + partial.append(walk_traceback(e.reason, n+1)) + return ul(partial) def read_write(socket1, socket2, max_idling=10): @@ -157,10 +172,15 @@ class ProxyRequestHandler(BaseHTTPRequestHandler): message = shortmsg if explain is None: explain = longmsg - content = message_format.format( + + content = error_template.substitute( code=code, message=message, - explain=explain, url=url, - now=datetime.today(), + explain=walk_traceback(explain), + url=url, + hostname=self.server.server_name, + address=self.server.server_address[0], + port=self.server.server_port, + now=datetime.today().isoformat(sep=' ', timespec='seconds'), server=self.server_version) body = content.encode('UTF-8', 'replace') self.send_response_only(code, message)