From b4bebdafe354f68a9b952772da109cccd73f6577 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Tue, 29 Apr 2014 10:03:28 +0200 Subject: Issue #20951: SSLSocket.send() now raises either SSLWantReadError or SSLWantWriteError on a non-blocking socket if the operation would block. Previously, it would return 0. Patch by Nikolaus Rath. --- Doc/library/ssl.rst | 21 +++++++++++++++++++-- Lib/ssl.py | 12 +----------- Lib/test/test_ssl.py | 30 ++++++++++++++++++++++++++++++ Misc/NEWS | 4 ++++ 4 files changed, 54 insertions(+), 13 deletions(-) diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index 79cbbdc..8c1484b 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -1604,8 +1604,25 @@ the sockets in non-blocking mode and use an event loop). Notes on non-blocking sockets ----------------------------- -When working with non-blocking sockets, there are several things you need -to be aware of: +SSL sockets behave slightly different than regular sockets in +non-blocking mode. When working with non-blocking sockets, there are +thus several things you need to be aware of: + +- Most :class:`SSLSocket` methods will raise either + :exc:`SSLWantWriteError` or :exc:`SSLWantReadError` instead of + :exc:`BlockingIOError` if an I/O operation would + block. :exc:`SSLWantReadError` will be raised if a read operation on + the underlying socket is necessary, and :exc:`SSLWantWriteError` for + a write operation on the underlying socket. Note that attempts to + *write* to an SSL socket may require *reading* from the underlying + socket first, and attempts to *read* from the SSL socket may require + a prior *write* to the underlying socket. + + .. versionchanged:: 3.5 + + In earlier Python versions, the :meth:`!SSLSocket.send` method + returned zero instead of raising :exc:`SSLWantWriteError` or + :exc:`SSLWantReadError`. - Calling :func:`~select.select` tells you that the OS-level socket can be read from (or written to), but it does not imply that there is sufficient diff --git a/Lib/ssl.py b/Lib/ssl.py index 9c91096..8f12513 100644 --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -664,17 +664,7 @@ class SSLSocket(socket): raise ValueError( "non-zero flags not allowed in calls to send() on %s" % self.__class__) - try: - v = self._sslobj.write(data) - except SSLError as x: - if x.args[0] == SSL_ERROR_WANT_READ: - return 0 - elif x.args[0] == SSL_ERROR_WANT_WRITE: - return 0 - else: - raise - else: - return v + return self._sslobj.write(data) else: return socket.send(self, data, flags) diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index a23d263..f72fb15 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -2547,6 +2547,36 @@ else: s.write(b"over\n") s.close() + def test_nonblocking_send(self): + server = ThreadedEchoServer(CERTFILE, + certreqs=ssl.CERT_NONE, + ssl_version=ssl.PROTOCOL_TLSv1, + cacerts=CERTFILE, + chatty=True, + connectionchatty=False) + with server: + s = ssl.wrap_socket(socket.socket(), + server_side=False, + certfile=CERTFILE, + ca_certs=CERTFILE, + cert_reqs=ssl.CERT_NONE, + ssl_version=ssl.PROTOCOL_TLSv1) + s.connect((HOST, server.port)) + s.setblocking(False) + + # If we keep sending data, at some point the buffers + # will be full and the call will block + buf = bytearray(8192) + def fill_buffer(): + while True: + s.send(buf) + self.assertRaises((ssl.SSLWantWriteError, + ssl.SSLWantReadError), fill_buffer) + + # Now read all the output and discard it + s.setblocking(True) + s.close() + def test_handshake_timeout(self): # Issue #5103: SSL handshake must respect the socket timeout server = socket.socket(socket.AF_INET) diff --git a/Misc/NEWS b/Misc/NEWS index cd51f2e..23245c0 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -60,6 +60,10 @@ Core and Builtins Library ------- +- Issue #20951: SSLSocket.send() now raises either SSLWantReadError or + SSLWantWriteError on a non-blocking socket if the operation would block. + Previously, it would return 0. Patch by Nikolaus Rath. + - Issue #13248: removed previously deprecated asyncore.dispatcher __getattr__ cheap inheritance hack. -- cgit v0.12