Skip to content

Commit e67c9b6

Browse files
[async] fix tests and missed rebase parts
1 parent 048e5a6 commit e67c9b6

File tree

2 files changed

+59
-3
lines changed

2 files changed

+59
-3
lines changed

src/snowflake/connector/aio/_wif_util.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414

1515
from ..errorcode import ER_WIF_CREDENTIALS_NOT_FOUND
1616
from ..errors import MissingDependencyError, ProgrammingError
17-
from ..session_manager import SessionManagerFactory
1817
from ..wif_util import (
1918
DEFAULT_ENTRA_SNOWFLAKE_RESOURCE,
2019
SNOWFLAKE_AUDIENCE,
@@ -24,7 +23,7 @@
2423
extract_iss_and_sub_without_signature_verification,
2524
get_aws_sts_hostname,
2625
)
27-
from ._session_manager import SessionManager
26+
from ._session_manager import SessionManager, SessionManagerFactory
2827

2928
logger = logging.getLogger(__name__)
3029

test/unit/aio/test_proxies_async.py

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
import urllib.request
34
from collections import deque
45
from test.unit.test_proxies import (
56
DbRequestFlags,
@@ -12,6 +13,9 @@
1213

1314
import aiohttp
1415
import pytest
16+
from aiohttp import BasicAuth
17+
from aiohttp.helpers import proxies_from_env
18+
from yarl import URL
1519

1620
from snowflake.connector.aio import connect as async_connect
1721

@@ -314,6 +318,57 @@ async def test_no_proxy_basic_param_proxy_bypass_backend(
314318
assert flags.proxy_saw_storage is True
315319

316320

321+
@pytest.fixture
322+
def fix_aiohttp_proxy_bypass(monkeypatch):
323+
"""Fix aiohttp's proxy bypass to check host:port instead of just host.
324+
325+
This fixture implements a two-step fix:
326+
1. Override get_env_proxy_for_url to use host_port_subcomponent for proxy_bypass
327+
2. Override urllib.request._splitport to return (host:port, port) for proper matching
328+
"""
329+
330+
# Step 1: Override get_env_proxy_for_url to pass host:port to proxy_bypass
331+
def get_env_proxy_for_url_with_port(url: URL) -> tuple[URL, BasicAuth | None]:
332+
"""Get a permitted proxy for the given URL from the env, checking host:port."""
333+
from urllib.request import proxy_bypass
334+
335+
# Check proxy bypass using host:port combination
336+
if url.host is not None:
337+
# Use host_port_subcomponent which includes port
338+
host_port = f"{url.host}:{url.port}" if url.port else url.host
339+
if proxy_bypass(host_port):
340+
raise LookupError(f"Proxying is disallowed for `{host_port!r}`")
341+
342+
proxies_in_env = proxies_from_env()
343+
try:
344+
proxy_info = proxies_in_env[url.scheme]
345+
except KeyError:
346+
raise LookupError(f"No proxies found for `{url!s}` in the env")
347+
else:
348+
return proxy_info.proxy, proxy_info.proxy_auth
349+
350+
# Step 2: Override _splitport to return host:port as first element
351+
original_splitport = urllib.request._splitport
352+
353+
def _splitport_with_port(host):
354+
"""Override to return (host:port, port) instead of (host, port)."""
355+
result = original_splitport(host)
356+
if result is None:
357+
return (host, None)
358+
host_only, port = result
359+
# If port was found, return the original host (with port) as first element
360+
if port is not None:
361+
return (host, port) # Return original host:port string
362+
return (host_only, port)
363+
364+
monkeypatch.setattr(
365+
aiohttp.client, "get_env_proxy_for_url", get_env_proxy_for_url_with_port
366+
)
367+
monkeypatch.setattr(urllib.request, "_splitport", _splitport_with_port)
368+
369+
yield
370+
371+
317372
@pytest.mark.skipolddriver
318373
@pytest.mark.parametrize("proxy_method", ["explicit_args", "env_vars"])
319374
@pytest.mark.parametrize("no_proxy_source", ["param", "env"])
@@ -325,6 +380,7 @@ async def test_no_proxy_source_vs_proxy_method_matrix(
325380
proxy_method,
326381
no_proxy_source,
327382
host_port_pooling,
383+
fix_aiohttp_proxy_bypass,
328384
):
329385
if proxy_method == "env_vars" and no_proxy_source == "param":
330386
pytest.xfail(
@@ -366,6 +422,7 @@ async def test_no_proxy_backend_matrix(
366422
proxy_method,
367423
no_proxy_source,
368424
host_port_pooling,
425+
fix_aiohttp_proxy_bypass,
369426
):
370427
if proxy_method == "env_vars" and no_proxy_source == "param":
371428
pytest.xfail(
@@ -420,7 +477,7 @@ async def test_no_proxy_multiple_values_param_only(
420477
wiremock_mapping_dir,
421478
proxy_env_vars,
422479
no_proxy_factory,
423-
host_port_pooling,
480+
host_port_pooling, # Unlike in synch code - Session stores no_proxy setup so it would be reused for proxy and backend since they are both on localhost
424481
):
425482
target_wm, storage_wm, proxy_wm = wiremock_backend_storage_proxy
426483
_setup_backend_storage_mappings(

0 commit comments

Comments
 (0)