diff --git a/tests/test_tcp.py b/tests/test_tcp.py index 5b40bb24..8ea6e592 100644 --- a/tests/test_tcp.py +++ b/tests/test_tcp.py @@ -2891,6 +2891,50 @@ async def client(addr, ctx): # SSLProtocol should be DECREF to 0 self.assertIsNone(ctx()) + def test_shutdown_timeout_handler_not_set(self): + loop = self.loop + + def server(sock): + sslctx = self._create_server_ssl_context(self.ONLYCERT, + self.ONLYKEY) + sock = sslctx.wrap_socket(sock, server_side=True) + sock.send(b'hello') + assert sock.recv(1024) == b'world' + time.sleep(0.1) + sock.send(b'extra bytes' * 1) + # sending EOF here + sock.shutdown(socket.SHUT_WR) + # make sure we have enough time to reproduce the issue + time.sleep(0.1) + sock.close() + + class Protocol(asyncio.Protocol): + def __init__(self): + self.fut = asyncio.Future(loop=loop) + self.transport = None + + def connection_made(self, transport): + self.transport = transport + + def data_received(self, data): + self.transport.write(b'world') + # pause reading would make incoming data stay in the sslobj + self.transport.pause_reading() + # resume for AIO to pass + loop.call_later(0.2, self.transport.resume_reading) + + def connection_lost(self, exc): + self.fut.set_result(None) + + async def client(addr): + ctx = self._create_client_ssl_context() + tr, pr = await loop.create_connection(Protocol, *addr, ssl=ctx) + await pr.fut + tr.close() + + with self.tcp_server(server) as srv: + loop.run_until_complete(client(srv.addr)) + class Test_UV_TCPSSL(_TestSSL, tb.UVTestCase): pass diff --git a/uvloop/sslproto.pyx b/uvloop/sslproto.pyx index 4fe6f909..c5b9c3a1 100644 --- a/uvloop/sslproto.pyx +++ b/uvloop/sslproto.pyx @@ -349,8 +349,10 @@ cdef class SSLProtocol: if self._shutdown_timeout_handle: self._shutdown_timeout_handle.cancel() + self._shutdown_timeout_handle = None if self._handshake_timeout_handle: self._handshake_timeout_handle.cancel() + self._handshake_timeout_handle = None def get_buffer(self, n): cdef size_t want = n @@ -495,7 +497,9 @@ cdef class SSLProtocol: self._on_handshake_complete(None) cdef _on_handshake_complete(self, handshake_exc): - self._handshake_timeout_handle.cancel() + if self._handshake_timeout_handle is not None: + self._handshake_timeout_handle.cancel() + self._shutdown_timeout_handle = None sslobj = self._sslobj try: @@ -588,7 +592,9 @@ cdef class SSLProtocol: self._on_shutdown_complete(None) cdef _on_shutdown_complete(self, shutdown_exc): - self._shutdown_timeout_handle.cancel() + if self._shutdown_timeout_handle is not None: + self._shutdown_timeout_handle.cancel() + self._shutdown_timeout_handle = None if shutdown_exc: self._fatal_error(shutdown_exc)