This commit is contained in:
2026-04-25 16:31:07 +09:00
parent 41b0cc6dd6
commit 9d61a19a6e
3 changed files with 34 additions and 25 deletions
+21 -22
View File
@@ -2,29 +2,28 @@ from http import HTTPStatus
from fastapi import Request, Response from fastapi import Request, Response
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
# TODO: こっちは普通のメッセージにする
default_messages = { default_messages = {
400: "日本語でおk", 400: "リクエストの構文が正しくないか、パラメータが不正です。",
401: "見たいのならログインすることね", 401: "このリソースにアクセスするには認証が必要です。",
402: "夢が欲しけりゃ金払え!", 402: "このリソースへのアクセスには支払いが必要です。",
403: "あんたなんかに見せるもんですか!", 403: "このリソースへのアクセス権がありません。",
404: "そんなページ知らないっ!", 404: "リクエストしたページまたはリソースが見つかりません。",
405: "そのMethodはNot Allowedだよ", 405: "このリソースではそのHTTPメソッドは許可されていません。",
406: "すまんがその条件ではお渡しできない", 406: "リクエストのAcceptヘッダーと一致するレスポンスを生成できません",
407: "うちのプロキシ使うんだったらまずログインしな", 407: "このリソースにアクセスするにはプロキシの認証が必要です",
408: "もう用がないならさっさと帰りなさい", 408: "リクエストが時間内に完了しませんでした",
409: "ちょっと待ったそんな話聞いてないぞ", 409: "現在のリソースの状態とリクエストが競合しています。",
410: "もう無いで", 410: "リクエストしたリソースは恒久的に削除されました",
411: "サイズを教えろ。話はそれからだ", 411: "リクエストにはContent-Lengthヘッダーが必要です",
412: "なにその条件美味しいの", 412: "リクエストの前提条件がサーバーの状態と一致しません。",
413: "そ、そそ、そんなの入りきらないよっ!", 413: "リクエストのボディがサーバーの許容サイズを超えています。",
414: "もちつけ", 414: "リクエストURIがサーバーの処理できる長さを超えています。",
415: "そんな形式知らない!", 415: "リクエストのメディア形式はサポートされていません。",
416: "ちっさぁ:heart:", 416: "リクエストしたレンジはリソースのサイズ内に存在しません。",
417: "期待させて悪かったわね!", 417: "リクエストのExpectヘッダーの要件をサーバーが満たせません。",
418: "ティーポット「私はコーヒーを注ぐためのものではありません!やだっ!」", 418: "このサーバーはティーポットです。コーヒーを淹れることはできません。",
421: "またあいつ案内先間違えてるよ...どうしよ...", 421: "リクエストが意図しないサーバーに到達しました。",
426: "それに答えるには、まずWebSocketに移動したい" 426: "このリクエストを処理するにはプロトコルのアップグレードが必要です",
} }
default_joke_messages = { default_joke_messages = {
+8 -2
View File
@@ -7,8 +7,7 @@ from datetime import datetime, timezone
access_log_path = Path.cwd().joinpath("logs", "access.log") access_log_path = Path.cwd().joinpath("logs", "access.log")
access_log_path.parent.mkdir(parents=True, exist_ok=True) access_log_path.parent.mkdir(parents=True, exist_ok=True)
# TODO: ステータスコードとかも含めたい でもそれにはレスポンスが出来上がってからログを書く必要があるので/echoとかを残すには工夫がいりそう def log_access(scope: Scope, write: bool = False):
def log_access(scope: Scope, write: bool = True):
client = scope.get("client") or ("", 0) client = scope.get("client") or ("", 0)
server = scope.get("server") or ("", 0) server = scope.get("server") or ("", 0)
headers = dict(scope.get("headers", [])) headers = dict(scope.get("headers", []))
@@ -33,3 +32,10 @@ def log_access(scope: Scope, write: bool = True):
with access_log_path.open("a", encoding="utf-8") as f: with access_log_path.open("a", encoding="utf-8") as f:
f.write(json.dumps(log, ensure_ascii=False) + "\n") f.write(json.dumps(log, ensure_ascii=False) + "\n")
return log return log
def finalize_log(log: dict, status_code: int, write: bool = True) -> None:
log["status_code"] = status_code
if write:
with access_log_path.open("a", encoding="utf-8") as f:
f.write(json.dumps(log, ensure_ascii=False) + "\n")
return log
+5 -1
View File
@@ -4,7 +4,7 @@ import subprocess
from fastapi import Response from fastapi import Response
from fastapi.responses import PlainTextResponse from fastapi.responses import PlainTextResponse
from starlette.types import Scope, ASGIApp, Receive, Send from starlette.types import Scope, ASGIApp, Receive, Send
from .logger import log_access from .logger import log_access, finalize_log
server_version = subprocess.run(["/usr/bin/git", "rev-parse", "--short", "HEAD"], text=True, capture_output=True).stdout.strip() server_version = subprocess.run(["/usr/bin/git", "rev-parse", "--short", "HEAD"], text=True, capture_output=True).stdout.strip()
onion_hostname = "4sbb7xhdn4meuesnqvcreewk6sjnvchrsx4lpnxmnjhz2soat74finid.onion" onion_hostname = "4sbb7xhdn4meuesnqvcreewk6sjnvchrsx4lpnxmnjhz2soat74finid.onion"
@@ -41,6 +41,7 @@ class Middleware:
if not any([hostname.endswith(candidate) for candidate in hostnames]): if not any([hostname.endswith(candidate) for candidate in hostnames]):
response = PlainTextResponse("許可されていないホスト名でのアクセスです。", status_code=400) response = PlainTextResponse("許可されていないホスト名でのアクセスです。", status_code=400)
await self._send(response, scope, receive, send) await self._send(response, scope, receive, send)
finalize_log(scope["log"], response.status_code)
return return
body = await self._read_body(receive) body = await self._read_body(receive)
@@ -54,13 +55,16 @@ class Middleware:
response = await self._get_response(scope, cached_receive, subdomain_path) response = await self._get_response(scope, cached_receive, subdomain_path)
if response.status_code < 400: if response.status_code < 400:
await self._send(response, scope, cached_receive, send) await self._send(response, scope, cached_receive, send)
finalize_log(scope["log"], response.status_code)
return return
response = await self._get_response(scope, cached_receive, original_path) response = await self._get_response(scope, cached_receive, original_path)
await self._send(response, scope, cached_receive, send) await self._send(response, scope, cached_receive, send)
finalize_log(scope["log"], response.status_code)
else: else:
response = await self._get_response(scope, cached_receive, scope["path"]) response = await self._get_response(scope, cached_receive, scope["path"])
await self._send(response, scope, cached_receive, send) await self._send(response, scope, cached_receive, send)
finalize_log(scope["log"], response.status_code)
async def _get_response(self, scope: Scope, receive: Receive, path: str) -> Response: async def _get_response(self, scope: Scope, receive: Receive, path: str) -> Response:
new_scope = dict(scope, path=path) new_scope = dict(scope, path=path)