fix: Rettungsstation loggt auch abgelehnte Methoden und Protokollfehler
do_POST (und PUT/DELETE/HEAD) riefen reject() auf, ohne eine Logzeile zu schreiben, und das ueberschriebene log_message() legte damit unbeabsichtigt auch log_error() lahm (BaseHTTPRequestHandler ruft es standardmaessig auf, z.B. bei einer kaputten Request-Zeile oder einem Timeout, bevor ueberhaupt ein Handler wie do_GET erreicht wird). Fuer das einzige Diagnosewerkzeug im Rettungsfall darf keine Anfrage stumm bleiben. do_POST loggt jetzt wie do_GET explizit, und log_error() ist separat ueberschrieben statt implizit mit log_message() stillgelegt zu werden. Die neuen Tests fuer den 405-Fall lesen den rohen Datei-Deskriptor des Server-Prozesses statt ueber TextIOWrapper.readline() zu gehen - Letzteres kann mehr Zeilen aus der Pipe in den eigenen Puffer lesen, als es zurueckgibt, was select() auf dem naechsten Datei-Deskriptor faelschlich "nichts da" melden liess. Der Test fuer die kaputte Request-Zeile ruft log_error() direkt auf: ein echter kaputter Rohsocket wird in dieser Sandbox von einer Netzwerkschicht abgefangen, bevor er den Server erreicht (sichtbar an einem untergeschobenen "Server: aiohttp"-Header). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
435884039b
commit
1d7d087cff
@@ -138,12 +138,26 @@ class Handler(BaseHTTPRequestHandler):
|
||||
def log_message(self, fmt: str, *args) -> None: # noqa: D102 - quieter default log
|
||||
pass
|
||||
|
||||
def log_error(self, fmt: str, *args) -> None:
|
||||
# BaseHTTPRequestHandler.log_error() calls log_message() by default, which we
|
||||
# silence above in favour of our own log() calls - but that also silences it for
|
||||
# requests that never reach do_GET/do_POST (a malformed request line, a client
|
||||
# timeout mid-request). The station is the only diagnostic tool available during a
|
||||
# rescue, so those cases must still produce a line instead of nothing.
|
||||
try:
|
||||
client = self.client_address[0]
|
||||
except (AttributeError, IndexError):
|
||||
client = "?"
|
||||
print(f"{now_iso()} {client} ERROR {fmt % args}", flush=True)
|
||||
|
||||
def log(self, status: int, nbytes: int, started: float) -> None:
|
||||
print(f"{now_iso()} {self.client_address[0]} {self.path} {status} "
|
||||
f"{nbytes}B {time.monotonic() - started:.1f}s", flush=True)
|
||||
|
||||
def do_POST(self) -> None:
|
||||
started = time.monotonic()
|
||||
self.reject(405, "method not allowed")
|
||||
self.log(405, 0, started)
|
||||
|
||||
do_PUT = do_DELETE = do_HEAD = do_POST
|
||||
|
||||
|
||||
Reference in New Issue
Block a user