prompt_template/web/handler.py

108 lines
3.6 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
"""
HTTP-Handler für den Template-Server.
Behandelt GET- und PUT-Anfragen für Templates und das Frontend.
"""
import http.server
import logging
from pathlib import Path
from urllib.parse import urlparse
# Support für direkte Ausführung und Package-Import
try:
from .path_validator import PathValidator
from .file_ops import read_file_binary, write_file, directory_exists
from .content_types import get_content_type
except ImportError:
from path_validator import PathValidator
from file_ops import read_file_binary, write_file, directory_exists
from content_types import get_content_type
logger = logging.getLogger(__name__)
MAX_BODY_SIZE = 10 * 1024 * 1024 # 10 MB
class Handler(http.server.SimpleHTTPRequestHandler):
"""HTTP-Handler für Template-Anfragen."""
validator = None # Wird von serve.py gesetzt
directory = None # Wird von serve.py gesetzt
def __init__(self, *args, directory=None, **kwargs):
super().__init__(*args, directory=directory or self.directory, **kwargs)
def do_PUT(self):
"""Speichert eine Template-Datei."""
file_path = self.validator.resolve_template_path(urlparse(self.path).path)
if file_path is None:
self.send_error(403, "Forbidden: Invalid path")
return
# Verzeichnis prüfen - muss existieren
file_dir = Path(file_path).parent
if not directory_exists(str(file_dir)):
self.send_error(404, "Directory not found")
return
# Content-Type prüfen
content_type = self.headers.get("Content-Type", "")
if "text/plain" not in content_type and not content_type.startswith("text/"):
self.send_error(400, "Unsupported content type")
return
# Inhalt lesen und speichern
content_length = int(self.headers.get("Content-Length", 0))
if content_length > MAX_BODY_SIZE:
self.send_error(413, "Request body too large")
return
if content_length <= 0:
self.send_error(400, "No content provided")
return
try:
file_content = self.rfile.read(content_length)
if not write_file(file_path, file_content):
raise Exception("write_file returned False")
response_content_type = get_content_type(file_path)
self.send_response(200)
self.send_header("Content-type", response_content_type)
self.end_headers()
self.wfile.write(b"File saved successfully")
except Exception as e:
logger.error("Failed to save file: %s", e)
self.send_error(500, f"Failed to save file: {e}")
def do_GET(self):
"""Liefert Dateien aus."""
parsed_path = urlparse(self.path).path
# Für Root-Pfad: index.html servieren
if parsed_path == "/" or parsed_path == "/index.html":
self.path = "/index.html"
return super().do_GET()
# Anfragen für /templates.json oder /templates/* umleiten
file_path = self.validator.resolve_template_path(urlparse(self.path).path)
if file_path is not None:
content_type = get_content_type(file_path)
file_content = read_file_binary(file_path)
if file_content is None:
self.send_error(404, "File not found")
return
self.send_response(200)
self.send_header("Content-type", content_type)
self.end_headers()
self.wfile.write(file_content)
return
return super().do_GET()