mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-21 05:15:06 +00:00
fix: close streaming response in finally block to avoid connection leak on 401
This commit is contained in:
parent
5ef6f4b579
commit
dc4fa82e6f
2 changed files with 36 additions and 2 deletions
|
|
@ -2925,8 +2925,10 @@ class MCPServerManager:
|
|||
handler = get_async_httpx_client(llm_provider=httpxSpecialProvider.MCP)
|
||||
response = await handler.get(server_url, stream=True)
|
||||
status_code = response.status_code
|
||||
response.raise_for_status()
|
||||
await response.aclose()
|
||||
try:
|
||||
response.raise_for_status()
|
||||
finally:
|
||||
await response.aclose()
|
||||
(
|
||||
authorization_servers,
|
||||
resource_scopes,
|
||||
|
|
|
|||
|
|
@ -7097,6 +7097,38 @@ class TestOBOEndpointDiscovery:
|
|||
mock_fetch_auth.assert_not_awaited()
|
||||
assert result is None or result.token_url is None
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_descovery_metadata_closes_stream_on_401_oauth_challenge(self):
|
||||
manager = MCPServerManager()
|
||||
server_url = "https://example.com/mcp"
|
||||
request = httpx.Request("GET", server_url)
|
||||
error_response = MagicMock()
|
||||
error_response.headers = {}
|
||||
|
||||
streaming_response = MagicMock()
|
||||
streaming_response.status_code = 401
|
||||
streaming_response.raise_for_status = MagicMock(
|
||||
side_effect=httpx.HTTPStatusError("unauthorized", request=request, response=error_response)
|
||||
)
|
||||
streaming_response.aclose = AsyncMock()
|
||||
|
||||
mock_handler = MagicMock()
|
||||
mock_handler.get = AsyncMock(return_value=streaming_response)
|
||||
|
||||
with (
|
||||
patch(
|
||||
"litellm.proxy._experimental.mcp_server.mcp_server_manager.get_async_httpx_client",
|
||||
return_value=mock_handler,
|
||||
),
|
||||
patch.object(manager, "_attempt_well_known_discovery", AsyncMock(return_value=([], None))),
|
||||
patch.object(manager, "_fetch_oauth_metadata_from_resource", AsyncMock(return_value=([], None))),
|
||||
patch.object(manager, "_fetch_authorization_server_metadata", AsyncMock(return_value=None)),
|
||||
):
|
||||
result = await manager._descovery_metadata(server_url)
|
||||
|
||||
streaming_response.aclose.assert_awaited_once()
|
||||
assert result is None
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_descovery_metadata_returns_none_for_no_auth_sse_server(self):
|
||||
manager = MCPServerManager()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue