Skip to content

Commit 1024cae

Browse files
committed
Extracting _modify_rpc_url into a update_card_rpc_url_from_request util function
1 parent 497aa31 commit 1024cae

File tree

3 files changed

+82
-112
lines changed

3 files changed

+82
-112
lines changed

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

Lines changed: 4 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from a2a.server.context import ServerCallContext
1919
from a2a.server.request_handlers.jsonrpc_handler import JSONRPCHandler
2020
from a2a.server.request_handlers.request_handler import RequestHandler
21+
from a2a.server.request_utils import update_card_rpc_url_from_request
2122
from a2a.types import (
2223
A2AError,
2324
A2ARequest,
@@ -58,7 +59,6 @@
5859
from sse_starlette.sse import EventSourceResponse
5960
from starlette.applications import Starlette
6061
from starlette.authentication import BaseUser
61-
from starlette.datastructures import URL
6262
from starlette.exceptions import HTTPException
6363
from starlette.requests import Request
6464
from starlette.responses import JSONResponse, Response
@@ -71,7 +71,6 @@
7171
from sse_starlette.sse import EventSourceResponse
7272
from starlette.applications import Starlette
7373
from starlette.authentication import BaseUser
74-
from starlette.datastructures import URL
7574
from starlette.exceptions import HTTPException
7675
from starlette.requests import Request
7776
from starlette.responses import JSONResponse, Response
@@ -89,6 +88,7 @@
8988
Request = Any
9089
JSONResponse = Any
9190
Response = Any
91+
URL = Any
9292
HTTP_413_REQUEST_ENTITY_TOO_LARGE = Any
9393

9494

@@ -492,58 +492,6 @@ async def event_generator(
492492
headers=headers,
493493
)
494494

495-
def _modify_rpc_url(self, agent_card: AgentCard, request: Request) -> None:
496-
"""Modifies Agent's RPC URL based on the AgentCard request.
497-
498-
Args:
499-
agent_card (AgentCard): Original AgentCard
500-
request (Request): AgentCard request
501-
"""
502-
rpc_url = URL(agent_card.url)
503-
rpc_path = rpc_url.path
504-
port = None
505-
if 'X-Forwarded-Host' in request.headers:
506-
host = request.headers['X-Forwarded-Host']
507-
else:
508-
host = request.url.hostname or rpc_url.hostname or 'localhost'
509-
port = request.url.port
510-
511-
if 'X-Forwarded-Proto' in request.headers:
512-
scheme = request.headers['X-Forwarded-Proto']
513-
port = None
514-
else:
515-
scheme = request.url.scheme
516-
if not scheme:
517-
scheme = 'http'
518-
if ':' in host: # type: ignore
519-
comps = host.rsplit(':', 1) # type: ignore
520-
host = comps[0]
521-
port = int(comps[1]) if comps[1] else port
522-
523-
# Handle URL maps,
524-
# e.g. "agents/my-agent/.well-known/agent-card.json"
525-
if 'X-Forwarded-Path' in request.headers:
526-
forwarded_path = request.headers['X-Forwarded-Path'].strip()
527-
if (
528-
forwarded_path
529-
and request.url.path != forwarded_path
530-
and forwarded_path.endswith(request.url.path)
531-
):
532-
# "agents/my-agent" for "agents/my-agent/.well-known/agent-card.json"
533-
extra_path = forwarded_path[: -len(request.url.path)]
534-
new_path = extra_path + rpc_path
535-
# If original path was just "/",
536-
# we remove trailing "/" in the extended one
537-
if len(new_path) > 1 and rpc_path == '/':
538-
new_path = new_path.rstrip('/')
539-
rpc_path = new_path
540-
541-
agent_card.url = str(
542-
rpc_url.replace(
543-
hostname=host, port=port, scheme=scheme, path=rpc_path
544-
)
545-
)
546-
547495
async def _handle_get_agent_card(self, request: Request) -> JSONResponse:
548496
"""Handles GET requests for the agent card endpoint.
549497
@@ -567,7 +515,7 @@ async def _handle_get_agent_card(self, request: Request) -> JSONResponse:
567515
card_to_serve = self.card_modifier(card_to_serve)
568516
# If agent's RPC URL was not modified, we build it dynamically.
569517
if rpc_url == card_to_serve.url:
570-
self._modify_rpc_url(card_to_serve, request)
518+
update_card_rpc_url_from_request(card_to_serve, request)
571519

572520
return JSONResponse(
573521
card_to_serve.model_dump(
@@ -602,7 +550,7 @@ async def _handle_get_authenticated_extended_agent_card(
602550
if card_to_serve:
603551
# If agent's RPC URL was not modified, we build it dynamically.
604552
if rpc_url == card_to_serve.url:
605-
self._modify_rpc_url(card_to_serve, request)
553+
update_card_rpc_url_from_request(card_to_serve, request)
606554
return JSONResponse(
607555
card_to_serve.model_dump(
608556
exclude_none=True,

src/a2a/server/apps/rest/rest_adapter.py

Lines changed: 3 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
if TYPE_CHECKING:
99
from sse_starlette.sse import EventSourceResponse
10-
from starlette.datastructures import URL
1110
from starlette.requests import Request
1211
from starlette.responses import JSONResponse, Response
1312

@@ -16,7 +15,6 @@
1615
else:
1716
try:
1817
from sse_starlette.sse import EventSourceResponse
19-
from starlette.datastructures import URL
2018
from starlette.requests import Request
2119
from starlette.responses import JSONResponse, Response
2220

@@ -36,6 +34,7 @@
3634
from a2a.server.context import ServerCallContext
3735
from a2a.server.request_handlers.request_handler import RequestHandler
3836
from a2a.server.request_handlers.rest_handler import RESTHandler
37+
from a2a.server.request_utils import update_card_rpc_url_from_request
3938
from a2a.types import AgentCard, AuthenticatedExtendedCardNotConfiguredError
4039
from a2a.utils.error_handlers import (
4140
rest_error_handler,
@@ -151,7 +150,7 @@ async def handle_get_agent_card(
151150
if self.card_modifier:
152151
card_to_serve = self.card_modifier(card_to_serve)
153152
if rpc_url == card_to_serve.url:
154-
self._modify_rpc_url(card_to_serve, request)
153+
update_card_rpc_url_from_request(card_to_serve, request)
155154

156155
return card_to_serve.model_dump(mode='json', exclude_none=True)
157156

@@ -188,62 +187,10 @@ async def handle_authenticated_agent_card(
188187
base_card = card_to_serve if card_to_serve else self.agent_card
189188
card_to_serve = self.extended_card_modifier(base_card, context)
190189
if rpc_url == card_to_serve.url:
191-
self._modify_rpc_url(card_to_serve, request)
190+
update_card_rpc_url_from_request(card_to_serve, request)
192191

193192
return card_to_serve.model_dump(mode='json', exclude_none=True)
194193

195-
def _modify_rpc_url(self, agent_card: AgentCard, request: Request) -> None:
196-
"""Modifies Agent's RPC URL based on the AgentCard request.
197-
198-
Args:
199-
agent_card (AgentCard): Original AgentCard
200-
request (Request): AgentCard request
201-
"""
202-
rpc_url = URL(agent_card.url)
203-
rpc_path = rpc_url.path
204-
port = None
205-
if 'X-Forwarded-Host' in request.headers:
206-
host = request.headers['X-Forwarded-Host']
207-
else:
208-
host = request.url.hostname or rpc_url.hostname or 'localhost'
209-
port = request.url.port
210-
211-
if 'X-Forwarded-Proto' in request.headers:
212-
scheme = request.headers['X-Forwarded-Proto']
213-
port = None
214-
else:
215-
scheme = request.url.scheme
216-
if not scheme:
217-
scheme = 'http'
218-
if ':' in host: # type: ignore
219-
comps = host.rsplit(':', 1) # type: ignore
220-
host = comps[0]
221-
port = int(comps[1]) if comps[1] else port
222-
223-
# Handle URL maps,
224-
# e.g. "agents/my-agent/.well-known/agent-card.json"
225-
if 'X-Forwarded-Path' in request.headers:
226-
forwarded_path = request.headers['X-Forwarded-Path'].strip()
227-
if (
228-
forwarded_path
229-
and request.url.path != forwarded_path
230-
and forwarded_path.endswith(request.url.path)
231-
):
232-
# "agents/my-agent" for "agents/my-agent/.well-known/agent-card.json"
233-
extra_path = forwarded_path[: -len(request.url.path)]
234-
new_path = extra_path + rpc_path
235-
# If original path was just "/",
236-
# we remove trailing "/" in the extended one
237-
if len(new_path) > 1 and rpc_path == '/':
238-
new_path = new_path.rstrip('/')
239-
rpc_path = new_path
240-
241-
agent_card.url = str(
242-
rpc_url.replace(
243-
hostname=host, port=port, scheme=scheme, path=rpc_path
244-
)
245-
)
246-
247194
def routes(self) -> dict[tuple[str, str], Callable[[Request], Any]]:
248195
"""Constructs a dictionary of API routes and their corresponding handlers.
249196

src/a2a/server/request_utils.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
from typing import TYPE_CHECKING, Any
2+
3+
from a2a.types import AgentCard
4+
5+
if TYPE_CHECKING:
6+
from starlette.datastructures import URL
7+
from starlette.requests import Request
8+
9+
_package_starlette_installed = True
10+
else:
11+
try:
12+
from starlette.datastructures import URL
13+
from starlette.requests import Request
14+
15+
_package_starlette_installed = True
16+
except ImportError:
17+
_package_starlette_installed = False
18+
URL = Any
19+
Request = Any
20+
21+
22+
def update_card_rpc_url_from_request(
23+
agent_card: AgentCard,
24+
request: Request
25+
) -> None:
26+
"""Modifies Agent's RPC URL based on the AgentCard request.
27+
28+
Args:
29+
agent_card (AgentCard): Original AgentCard
30+
request (Request): AgentCard request
31+
"""
32+
rpc_url = URL(agent_card.url)
33+
rpc_path = rpc_url.path
34+
port = None
35+
if 'X-Forwarded-Host' in request.headers:
36+
host = request.headers['X-Forwarded-Host']
37+
else:
38+
host = request.url.hostname or rpc_url.hostname or 'localhost'
39+
port = request.url.port
40+
41+
if 'X-Forwarded-Proto' in request.headers:
42+
scheme = request.headers['X-Forwarded-Proto']
43+
port = None
44+
else:
45+
scheme = request.url.scheme
46+
if not scheme:
47+
scheme = 'http'
48+
if ':' in host: # type: ignore
49+
comps = host.rsplit(':', 1) # type: ignore
50+
host = comps[0]
51+
port = int(comps[1]) if comps[1] else port
52+
53+
# Handle URL maps,
54+
# e.g. "agents/my-agent/.well-known/agent-card.json"
55+
if 'X-Forwarded-Path' in request.headers:
56+
forwarded_path = request.headers['X-Forwarded-Path'].strip()
57+
if (
58+
forwarded_path
59+
and request.url.path != forwarded_path
60+
and forwarded_path.endswith(request.url.path)
61+
):
62+
# "agents/my-agent" for "agents/my-agent/.well-known/agent-card.json"
63+
extra_path = forwarded_path[: -len(request.url.path)]
64+
new_path = extra_path + rpc_path
65+
# If original path was just "/",
66+
# we remove trailing "/" in the extended one
67+
if len(new_path) > 1 and rpc_path == '/':
68+
new_path = new_path.rstrip('/')
69+
rpc_path = new_path
70+
71+
agent_card.url = str(
72+
rpc_url.replace(
73+
hostname=host, port=port, scheme=scheme, path=rpc_path
74+
)
75+
)

0 commit comments

Comments
 (0)