Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 598b16f

Browse files
authored
Fix loop.getaddrinfo() and tests (#495)
* ai_canonname always follows the flag AI_CANONNAME in static resolving (#494) * AddressFamily and SocketKind can be enums * Also fixed failing test
1 parent d6a2b59 commit 598b16f

File tree

5 files changed

+85
-15
lines changed

5 files changed

+85
-15
lines changed

‎tests/test_dns.py

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,32 @@
55
from uvloop import _testbase as tb
66

77

8+
def patched_getaddrinfo(*args, **kwargs):
9+
# corrected socket.getaddrinfo() behavior: ai_canonname always follows the
10+
# flag AI_CANONNAME, even if `host` is an IP
11+
rv = []
12+
result = socket.getaddrinfo(*args, **kwargs)
13+
for af, sk, proto, canon_name, addr in result:
14+
if kwargs.get('flags', 0) & socket.AI_CANONNAME:
15+
if not canon_name:
16+
canon_name = args[0]
17+
if not isinstance(canon_name, str):
18+
canon_name = canon_name.decode('ascii')
19+
elif canon_name:
20+
canon_name = ''
21+
rv.append((af, sk, proto, canon_name, addr))
22+
return rv
23+
24+
825
class BaseTestDNS:
926

10-
def _test_getaddrinfo(self, *args, **kwargs):
27+
def _test_getaddrinfo(self, *args, _patch=False, **kwargs):
1128
err = None
1229
try:
13-
a1 = socket.getaddrinfo(*args, **kwargs)
30+
if _patch:
31+
a1 = patched_getaddrinfo(*args, **kwargs)
32+
else:
33+
a1 = socket.getaddrinfo(*args, **kwargs)
1434
except socket.gaierror as ex:
1535
err = ex
1636

@@ -100,20 +120,36 @@ def test_getaddrinfo_11(self):
100120
self._test_getaddrinfo(b'example.com', '80', type=socket.SOCK_STREAM)
101121

102122
def test_getaddrinfo_12(self):
123+
# musl always returns ai_canonname but we don't
124+
patch = self.implementation != 'asyncio'
125+
103126
self._test_getaddrinfo('127.0.0.1', '80')
104-
self._test_getaddrinfo('127.0.0.1', '80', type=socket.SOCK_STREAM)
127+
self._test_getaddrinfo('127.0.0.1', '80', type=socket.SOCK_STREAM,
128+
_patch=patch)
105129

106130
def test_getaddrinfo_13(self):
131+
# musl always returns ai_canonname but we don't
132+
patch = self.implementation != 'asyncio'
133+
107134
self._test_getaddrinfo(b'127.0.0.1', b'80')
108-
self._test_getaddrinfo(b'127.0.0.1', b'80', type=socket.SOCK_STREAM)
135+
self._test_getaddrinfo(b'127.0.0.1', b'80', type=socket.SOCK_STREAM,
136+
_patch=patch)
109137

110138
def test_getaddrinfo_14(self):
139+
# musl always returns ai_canonname but we don't
140+
patch = self.implementation != 'asyncio'
141+
111142
self._test_getaddrinfo(b'127.0.0.1', b'http')
112-
self._test_getaddrinfo(b'127.0.0.1', b'http', type=socket.SOCK_STREAM)
143+
self._test_getaddrinfo(b'127.0.0.1', b'http', type=socket.SOCK_STREAM,
144+
_patch=patch)
113145

114146
def test_getaddrinfo_15(self):
147+
# musl always returns ai_canonname but we don't
148+
patch = self.implementation != 'asyncio'
149+
115150
self._test_getaddrinfo('127.0.0.1', 'http')
116-
self._test_getaddrinfo('127.0.0.1', 'http', type=socket.SOCK_STREAM)
151+
self._test_getaddrinfo('127.0.0.1', 'http', type=socket.SOCK_STREAM,
152+
_patch=patch)
117153

118154
def test_getaddrinfo_16(self):
119155
self._test_getaddrinfo('localhost', 'http')
@@ -128,12 +164,26 @@ def test_getaddrinfo_18(self):
128164
self._test_getaddrinfo('localhost', b'http', type=socket.SOCK_STREAM)
129165

130166
def test_getaddrinfo_19(self):
167+
# musl always returns ai_canonname while macOS never return for IPs,
168+
# but we strictly follow the docs to use the AI_CANONNAME flag
169+
patch = self.implementation != 'asyncio'
170+
131171
self._test_getaddrinfo('::1', 80)
132-
self._test_getaddrinfo('::1', 80, type=socket.SOCK_STREAM)
172+
self._test_getaddrinfo('::1', 80, type=socket.SOCK_STREAM,
173+
_patch=patch)
174+
self._test_getaddrinfo('::1', 80, type=socket.SOCK_STREAM,
175+
flags=socket.AI_CANONNAME, _patch=patch)
133176

134177
def test_getaddrinfo_20(self):
178+
# musl always returns ai_canonname while macOS never return for IPs,
179+
# but we strictly follow the docs to use the AI_CANONNAME flag
180+
patch = self.implementation != 'asyncio'
181+
135182
self._test_getaddrinfo('127.0.0.1', 80)
136-
self._test_getaddrinfo('127.0.0.1', 80, type=socket.SOCK_STREAM)
183+
self._test_getaddrinfo('127.0.0.1', 80, type=socket.SOCK_STREAM,
184+
_patch=patch)
185+
self._test_getaddrinfo('127.0.0.1', 80, type=socket.SOCK_STREAM,
186+
flags=socket.AI_CANONNAME, _patch=patch)
137187

138188
######
139189

‎tests/test_tcp.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ def test_create_server_4(self):
222222

223223
with self.assertRaisesRegex(OSError,
224224
r"error while attempting.*\('127.*: "
225-
r"address already in use"):
225+
r"address( already)? in use"):
226226

227227
self.loop.run_until_complete(
228228
self.loop.create_server(object, *addr))

‎uvloop/dns.pyx

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,21 @@ cdef __static_getaddrinfo_pyaddr(object host, object port,
245245
except Exception:
246246
return
247247

248-
return af, type, proto, '', pyaddr
248+
if flags & socket_AI_CANONNAME:
249+
if isinstance(host, str):
250+
canon_name = host
251+
else:
252+
canon_name = host.decode('ascii')
253+
else:
254+
canon_name = ''
255+
256+
return (
257+
_intenum_converter(af, socket_AddressFamily),
258+
_intenum_converter(type, socket_SocketKind),
259+
proto,
260+
canon_name,
261+
pyaddr,
262+
)
249263

250264

251265
@cython.freelist(DEFAULT_FREELIST_SIZE)
@@ -276,8 +290,8 @@ cdef class AddrInfo:
276290
while ptr != NULL:
277291
if ptr.ai_addr.sa_family in (uv.AF_INET, uv.AF_INET6):
278292
result.append((
279-
ptr.ai_family,
280-
ptr.ai_socktype,
293+
_intenum_converter(ptr.ai_family, socket_AddressFamily),
294+
_intenum_converter(ptr.ai_socktype, socket_SocketKind),
281295
ptr.ai_protocol,
282296
('' if ptr.ai_canonname is NULL else
283297
(<bytes>ptr.ai_canonname).decode()),
@@ -370,6 +384,13 @@ cdef class NameInfoRequest(UVRequest):
370384
self.callback(convert_error(err))
371385

372386

387+
cdef _intenum_converter(value, enum_klass):
388+
try:
389+
return enum_klass(value)
390+
except ValueError:
391+
return value
392+
393+
373394
cdef void __on_addrinfo_resolved(uv.uv_getaddrinfo_t *resolver,
374395
int status, system.addrinfo *res) with gil:
375396

‎uvloop/includes/stdlib.pxi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ cdef int has_SO_REUSEPORT = hasattr(socket, 'SO_REUSEPORT')
7272
cdef int SO_REUSEPORT = getattr(socket, 'SO_REUSEPORT', 0)
7373
cdef int SO_BROADCAST = getattr(socket, 'SO_BROADCAST')
7474
cdef int SOCK_NONBLOCK = getattr(socket, 'SOCK_NONBLOCK', -1)
75+
cdef int socket_AI_CANONNAME = getattr(socket, 'AI_CANONNAME')
7576

7677
cdef socket_gaierror = socket.gaierror
7778
cdef socket_error = socket.error

‎uvloop/loop.pyx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1527,9 +1527,7 @@ cdef class Loop:
15271527
addr = __static_getaddrinfo_pyaddr(host, port, family,
15281528
type, proto, flags)
15291529
if addr is not None:
1530-
fut = self._new_future()
1531-
fut.set_result([addr])
1532-
return await fut
1530+
return [addr]
15331531

15341532
return await self._getaddrinfo(
15351533
host, port, family, type, proto, flags, 1)

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /