diff --git a/api/helpers.py b/api/helpers.py index 679bf713..9a8e7f36 100644 --- a/api/helpers.py +++ b/api/helpers.py @@ -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: diff --git a/tests/test_read_body_json_validation.py b/tests/test_read_body_json_validation.py index a88a0f33..45451519 100644 --- a/tests/test_read_body_json_validation.py +++ b/tests/test_read_body_json_validation.py @@ -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