#!/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()