All Projects → michael-lazar → flask-gopher

michael-lazar / flask-gopher

Licence: GPL-3.0 license
A Flask extension to support the Gopher protocol

Programming Languages

python
139335 projects - #7 most used programming language

Projects that are alternatives of or similar to flask-gopher

burrow
burrow is a helper for building and managing a gopher hole
Stars: ✭ 43 (-36.76%)
Mutual labels:  gopher, gopher-server
fortran-curl
Fortran 2008 interface bindings to libcurl
Stars: ✭ 25 (-63.24%)
Mutual labels:  gopher
gopherbot
Source code for the gopher Slack Bot rewrite
Stars: ✭ 29 (-57.35%)
Mutual labels:  gopher
waffle
Haskell Gopher Protocol TUI Client 🧇
Stars: ✭ 19 (-72.06%)
Mutual labels:  gopher-protocol
gopher
A gopher browser for plan9
Stars: ✭ 33 (-51.47%)
Mutual labels:  gopher
htmlhost
hostHTML.live is downright the fastest way of hosting your single page HTML!
Stars: ✭ 21 (-69.12%)
Mutual labels:  gopher
Gophers
Free gophers
Stars: ✭ 2,542 (+3638.24%)
Mutual labels:  gopher
Free Gophers Pack
✨ This pack of 100+ gopher pictures and elements will help you to build own design of almost anything related to Go Programming Language: presentations, posts in blogs or social media, courses, videos and many, many more.
Stars: ✭ 2,343 (+3345.59%)
Mutual labels:  gopher
Algernon
🎩 Small self-contained pure-Go web server with Lua, Markdown, HTTP/2, QUIC, Redis and PostgreSQL support
Stars: ✭ 1,880 (+2664.71%)
Mutual labels:  gopher
Night
Weekly Go Online Meetup via Bilibili|Go 夜读|通过 bilibili 在线直播的方式分享 Go 相关的技术话题,每天大家在微信/telegram/Slack 上及时沟通交流编程技术话题。
Stars: ✭ 10,058 (+14691.18%)
Mutual labels:  gopher
Curl
A command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, POP3, POP3S, RTMP, RTMPS, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET and TFTP. libcurl offers a myriad of powerful features
Stars: ✭ 22,875 (+33539.71%)
Mutual labels:  gopher
Go42
《Go语言四十二章经》详细讲述Go语言规范与语法细节及开发中常见的误区,通过研读标准库等经典代码设计模式,启发读者深刻理解Go语言的核心思维,进入Go语言开发的更高阶段。
Stars: ✭ 4,129 (+5972.06%)
Mutual labels:  gopher
gopher
A simple server for the Gopher protocol written in Go.
Stars: ✭ 17 (-75%)
Mutual labels:  gopher
go-sensor
🚀 Go Distributed Tracing & Metrics Sensor for Instana
Stars: ✭ 90 (+32.35%)
Mutual labels:  gopher
overbitenx
Because Firefox isn't complete without Gopherspace.
Stars: ✭ 50 (-26.47%)
Mutual labels:  gopher
gophersnake
Stand-alone Gopher client for modern desktops
Stars: ✭ 14 (-79.41%)
Mutual labels:  gopher

Flask-Gopher

A Flask extension to support the Gopher protocol.

gopher

pypi python travis-ci coveralls

Contents

Demo

A live demonstration of the Flask-Gopher server is available in gopherspace at the following URL:


gopher://mozz.us:7005


About

What is gopher?

Gopher is an alternative to the World Wide Web that peaked in popularity in the early 90's. There are still a handful of gopher sites maintained by enthusiasts; you can learn more about its history at floodgap.

What is flask-gopher?

Flask-Gopher is a Flask extension that adds a thin Gopher -> HTTP compatability layer around the built-in webserver. It allows you to build fully RFC 1466 compliant gopher servers, with complete access to Flask's routing, templating engine, debugger, and more!

Who is this for?

I created this extension because I wanted to experiment with building dynamic gopher applications, and I felt limited by the lack of flexibility in other gopher servers. The target audience is web developers with experience using a high level web framework like Django or Ruby on Rails. You should feel comfortable writing python code and cross-referencing the official Flask documentation.

