diff --git a/pyproject.toml b/pyproject.toml index 6a6d4b9..53ab4fa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,10 +7,12 @@ name = "nercone-website" version = "1.0.0" requires-python = ">=3.8" dependencies = [ - "httpx", - "websockets", + "rjsmin", + "rcssmin", "markitdown", "beautifulsoup4", + "httpx", + "websockets", "jinja2", "fastapi", "uvicorn[standard]" diff --git a/src/nercone_website/middleware.py b/src/nercone_website/middleware.py index c75448b..151c63e 100644 --- a/src/nercone_website/middleware.py +++ b/src/nercone_website/middleware.py @@ -1,3 +1,5 @@ +import rjsmin +import rcssmin import subprocess from fastapi import Response from fastapi.responses import PlainTextResponse @@ -28,7 +30,7 @@ class Middleware: if not any([hostname.endswith(candidate) for candidate in hostnames]): response = PlainTextResponse("許可されていないホスト名でのアクセスです。", status_code=400) - await self._send_with_headers(response, scope, receive, send) + await self._send(response, scope, receive, send) return hostname_parts = hostname.split(".") @@ -47,14 +49,14 @@ class Middleware: response = await self._get_response(scope, cached_receive, subdomain_path) if response.status_code < 400: - await self._send_with_headers(response, scope, cached_receive, send) + await self._send(response, scope, cached_receive, send) return response = await self._get_response(scope, cached_receive, original_path) - await self._send_with_headers(response, scope, cached_receive, send) + await self._send(response, scope, cached_receive, send) else: response = await self._get_response(scope, cached_receive, scope["path"]) - await self._send_with_headers(response, scope, cached_receive, send) + await self._send(response, scope, cached_receive, send) async def _get_response(self, scope: Scope, receive: Receive, path: str) -> Response: new_scope = dict(scope, path=path) @@ -96,11 +98,32 @@ class Middleware: break return body - async def _send_with_headers(self, response: Response, scope, receive, send): + async def _send(self, response: Response, scope, receive, send): + content_type = response.headers.get("content-type", "") + response.headers["Server"] = f"nercone.dev ({server_version})" response.headers["Onion-Location"] = f"http://{onion_hostname}/" + if "access-control-allow-origin" not in response.headers: response.headers["Access-Control-Allow-Origin"] = "*" response.headers["Access-Control-Allow-Methods"] = "*" response.headers["Access-Control-Allow-Headers"] = "*" + + if any(content_type.startswith(t) for t in ["text/html", "text/css", "text/javascript", "application/javascript"]): + response.headers["Cache-Control"] = "no-cache" + else: + response.headers["Cache-Control"] = "public, max-age=3600" + + if "text/css" in content_type: + try: + response.body = rcssmin.cssmin(response.body.decode("utf-8", errors="replace")).encode("utf-8") + except Exception: + pass + elif any(content_type.startswith(t) for t in ["text/javascript", "application/javascript"]): + try: + response.body = rjsmin.jsmin(response.body.decode("utf-8", errors="replace")).encode("utf-8") + except Exception: + pass + response.headers["Content-Length"] = str(len(response.body)) + await response(scope, receive, send)