diff --git a/CHANGELOG.md b/CHANGELOG.md index e35eed8..a497730 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,30 +5,30 @@ #### Features - Added support for python 3.8. -- Added a new server diagnostics tool ``jetforce-diagnostics``. +- Added a new server diagnostics tool, ``jetforce-diagnostics``. - Added ability to binding to IPv6 addresses (if supported by your OS): - - For IPv4 : --host "0.0.0.0" - - For IPv6 : --host "::" - - For IPv4 + IPv6 : --host "" + - For IPv4 : ``--host "0.0.0.0"`` + - For IPv6 : ``--host "::"`` + - For IPv4 + IPv6 : ``--host ""`` - Various improvements have been made to the project documentation. #### Bugfixes - A URL missing a scheme will now be interpreted as "gemini://". -- A request to the root URL without a trailing slash will now return a 31 - permanent redirect. +- A request to the root URL without a trailing slash will now return a + ``31 PERMANENT REDIRECT``. - Requests containing an invalid or unparsable URL format will now return a - status of 59 Bad Request instead of 50 Permanent Failure. + status of ``59 BAD REQUEST`` instead of ``50 PERMANENT FAILURE``. - Files starting with ``~`` will now be included in directory listings. - Requests containing an incorrect scheme, hostname, or port will now return a - 53 Proxy Refused instead of a 50 Permanent Failure. + ``53 PROXY REFUSED`` instead of a ``50 PERMANENT FAILURE``. - The port number in the URL (if provided) is now validated against the server's port number. -- OS errors when attempting to read a file will return a 51 NOT FOUND status - instead of a 42 CGI Error. This is a precaution to prevent leaking sensitive - information about the server's filesystem. -- For security, unhandled exceptions now display a generic error message - instead of the specific exception string. +- OS errors when attempting to read a file will return a ``51 NOT FOUND`` + status instead of a ``42 CGI Error``. This is a precaution to prevent leaking + sensitive information about the server's filesystem. +- For security, unhandled exceptions will now display a generic error message + instead of the plain exception string. ### v0.1.0 (2019-09-22) diff --git a/jetforce.py b/jetforce.py index 5d0a8b7..0458d31 100755 --- a/jetforce.py +++ b/jetforce.py @@ -1,4 +1,37 @@ #!/usr/bin/env python3 +""" +Jetforce, an experimental Gemini server. + +Overview +-------- + +GeminiServer: + An asynchronous TCP server built on top of python's asyncio stream + abstraction. This is a lightweight class that accepts incoming requests, + logs them, and sends them to a configurable request handler to be processed. + +GeminiRequestHandler: + The request handler manages the life of a single gemini request. It exposes + a simplified interface to read the request URL and write the gemini response + status line and body to the socket. The request URL and other server + information is stuffed into an ``environ`` dictionary that encapsulates the + request at a low level. This dictionary, along with a callback to write the + response data, and passed to a configurable "application" function or class. + +JetforceApplication: + This is a base class for writing jetforce server applications. It doesn't + anything on its own, but it does provide a convenient interface to define + custom server endpoints using route decorators. If you want to utilize + jetforce as a library and write your own server in python, this is the class + that you want to extend. The examples/ directory contains some examples of + how to accomplish this. + +StaticDirectoryApplication: + This is a pre-built application that serves files from a static directory. + It provides an "out-of-the-box" gemini server without needing to write any + lines of code. This is what is invoked when you launch jetforce from the + command line. +""" from __future__ import annotations import argparse @@ -150,6 +183,13 @@ class RoutePattern: class JetforceApplication: """ Base Jetforce application class with primitive URL routing. + + This is a base class for writing jetforce server applications. It doesn't + anything on its own, but it does provide a convenient interface to define + custom server endpoints using route decorators. If you want to utilize + jetforce as a library and write your own server in python, this is the class + that you want to extend. The examples/ directory contains some examples of + how to accomplish this. """ def __init__(self): @@ -216,7 +256,12 @@ class JetforceApplication: class StaticDirectoryApplication(JetforceApplication): """ - Serve a static directory over Gemini. + Application for serving static files & CGI over gemini. + + This is a pre-built application that serves files from a static directory. + It provides an "out-of-the-box" gemini server without needing to write any + lines of code. This is what is invoked when you launch jetforce from the + command line. If a directory contains a file with the name "index.gmi", that file will be returned when the directory path is requested. Otherwise, a directory @@ -388,11 +433,18 @@ class GeminiRequestHandler: """ Handle a single Gemini Protocol TCP request. + The request handler manages the life of a single gemini request. It exposes + a simplified interface to read the request URL and write the gemini response + status line and body to the socket. The request URL and other server + information is stuffed into an ``environ`` dictionary that encapsulates the + request at a low level. This dictionary, along with a callback to write the + response data, and passed to a configurable "application" function or class. + This design borrows heavily from the standard library's HTTP request handler (http.server.BaseHTTPRequestHandler). However, I did not make any attempts to directly emulate the existing conventions, because Gemini is an inherently simpler protocol than HTTP and much of the boilerplate could be - removed or slimmed-down. + removed. """ TIMESTAMP_FORMAT = "%d/%b/%Y:%H:%M:%S %z" @@ -551,7 +603,10 @@ class GeminiRequestHandler: class GeminiServer: """ - An asynchronous TCP server that understands the Gemini Protocol. + An asynchronous TCP server that uses the asyncio stream abstraction. + + This is a lightweight class that accepts incoming requests, logs them, and + sends them to a configurable request handler to be processed. """ request_handler_class = GeminiRequestHandler