Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions Include/cpython/pyerrors.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ PyAPI_FUNC(PyObject *) _PyErr_TrySetFromCause(

int PySignal_SetWakeupFd(int fd);
PyAPI_FUNC(int) _PyErr_CheckSignals(void);
PyAPI_FUNC(int) _PyErr_CheckSignalsTrippedNoGil(void);

/* Support for adding program text to SyntaxErrors */

Expand Down
57 changes: 52 additions & 5 deletions Lib/test/test_ssl.py
Original file line number Diff line number Diff line change
Expand Up @@ -2120,6 +2120,49 @@ def test_bio_read_write_data(self):
self.assertEqual(buf, b'foo\n')
self.ssl_io_loop(sock, incoming, outgoing, sslobj.unwrap)

def test_bulk_nonblocking_read(self):
# 65536 bytes divide up into 4 TLS records (16 KB each)
# In nonblocking mode, we should be able to read all four in a single
# drop of the GIL.
size = 65536
trips = []

client_context, server_context, hostname = testing_context()
server = ThreadedEchoServer(context=server_context, chatty=False,
buffer_size=size)
with server:
sock = socket.create_connection((HOST, server.port))
sock.settimeout(0.0)
s = client_context.wrap_socket(sock, server_hostname=hostname,
do_handshake_on_connect=False)

with s:
while True:
try:
s.do_handshake()
break
except ssl.SSLWantReadError:
select.select([s], [], [])
except ssl.SSLWantWriteError:
select.select([], [s], [])

s.send(b'\x00' * size)

select.select([s], [], [])

while size > 0:
try:
count = len(s.recv(size))
except ssl.SSLWantReadError:
select.select([s], [], [])
# Give the sender some more time to complete sending.
time.sleep(0.01)
else:
if count > 16384:
return
size -= count

self.fail("All TLS reads were smaller than 16KB")

@support.requires_resource('network')
class NetworkedTests(unittest.TestCase):
Expand Down Expand Up @@ -2179,7 +2222,7 @@ class ConnectionHandler(threading.Thread):
with and without the SSL wrapper around the socket connection, so
that we can test the STARTTLS functionality."""

def __init__(self, server, connsock, addr):
def __init__(self, server, connsock, addr, buffer_size):
self.server = server
self.running = False
self.sock = connsock
Expand All @@ -2188,6 +2231,7 @@ def __init__(self, server, connsock, addr):
self.sslconn = None
threading.Thread.__init__(self)
self.daemon = True
self.buffer_size = buffer_size

def wrap_conn(self):
try:
Expand Down Expand Up @@ -2253,9 +2297,9 @@ def wrap_conn(self):

def read(self):
if self.sslconn:
return self.sslconn.read()
return self.sslconn.read(self.buffer_size)
else:
return self.sock.recv(1024)
return self.sock.recv(self.buffer_size)

def write(self, bytes):
if self.sslconn:
Expand Down Expand Up @@ -2374,7 +2418,8 @@ def __init__(self, certificate=None, ssl_version=None,
certreqs=None, cacerts=None,
chatty=True, connectionchatty=False, starttls_server=False,
alpn_protocols=None,
ciphers=None, context=None):
ciphers=None, context=None,
buffer_size=1024):
if context:
self.context = context
else:
Expand Down Expand Up @@ -2403,6 +2448,7 @@ def __init__(self, certificate=None, ssl_version=None,
self.conn_errors = []
threading.Thread.__init__(self)
self.daemon = True
self.buffer_size = buffer_size

def __enter__(self):
self.start(threading.Event())
Expand Down Expand Up @@ -2430,7 +2476,8 @@ def run(self):
if support.verbose and self.chatty:
sys.stdout.write(' server: new connection from '
+ repr(connaddr) + '\n')
handler = self.ConnectionHandler(self, newconn, connaddr)
handler = self.ConnectionHandler(self, newconn, connaddr,
self.buffer_size)
handler.start()
handler.join()
except TimeoutError as e:
Expand Down
Loading