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.
This commit is contained in:
Antoine Pitrou 2014-04-29 10:03:28 +02:00
parent 727a463aa6
commit b4bebdafe3
4 changed files with 54 additions and 13 deletions

View File

@ -1604,8 +1604,25 @@ the sockets in non-blocking mode and use an event loop).
Notes on non-blocking sockets Notes on non-blocking sockets
----------------------------- -----------------------------
When working with non-blocking sockets, there are several things you need SSL sockets behave slightly different than regular sockets in
to be aware of: 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 - 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 read from (or written to), but it does not imply that there is sufficient

View File

@ -664,17 +664,7 @@ class SSLSocket(socket):
raise ValueError( raise ValueError(
"non-zero flags not allowed in calls to send() on %s" % "non-zero flags not allowed in calls to send() on %s" %
self.__class__) self.__class__)
try: return self._sslobj.write(data)
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
else: else:
return socket.send(self, data, flags) return socket.send(self, data, flags)

View File

@ -2547,6 +2547,36 @@ else:
s.write(b"over\n") s.write(b"over\n")
s.close() 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): def test_handshake_timeout(self):
# Issue #5103: SSL handshake must respect the socket timeout # Issue #5103: SSL handshake must respect the socket timeout
server = socket.socket(socket.AF_INET) server = socket.socket(socket.AF_INET)

View File

@ -60,6 +60,10 @@ Core and Builtins
Library 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__ - Issue #13248: removed previously deprecated asyncore.dispatcher __getattr__
cheap inheritance hack. cheap inheritance hack.