diff --git a/README.md b/README.md index 75753af..22d1791 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,12 @@ -# wobbly +# Wobbly, the Web Browser Based Gemini Browser + +This is a very basic browser for the gemini network protocol, implemented as a web service. + +The frontend is a webpage designed to look like a simple browser window. It has some javascript to make the experience smoother and reduce load on the backend. It also has a startpage in geminispace. + +The backend is a CGI script that takes a URL and fetches it over gemini, parsing and transforming it into an HTML response which is then presented in the browser's main window. + +## Dependencies + +The backend depends on `gemcall` and `gemtextparser`, available near this repository. diff --git a/public_gemini/index.gmi b/public_gemini/index.gmi new file mode 100644 index 0000000..d9ebf6b --- /dev/null +++ b/public_gemini/index.gmi @@ -0,0 +1,24 @@ +# Welcome to Wobbly! + +You might be wondering what this is. That's okay. + +You know how website addresses start with http:// or https://? Those are network protocols, and they're not the only ones. The gemini network protocol was invented in 2019. It has some serious drawbacks that makes it a bad replacement for HTTP/HTTPS, but that's also its main selling point. Its real aim is a simplified experience, both as a developer, producer and consumer of content. + +=> gemini://gemini.circumlunar.space/ You can read more about gemini here. + +But a web browser doesn't understand the gemini network protocol, nor the gemtext markup language. It speaks HTTP/HTTPS and HTML/CSS/JavaScript. Therefore, I've made Wobbly. + +Wobbly is a gemini browser that runs inside your web browser. It's very basic: +* It has a help button. +* Back, Up (in the directory tree), Forward. +* A URL address bar, and a button to Go! + +Try opening this web page in full screen mode in your web browser! It'll probably look more familiar then. + +Wanna see what's up in geminispace? + +=> gemini://warmedal.se/~antenna/ Check out Antenna, which aggregates a lot of content published in the last week. + +Cheers, +ew0k + diff --git a/public_html/browser.cgi b/public_html/browser.cgi new file mode 100755 index 0000000..53b6f4d --- /dev/null +++ b/public_html/browser.cgi @@ -0,0 +1,109 @@ +#!/usr/bin/env python3 +# vim: tabstop=4 shiftwidth=4 expandtab + +import gemcall +import gemtextparser +import urllib.parse +import sys +from os import getenv + +urllib.parse.uses_relative.append("gemini") +urllib.parse.uses_netloc.append("gemini") + +def clean(text): + return text.replace('<','<').replace('>','>') + +print("Content-type: text/html\n\n") + +if getenv('QUERY_STRING'): + try: + baseurl = getenv('QUERY_STRING').split('?')[0] + response = gemcall.request(baseurl) + if response.responsecode in [30, 31]: + newtarget = urllib.parse.urljoin(baseurl, response.meta) + print(f"

RESPONSE: \"{str(response.responsecode)} {response.meta}\"

This address redirects to {newtarget}.

") + elif response.responsecode == 20 and "text/" in response.meta: + responsetext = response.read(20*1024) # We don't support more than 20kb + if "text/gemini" in response.meta: + parser = gemtextparser.GemtextParser() + preform = False + listmode = False + blockquote = False + for line in parser.parseText(responsetext.decode()): + if line.linetype == gemtextparser.LineType.PREFORM: + if not preform: + print("
")
+                            preform = True
+                        print(clean(line.text()))
+                        continue
+                    if not line.linetype == gemtextparser.LineType.PREFORM and preform:
+                        print("
") + preform = False + + if line.linetype == gemtextparser.LineType.LISTITEM: + if not listmode: + print("") + listmode = False + + if line.linetype == gemtextparser.LineType.BLOCKQUOTE: + if not blockquote: + print("
") + blockquote = True + print(clean(line.text())) + continue + if not line.linetype == gemtextparser.LineType.BLOCKQUOTE and blockquote: + print("
") + blockquote = False + + if line.linetype == gemtextparser.LineType.H1 and line.text(): + print(f"

{clean(line.text())}

") + continue + if line.linetype == gemtextparser.LineType.H2 and line.text(): + print(f"

{clean(line.text())}

") + continue + if line.linetype == gemtextparser.LineType.H3 and line.text(): + print(f"

{clean(line.text())}

") + continue + + if line.linetype == gemtextparser.LineType.LINK: + linkURL = urllib.parse.urljoin(baseurl, clean(line.linkURL().replace("'",""))) + target = "" if linkURL.startswith("gemini://") else " target='_blank'" + if line.text(): + print(f"{clean(line.text())}
") + else: + print(f"{linkURL}
") + continue + + if line.linetype == gemtextparser.LineType.PLAIN: + print(f"{clean(line.text())}
") + if listmode: + print("") + if blockquote: + print("") + if preform: + print("") + + else: + print("
")
+                print(clean(responsetext.decode()))
+                print("
") + + elif response.responsecode == 20: + print(f"

RESPONSE: \"20 Success\", but...

The Wobbly browser only supports text responses, and this response is '{clean(response.meta)}'.

") + elif response.responsecode in [40, 41, 42, 43, 44, 50, 51, 52, 53, 59]: + print(f"

RESPONSE: \"{str(response.responsecode)} {clean(response.meta)}\"

This is an error message from the server. Hopefully it makes sense to you.

") + elif response.responsecode in [60, 61, 62]: + print(f"

RESPONSE: \"{str(response.responsecode)} {clean(response.meta)}\"

The Wobbly browser does not support client certificates. Please install a more full-featured browser to visit this page.

") + elif response.responsecode in [10,11]: + print(f"

RESPONSE: \"{str(response.responsecode)} {clean(response.meta)}\"

The status codes 10 and 11 are requests for user input.

The only means of submitting user input to a server in gemini is via the so-called QUERY_STRING; the part of a URL that follows after a '?'. The Wobbly browser does not support this for privacy/security reasons. Please install a more full-featured browser to be able to submit data.

") + + response.discard() + except: + print(f"

Unknown Error

Something went wrong when trying to fetch '{getenv('QUERY_STRING')}'. Could not recover.

") +else: + print("

What?

I'm sorry, but I don't know what you want me to do without a URL.

") diff --git a/public_html/index.html b/public_html/index.html new file mode 100644 index 0000000..d92194a --- /dev/null +++ b/public_html/index.html @@ -0,0 +1,134 @@ + + + Wobbly, the Web-based Gemini Browser + + + + + + + +
+
+ + + + + + +
+
+
+
+

Wobbly Help Section

+ +
+
+
+

This Browser Requires Javascript

+

Sorry, there's no meaningful way around that. It's not terribly much, however. Feel free to check the source code.

+
+ +