From 1ef62c2c3044b5b11dae92a08be5d83a780392b4 Mon Sep 17 00:00:00 2001 From: Matt Singleton Date: Sun, 16 Jan 2022 20:56:29 -0600 Subject: handle error codes and network errors --- TODO.md | 4 +-- browser.py | 2 +- error_template.html | 14 ++++++++ gemini.py | 99 ++++++++++++++++++++++++++++++++--------------------- page_template.html | 30 +--------------- style.css | 30 ++++++++-------- 6 files changed, 93 insertions(+), 86 deletions(-) create mode 100644 error_template.html diff --git a/TODO.md b/TODO.md index dc5ba0c..93e8d78 100644 --- a/TODO.md +++ b/TODO.md @@ -3,12 +3,12 @@ - [x] scroll - [ ] highlight and follow links - [x] forward and back - - [ ] url bar + - [x] url bar - [ ] search in page - [x] stdlib url parsing in gemini module - [x] nice typography - [x] html templates - [ ] deal with non utf8 charsets - [ ] handle all response codes - - [ ] errors (4x, 5x) + - [x] errors (4x, 5x) - [ ] search diff --git a/browser.py b/browser.py index 0c718b4..f6107e9 100755 --- a/browser.py +++ b/browser.py @@ -27,7 +27,7 @@ class GeminiSchemeHandler(QtWebEngineCore.QWebEngineUrlSchemeHandler): print(gem['status'], gem['meta']) buf = QtCore.QBuffer(parent=request) buf.open(QtCore.QIODevice.WriteOnly) - buf.write(gemini.gem2html(gem['body']).encode('utf8')) + buf.write(gemini.gem2html(gem).encode('utf8')) buf.seek(0) buf.close() request.reply(b'text/html', buf) diff --git a/error_template.html b/error_template.html new file mode 100644 index 0000000..3daacb7 --- /dev/null +++ b/error_template.html @@ -0,0 +1,14 @@ + + + + + + + + +

$status

+

$meta

+ + diff --git a/gemini.py b/gemini.py index e820619..275eab9 100644 --- a/gemini.py +++ b/gemini.py @@ -12,16 +12,31 @@ def htmlescape(text: str) -> str: return text.replace('<', '<').replace('>', '>') -def gem2html(gem: str) -> str: - template = string.Template(open('page_template.html').read()) - body = io.StringIO() - parser = fsm.Parser(gem.split('\n'), body) - parser.parse() - html = template.substitute( - body=body.getvalue(), - charset='utf-8', - lang='en', - ) +def gem2html(gem: dict) -> str: + params = { + 'charset': 'utf-8', + 'lang': 'en', + 'css': open('style.css').read() + } + if gem['status'][0] == '2': + template = string.Template(open('page_template.html').read()) + body = io.StringIO() + parser = fsm.Parser(gem['body'].split('\n'), body) + parser.parse() + params['body'] = body.getvalue() + else: + template = string.Template(open('error_template.html').read()) + if gem['status'] == '00': + params['status'] = 'CLIENT ERROR' + elif gem['status'][0] == '4': + params['status'] = gem['status'] + ' TEMPORARY FAILURE' + elif gem['status'][0] == '5': + params['status'] = gem['status'] + ' PERMANENT FAILURE' + else: + params['status'] = 'UNHANDLED STATUS {}'.format(gem['status']) + params['meta'] = gem['meta'] + + html = template.substitute(params) with open('latest.html', 'w') as fp: fp.write(html) return html @@ -42,8 +57,8 @@ def get(url: str, follow_redirects: bool = True) -> dict: while response['status'][0] == '3': count += 1 if count > 20: - raise Exception('Redirect loop') - print('redirect: {}'.format(response['meta'])) + return {'status': '00', 'meta': 'Too many redirects'} + print('{status} {meta}'.format(**response)) response = _get(response['meta']) return response @@ -72,30 +87,36 @@ def _get(url: str) -> dict: url_parts.fragment, )) } - context = ssl.create_default_context() - context.check_hostname = False - context.verify_mode = ssl.CERT_NONE - port = 1965 if url_parts.port is None else url_parts.port - with socket.create_connection((url_parts.hostname, port)) as sock: - with context.wrap_socket(sock, server_hostname=url_parts.hostname) as ssock: - ssock.sendall('{url}\r\n'.format(url=url).encode('utf8')) - fp = ssock.makefile(mode='rb') - header = fp.readline(1027) - parts = header.decode('utf8').split(None, 1) - status = parts[0] - if len(parts) == 1: - meta = '' - else: - meta = parts[1] - if status[0] != '2': - return { - 'status': status, - 'meta': meta.strip(), - } - meta_params = _parse_meta(meta) - body = fp.read() - return { - 'status': status, - 'meta': meta.strip(), - 'body': body.decode(meta_params.get('charset', 'utf8')), - } + try: + context = ssl.create_default_context() + context.check_hostname = False + context.verify_mode = ssl.CERT_NONE + port = 1965 if url_parts.port is None else url_parts.port + with socket.create_connection((url_parts.hostname, port)) as sock: + with context.wrap_socket(sock, server_hostname=url_parts.hostname) as ssock: + ssock.sendall('{url}\r\n'.format(url=url).encode('utf8')) + fp = ssock.makefile(mode='rb') + header = fp.readline(1027) + parts = header.decode('utf8').split(None, 1) + status = parts[0] + if len(parts) == 1: + meta = '' + else: + meta = parts[1] + if status[0] != '2': + return { + 'status': status, + 'meta': meta.strip(), + } + meta_params = _parse_meta(meta) + body = fp.read() + return { + 'status': status, + 'meta': meta.strip(), + 'body': body.decode(meta_params.get('charset', 'utf8')), + } + except Exception as ex: + return { + 'status': '00', + 'meta': '{}'.format(ex), + } diff --git a/page_template.html b/page_template.html index 2a4baf5..e049d56 100644 --- a/page_template.html +++ b/page_template.html @@ -4,35 +4,7 @@ diff --git a/style.css b/style.css index b75a239..6b06966 100644 --- a/style.css +++ b/style.css @@ -1,29 +1,29 @@ html { - font-size: 18px; - font-family: Garamond, Georgia, sans-serif; + font-size: 18px; + font-family: Garamond, Georgia, sans-serif; } pre { - font-family: Courier, monospace; + font-family: Courier, monospace; } blockquote { - border-left: 5px solid #ddd; - padding: 0.6em 0.6em 0.2em; - font-style: italic; + border-left: 5px solid #ddd; + padding: 0.6em 0.6em 0.2em; + font-style: italic; } blockquote:before { - content: "\201C"; - display: inline-block; - padding-right: 0.4rem; - font-size: 4em; - line-height: 0; - vertical-align: -0.4em; - color: lightgrey; - margin-right: 0.1em; + content: "\201C"; + display: inline-block; + padding-right: 0.4rem; + font-size: 4em; + line-height: 0; + vertical-align: -0.4em; + color: lightgrey; + margin-right: 0.1em; } li.link::marker { - content: '⇒ '; + content: '⇒ '; } -- cgit v1.2.3