141141from langchain_openai .data ._profiles import _PROFILES
142142
143143if TYPE_CHECKING :
144+ import httpx
144145 from langchain_core .language_models import ModelProfile
145146 from openai .types .responses import Response
146147
150151# https://www.python-httpx.org/advanced/ssl/#configuring-client-instances
151152global_ssl_context = ssl .create_default_context (cafile = certifi .where ())
152153
154+ _ssrf_client : httpx .Client | None = None
155+
156+
157+ def _get_ssrf_safe_client () -> httpx .Client :
158+ global _ssrf_client
159+ if _ssrf_client is None :
160+ from langchain_core ._security ._transport import ssrf_safe_client
161+
162+ _ssrf_client = ssrf_safe_client (
163+ verify = global_ssl_context , follow_redirects = False
164+ )
165+ return _ssrf_client
166+
167+
153168_MODEL_PROFILES = cast (ModelProfileRegistry , _PROFILES )
154169
155170
@@ -3638,28 +3653,7 @@ def _url_to_size(image_source: str) -> tuple[int, int] | None:
36383653 )
36393654 return None
36403655 if _is_url (image_source ):
3641- try :
3642- import httpx
3643- except ImportError :
3644- logger .info (
3645- "Unable to count image tokens. To count image tokens please install "
3646- "`pip install -U httpx`."
3647- )
3648- return None
3649-
3650- # Validate URL for SSRF protection
3651- try :
3652- from langchain_core ._security ._ssrf_protection import validate_safe_url
3653-
3654- validate_safe_url (image_source , allow_private = False , allow_http = True )
3655- except ImportError :
3656- logger .warning (
3657- "SSRF protection not available. "
3658- "Update langchain-core to get SSRF protection."
3659- )
3660- except ValueError as e :
3661- logger .warning ("Image URL failed SSRF validation: %s" , e )
3662- return None
3656+ import httpx
36633657
36643658 # Set reasonable limits to prevent resource exhaustion
36653659 # Timeout prevents indefinite hangs on slow/malicious servers
@@ -3668,10 +3662,7 @@ def _url_to_size(image_source: str) -> tuple[int, int] | None:
36683662 max_size = 50 * 1024 * 1024 # 50 MB
36693663
36703664 try :
3671- response = httpx .get (
3672- image_source ,
3673- timeout = timeout ,
3674- )
3665+ response = _get_ssrf_safe_client ().get (image_source , timeout = timeout )
36753666 response .raise_for_status ()
36763667
36773668 # Check response size before loading into memory
0 commit comments