Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2934262

Browse files
committed
asyncio: sync with Tulip
* Cleanup gather(): use cancelled() method instead of using private Future attribute * Fix _UnixReadPipeTransport and _UnixWritePipeTransport. Only start reading when connection_made() has been called. * Issue #23333: Fix BaseSelectorEventLoop._accept_connection(). Close the transport on error. In debug mode, log errors using call_exception_handler()
1 parent 54a231d commit 2934262

5 files changed

Lines changed: 85 additions & 44 deletions

File tree

Lib/asyncio/selector_events.py

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from . import selectors
2323
from . import transports
2424
from . import sslproto
25+
from .coroutines import coroutine
2526
from .log import logger
2627

2728

@@ -181,16 +182,47 @@ def _accept_connection(self, protocol_factory, sock,
181182
else:
182183
raise # The event loop will catch, log and ignore it.
183184
else:
185+
extra = {'peername': addr}
186+
accept = self._accept_connection2(protocol_factory, conn, extra,
187+
sslcontext, server)
188+
self.create_task(accept)
189+
190+
@coroutine
191+
def _accept_connection2(self, protocol_factory, conn, extra,
192+
sslcontext=None, server=None):
193+
protocol = None
194+
transport = None
195+
try:
184196
protocol = protocol_factory()
197+
waiter = futures.Future(loop=self)
185198
if sslcontext:
186-
self._make_ssl_transport(
187-
conn, protocol, sslcontext,
188-
server_side=True, extra={'peername': addr}, server=server)
199+
transport = self._make_ssl_transport(
200+
conn, protocol, sslcontext, waiter=waiter,
201+
server_side=True, extra=extra, server=server)
189202
else:
190-
self._make_socket_transport(
191-
conn, protocol , extra={'peername': addr},
203+
transport = self._make_socket_transport(
204+
conn, protocol, waiter=waiter, extra=extra,
192205
server=server)
193-
# It's now up to the protocol to handle the connection.
206+
207+
try:
208+
yield from waiter
209+
except:
210+
transport.close()
211+
raise
212+
213+
# It's now up to the protocol to handle the connection.
214+
except Exception as exc:
215+
if self.get_debug():
216+
context = {
217+
'message': ('Error on transport creation '
218+
'for incoming connection'),
219+
'exception': exc,
220+
}
221+
if protocol is not None:
222+
context['protocol'] = protocol
223+
if transport is not None:
224+
context['transport'] = transport
225+
self.call_exception_handler(context)
194226

195227
def add_reader(self, fd, callback, *args):
196228
"""Add a reader callback."""

Lib/asyncio/tasks.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,7 @@ def _done_callback(i, fut):
592592
fut.exception()
593593
return
594594

595-
if fut._state == futures._CANCELLED:
595+
if fut.cancelled():
596596
res = futures.CancelledError()
597597
if not return_exceptions:
598598
outer.set_exception(res)

Lib/asyncio/unix_events.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -298,8 +298,10 @@ def __init__(self, loop, pipe, protocol, waiter=None, extra=None):
298298
_set_nonblocking(self._fileno)
299299
self._protocol = protocol
300300
self._closing = False
301-
self._loop.add_reader(self._fileno, self._read_ready)
302301
self._loop.call_soon(self._protocol.connection_made, self)
302+
# only start reading when connection_made() has been called
303+
self._loop.call_soon(self._loop.add_reader,
304+
self._fileno, self._read_ready)
303305
if waiter is not None:
304306
# only wake up the waiter when connection_made() has been called
305307
self._loop.call_soon(waiter._set_result_unless_cancelled, None)
@@ -401,13 +403,16 @@ def __init__(self, loop, pipe, protocol, waiter=None, extra=None):
401403
self._conn_lost = 0
402404
self._closing = False # Set when close() or write_eof() called.
403405

404-
# On AIX, the reader trick only works for sockets.
405-
# On other platforms it works for pipes and sockets.
406-
# (Exception: OS X 10.4? Issue #19294.)
406+
self._loop.call_soon(self._protocol.connection_made, self)
407+
408+
# On AIX, the reader trick (to be notified when the read end of the
409+
# socket is closed) only works for sockets. On other platforms it
410+
# works for pipes and sockets. (Exception: OS X 10.4? Issue #19294.)
407411
if is_socket or not sys.platform.startswith("aix"):
408-
self._loop.add_reader(self._fileno, self._read_ready)
412+
# only start reading when connection_made() has been called
413+
self._loop.call_soon(self._loop.add_reader,
414+
self._fileno, self._read_ready)
409415

410-
self._loop.call_soon(self._protocol.connection_made, self)
411416
if waiter is not None:
412417
# only wake up the waiter when connection_made() has been called
413418
self._loop.call_soon(waiter._set_result_unless_cancelled, None)

Lib/test/test_asyncio/test_events.py

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -886,13 +886,18 @@ def test_create_server_ssl_verify_failed(self):
886886
if hasattr(sslcontext_client, 'check_hostname'):
887887
sslcontext_client.check_hostname = True
888888

889+
889890
# no CA loaded
890891
f_c = self.loop.create_connection(MyProto, host, port,
891892
ssl=sslcontext_client)
892-
with test_utils.disable_logger():
893-
with self.assertRaisesRegex(ssl.SSLError,
894-
'certificate verify failed '):
895-
self.loop.run_until_complete(f_c)
893+
with mock.patch.object(self.loop, 'call_exception_handler'):
894+
with test_utils.disable_logger():
895+
with self.assertRaisesRegex(ssl.SSLError,
896+
'certificate verify failed '):
897+
self.loop.run_until_complete(f_c)
898+
899+
# execute the loop to log the connection error
900+
test_utils.run_briefly(self.loop)
896901

897902
# close connection
898903
self.assertIsNone(proto.transport)
@@ -919,15 +924,20 @@ def test_create_unix_server_ssl_verify_failed(self):
919924
f_c = self.loop.create_unix_connection(MyProto, path,
920925
ssl=sslcontext_client,
921926
server_hostname='invalid')
922-
with test_utils.disable_logger():
923-
with self.assertRaisesRegex(ssl.SSLError,
924-
'certificate verify failed '):
925-
self.loop.run_until_complete(f_c)
927+
with mock.patch.object(self.loop, 'call_exception_handler'):
928+
with test_utils.disable_logger():
929+
with self.assertRaisesRegex(ssl.SSLError,
930+
'certificate verify failed '):
931+
self.loop.run_until_complete(f_c)
932+
933+
# execute the loop to log the connection error
934+
test_utils.run_briefly(self.loop)
926935

927936
# close connection
928937
self.assertIsNone(proto.transport)
929938
server.close()
930939

940+
931941
def test_legacy_create_unix_server_ssl_verify_failed(self):
932942
with test_utils.force_legacy_ssl_support():
933943
self.test_create_unix_server_ssl_verify_failed()
@@ -949,11 +959,12 @@ def test_create_server_ssl_match_failed(self):
949959
# incorrect server_hostname
950960
f_c = self.loop.create_connection(MyProto, host, port,
951961
ssl=sslcontext_client)
952-
with test_utils.disable_logger():
953-
with self.assertRaisesRegex(
954-
ssl.CertificateError,
955-
"hostname '127.0.0.1' doesn't match 'localhost'"):
956-
self.loop.run_until_complete(f_c)
962+
with mock.patch.object(self.loop, 'call_exception_handler'):
963+
with test_utils.disable_logger():
964+
with self.assertRaisesRegex(
965+
ssl.CertificateError,
966+
"hostname '127.0.0.1' doesn't match 'localhost'"):
967+
self.loop.run_until_complete(f_c)
957968

958969
# close connection
959970
proto.transport.close()

Lib/test/test_asyncio/test_unix_events.py

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -350,16 +350,13 @@ def read_pipe_transport(self, waiter=None):
350350
return transport
351351

352352
def test_ctor(self):
353-
tr = self.read_pipe_transport()
354-
self.loop.assert_reader(5, tr._read_ready)
355-
test_utils.run_briefly(self.loop)
356-
self.protocol.connection_made.assert_called_with(tr)
353+
waiter = asyncio.Future(loop=self.loop)
354+
tr = self.read_pipe_transport(waiter=waiter)
355+
self.loop.run_until_complete(waiter)
357356

358-
def test_ctor_with_waiter(self):
359-
fut = asyncio.Future(loop=self.loop)
360-
tr = self.read_pipe_transport(waiter=fut)
361-
test_utils.run_briefly(self.loop)
362-
self.assertIsNone(fut.result())
357+
self.protocol.connection_made.assert_called_with(tr)
358+
self.loop.assert_reader(5, tr._read_ready)
359+
self.assertIsNone(waiter.result())
363360

364361
@mock.patch('os.read')
365362
def test__read_ready(self, m_read):
@@ -502,17 +499,13 @@ def write_pipe_transport(self, waiter=None):
502499
return transport
503500

504501
def test_ctor(self):
505-
tr = self.write_pipe_transport()
506-
self.loop.assert_reader(5, tr._read_ready)
507-
test_utils.run_briefly(self.loop)
508-
self.protocol.connection_made.assert_called_with(tr)
502+
waiter = asyncio.Future(loop=self.loop)
503+
tr = self.write_pipe_transport(waiter=waiter)
504+
self.loop.run_until_complete(waiter)
509505

510-
def test_ctor_with_waiter(self):
511-
fut = asyncio.Future(loop=self.loop)
512-
tr = self.write_pipe_transport(waiter=fut)
506+
self.protocol.connection_made.assert_called_with(tr)
513507
self.loop.assert_reader(5, tr._read_ready)
514-
test_utils.run_briefly(self.loop)
515-
self.assertEqual(None, fut.result())
508+
self.assertEqual(None, waiter.result())
516509

517510
def test_can_write_eof(self):
518511
tr = self.write_pipe_transport()

0 commit comments

Comments
 (0)