Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/a2a/server/apps/jsonrpc/fastapi_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,35 +66,38 @@
(SSE).
"""

def __init__( # noqa: PLR0913
self,
agent_card: AgentCard,
http_handler: RequestHandler,
extended_agent_card: AgentCard | None = None,
context_builder: CallContextBuilder | None = None,
card_modifier: Callable[[AgentCard], AgentCard] | None = None,
extended_card_modifier: Callable[
[AgentCard, ServerCallContext], AgentCard
]
| None = None,
disable_content_length_check: bool = False,
) -> None:
"""Initializes the A2AFastAPIApplication.

Args:
agent_card: The AgentCard describing the agent's capabilities.
http_handler: The handler instance responsible for processing A2A
requests via http.
extended_agent_card: An optional, distinct AgentCard to be served
at the authenticated extended card endpoint.
context_builder: The CallContextBuilder used to construct the
ServerCallContext passed to the http_handler. If None, no
ServerCallContext is passed.
card_modifier: An optional callback to dynamically modify the public
agent card before it is served.
extended_card_modifier: An optional callback to dynamically modify
the extended agent card before it is served. It receives the
call context.
disable_content_length_check: An optional, if True disables the check
for oversized payloads.
"""

Check notice on line 100 in src/a2a/server/apps/jsonrpc/fastapi_app.py

View workflow job for this annotation

GitHub Actions / Lint Code Base

Copy/pasted code

see src/a2a/server/apps/rest/rest_adapter.py (55-82)
if not _package_fastapi_installed:
raise ImportError(
'The `fastapi` package is required to use the `A2AFastAPIApplication`.'
Expand All @@ -108,6 +111,7 @@
context_builder=context_builder,
card_modifier=card_modifier,
extended_card_modifier=extended_card_modifier,
disable_content_length_check=disable_content_length_check,
)

def add_routes_to_app(
Expand Down
30 changes: 19 additions & 11 deletions src/a2a/server/apps/jsonrpc/jsonrpc_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,35 +174,38 @@
for model in A2ARequestModel.__args__
}

def __init__( # noqa: PLR0913
self,
agent_card: AgentCard,
http_handler: RequestHandler,
extended_agent_card: AgentCard | None = None,
context_builder: CallContextBuilder | None = None,
card_modifier: Callable[[AgentCard], AgentCard] | None = None,
extended_card_modifier: Callable[
[AgentCard, ServerCallContext], AgentCard
]
| None = None,
disable_content_length_check: bool = False,
) -> None:
"""Initializes the JSONRPCApplication.

Args:
agent_card: The AgentCard describing the agent's capabilities.
http_handler: The handler instance responsible for processing A2A
requests via http.
extended_agent_card: An optional, distinct AgentCard to be served
at the authenticated extended card endpoint.
context_builder: The CallContextBuilder used to construct the
ServerCallContext passed to the http_handler. If None, no
ServerCallContext is passed.
card_modifier: An optional callback to dynamically modify the public
agent card before it is served.
extended_card_modifier: An optional callback to dynamically modify
the extended agent card before it is served. It receives the
call context.
disable_content_length_check: An optional, if True disables the check
for oversized payloads.
"""

Check notice on line 208 in src/a2a/server/apps/jsonrpc/jsonrpc_app.py

View workflow job for this annotation

GitHub Actions / Lint Code Base

Copy/pasted code

see src/a2a/server/apps/rest/rest_adapter.py (55-82)
if not _package_starlette_installed:
raise ImportError(
'Packages `starlette` and `sse-starlette` are required to use the'
Expand All @@ -220,6 +223,7 @@
extended_card_modifier=extended_card_modifier,
)
self._context_builder = context_builder or DefaultCallContextBuilder()
self._disable_content_length_check = disable_content_length_check

def _generate_error_response(
self, request_id: str | int | None, error: JSONRPCError | A2AError
Expand Down Expand Up @@ -261,7 +265,7 @@
status_code=200,
)

async def _handle_requests(self, request: Request) -> Response: # noqa: PLR0911

Check failure on line 268 in src/a2a/server/apps/jsonrpc/jsonrpc_app.py

View workflow job for this annotation

GitHub Actions / Lint Code Base

Ruff (PLR0912)

src/a2a/server/apps/jsonrpc/jsonrpc_app.py:268:15: PLR0912 Too many branches (13 > 12)
"""Handles incoming POST requests to the main A2A endpoint.

