Updated status codes for v0.9.1 spec.
Added command line argument for server hostname.
This commit is contained in:
parent
a283fc1d14
commit
224c98966e
|
@ -38,13 +38,31 @@ If the TLS cert/keyfile is not provided, a self-signed certificate will
|
||||||
automatically be generated and saved to your temporary file directory.
|
automatically be generated and saved to your temporary file directory.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Gemini response status codes
|
STATUS_INPUT = 10
|
||||||
STATUS_INPUT_REQUIRED = 10
|
|
||||||
STATUS_SUCCESS = 20
|
STATUS_SUCCESS = 20
|
||||||
STATUS_REDIRECT = 30
|
STATUS_SUCCESS_END_OF_SESSION = 21
|
||||||
STATUS_NOT_FOUND = 40
|
|
||||||
STATUS_SERVER_ERROR = 50
|
STATUS_REDIRECT_TEMPORARY = 30
|
||||||
STATUS_CERTIFICATE_ERROR = 60
|
STATUS_REDIRECT_PERMANENT = 31
|
||||||
|
STATUS_TEMPORARY_FAILURE = 40
|
||||||
|
STATUS_SERVER_UNAVAILABLE = 41
|
||||||
|
STATUS_CGI_ERROR = 42
|
||||||
|
STATUS_PROXY_ERROR = 43
|
||||||
|
STATUS_SLOW_DOWN = 44
|
||||||
|
|
||||||
|
STATUS_PERMANENT_FAILURE = 50
|
||||||
|
STATUS_NOT_FOUND = 51
|
||||||
|
STATUS_GONE = 52
|
||||||
|
STATUS_PROXY_REQUEST_REFUSED = 53
|
||||||
|
STATUS_BAD_REQUEST = 59
|
||||||
|
|
||||||
|
STATUS_CLIENT_CERTIFICATE_REQUIRED = 60
|
||||||
|
STATUS_TRANSIENT_CERTIFICATE_REQUESTED = 61
|
||||||
|
STATUS_AUTHORISED_CERTIFICATE_REQUIRED = 62
|
||||||
|
STATUS_CERTIFICATE_NOT_ACCEPTED = 63
|
||||||
|
STATUS_FUTURE_CERTIFICATE_REJECTED = 64
|
||||||
|
STATUS_EXPIRED_CERTIFICATE_REJECTED = 65
|
||||||
|
|
||||||
|
|
||||||
class EchoApp:
|
class EchoApp:
|
||||||
|
@ -199,7 +217,7 @@ class GeminiRequestHandler:
|
||||||
for data in app:
|
for data in app:
|
||||||
await self.write_body(data)
|
await self.write_body(data)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.write_status(STATUS_SERVER_ERROR, str(e))
|
self.write_status(STATUS_CGI_ERROR, str(e))
|
||||||
raise
|
raise
|
||||||
finally:
|
finally:
|
||||||
await self.flush_status()
|
await self.flush_status()
|
||||||
|
@ -288,11 +306,17 @@ class GeminiServer:
|
||||||
request_handler_class = GeminiRequestHandler
|
request_handler_class = GeminiRequestHandler
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, host: str, port: int, ssl_context: ssl.SSLContext, app: typing.Callable
|
self,
|
||||||
|
host: str,
|
||||||
|
port: int,
|
||||||
|
ssl_context: ssl.SSLContext,
|
||||||
|
hostname: str,
|
||||||
|
app: typing.Callable,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.host = host
|
self.host = host
|
||||||
self.port = port
|
self.port = port
|
||||||
self.ssl_context = ssl_context
|
self.ssl_context = ssl_context
|
||||||
|
self.hostname = hostname
|
||||||
self.app = app
|
self.app = app
|
||||||
|
|
||||||
async def run(self) -> None:
|
async def run(self) -> None:
|
||||||
|
@ -305,6 +329,7 @@ class GeminiServer:
|
||||||
)
|
)
|
||||||
|
|
||||||
socket_info = server.sockets[0].getsockname()
|
socket_info = server.sockets[0].getsockname()
|
||||||
|
self.log_message(f"Server hostname is {self.hostname}")
|
||||||
self.log_message(f"Listening on {socket_info[0]}:{socket_info[1]}")
|
self.log_message(f"Listening on {socket_info[0]}:{socket_info[1]}")
|
||||||
|
|
||||||
async with server:
|
async with server:
|
||||||
|
@ -332,8 +357,7 @@ class GeminiServer:
|
||||||
def generate_tls_certificate(hostname: str) -> typing.Tuple[str, str]:
|
def generate_tls_certificate(hostname: str) -> typing.Tuple[str, str]:
|
||||||
"""
|
"""
|
||||||
Utility function to generate a self-signed SSL certificate key pair if
|
Utility function to generate a self-signed SSL certificate key pair if
|
||||||
one isn't provided. This should only be used for development, know what
|
one isn't provided. Results may vary depending on your version of OpenSSL.
|
||||||
you're doing if you plan to make your server public!
|
|
||||||
"""
|
"""
|
||||||
certfile = pathlib.Path(tempfile.gettempdir()) / f"{hostname}.crt"
|
certfile = pathlib.Path(tempfile.gettempdir()) / f"{hostname}.crt"
|
||||||
keyfile = pathlib.Path(tempfile.gettempdir()) / f"{hostname}.key"
|
keyfile = pathlib.Path(tempfile.gettempdir()) / f"{hostname}.key"
|
||||||
|
@ -360,16 +384,17 @@ def run_server() -> None:
|
||||||
epilog=EPILOG,
|
epilog=EPILOG,
|
||||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||||
)
|
)
|
||||||
parser.add_argument("--host", help="server host", default="127.0.0.1")
|
parser.add_argument("--host", help="Address to bind server to", default="127.0.0.1")
|
||||||
parser.add_argument("--port", help="server port", type=int, default=1965)
|
parser.add_argument("--port", help="Port to bind server to", type=int, default=1965)
|
||||||
parser.add_argument("--tls-certfile", help="TLS certificate file", metavar="FILE")
|
parser.add_argument("--tls-certfile", help="TLS certificate file", metavar="FILE")
|
||||||
parser.add_argument("--tls-keyfile", help="TLS private key file", metavar="FILE")
|
parser.add_argument("--tls-keyfile", help="TLS private key file", metavar="FILE")
|
||||||
|
parser.add_argument("--hostname", help="Server hostname", default="localhost")
|
||||||
parser.add_argument("--dir", help="local directory to serve", default="/var/gemini")
|
parser.add_argument("--dir", help="local directory to serve", default="/var/gemini")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
certfile, keyfile = args.tls_certfile, args.tls_keyfile
|
certfile, keyfile = args.tls_certfile, args.tls_keyfile
|
||||||
if not certfile:
|
if not certfile:
|
||||||
certfile, keyfile = generate_tls_certificate("localhost")
|
certfile, keyfile = generate_tls_certificate(args.hostname)
|
||||||
|
|
||||||
ssl_context = ssl.SSLContext()
|
ssl_context = ssl.SSLContext()
|
||||||
ssl_context.load_cert_chain(certfile, keyfile)
|
ssl_context.load_cert_chain(certfile, keyfile)
|
||||||
|
@ -378,6 +403,7 @@ def run_server() -> None:
|
||||||
host=args.host,
|
host=args.host,
|
||||||
port=args.port,
|
port=args.port,
|
||||||
ssl_context=ssl_context,
|
ssl_context=ssl_context,
|
||||||
|
hostname=args.hostname,
|
||||||
app=StaticDirectoryApp.serve_directory(args.dir),
|
app=StaticDirectoryApp.serve_directory(args.dir),
|
||||||
)
|
)
|
||||||
asyncio.run(server.run())
|
asyncio.run(server.run())
|
||||||
|
|
Loading…
Reference in New Issue