Quickstart

from flask import Flask, url_for
from flask_gopher import GopherExtension, GopherRequestHandler

app = Flask(__name__)
gopher = GopherExtension(app)

@app.route('/')
def index():
    return gopher.render_menu(
        gopher.menu.title('My GopherHole'),
        gopher.menu.dir('Home', url_for('index')),
        gopher.menu.info("Look Ma, it's a gopher server!"))

if __name__ == '__main__':
   app.run('127.0.0.1', 70, request_handler=GopherRequestHandler)

Installation

This package requires Python v3.5 or higher

pip install flask_gopher

Building Gopher Menus

Gopher menus are structured text files that display information about the current page and contain links to other gopher resources. A gopher menu is loosely equivalent to an HTML document with only <a> and <span> tags. Each line in the menu has a type that decribes what kind of resource it links to (text, binary, html, telnet, etc.).

Flask-Gopher provides several helper methods for constructing gopher menu lines:

Method Link Descriptor Meaning
menu.text 0 Plain text file
menu.dir 1 Gopher menu
menu.ccso 2 CCSO database; other databases
menu.error 3 Error message
menu.binhex 4 Macintosh BinHex file
menu.archive 5 Archive file (zip, tar, gzip)
menu.uuencoded 6 UUEncoded file
menu.query 7 Search query
menu.telnet 8 Telnet session
menu.bin 9 Binary file
menu.gif g GIF format graphics file
menu.image I Other Image file
menu.doc d Word processing document (ps, pdf, doc)
menu.sound s Sound file
menu.video ; Video file
menu.info i Information line
menu.title i Title line
menu.html h HTML document

Most of these methods require a text description for the link, and will accept a path selector and a host/port. They return a line of text that has been pre-formatted for a gopher menu. You can then pass all of the lines along into gopher.render_menu() to build the response body.

@app.route('/')
def index():
    return gopher.render_menu(
        # Link to an internal gopher menu
        gopher.menu.dir('Home', '/'),
        
        # Link to an external gopher menu
        gopher.menu.dir('XKCD comics', '/fun/xkcd', host='gopher.floodgap.com', port=70),
        
        # Link to a static file, using flask.url_for() to build a relative path
        gopher.menu.image('Picture of a cat', url_for('static', filename='cat.png')),
        
        # Link to an external web page
        gopher.menu.html('Project source', 'https://github.com/michael-lazar/flask-gopher'),
        
        # A text info line
        gopher.menu.info('This is informational text'),

        # Plain text will be converted into info lines
        "\n    There's no place\n    like ::1\n",

        # You can also format your links manually
        "0About this page\t/about.txt\t127.0.0.1\t8007")

Here's what the rendered menu looks like as plain text:

$ curl gopher://localhost:8007
1Home	/	127.0.0.1	8007
1XKCD comics	/fun/xkcd	gopher.floodgap.com	70
IPicture of a cat	/static/cat.png	127.0.0.1	8007
hProject source	URL:https://github.com/michael-lazar/flask-gopher	127.0.0.1	8007
iThis is informational text	fake	example.com	0
i 	fake	example.com	0
i    There's no place	fake	example.com	0
i    like ::1	fake	example.com	0
i 	fake	example.com	0
0About this page	/about.txt	127.0.0.1	8007

And here's what it looks like inside of a gopher client:

gopher

Using Templates

You can use Flask's Jinja2 templating engine to layout gopher menus. Flask-Gopher attaches gopher to the template namespace so you can access the menu helper functions. The recommended naming convention for gopher template files is to add a .gopher suffix. An example template file is shown below:

templates/example_menu.gopher

{{ 'Centered Title' | underline('-') | center }}

{{ gopher.menu.dir('Home', url_for('index')) }}

Hello from my gopher template!
Your IP address is {{ request.remote_addr }}

{{ '_' * gopher.width }}
{{ ('Served by ' + request.environ['SERVER_SOFTWARE']) | rjust }}

Call gopher.render_menu_template() from inside of your route to compile the template into a gopher menu.

