Skip to content

Commit b8f15eb

Browse files
committed
Define instance variable max_content_length. This commit depricates hardcoded MAX_CONTENT_LENGTH and introduces an instance variable max_content_length.
1 parent 22b111a commit b8f15eb

File tree

4 files changed

+36
-29
lines changed

4 files changed

+36
-29
lines changed

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ def __init__( # noqa: PLR0913
7777
[AgentCard, ServerCallContext], AgentCard
7878
]
7979
| None = None,
80-
disable_content_length_check: bool = False,
80+
max_content_length: int | None = 10 * 1024 * 1024, # 10MB
8181
) -> None:
8282
"""Initializes the A2AFastAPIApplication.
8383
@@ -95,8 +95,8 @@ def __init__( # noqa: PLR0913
9595
extended_card_modifier: An optional callback to dynamically modify
9696
the extended agent card before it is served. It receives the
9797
call context.
98-
disable_content_length_check: An optional, if True disables the check
99-
for oversized payloads.
98+
max_content_length: The maximum allowed content length for incoming
99+
requests. Defaults to 10MB. Set to None for unbounded maximum.
100100
"""
101101
if not _package_fastapi_installed:
102102
raise ImportError(
@@ -111,7 +111,7 @@ def __init__( # noqa: PLR0913
111111
context_builder=context_builder,
112112
card_modifier=card_modifier,
113113
extended_card_modifier=extended_card_modifier,
114-
disable_content_length_check=disable_content_length_check,
114+
max_content_length=max_content_length,
115115
)
116116

117117
def add_routes_to_app(

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

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,6 @@
9191
Response = Any
9292
HTTP_413_REQUEST_ENTITY_TOO_LARGE = Any
9393

94-
MAX_CONTENT_LENGTH = 10_000_000
95-
9694

9795
class StarletteUserProxy(A2AUser):
9896
"""Adapts the Starlette User class to the A2A user representation."""
@@ -134,7 +132,7 @@ def build(self, request: Request) -> ServerCallContext:
134132
"""
135133
user: A2AUser = UnauthenticatedUser()
136134
state = {}
137-
with contextlib.suppress(Exception):
135+
with contextlib.suppress(AttributeError):
138136
user = StarletteUserProxy(request.user)
139137
state['auth'] = request.auth
140138
state['headers'] = dict(request.headers)
@@ -185,7 +183,7 @@ def __init__( # noqa: PLR0913
185183
[AgentCard, ServerCallContext], AgentCard
186184
]
187185
| None = None,
188-
disable_content_length_check: bool = False,
186+
max_content_length: int | None = 10 * 1024 * 1024, # 10MB
189187
) -> None:
190188
"""Initializes the JSONRPCApplication.
191189
@@ -203,8 +201,8 @@ def __init__( # noqa: PLR0913
203201
extended_card_modifier: An optional callback to dynamically modify
204202
the extended agent card before it is served. It receives the
205203
call context.
206-
disable_content_length_check: An optional, if True disables the check
207-
for oversized payloads.
204+
max_content_length: The maximum allowed content length for incoming
205+
requests. Defaults to 10MB. Set to None for unbounded maximum.
208206
"""
209207
if not _package_starlette_installed:
210208
raise ImportError(
@@ -223,7 +221,7 @@ def __init__( # noqa: PLR0913
223221
extended_card_modifier=extended_card_modifier,
224222
)
225223
self._context_builder = context_builder or DefaultCallContextBuilder()
226-
self._disable_content_length_check = disable_content_length_check
224+
self._max_content_length = max_content_length
227225

228226
def _generate_error_response(
229227
self, request_id: str | int | None, error: JSONRPCError | A2AError
@@ -265,19 +263,19 @@ def _generate_error_response(
265263
status_code=200,
266264
)
267265

268-
def _check_content_length(self, request: Request) -> bool:
269-
"""Checks if the request content length exceeds the maximum allowed size.
266+
def _allowed_content_length(self, request: Request) -> bool:
267+
"""Checks if the request content length is within the allowed maximum.
270268
271269
Args:
272270
request: The incoming Starlette Request object.
273271
274272
Returns:
275-
True if the content length is within the allowed limit, False otherwise.
273+
False if the content length is larger than the allowed maximum, True otherwise.
276274
"""
277-
if not self._disable_content_length_check:
278-
with contextlib.suppress(Exception):
275+
if self._max_content_length is not None:
276+
with contextlib.suppress(ValueError):
279277
content_length = int(request.headers.get('content-length', '0'))
280-
if content_length and content_length > MAX_CONTENT_LENGTH:
278+
if content_length and content_length > self._max_content_length:
281279
return False
282280
return True
283281

@@ -311,9 +309,8 @@ async def _handle_requests(self, request: Request) -> Response: # noqa: PLR0911
311309
request_id, str | int
312310
):
313311
request_id = None
314-
# If content length check is not disabled,
315-
# treat very large payloads as invalid request (-32600) before routing
316-
if not self._check_content_length(request):
312+
# Treat payloads lager than allowed as invalid request (-32600) before routing
313+
if not self._allowed_content_length(request):
317314
return self._generate_error_response(
318315
request_id,
319316
A2AError(

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def __init__( # noqa: PLR0913
5959
[AgentCard, ServerCallContext], AgentCard
6060
]
6161
| None = None,
62-
disable_content_length_check: bool = False,
62+
max_content_length: int | None = 10 * 1024 * 1024, # 10MB
6363
) -> None:
6464
"""Initializes the A2AStarletteApplication.
6565
@@ -77,8 +77,8 @@ def __init__( # noqa: PLR0913
7777
extended_card_modifier: An optional callback to dynamically modify
7878
the extended agent card before it is served. It receives the
7979
call context.
80-
disable_content_length_check: An optional, if True disables the check
81-
for oversized payloads.
80+
max_content_length: The maximum allowed content length for incoming
81+
requests. Defaults to 10MB. Set to None for unbounded maximum.
8282
"""
8383
if not _package_starlette_installed:
8484
raise ImportError(
@@ -93,7 +93,7 @@ def __init__( # noqa: PLR0913
9393
context_builder=context_builder,
9494
card_modifier=card_modifier,
9595
extended_card_modifier=extended_card_modifier,
96-
disable_content_length_check=disable_content_length_check,
96+
max_content_length=max_content_length,
9797
)
9898

9999
def routes(

tests/server/apps/jsonrpc/test_serialization.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -136,13 +136,22 @@ def test_handle_oversized_payload(agent_card_with_api_key: AgentCard):
136136
assert data['error']['code'] == InvalidRequestError().code
137137

138138

139-
def test_handle_oversized_payload_with_check_disabled(
139+
@pytest.mark.parametrize(
140+
'max_content_length',
141+
[
142+
None,
143+
11 * 1024 * 1024,
144+
30 * 1024 * 1024,
145+
],
146+
)
147+
def test_handle_oversized_payload_with_max_content_length(
140148
agent_card_with_api_key: AgentCard,
149+
max_content_length: int | None,
141150
):
142-
"""Test handling of oversized JSON payloads when the check is disabled."""
151+
"""Test handling of JSON payloads with sizes within custom max_content_length."""
143152
handler = mock.AsyncMock()
144153
app_instance = A2AStarletteApplication(
145-
agent_card_with_api_key, handler, disable_content_length_check=True
154+
agent_card_with_api_key, handler, max_content_length=max_content_length
146155
)
147156
client = TestClient(app_instance.build())
148157

@@ -157,8 +166,9 @@ def test_handle_oversized_payload_with_check_disabled(
157166
response = client.post('/', json=payload)
158167
assert response.status_code == 200
159168
data = response.json()
160-
# With the check disabled, it shouldn't return InvalidRequestError due to size.
161-
# It will likely error out deeper in the handler, but not with the size-specific code.
169+
# When max_content_length is set, requests up to that size should not be
170+
# rejected due to payload size. The request might fail for other reasons,
171+
# but it shouldn't be an InvalidRequestError related to the content length.
162172
assert data['error']['code'] != InvalidRequestError().code
163173

164174

0 commit comments

Comments
 (0)