Add virtual hosting
This commit is contained in:
parent
2b9f98adf7
commit
478fb81094
|
@ -2,7 +2,10 @@
|
||||||
|
|
||||||
### Unreleased
|
### Unreleased
|
||||||
|
|
||||||
N/A
|
- Allow virtual hosting by specifying an alternate hostname in the application
|
||||||
|
route pattern.
|
||||||
|
- Jetforce will no longer raise an exception when attempting to log dropped
|
||||||
|
connections or other malformed requests.
|
||||||
|
|
||||||
### v0.2.0 (2012-01-21)
|
### v0.2.0 (2012-01-21)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
"""
|
||||||
|
This is an example of using virtual hosting to serve URLs for multiple
|
||||||
|
subdomains from a single jetforce server.
|
||||||
|
"""
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
import jetforce
|
||||||
|
from jetforce import Response, Status
|
||||||
|
|
||||||
|
app = jetforce.JetforceApplication()
|
||||||
|
|
||||||
|
|
||||||
|
@app.route(hostname="apple.localhost")
|
||||||
|
def serve_apple_domain(request):
|
||||||
|
return Response(Status.SUCCESS, "text/plain", f"apple\n{request.path}")
|
||||||
|
|
||||||
|
|
||||||
|
@app.route(hostname="banana.localhost")
|
||||||
|
def serve_banana_domain(request):
|
||||||
|
return Response(Status.SUCCESS, "text/plain", f"banana\n{request.path}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
args = jetforce.command_line_parser().parse_args()
|
||||||
|
ssl_context = jetforce.make_ssl_context(
|
||||||
|
args.hostname, args.certfile, args.keyfile, args.cafile, args.capath
|
||||||
|
)
|
||||||
|
server = jetforce.GeminiServer(
|
||||||
|
host=args.host, port=args.port, ssl_context=ssl_context, app=app
|
||||||
|
)
|
||||||
|
asyncio.run(server.run())
|
29
jetforce.py
29
jetforce.py
|
@ -152,6 +152,7 @@ class RoutePattern:
|
||||||
|
|
||||||
path: str = ""
|
path: str = ""
|
||||||
scheme: str = "gemini"
|
scheme: str = "gemini"
|
||||||
|
hostname: typing.Optional[str] = None
|
||||||
|
|
||||||
strict_hostname: bool = True
|
strict_hostname: bool = True
|
||||||
strict_port: bool = True
|
strict_port: bool = True
|
||||||
|
@ -161,7 +162,10 @@ class RoutePattern:
|
||||||
"""
|
"""
|
||||||
Check if the given request URL matches this route pattern.
|
Check if the given request URL matches this route pattern.
|
||||||
"""
|
"""
|
||||||
server_hostname = request.environ["HOSTNAME"]
|
if self.hostname is None:
|
||||||
|
server_hostname = request.environ["HOSTNAME"]
|
||||||
|
else:
|
||||||
|
server_hostname = self.hostname
|
||||||
server_port = int(request.environ["SERVER_PORT"])
|
server_port = int(request.environ["SERVER_PORT"])
|
||||||
|
|
||||||
if self.strict_hostname and request.hostname != server_hostname:
|
if self.strict_hostname and request.hostname != server_hostname:
|
||||||
|
@ -225,6 +229,7 @@ class JetforceApplication:
|
||||||
self,
|
self,
|
||||||
path: str = "",
|
path: str = "",
|
||||||
scheme: str = "gemini",
|
scheme: str = "gemini",
|
||||||
|
hostname: typing.Optional[str] = None,
|
||||||
strict_hostname: bool = True,
|
strict_hostname: bool = True,
|
||||||
strict_trailing_slash: bool = False,
|
strict_trailing_slash: bool = False,
|
||||||
) -> typing.Callable:
|
) -> typing.Callable:
|
||||||
|
@ -238,7 +243,7 @@ class JetforceApplication:
|
||||||
return Response(Status.SUCCESS, 'text/plain', 'Hello world!')
|
return Response(Status.SUCCESS, 'text/plain', 'Hello world!')
|
||||||
"""
|
"""
|
||||||
route_pattern = RoutePattern(
|
route_pattern = RoutePattern(
|
||||||
path, scheme, strict_hostname, strict_trailing_slash
|
path, scheme, hostname, strict_hostname, strict_trailing_slash
|
||||||
)
|
)
|
||||||
|
|
||||||
def wrap(func: typing.Callable) -> typing.Callable:
|
def wrap(func: typing.Callable) -> typing.Callable:
|
||||||
|
@ -591,14 +596,18 @@ class GeminiRequestHandler:
|
||||||
"""
|
"""
|
||||||
Log a gemini request using a format derived from the Common Log Format.
|
Log a gemini request using a format derived from the Common Log Format.
|
||||||
"""
|
"""
|
||||||
self.server.log_message(
|
try:
|
||||||
f"{self.remote_addr} "
|
self.server.log_message(
|
||||||
f"[{time.strftime(self.TIMESTAMP_FORMAT, self.received_timestamp)}] "
|
f"{self.remote_addr} "
|
||||||
f'"{self.url}" '
|
f"[{time.strftime(self.TIMESTAMP_FORMAT, self.received_timestamp)}] "
|
||||||
f"{self.status} "
|
f'"{self.url}" '
|
||||||
f'"{self.meta}" '
|
f"{self.status} "
|
||||||
f"{self.response_size}"
|
f'"{self.meta}" '
|
||||||
)
|
f"{self.response_size}"
|
||||||
|
)
|
||||||
|
except AttributeError:
|
||||||
|
# Malformed request or dropped connection
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class GeminiServer:
|
class GeminiServer:
|
||||||
|
|
Loading…
Reference in New Issue