Skip to content

Commit f900b73

Browse files
authored
Fix parsing of IPv6 addresses in the connection URI (#845)
Plain IPv6 addresses specified in square brackets in the connection URI are now parsed correctly. Fixes: #838.
1 parent 03a3d18 commit f900b73

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
@@ -1813,7 +1813,13 @@ async def connect(dsn=None, *,
18131813
.. note::
18141814
18151815
The URI must be *valid*, which means that all components must
1816-
be properly quoted with :py:func:`urllib.parse.quote`.
1816+
be properly quoted with :py:func:`urllib.parse.quote`, and
1817+
any literal IPv6 addresses must be enclosed in square brackets.
1818+
For example:
1819+
1820+
.. code-block:: text
1821+
1822+
postgres://dbuser@[fe80::1ff:fe23:4567:890a%25eth0]/dbname
18171823
18181824
:param host:
18191825
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)