Documentation updates, other minor changes
This commit is contained in:
parent
44c91a859f
commit
3c66b0d73e
77
README.md
77
README.md
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
32
jetforce.py
32
jetforce.py
|
@ -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()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue