mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-09 03:18:44 +00:00
fix - checking proxy settings (#11947)
This commit is contained in:
parent
a44ff7c486
commit
cde20cf825
3 changed files with 79 additions and 1 deletions
|
|
@ -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.
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue