1010from typing import TYPE_CHECKING , Any , Callable , Generator , Mapping
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
@@ -76,8 +77,15 @@ def get_connection(
7677 proxy_manager = self .proxy_manager_for (proxy )
7778
7879 if isinstance (proxy_manager , ProxyManager ):
79- # Add Host to proxy header SNOW-232777
80- proxy_manager .proxy_headers ["Host" ] = parsed_url .hostname
80+ # Add Host to proxy header SNOW-232777 and SNOW-694457
81+
82+ # RFC 7230 / 5.4 – a proxy’s Host header must repeat the request authority
83+ # verbatim: <hostname>[:<port>] with IPv6 still in [brackets]. We take that
84+ # straight from urlparse(url).netloc, which preserves port and brackets (and case-sensitive hostname).
85+ # Note: netloc also keeps user-info (user:pass@host) if present in URL. The driver never sends
86+ # URLs with embedded credentials, so we leave them unhandled — for full support
87+ # we’d need to manually concatenate hostname with optional port and IPv6 brackets.
88+ proxy_manager .proxy_headers ["Host" ] = parsed_url .netloc
8189 else :
8290 logger .debug (
8391 f"Unable to set 'Host' to proxy manager of type { type (proxy_manager )} as"
@@ -112,6 +120,10 @@ class HttpConfig:
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 ) -> HttpConfig :
117129 """Return a new HttpConfig with overrides applied."""
@@ -293,13 +305,13 @@ class SessionManager(_RequestVerbsUsingSessionMixin):
293305 **Two Operating Modes**:
294306 - use_pooling=False: One-shot sessions (create, use, close) - suitable for infrequent requests
295307 - use_pooling=True: Per-hostname session pools - reuses TCP connections, avoiding handshake
296- and SSL/TLS negotiation overhead for repeated requests to the same host
308+ and SSL/TLS negotiation overhead for repeated requests to the same host.
297309
298310 **Key Benefits**:
299311 - Centralized HTTP configuration management and easy propagation across the codebase
300312 - Consistent proxy setup (SNOW-694457) and headers customization (SNOW-2043816)
301313 - HTTPAdapter customization for connection-level request manipulation
302- - Performance optimization through connection reuse for high-traffic scenarios
314+ - Performance optimization through connection reuse for high-traffic scenarios.
303315
304316 **Usage**: Create the base session manager, then use clone() for derived managers to ensure
305317 proper config propagation. Pre-commit checks enforce usage to prevent code drift back to
@@ -315,7 +327,6 @@ def __init__(self, config: HttpConfig | None = None, **http_config_kwargs) -> No
315327 logger .debug ("Creating a config for the SessionManager" )
316328 config = HttpConfig (** http_config_kwargs )
317329 self ._cfg : HttpConfig = config
318-
319330 self ._sessions_map : dict [str | None , SessionPool ] = collections .defaultdict (
320331 lambda : SessionPool (self )
321332 )
@@ -338,6 +349,19 @@ def from_config(cls, cfg: HttpConfig, **overrides: Any) -> SessionManager:
338349 def config (self ) -> HttpConfig :
339350 return self ._cfg
340351
352+ @config .setter
353+ def config (self , cfg : HttpConfig ) -> None :
354+ self ._cfg = cfg
355+
356+ @property
357+ def proxy_url (self ) -> str :
358+ return get_proxy_url (
359+ self ._cfg .proxy_host ,
360+ self ._cfg .proxy_port ,
361+ self ._cfg .proxy_user ,
362+ self ._cfg .proxy_password ,
363+ )
364+
341365 @property
342366 def use_pooling (self ) -> bool :
343367 return self ._cfg .use_pooling
@@ -395,6 +419,7 @@ def _mount_adapters(self, session: requests.Session) -> None:
395419 def make_session (self ) -> Session :
396420 session = requests .Session ()
397421 self ._mount_adapters (session )
422+ session .proxies = {"http" : self .proxy_url , "https" : self .proxy_url }
398423 return session
399424
400425 @contextlib .contextmanager
0 commit comments