|
4 | 4 | import platform |
5 | 5 | import ssl |
6 | 6 | import sys |
| 7 | +from contextlib import suppress |
7 | 8 | from re import match as match_regex |
8 | 9 | from typing import Awaitable, Callable |
9 | 10 | from unittest import mock |
|
17 | 18 | from aiohttp import ClientResponse, web |
18 | 19 | from aiohttp.client_exceptions import ClientConnectionError |
19 | 20 | from aiohttp.helpers import IS_MACOS, IS_WINDOWS |
| 21 | +from aiohttp.pytest_plugin import AiohttpServer |
20 | 22 |
|
21 | 23 | ASYNCIO_SUPPORTS_TLS_IN_TLS = sys.version_info >= (3, 11) |
22 | 24 |
|
@@ -884,3 +886,46 @@ async def test_proxy_auth() -> None: |
884 | 886 | proxy_auth=("user", "pass"), |
885 | 887 | ): |
886 | 888 | pass |
| 889 | + |
| 890 | + |
| 891 | +async def test_https_proxy_connect_tunnel_session_close_no_hang( |
| 892 | + aiohttp_server: AiohttpServer, |
| 893 | +) -> None: |
| 894 | + """Test that CONNECT tunnel connections are not pooled.""" |
| 895 | + # Regression test for issue #11273. |
| 896 | + |
| 897 | + # Create a minimal proxy server |
| 898 | + # The CONNECT method is handled at the protocol level, not by the handler |
| 899 | + proxy_app = web.Application() |
| 900 | + proxy_server = await aiohttp_server(proxy_app) |
| 901 | + proxy_url = f"http://{proxy_server.host}:{proxy_server.port}" |
| 902 | + |
| 903 | + # Create session and make HTTPS request through proxy |
| 904 | + session = aiohttp.ClientSession() |
| 905 | + |
| 906 | + try: |
| 907 | + # This will fail during TLS upgrade because proxy doesn't establish tunnel |
| 908 | + with suppress(aiohttp.ClientError): |
| 909 | + async with session.get("https://example.com/test", proxy=proxy_url) as resp: |
| 910 | + await resp.read() |
| 911 | + |
| 912 | + # The critical test: Check if any connections were pooled with proxy=None |
| 913 | + # This is the root cause of the hang - CONNECT tunnel connections |
| 914 | + # should NOT be pooled |
| 915 | + connector = session.connector |
| 916 | + assert connector is not None |
| 917 | + |
| 918 | + # Count connections with proxy=None in the pool |
| 919 | + proxy_none_keys = [key for key in connector._conns if key.proxy is None] |
| 920 | + proxy_none_count = len(proxy_none_keys) |
| 921 | + |
| 922 | + # Before the fix, there would be a connection with proxy=None |
| 923 | + # After the fix, CONNECT tunnel connections are not pooled |
| 924 | + assert proxy_none_count == 0, ( |
| 925 | + f"Found {proxy_none_count} connections with proxy=None in pool. " |
| 926 | + f"CONNECT tunnel connections should not be pooled - this is bug #11273" |
| 927 | + ) |
| 928 | + |
| 929 | + finally: |
| 930 | + # Clean close |
| 931 | + await session.close() |
0 commit comments