summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO.md4
-rwxr-xr-xbrowser.py2
-rw-r--r--error_template.html14
-rw-r--r--gemini.py99
-rw-r--r--page_template.html30
-rw-r--r--style.css30
6 files changed, 93 insertions, 86 deletions
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 @@
+<!DOCTYPE html>
+<html lang="en">
+ <html>
+ <head>
+ <meta charset="$charset"/>
+ <style type="text/css">
+$css
+ </style>
+ </head>
+ <body>
+ <h1>$status</h1>
+ <p>$meta</p>
+ </body>
+ </html>
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('<', '&lt;').replace('>', '&gt;')
-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 @@
<head>
<meta charset="$charset"/>
<style type="text/css">
-html {
- font-size: 18px;
- font-family: Garamond, Georgia, sans-serif;
-}
-
-pre {
- font-family: Courier, monospace;
-}
-
-blockquote {
- 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;
-}
-
-li.link::marker {
- content: '⇒ ';
-}
+$css
</style>
</head>
<body>
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: '⇒ ';
}