1010from typing import TYPE_CHECKING , Any , Callable , Generator , Generic , Mapping , TypeVar
1111
1212from .compat import urlparse
13+ from .proxy import get_proxy_url
1314from .vendored import requests
1415from .vendored .requests import Response , Session
1516from .vendored .requests .adapters import BaseAdapter , HTTPAdapter
@@ -79,8 +80,15 @@ def get_connection(
7980 proxy_manager = self .proxy_manager_for (proxy )
8081
8182 if isinstance (proxy_manager , ProxyManager ):
82- # Add Host to proxy header SNOW-232777
83- proxy_manager .proxy_headers ["Host" ] = parsed_url .hostname
83+ # Add Host to proxy header SNOW-232777 and SNOW-694457
84+
85+ # RFC 7230 / 5.4 – a proxy’s Host header must repeat the request authority
86+ # verbatim: <hostname>[:<port>] with IPv6 still in [brackets]. We take that
87+ # straight from urlparse(url).netloc, which preserves port and brackets (and case-sensitive hostname).
88+ # Note: netloc also keeps user-info (user:pass@host) if present in URL. The driver never sends
89+ # URLs with embedded credentials, so we leave them unhandled — for full support
90+ # we’d need to manually concatenate hostname with optional port and IPv6 brackets.
91+ proxy_manager .proxy_headers ["Host" ] = parsed_url .netloc
8492 else :
8593 logger .debug (
8694 f"Unable to set 'Host' to proxy manager of type { type (proxy_manager )} as"
@@ -112,6 +120,10 @@ class BaseHttpConfig:
112120
113121 use_pooling : bool = True
114122 max_retries : int | None = REQUESTS_RETRY
123+ proxy_host : str | None = None
124+ proxy_port : str | None = None
125+ proxy_user : str | None = None
126+ proxy_password : str | None = None
115127
116128 def copy_with (self , ** overrides : Any ) -> BaseHttpConfig :
117129 """Return a new config with overrides applied."""
@@ -325,13 +337,13 @@ class SessionManager(_RequestVerbsUsingSessionMixin):
325337 **Two Operating Modes**:
326338 - use_pooling=False: One-shot sessions (create, use, close) - suitable for infrequent requests
327339 - use_pooling=True: Per-hostname session pools - reuses TCP connections, avoiding handshake
328- and SSL/TLS negotiation overhead for repeated requests to the same host
340+ and SSL/TLS negotiation overhead for repeated requests to the same host.
329341
330342 **Key Benefits**:
331343 - Centralized HTTP configuration management and easy propagation across the codebase
332344 - Consistent proxy setup (SNOW-694457) and headers customization (SNOW-2043816)
333345 - HTTPAdapter customization for connection-level request manipulation
334- - Performance optimization through connection reuse for high-traffic scenarios
346+ - Performance optimization through connection reuse for high-traffic scenarios.
335347
336348 **Usage**: Create the base session manager, then use clone() for derived managers to ensure
337349 proper config propagation. Pre-commit checks enforce usage to prevent code drift back to
@@ -347,7 +359,6 @@ def __init__(self, config: HttpConfig | None = None, **http_config_kwargs) -> No
347359 logger .debug ("Creating a config for the SessionManager" )
348360 config = HttpConfig (** http_config_kwargs )
349361 self ._cfg : HttpConfig = config
350-
351362 self ._sessions_map : dict [str | None , SessionPool ] = collections .defaultdict (
352363 lambda : SessionPool (self )
353364 )
@@ -370,6 +381,19 @@ def from_config(cls, cfg: HttpConfig, **overrides: Any) -> SessionManager:
370381 def config (self ) -> HttpConfig :
371382 return self ._cfg
372383
384+ @config .setter
385+ def config (self , cfg : HttpConfig ) -> None :
386+ self ._cfg = cfg
387+
388+ @property
389+ def proxy_url (self ) -> str :
390+ return get_proxy_url (
391+ self ._cfg .proxy_host ,
392+ self ._cfg .proxy_port ,
393+ self ._cfg .proxy_user ,
394+ self ._cfg .proxy_password ,
395+ )
396+
373397 @property
374398 def use_pooling (self ) -> bool :
375399 return self ._cfg .use_pooling
@@ -427,6 +451,7 @@ def _mount_adapters(self, session: requests.Session) -> None:
427451 def make_session (self ) -> Session :
428452 session = requests .Session ()
429453 self ._mount_adapters (session )
454+ session .proxies = {"http" : self .proxy_url , "https" : self .proxy_url }
430455 return session
431456
432457 @contextlib .contextmanager
0 commit comments