Skip to content

Commit 7b7ea2b

Browse files
committed
Fix parsing of IPv6 addresses in the connection URI
Plain IPv6 addresses specified in square brackets in the connection URI are now parsed correctly. Fixes: #838.
1 parent 4d39a05 commit 7b7ea2b

File tree

3 files changed

+52
-4
lines changed

3 files changed

+52
-4
lines changed

asyncpg/connect_utils.py

+17-3
Original file line numberDiff line numberDiff line change
@@ -197,11 +197,25 @@ def _parse_hostlist(hostlist, port, *, unquote=False):
197197
port = _validate_port_spec(hostspecs, port)
198198

199199
for i, hostspec in enumerate(hostspecs):
200-
if not hostspec.startswith('/'):
201-
addr, _, hostspec_port = hostspec.partition(':')
202-
else:
200+
if hostspec[0] == '/':
201+
# Unix socket
203202
addr = hostspec
204203
hostspec_port = ''
204+
elif hostspec[0] == '[':
205+
# IPv6 address
206+
m = re.match(r'(?:\[([^\]]+)\])(?::([0-9]+))?', hostspec)
207+
if m:
208+
addr = m.group(1)
209+
hostspec_port = m.group(2)
210+
else:
211+
raise ValueError(
212+
'invalid IPv6 address in the connection URI: {!r}'.format(
213+
hostspec
214+
)
215+
)
216+
else:
217+
# IPv4 address
218+
addr, _, hostspec_port = hostspec.partition(':')
205219

206220
if unquote:
207221
addr = urllib.parse.unquote(addr)

asyncpg/connection.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -1796,7 +1796,13 @@ async def connect(dsn=None, *,
17961796
.. note::
17971797
17981798
The URI must be *valid*, which means that all components must
1799-
be properly quoted with :py:func:`urllib.parse.quote`.
1799+
be properly quoted with :py:func:`urllib.parse.quote`, and
1800+
any literal IPv6 addresses must be enclosed in square brackets.
1801+
For example:
1802+
1803+
.. code-block:: text
1804+
1805+
postgres://dbuser@[fe80::1ff:fe23:4567:890a%25eth0]/dbname
18001806
18011807
:param host:
18021808
Database host address as one of the following:

tests/test_connect.py

+28
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,34 @@ class TestConnectParams(tb.TestCase):
511511
})
512512
},
513513

514+
{
515+
'name': 'dsn_ipv6_multi_host',
516+
'dsn': 'postgresql://user@[2001:db8::1234%25eth0],[::1]/db',
517+
'result': ([('2001:db8::1234%eth0', 5432), ('::1', 5432)], {
518+
'database': 'db',
519+
'user': 'user',
520+
})
521+
},
522+
523+
{
524+
'name': 'dsn_ipv6_multi_host_port',
525+
'dsn': 'postgresql://user@[2001:db8::1234]:1111,[::1]:2222/db',
526+
'result': ([('2001:db8::1234', 1111), ('::1', 2222)], {
527+
'database': 'db',
528+
'user': 'user',
529+
})
530+
},
531+
532+
{
533+
'name': 'dsn_ipv6_multi_host_query_part',
534+
'dsn': 'postgresql:///db?user=user&host=[2001:db8::1234],[::1]',
535+
'result': ([('2001:db8::1234', 5432), ('::1', 5432)], {
536+
'database': 'db',
537+
'user': 'user',
538+
})
539+
},
540+
541+
514542
{
515543
'name': 'dsn_combines_env_multi_host',
516544
'env': {

0 commit comments

Comments
 (0)