fix - checking proxy settings (#11947)

This commit is contained in:
Ishaan Jaff 2025-06-23 09:30:40 -07:00 • committed by GitHub
parent a44ff7c486
commit cde20cf825
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 79 additions and 1 deletions

View file

@ -324,6 +324,7 @@ use_aiohttp_transport: bool = (
True # Older variable, aiohttp is now the default. use disable_aiohttp_transport instead.
)
disable_aiohttp_transport: bool = False # Set this to true to use httpx instead
disable_aiohttp_trust_env: bool = False # When False, aiohttp will respect HTTP(S)_PROXY env vars
force_ipv4: bool = (
False # when True, litellm will force ipv4 for all LLM requests. Some users have seen httpx ConnectionError when using ipv6.
)

View file

@ -1,6 +1,8 @@
import asyncio
import contextlib
import os
import typing
import urllib.request
from typing import Callable, Dict, Union
import aiohttp
@ -9,7 +11,9 @@ import aiohttp.http_exceptions
import httpx
from aiohttp.client import ClientResponse, ClientSession
import litellm
from litellm._logging import verbose_logger
from litellm.secret_managers.main import str_to_bool
AIOHTTP_EXC_MAP: Dict = {
# Order matters here, most specific exception first
@ -182,7 +186,7 @@ class LiteLLMAiohttpTransport(AiohttpTransport):
self.client = ClientSession()
return self.client
async def handle_async_request(
self,
request: httpx.Request,
@ -196,6 +200,9 @@ class LiteLLMAiohttpTransport(AiohttpTransport):
# Use helper to ensure we have a valid session for the current event loop
client_session = self._get_valid_client_session()
# Resolve proxy settings from environment variables
proxy = await self._get_proxy_settings(request)
with map_aiohttp_exceptions():
try:
data = request.content
@ -215,6 +222,7 @@ class LiteLLMAiohttpTransport(AiohttpTransport):
sock_read=timeout.get("read"),
connect=timeout.get("pool"),
),
proxy=proxy,
server_hostname=sni_hostname,
).__aenter__()
@ -224,3 +232,29 @@ class LiteLLMAiohttpTransport(AiohttpTransport):
content=AiohttpResponseStream(response),
request=request,
)
async def _get_proxy_settings(self, request: httpx.Request):
proxy = None
if not (
litellm.disable_aiohttp_trust_env
or str_to_bool(os.getenv("DISABLE_AIOHTTP_TRUST_ENV", "False"))
):
try:
proxy = self._proxy_from_env(request.url)
except Exception as e: # pragma: no cover - best effort
verbose_logger.debug(f"Error reading proxy env: {e}")
return proxy
def _proxy_from_env(self, url: httpx.URL) -> typing.Optional[str]:
"""Return proxy URL from env for the given request URL."""
proxies = urllib.request.getproxies()
if urllib.request.proxy_bypass(url.host):
return None
proxy = proxies.get(url.scheme) or proxies.get("all")
if proxy and "://" not in proxy:
proxy = f"http://{proxy}"
return proxy

View file

@ -176,3 +176,46 @@ async def test_timeout_exception_gets_mapped():
# Should have received the first chunk before the error
assert received_chunks == [b"chunk1"]
@pytest.mark.asyncio
async def test_handle_async_request_uses_env_proxy(monkeypatch):
"""Aiohttp transport should honor HTTP(S)_PROXY env vars"""
proxy_url = "http://proxy.local:3128"
monkeypatch.setenv("HTTP_PROXY", proxy_url)
monkeypatch.setenv("http_proxy", proxy_url)
monkeypatch.setenv("HTTPS_PROXY", proxy_url)
monkeypatch.setenv("https_proxy", proxy_url)
monkeypatch.delenv("DISABLE_AIOHTTP_TRUST_ENV", raising=False)
captured = {}
class FakeSession:
def request(self, *args, **kwargs):
captured["proxy"] = kwargs.get("proxy")
class Resp:
status = 200
headers = {}
async def __aenter__(self):
return self
async def __aexit__(self, exc_type, exc, tb):
pass
@property
def content(self):
class C:
async def iter_chunked(self, size):
yield b""
return C()
return Resp()
transport = LiteLLMAiohttpTransport(client=lambda: FakeSession())
request = httpx.Request("GET", "http://example.com")
await transport.handle_async_request(request)
assert captured["proxy"] == proxy_url