Skip to content

Commit 4a6d986

Browse files
Lukas Geigerclaude
andcommitted
fix(server): drain oversized request body before answering 413
Der Handler sendete bei Content-Length > MAX_REQUEST_SIZE sofort 413 und kehrte zurueck, ohne den angekuendigten Body zu lesen. Waehrend der Client noch 2 MB sendete, schloss der Server die Verbindung -- der Client sah statt der 413-Antwort einen BrokenPipeError. Das machte test_request_larger_than_limit_returns_413 auf den Linux- und macOS-Runnern rot (lokal unter Windows nicht reproduzierbar). Der Body wird jetzt blockweise verworfen, begrenzt auf das Vierfache des Limits. Verifiziert: 52/52 Tests der Smoke-Suite gruen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QnnBmjHnUxYp9ZKcFko4A4
1 parent d56195d commit 4a6d986

1 file changed

Lines changed: 17 additions & 0 deletions

File tree

webapp/server.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,10 @@ def do_POST(self) -> None:
315315
self._send_json({"ok": False, "error": "Leerer Request."}, status=400)
316316
return
317317
if length > MAX_REQUEST_SIZE:
318+
# Erst den angekündigten Body verwerfen, dann antworten: Sonst schließt
319+
# der Server, während der Client noch sendet, und der Client sieht statt
320+
# der 413-Antwort einen BrokenPipeError.
321+
self._drain_request_body(length)
318322
self._send_json(
319323
{"ok": False, "error": "Request ist größer als 2 MB."},
320324
status=413,
@@ -374,6 +378,19 @@ def _send_file_or_404(self, target: Path | None) -> None:
374378
self.end_headers()
375379
self.wfile.write(body)
376380

381+
def _drain_request_body(self, length: int, limit: int = 4 * MAX_REQUEST_SIZE) -> None:
382+
"""Liest einen abgelehnten Request-Body blockweise weg und verwirft ihn.
383+
384+
Begrenzt auf `limit`, damit ein übergroßer Upload den lokalen Server nicht
385+
beschäftigt hält; darüber hinaus wird die Verbindung ohnehin geschlossen.
386+
"""
387+
remaining = min(length, limit)
388+
while remaining > 0:
389+
chunk = self.rfile.read(min(65536, remaining))
390+
if not chunk:
391+
break
392+
remaining -= len(chunk)
393+
377394
def _send_json(self, payload: dict[str, Any], status: int = 200) -> None:
378395
body = json.dumps(payload, ensure_ascii=False, indent=2).encode("utf-8")
379396
self.send_response(status)

0 commit comments

Comments
 (0)