Parses the request body as JSON, validates it against A2A request types,
Expand Down Expand Up @@ -291,18 +295,22 @@
request_id, str | int
):
request_id = None
# Treat very large payloads as invalid request (-32600) before routing
with contextlib.suppress(Exception):
content_length = int(request.headers.get('content-length', '0'))
if content_length and content_length > MAX_CONTENT_LENGTH:
return self._generate_error_response(
request_id,
A2AError(
root=InvalidRequestError(
message='Payload too large'
)
),
# If content lenght check is not diasbled,

Check failure on line 298 in src/a2a/server/apps/jsonrpc/jsonrpc_app.py

View workflow job for this annotation

GitHub Actions / Check Spelling

`diasbled` is not a recognized word. (unrecognized-spelling)

Check failure on line 298 in src/a2a/server/apps/jsonrpc/jsonrpc_app.py

View workflow job for this annotation

GitHub Actions / Check Spelling

`lenght` is not a recognized word. (unrecognized-spelling)
# treat very large payloads as invalid request (-32600) before routing
if not self._disable_content_length_check:
with contextlib.suppress(Exception):
content_length = int(
request.headers.get('content-length', '0')
)
if content_length and content_length > MAX_CONTENT_LENGTH:
return self._generate_error_response(
request_id,
A2AError(
root=InvalidRequestError(
message='Payload too large'
)
),
)
logger.debug('Request body: %s', body)
# 1) Validate base JSON-RPC structure only (-32600 on failure)
try:
Expand Down
4 changes: 4 additions & 0 deletions src/a2a/server/apps/jsonrpc/starlette_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,18 @@
(SSE).
"""

def __init__( # noqa: PLR0913
self,
agent_card: AgentCard,
http_handler: RequestHandler,
extended_agent_card: AgentCard | None = None,
context_builder: CallContextBuilder | None = None,
card_modifier: Callable[[AgentCard], AgentCard] | None = None,
extended_card_modifier: Callable[
[AgentCard, ServerCallContext], AgentCard
]
| None = None,
disable_content_length_check: bool = False,

Check notice on line 62 in src/a2a/server/apps/jsonrpc/starlette_app.py

View workflow job for this annotation

GitHub Actions / Lint Code Base

Copy/pasted code

see src/a2a/server/apps/rest/rest_adapter.py (55-66)
) -> None:
"""Initializes the A2AStarletteApplication.

Expand All @@ -76,6 +77,8 @@
extended_card_modifier: An optional callback to dynamically modify
the extended agent card before it is served. It receives the
call context.
disable_content_length_check: An optional, if True disables the check
for oversized payloads.
"""
if not _package_starlette_installed:
raise ImportError(
Expand All @@ -90,6 +93,7 @@
context_builder=context_builder,
card_modifier=card_modifier,
extended_card_modifier=extended_card_modifier,
disable_content_length_check=disable_content_length_check,
)

def routes(
Expand Down
26 changes: 26 additions & 0 deletions tests/server/apps/jsonrpc/test_serialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,32 @@ def test_handle_oversized_payload(agent_card_with_api_key: AgentCard):
assert data['error']['code'] == InvalidRequestError().code


def test_handle_oversized_payload_with_check_disabled(
agent_card_with_api_key: AgentCard,
):
"""Test handling of oversized JSON payloads when the check is disabled."""
handler = mock.AsyncMock()
app_instance = A2AStarletteApplication(
agent_card_with_api_key, handler, disable_content_length_check=True
)
client = TestClient(app_instance.build())

large_string = 'a' * 11 * 1_000_000 # 11MB string
payload = {
'jsonrpc': '2.0',
'method': 'test',
'id': 1,
'params': {'data': large_string},
}

response = client.post('/', json=payload)
assert response.status_code == 200
data = response.json()
# With the check disabled, it shouldn't return InvalidRequestError due to size.
# It will likely error out deeper in the handler, but not with the size-specific code.
assert data['error']['code'] != InvalidRequestError().code


def test_handle_unicode_characters(agent_card_with_api_key: AgentCard):
"""Test handling of unicode characters in JSON payload."""
handler = mock.AsyncMock()
Expand Down
Loading