@app.route('/')
def index():
    return gopher.render_menu_template('example_menu.gopher')

gopher

Gopher and WSGI

Python's WSGI (Web Server Gateway Interface) is an established API that defines how python web servers (gunicorn, mod_wsgi, etc) communicate with application frameworks (Flask, Django, etc). It defines a clean boundary between low-level socket and request handling, and high-level application logic.

WSGI was designed to be a very simple and flexible API, but at its heart it's built around HTTP requests. As such, it incorperates some HTTP specific components like request/response headers and status codes. Gopher is more simplistic and doesn't use these components. Here's an example of the difference in fetching a document with the two protocols:

HTTPGopher
requestresponserequestresponse
GET /path HTTP/1.1
Accept: text/plain
Accept-Charset: utf-8
...more headers
HTTP/1.1 200 OK
Server: Apache
Content-Type: text/html
...more headers
(body)
/path\r\n
(body)

In order to resolve the differences between gopher and HTTP, Flask-Gopher implements a custom GopherRequestHandler. The handler hooks into the WSGI server (werkzeug.BaseWSGIServer). It reads the first line of every TCP connection and determines which protocol the client is attempting to use. If the client is using gopher, the following assumptions are made:

  • Set the request's REQUEST_METHOD to GET
  • Set the request's SERVER_PROTOCOL (e.g. HTTP/1.1) to gopher
  • Set the request's wsgi.url_scheme (e.g. https) to gopher
  • Discard the response status line
  • Discard all response headers

Doing this makes a gopher connection appear like a normal HTTP request from the perspective of the WSGI application. It also provides metadata hooks that can be accessed from the Flask request. For example, you can respond the the request differently depending on which protocol is being used:

@app.route('/')
def index():
    if flask.request.scheme == 'gopher':
        return "iThis was a gopher request\tfake\texample.com\t0\r\n"
    else:
        return "<html><body>This was an HTTP request</body></html>" 

TLS Support

There were never any official guidelines released on how to establish secure connections over gopher. There's no http:// vs https:// or port 80 vs port 443 distinction like we have in the HTTP world. However, this topic has a growing interest within the gopher community. New gopher clients and servers are starting to experiment with varying degrees of support for TLS.

Flask-Gopher solves the security problem by peeking at every incoming connection to determine if a TLS handshake is being attempted by the client. If so, the requested content will automatically be returned over a secure socket. Otherwise, the content will be returned as plain text. This scheme has the advantage of being fully backwards compatible with older gopher clients. All content is served by a single gopher server running on port 70, and clients are in control over how they want to receive it.

Flask's WSGI server (like all good python WSGI servers) is designed to handle HTTPS with an "all-or-nothing" approach. Either TLS is turned on for all requests or it's not turned on at all. Flask-Gopher is able to overcome this limitation by slightly modifying the builtin Flask WSGI server. Here's an example of how to enable TLS support:

from flask_gopher import make_gopher_ssl_server

app = ...

if __name__ == '__main__':  
    server = make_gopher_ssl_server(
        '0.0.0.0',
        70,
        app=app,
        threaded=True,
        request_handler=GopherRequestHandler,
        ssl_context=('/path/to/public_cert.pem', '/path/to/private_cert.pem'))
    server.serve_forever()

When TLS is enabled, the request.environ['SECURE'] variable contains whether or not the current request is being made over a secure socket.

Looking for a gopher client with to try this out with? Solderpunk's VF-1 is an excellent choice:

$ vf1 mozz.us:7005/1/demo-ssl --tls

Gopher Protocol References

An interesting side note, the python standard library used to contain its own gopher module. It was deprecated in 2.5, and removed in 2.6. (https://www.python.org/dev/peps/pep-0004/)

Module name:   gopherlib
Rationale:     The gopher protocol is not in active use anymore.
Date:          1-Oct-2000.
Documentation: Documented as deprecated since Python 2.5.  Removed
               in Python 2.6.

A reference gopher client still exists in the old python SVN trunk: https://svn.python.org/projects/python/trunk/Demo/sockets/gopher.py

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].