Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 17 additions & 27 deletions Lib/asyncio/sslproto.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,11 +238,8 @@ def abort(self):
The protocol's connection_lost() method will (eventually) be
called with None as its argument.
"""
self._force_close(None)

def _force_close(self, exc):
Comment thread
asvetlov marked this conversation as resolved.
Resolved
self._closed = True
self._ssl_protocol._abort(exc)
self._ssl_protocol._abort()

def _test__append_write_backlog(self, data):
# for test only
Expand All @@ -253,9 +250,6 @@ def _test__append_write_backlog(self, data):
class SSLProtocol(protocols.BufferedProtocol):
max_size = 256 * 1024 # Buffer size passed to read()

_sslobj_read = None
_sslobj_write = None

_handshake_start_time = None
_handshake_timeout_handle = None
_shutdown_timeout_handle = None
Expand All @@ -265,6 +259,9 @@ def __init__(self, loop, app_protocol, sslcontext, waiter,
call_connection_made=True,
ssl_handshake_timeout=None,
ssl_shutdown_timeout=None):
if ssl is None:
raise RuntimeError("stdlib ssl module not available")

self._ssl_buffer = bytearray(self.max_size)
self._ssl_buffer_view = memoryview(self._ssl_buffer)

Expand Down Expand Up @@ -309,7 +306,6 @@ def __init__(self, loop, app_protocol, sslcontext, waiter,
self._ssl_handshake_timeout = ssl_handshake_timeout
self._ssl_shutdown_timeout = ssl_shutdown_timeout
# SSL and state machine
self._sslobj = None
self._incoming = ssl.MemoryBIO()
self._outgoing = ssl.MemoryBIO()
self._state = SSLProtocolState.UNWRAPPED
Expand All @@ -318,6 +314,10 @@ def __init__(self, loop, app_protocol, sslcontext, waiter,
self._app_state = AppProtocolState.STATE_INIT
else:
self._app_state = AppProtocolState.STATE_CON_MADE
self._sslobj = self._sslcontext.wrap_bio(
self._incoming, self._outgoing,
server_side=self._server_side,
server_hostname=self._server_hostname)

# Flow Control

Expand All @@ -335,6 +335,7 @@ def __init__(self, loop, app_protocol, sslcontext, waiter,
self._outgoing_high_water = 0
self._outgoing_low_water = 0
self._set_write_buffer_limits()
self._get_app_transport()

def _set_app_protocol(self, app_protocol):
self._app_protocol = app_protocol
Expand Down Expand Up @@ -530,17 +531,7 @@ def _start_handshake(self):
self._loop.call_later(self._ssl_handshake_timeout,
lambda: self._check_handshake_timeout())

try:
self._sslobj = self._sslcontext.wrap_bio(
self._incoming, self._outgoing,
server_side=self._server_side,
server_hostname=self._server_hostname)
self._sslobj_read = self._sslobj.read
self._sslobj_write = self._sslobj.write
except Exception as ex:
self._on_handshake_complete(ex)
else:
self._do_handshake()
self._do_handshake()

def _check_handshake_timeout(self):
if self._state == SSLProtocolState.DO_HANDSHAKE:
Expand All @@ -562,7 +553,6 @@ def _do_handshake(self):
self._on_handshake_complete(None)

def _on_handshake_complete(self, handshake_exc):
print("Handshake complete", handshake_exc)
if self._handshake_timeout_handle is not None:
self._handshake_timeout_handle.cancel()
self._shutdown_timeout_handle = None
Expand Down Expand Up @@ -613,7 +603,7 @@ def _start_shutdown(self):
if self._app_transport is not None:
self._app_transport._closed = True
if self._state == SSLProtocolState.DO_HANDSHAKE:
self._abort(None)
self._abort()
else:
self._set_state(SSLProtocolState.FLUSHING)
self._shutdown_timeout_handle = self._loop.call_later(
Expand Down Expand Up @@ -660,10 +650,10 @@ def _on_shutdown_complete(self, shutdown_exc):
else:
self._loop.call_soon(self._transport.close)

def _abort(self, exc):
def _abort(self):
self._set_state(SSLProtocolState.UNWRAPPED)
if self._transport is not None:
self._transport._force_close(exc)
self._transport.abort()

# Outgoing flow

Expand Down Expand Up @@ -695,7 +685,7 @@ def _do_write(self):
try:
while self._write_backlog:
data = self._write_backlog[0]
count = self._sslobj_write(data)
count = self._sslobj.write(data)
data_len = len(data)
if count < data_len:
self._write_backlog[0] = data[count:]
Expand Down Expand Up @@ -746,12 +736,12 @@ def _do_read__buffered(self):
wants = len(buf)

try:
count = self._sslobj_read(wants, buf)
count = self._sslobj.read(wants, buf)

if count > 0:
offset = count
while offset < wants:
count = self._sslobj_read(wants - offset, buf[offset:])
count = self._sslobj.read(wants - offset, buf[offset:])
if count > 0:
offset += count
else:
Expand All @@ -774,7 +764,7 @@ def _do_read__copied(self):

try:
while True:
chunk = self._sslobj_read(self.max_size)
chunk = self._sslobj.read(self.max_size)
if not chunk:
break
if zero:
Expand Down
38 changes: 0 additions & 38 deletions Lib/test/test_asyncio/test_selector_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,44 +70,6 @@ def test_make_socket_transport(self):

close_transport(transport)

@unittest.skipIf(ssl is None, 'No ssl module')
def test_make_ssl_transport(self):
m = mock.Mock()
self.loop._add_reader = mock.Mock()
self.loop._add_reader._is_coroutine = False
self.loop._add_writer = mock.Mock()
self.loop._remove_reader = mock.Mock()
self.loop._remove_writer = mock.Mock()
waiter = self.loop.create_future()
with test_utils.disable_logger():
transport = self.loop._make_ssl_transport(
m, asyncio.Protocol(), m, waiter)

with self.assertRaisesRegex(RuntimeError,
r'SSL transport.*not.*initialized'):
transport.is_reading()

# execute the handshake while the logger is disabled
# to ignore SSL handshake failure
test_utils.run_briefly(self.loop)

self.assertTrue(transport.is_reading())
transport.pause_reading()
transport.pause_reading()
self.assertFalse(transport.is_reading())
transport.resume_reading()
transport.resume_reading()
self.assertTrue(transport.is_reading())

# Sanity check
class_name = transport.__class__.__name__
self.assertIn("ssl", class_name.lower())
self.assertIn("transport", class_name.lower())

transport.close()
# execute pending callbacks to close the socket transport
test_utils.run_briefly(self.loop)

@mock.patch('asyncio.selector_events.ssl', None)
@mock.patch('asyncio.sslproto.ssl', None)
def test_make_ssl_transport_without_ssl_error(self):
Expand Down
24 changes: 11 additions & 13 deletions Lib/test/test_asyncio/test_sslproto.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import logging
import socket
import sys
from test import support
import unittest
import weakref
Expand All @@ -16,7 +15,6 @@
from asyncio import log
from asyncio import protocols
from asyncio import sslproto
from test import support
from test.test_asyncio import utils as test_utils
from test.test_asyncio import functional as func_tests

Expand Down Expand Up @@ -45,16 +43,13 @@ def ssl_protocol(self, *, waiter=None, proto=None):

def connection_made(self, ssl_proto, *, do_handshake=None):
transport = mock.Mock()
sslpipe = mock.Mock()
sslpipe.shutdown.return_value = b''
if do_handshake:
sslpipe.do_handshake.side_effect = do_handshake
else:
def mock_handshake(callback):
return []
sslpipe.do_handshake.side_effect = mock_handshake
with mock.patch('asyncio.sslproto._SSLPipe', return_value=sslpipe):
ssl_proto.connection_made(transport)
sslobj = mock.Mock()
# emulate reading decompressed data
sslobj.read.side_effect = ssl.SSLWantReadError
if do_handshake is not None:
sslobj.do_handshake = do_handshake
ssl_proto._sslobj = sslobj
ssl_proto.connection_made(transport)
return transport

def test_handshake_timeout_zero(self):
Expand Down Expand Up @@ -111,7 +106,10 @@ def test_close_during_handshake(self):
waiter = self.loop.create_future()
ssl_proto = self.ssl_protocol(waiter=waiter)

transport = self.connection_made(ssl_proto)
transport = self.connection_made(
ssl_proto,
do_handshake=mock.Mock(side_effect=ssl.SSLWantReadError)
)
test_utils.run_briefly(self.loop)

ssl_proto._app_transport.close()
Expand Down