2828 ("POST" , {"Content-Type" : "text/plain" }, "{}" , 415 ),
2929 ("POST" , {"Content-Type" : "application/json" }, "invalid" , 400 ),
3030 ("POST" , {"Content-Type" : "application/json" }, "null" , 400 ),
31- ("POST" , {"Content-Type" : "application/json" }, "[]" , 501 ),
31+ ("POST" , {"Content-Type" : "application/json" }, "[]" , 400 ),
32+ ("POST" , {"Content-Type" : "application/json" }, '[{"jsonrpc":"2.0","method":"probe","id":1}]' , 501 ),
3233 ("GET" , {"Accept" : "application/json" }, "" , 406 ),
3334 ("GET" , {"Accept" : "text/event-stream" }, "" , 400 ),
3435 ("GET" , {"Accept" : "text/event-stream" , CONNECTION_ID_HEADER : "unknown" }, "" , 404 ),
@@ -47,6 +48,35 @@ async def test_http_errors(method: str, headers: dict[str, str], body: str, stat
4748 assert "error" in response .json ()
4849
4950
51+ @pytest .mark .asyncio
52+ @pytest .mark .parametrize (
53+ ("payload" , "code" ),
54+ [
55+ ("invalid json" , - 32700 ),
56+ ("null" , - 32600 ),
57+ ("[]" , - 32600 ),
58+ ("{}" , - 32600 ),
59+ ("true" , - 32600 ),
60+ ("42" , - 32600 ),
61+ ('"text"' , - 32600 ),
62+ ],
63+ )
64+ async def test_invalid_post_returns_protocol_error_without_losing_connection (payload : str , code : int ) -> None :
65+ app = create_asgi_app (lambda conn : TestAgent ())
66+ async with (
67+ app .router .lifespan_context (app ),
68+ httpx2 .AsyncClient (transport = httpx2 .ASGITransport (app = app ), base_url = "http://test" ) as client ,
69+ ):
70+ initialized = await client .post ("/acp" , json = INITIALIZE )
71+ headers = {"Content-Type" : "application/json" , CONNECTION_ID_HEADER : initialized .headers [CONNECTION_ID_HEADER ]}
72+ response = await client .post ("/acp" , content = payload , headers = headers )
73+ assert response .status_code == 400
74+ body = response .json ()
75+ assert body ["jsonrpc" ] == "2.0" and body ["id" ] is None
76+ assert body ["error" ]["code" ] == code
77+ assert (await client .delete ("/acp" , headers = headers )).status_code == 202
78+
79+
5080@pytest .mark .asyncio
5181@pytest .mark .parametrize ("method" , ["PUT" , "OPTIONS" ])
5282async def test_unsupported_methods_do_not_open_a_stream (method : str ) -> None :
0 commit comments