Skip to content

Commit c2b6068

Browse files
committed
feat: add option to disable oversized payload check in JSONRPC applications
1 parent acdc0de commit c2b6068

File tree

3 files changed

+50
-11
lines changed

3 files changed

+50
-11
lines changed

src/a2a/server/apps/jsonrpc/jsonrpc_app.py

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ def __init__( # noqa: PLR0913
185185
[AgentCard, ServerCallContext], AgentCard
186186
]
187187
| None = None,
188+
disable_content_length_check: bool = False,
188189
) -> None:
189190
"""Initializes the JSONRPCApplication.
190191
@@ -202,6 +203,8 @@ def __init__( # noqa: PLR0913
202203
extended_card_modifier: An optional callback to dynamically modify
203204
the extended agent card before it is served. It receives the
204205
call context.
206+
disable_content_length_check: An optional, if True disables the check
207+
for oversized payloads.
205208
"""
206209
if not _package_starlette_installed:
207210
raise ImportError(
@@ -220,6 +223,7 @@ def __init__( # noqa: PLR0913
220223
extended_card_modifier=extended_card_modifier,
221224
)
222225
self._context_builder = context_builder or DefaultCallContextBuilder()
226+
self._disable_content_length_check = disable_content_length_check
223227

224228
def _generate_error_response(
225229
self, request_id: str | int | None, error: JSONRPCError | A2AError
@@ -291,18 +295,22 @@ async def _handle_requests(self, request: Request) -> Response: # noqa: PLR0911
291295
request_id, str | int
292296
):
293297
request_id = None
294-
# Treat very large payloads as invalid request (-32600) before routing
295-
with contextlib.suppress(Exception):
296-
content_length = int(request.headers.get('content-length', '0'))
297-
if content_length and content_length > MAX_CONTENT_LENGTH:
298-
return self._generate_error_response(
299-
request_id,
300-
A2AError(
301-
root=InvalidRequestError(
302-
message='Payload too large'
303-
)
304-
),
298+
# If content lenght check is not diasbled,
299+
# treat very large payloads as invalid request (-32600) before routing
300+
if not self._disable_content_length_check:
301+
with contextlib.suppress(Exception):
302+
content_length = int(
303+
request.headers.get('content-length', '0')
305304
)
305+
if content_length and content_length > MAX_CONTENT_LENGTH:
306+
return self._generate_error_response(
307+
request_id,
308+
A2AError(
309+
root=InvalidRequestError(
310+
message='Payload too large'
311+
)
312+
),
313+
)
306314
logger.debug('Request body: %s', body)
307315
# 1) Validate base JSON-RPC structure only (-32600 on failure)
308316
try:

src/a2a/server/apps/jsonrpc/starlette_app.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ def __init__( # noqa: PLR0913
5959
[AgentCard, ServerCallContext], AgentCard
6060
]
6161
| None = None,
62+
disable_content_length_check: bool = False,
6263
) -> None:
6364
"""Initializes the A2AStarletteApplication.
6465
@@ -76,6 +77,8 @@ def __init__( # noqa: PLR0913
7677
extended_card_modifier: An optional callback to dynamically modify
7778
the extended agent card before it is served. It receives the
7879
call context.
80+
disable_content_length_check: An optional, if True disables the check
81+
for oversized payloads.
7982
"""
8083
if not _package_starlette_installed:
8184
raise ImportError(
@@ -90,6 +93,7 @@ def __init__( # noqa: PLR0913
9093
context_builder=context_builder,
9194
card_modifier=card_modifier,
9295
extended_card_modifier=extended_card_modifier,
96+
disable_content_length_check=disable_content_length_check,
9397
)
9498

9599
def routes(

tests/server/apps/jsonrpc/test_serialization.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from pydantic import ValidationError
77
from starlette.testclient import TestClient
88

9+
from a2a.server.apps.jsonrpc.jsonrpc_app import MAX_CONTENT_LENGTH
910
from a2a.server.apps import A2AFastAPIApplication, A2AStarletteApplication
1011
from a2a.types import (
1112
APIKeySecurityScheme,
@@ -136,6 +137,32 @@ def test_handle_oversized_payload(agent_card_with_api_key: AgentCard):
136137
assert data['error']['code'] == InvalidRequestError().code
137138

138139

140+
def test_handle_oversized_payload_with_check_disabled(
141+
agent_card_with_api_key: AgentCard,
142+
):
143+
"""Test handling of oversized JSON payloads when the check is disabled."""
144+
handler = mock.AsyncMock()
145+
app_instance = A2AStarletteApplication(
146+
agent_card_with_api_key, handler, disable_content_length_check=True
147+
)
148+
client = TestClient(app_instance.build())
149+
150+
large_string = 'a' * 11 * 1_000_000 # 11MB string
151+
payload = {
152+
'jsonrpc': '2.0',
153+
'method': 'test',
154+
'id': 1,
155+
'params': {'data': large_string},
156+
}
157+
158+
response = client.post('/', json=payload)
159+
assert response.status_code == 200
160+
data = response.json()
161+
# With the check disabled, it shouldn't return InvalidRequestError due to size.
162+
# It will likely error out deeper in the handler, but not with the size-specific code.
163+
assert data['error']['code'] != InvalidRequestError().code
164+
165+
139166
def test_handle_unicode_characters(agent_card_with_api_key: AgentCard):
140167
"""Test handling of unicode characters in JSON payload."""
141168
handler = mock.AsyncMock()

0 commit comments

Comments
 (0)