Documentation updates, other minor changes

This commit is contained in:
Michael Lazar 2019-08-27 22:52:38 -04:00
parent 44c91a859f
commit 3c66b0d73e
3 changed files with 71 additions and 44 deletions

View File

@ -1,61 +1,63 @@
# Jetforce # Jetforce
An experimental python server for the new, under development Gemini Protocol. An experimental TCP server for the new, under development
[Gemini Protocol](https://gopher.commons.host/gopher://zaibatsu.circumlunar.space/1/~solderpunk/gemini).
Learn more about Project Gemini [here](https://gopher.commons.host/gopher://zaibatsu.circumlunar.space/1/~solderpunk/gemini).
![Rocket Launch](resources/rocket.jpg) ![Rocket Launch](resources/rocket.jpg)
## Features ## Features
- A modern python codebase with type hinting and black formatting. - A built-in static file server with support for gemini directories and
- A built-in static file server with support for gemini directory files. CGI scripts.
- Lightweight, single-file framework with zero dependencies. - Lightweight, single-file framework with zero external dependencies.
- Modern python codebase with type hinting and black style formatting.
- Supports concurrent connections using an asynchronous event loop. - Supports concurrent connections using an asynchronous event loop.
- Extendable - loosely implements the [WSGI](https://en.wikipedia.org/wiki/Web_Server_Gateway_Interface) - Extendable components that loosely implement the [WSGI](https://en.wikipedia.org/wiki/Web_Server_Gateway_Interface)
server/application pattern. server/application pattern.
## Installation ## Installation
Requires Python 3.7+ and OpenSSL. Requires Python 3.7+
The latest release can be installed from [PyPI](https://pypi.org/project/Jetforce/) The latest release can be installed from [PyPI](https://pypi.org/project/Jetforce/):
``` ```bash
$ pip install jetforce $ pip install jetforce
``` ```
Or, simply clone the repository and run the script directly Or, clone the repository and run the script directly:
``` ```bash
$ git clone https://github.com/michael-lazar/jetforce $ git clone https://github.com/michael-lazar/jetforce
$ cd jetforce $ cd jetforce
$ ./jetforce.py $ python3 jetforce.py
``` ```
## Usage ## Usage
Use the ``--help`` flag to view command-line options: Use the ``--help`` flag to view command-line options:
```bash
```
$ jetforce --help $ jetforce --help
usage: jetforce [-h] [--host HOST] [--port PORT] [--tls-certfile FILE] usage: jetforce [-h] [--host HOST] [--port PORT] [--tls-certfile FILE]
[--tls-keyfile FILE] [--hostname HOSTNAME] [--dir DIR] [--tls-keyfile FILE] [--hostname HOSTNAME] [--dir DIR]
[--index-file INDEX_FILE] [--cgi-dir DIR] [--index-file FILE]
An Experimental Gemini Protocol Server An Experimental Gemini Protocol Server
optional arguments: optional arguments:
-h, --help show this help message and exit -h, --help show this help message and exit
--host HOST Address to bind server to (default: 127.0.0.1) --host HOST Server address to bind to (default: 127.0.0.1)
--port PORT Port to bind server to (default: 1965) --port PORT Server port to bind to (default: 1965)
--tls-certfile FILE TLS certificate file (default: None) --tls-certfile FILE Server TLS certificate file (default: None)
--tls-keyfile FILE TLS private key file (default: None) --tls-keyfile FILE Server TLS private key file (default: None)
--hostname HOSTNAME Server hostname (default: localhost) --hostname HOSTNAME Server hostname (default: localhost)
--dir DIR Path on the filesystem to serve (default: /var/gemini) --dir DIR Local directory to serve (default: /var/gemini)
--index-file INDEX_FILE --cgi-dir DIR CGI script directory, relative to the server's root
The gemini directory index file (default: index.gmi) directory (default: cgi-bin)
--index-file FILE If a directory contains a file with this name, that
file will be served instead of auto-generating an index
page (default: index.gmi)
If the TLS cert/keyfile is not provided, a self-signed certificate will If the TLS cert/keyfile is not provided, a self-signed certificate will
automatically be generated and saved to your temporary directory. automatically be generated and saved to your temporary directory.
@ -78,8 +80,6 @@ $ openssl req -newkey rsa:2048 -nodes -keyout {hostname}.key \
-nodes -x509 -out {hostname}.crt -subj "/CN={hostname}" -nodes -x509 -out {hostname}.crt -subj "/CN={hostname}"
``` ```
#### TLS Client Certificates
There are currently no plans to support transient self-signed client certificates. There are currently no plans to support transient self-signed client certificates.
This is due to a techinical limitation of the python standard library's ``ssl`` This is due to a techinical limitation of the python standard library's ``ssl``
module, which is described in detail module, which is described in detail
@ -90,13 +90,13 @@ Support for verified client certificates will be added in a future version.
### Hostname ### Hostname
Because the gemini protocol sends the *whole* URL in the request, it's required Because the gemini protocol sends the *whole* URL in the request, it's required
that you declare which hostname your server is expecting to receive traffic under. that you declare the hostname that your server is expecting to receive traffic
Jetforce will respond to any request containing a URL that don't match your hostname under. Jetforce will reject any request that doesn't match your hostname with a
with a status of ``Proxy Request Refused``. status of ``Proxy Request Refused``.
Using python, you can modify this behavior to do fancy things like building a proxy Using python, you can modify this behavior to do fancy things like building a
server for HTTP requests. See [http_proxy.py](examples/http_proxy.py) for proxy server for HTTP requests. See [http_proxy.py](examples/http_proxy.py) for
an example of how to accomplish this. an example of how this is done.
### Serving Files ### Serving Files
@ -107,7 +107,20 @@ Jetforce serves files from the ``/var/gemini/`` directory by default:
- Directories will look for a file with the name **index.gmi**. - Directories will look for a file with the name **index.gmi**.
- If an index file does not exist, a directory listing will be generated. - If an index file does not exist, a directory listing will be generated.
CGI scripts are not currently supported. This feature might be added in a future version. ### CGI Scripts
Jetforce implements a slightly modified version of the official CGI
specification. Because Gemini is a less complex than HTTP, the CGI interface is
also inherently easier and more straightforward to use.
The main difference in this implementation is that the CGI script is expected
to write the entire gemini response *verbetim* to stdout:
1. The status code and meta on the first line
2. Any additional response body on subsequent lines
Unlike HTTP's CGI, there are no request/response headers or other special
fields to perform actions like redirects.
## License ## License

View File

@ -19,7 +19,7 @@ import urllib.parse
query = os.environ["QUERY_STRING"] query = os.environ["QUERY_STRING"]
if not query: if not query:
print("10 Enter your cowsay message") print("10 Enter your cowsay message: ")
sys.exit() sys.exit()
text = urllib.parse.unquote(query) text = urllib.parse.unquote(query)

View File

@ -204,7 +204,7 @@ class StaticDirectoryApplication(JetforceApplication):
self, self,
root_directory: str = "/var/gemini", root_directory: str = "/var/gemini",
index_file: str = "index.gmi", index_file: str = "index.gmi",
cgi_directory: str = "/cgi-bin", cgi_directory: str = "cgi-bin",
): ):
super().__init__() super().__init__()
self.routes.append((RoutePattern(), self.serve_static_file)) self.routes.append((RoutePattern(), self.serve_static_file))
@ -568,13 +568,19 @@ def command_line_parser() -> argparse.ArgumentParser:
epilog=EPILOG, epilog=EPILOG,
formatter_class=argparse.ArgumentDefaultsHelpFormatter, formatter_class=argparse.ArgumentDefaultsHelpFormatter,
) )
parser.add_argument("--host", help="Address to bind server to", default="127.0.0.1") parser.add_argument("--host", help="Server address to bind to", default="127.0.0.1")
parser.add_argument("--port", help="Port to bind server to", type=int, default=1965) parser.add_argument("--port", help="Server port to bind to", type=int, default=1965)
parser.add_argument( parser.add_argument(
"--tls-certfile", dest="certfile", help="TLS certificate file", metavar="FILE" "--tls-certfile",
dest="certfile",
help="Server TLS certificate file",
metavar="FILE",
) )
parser.add_argument( parser.add_argument(
"--tls-keyfile", dest="keyfile", help="TLS private key file", metavar="FILE" "--tls-keyfile",
dest="keyfile",
help="Server TLS private key file",
metavar="FILE",
) )
parser.add_argument("--hostname", help="Server hostname", default="localhost") parser.add_argument("--hostname", help="Server hostname", default="localhost")
return parser return parser
@ -586,15 +592,23 @@ def run_server() -> None:
""" """
parser = command_line_parser() parser = command_line_parser()
parser.add_argument( parser.add_argument(
"--dir", help="Root path on the filesystem to serve", default="/var/gemini" "--dir",
help="Root directory on the filesystem to serve",
default="/var/gemini",
metavar="DIR",
) )
parser.add_argument( parser.add_argument(
"--cgi-dir", "--cgi-dir",
help="CGI script folder, relative to the server's root directory", help="CGI script directory, relative to the server's root directory",
default="/cgi-bin", default="cgi-bin",
metavar="DIR",
) )
parser.add_argument( parser.add_argument(
"--index-file", help="The gemini directory index file", default="index.gmi" "--index-file",
help="If a directory contains a file with this name, that file will be "
"served instead of auto-generating an index page",
default="index.gmi",
metavar="FILE",
) )
args = parser.parse_args() args = parser.parse_args()