Files
contact.allucanget.biz/server/middleware.py
zwitschi b5a0817760
All checks were successful
CI / test (3.11) (push) Successful in 8s
CI / build-image (push) Successful in 46s
fix: format code for better readability and add CORS handling for OPTIONS requests
2025-10-30 13:06:08 +01:00

90 lines
3.1 KiB
Python

"""HTTP middleware helpers (Flask request hooks)."""
from __future__ import annotations
import logging
import time
from flask import Flask, g, request
from . import settings
from .metrics import observe_request
from .utils import generate_request_id
def register_request_hooks(app: Flask) -> None:
"""Attach before/after request handlers for logging and correlation."""
@app.before_request
def attach_request_id_and_log(): # type: ignore[unused-ignore]
rid = request.headers.get("X-Request-Id")
if not rid:
rid = generate_request_id()
request.environ["HTTP_X_REQUEST_ID"] = rid
request.request_id = rid # type: ignore[attr-defined]
if settings.ENABLE_REQUEST_LOGS:
try:
logging.info(
"request.start",
extra={
"request_id": rid,
"method": request.method,
"path": request.path,
"remote_addr": request.remote_addr,
},
)
except Exception:
pass
try:
g._start_time = time.time()
except Exception:
g._start_time = None # type: ignore[attr-defined]
@app.after_request
def add_request_id_header(response): # type: ignore[unused-ignore]
try:
rid = getattr(request, "request_id", None) or request.environ.get(
"HTTP_X_REQUEST_ID")
if rid:
response.headers["X-Request-Id"] = rid
if settings.ENABLE_REQUEST_LOGS:
try:
logging.info(
"request.end",
extra={
"request_id": rid,
"status": response.status_code,
"path": request.path,
},
)
except Exception:
pass
start_time = getattr(g, "_start_time", None)
observe_request(request.method, request.path,
start_time, response.status_code)
except Exception:
pass
return response
@app.after_request
def add_cors_headers(response): # type: ignore[unused-ignore]
# Add CORS headers for embedded forms
if request.path.startswith("/api/"):
response.headers["Access-Control-Allow-Origin"] = "*"
response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS"
response.headers["Access-Control-Allow-Headers"] = "Content-Type, Authorization"
return response
@app.before_request
def handle_options(): # type: ignore[unused-ignore]
if request.method == "OPTIONS":
response = app.response_class()
response.headers["Access-Control-Allow-Origin"] = "*"
response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS"
response.headers["Access-Control-Allow-Headers"] = "Content-Type, Authorization"
return response