From: Daniele Varrazzo Date: Tue, 12 Dec 2023 16:56:37 +0000 (+0100) Subject: fix: fix iteration resolving hosts with multiple IP addresses in async mode X-Git-Tag: 3.1.15~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7f72e4c1e43285e7fa5a126271934a329d563490;p=thirdparty%2Fpsycopg.git fix: fix iteration resolving hosts with multiple IP addresses in async mode Fix #695 (not 100% sure, but probably). --- diff --git a/docs/news.rst b/docs/news.rst index b2d742124..17d5638eb 100644 --- a/docs/news.rst +++ b/docs/news.rst @@ -7,6 +7,16 @@ ``psycopg`` release notes ========================= +Future releases +--------------- + +Psycopg 3.1.15 (unreleased) +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Fix async connection to hosts resolving to multiple IP addresses + (:ticket:`#695`). + + Current release --------------- diff --git a/psycopg/psycopg/conninfo.py b/psycopg/psycopg/conninfo.py index bdb5526d3..6c48da734 100644 --- a/psycopg/psycopg/conninfo.py +++ b/psycopg/psycopg/conninfo.py @@ -448,10 +448,8 @@ async def _split_attempts_and_resolve(params: ConnDict) -> AsyncIterator[ConnDic host, port, proto=socket.IPPROTO_TCP, type=socket.SOCK_STREAM ) - attempt = params.copy() for item in ans: - attempt["hostaddr"] = item[4][0] - yield attempt + yield {**params, "hostaddr": item[4][0]} @cache diff --git a/tests/test_conninfo.py b/tests/test_conninfo.py index 2ae1d142a..83174026f 100644 --- a/tests/test_conninfo.py +++ b/tests/test_conninfo.py @@ -436,6 +436,11 @@ async def test_conninfo_attempts_async_no_resolve( "host=foo.com,qux.com hostaddr=1.1.1.1,2.2.2.2", {}, ), + ( + "host=dup.com", + "host=dup.com,dup.com hostaddr=3.3.3.3,3.3.3.4", + None, + ), ], ) @pytest.mark.anyio @@ -499,19 +504,26 @@ def test_conninfo_random(dsn, conn_cls): @pytest.fixture async def fake_resolve(monkeypatch): fake_hosts = { - "localhost": "127.0.0.1", - "foo.com": "1.1.1.1", - "qux.com": "2.2.2.2", + "localhost": ["127.0.0.1"], + "foo.com": ["1.1.1.1"], + "qux.com": ["2.2.2.2"], + "dup.com": ["3.3.3.3", "3.3.3.4"], } + def family(host): + return socket.AF_INET6 if ":" in host else socket.AF_INET + async def fake_getaddrinfo(host, port, **kwargs): assert isinstance(port, int) or (isinstance(port, str) and port.isdigit()) try: - addr = fake_hosts[host] + addrs = fake_hosts[host] except KeyError: raise OSError(f"unknown test host: {host}") else: - return [(socket.AF_INET, socket.SOCK_STREAM, 6, "", (addr, 432))] + return [ + (family(addr), socket.SOCK_STREAM, 6, "", (addr, port)) + for addr in addrs + ] monkeypatch.setattr(asyncio.get_running_loop(), "getaddrinfo", fake_getaddrinfo)