fix: treat whitespace-only body as empty ({}) not a 400

Gate finding on #7336: read_body() rejected whitespace-only bodies that
worked on master (a body-optional DELETE/PATCH/PUT can send b' \n'), returning
400 Invalid JSON body. Normalize a fully-whitespace body to {} before json.loads,
matching the pre-#7336 lenient behavior for that shape. Adds a parametrized
regression test.

Co-authored-by: zicochaos <zicochaos@users.noreply.github.com>
This commit is contained in:
nandzicochaos committed 2026-09-09 04:21:46 +00:00
1 parent 1f57afd84c
commit 1e17127f49
2 files changed
+14

No files matched your search

+5
View File
@@ -1268,6 +1268,11 @@ def read_body(handler) -> dict:
pass
raise ValueError(f'Request body too large ({length} bytes, max {MAX_BODY_BYTES})')
raw = handler.rfile.read(length) if length else b'{}'
# A body-optional endpoint (e.g. DELETE /api/mcp/servers/{name}) may send a
# whitespace-only body; treat it like an empty body ({}) rather than a 400,
# matching the pre-#7336 lenient behavior for that shape (see gate finding).
if not raw.strip():
return {}
try:
parsed = _json.loads(raw)
except Exception:
+9
View File
@@ -42,6 +42,15 @@ def test_read_body_empty_body_defaults_to_empty_dict():
assert read_body(handler) == {}
@pytest.mark.parametrize("raw", [b" ", b"\n", b" \n\t ", b"\r\n"])
def test_read_body_whitespace_only_body_defaults_to_empty_dict(raw):
"""A body-optional endpoint (e.g. DELETE /api/mcp/servers/{name}) may send a
whitespace-only body; it must be treated like an empty body ({}), not a 400."""
from api.helpers import read_body
assert read_body(_handler(raw)) == {}
@pytest.mark.parametrize("raw", [b"{bad json"])
def test_read_body_raises_on_malformed_json(raw):
from api.helpers import read_body