[Python-checkins] bpo-42854: Use SSL_read/write_ex() (GH-25468)

tiran webhook-mailer at python.org
Mon Apr 19 00:55:38 EDT 2021


https://github.com/python/cpython/commit/89d1550d14ba689af12eeb726e4ff8ce73cee7e1
commit: 89d1550d14ba689af12eeb726e4ff8ce73cee7e1
branch: master
author: Christian Heimes <christian at python.org>
committer: tiran <christian at python.org>
date: 2021-04-19T06:55:30+02:00
summary:

bpo-42854: Use SSL_read/write_ex() (GH-25468)

The ssl module now uses ``SSL_read_ex`` and ``SSL_write_ex``
internally. The functions support reading and writing of data larger
than 2 GB. Writing zero-length data no longer fails with a protocol
violation error.

Signed-off-by: Christian Heimes <christian at python.org>

files:
A Misc/NEWS.d/next/Library/2021-04-19-03-54-29.bpo-42854.Y4M7Tv.rst
M Doc/library/ssl.rst
M Lib/test/test_ssl.py
M Modules/_ssl.c

diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst
index 9d5e063456ec2..8bac365ffc0e4 100644
--- a/Doc/library/ssl.rst
+++ b/Doc/library/ssl.rst
@@ -1122,6 +1122,11 @@ SSL Sockets
       to create instances directly. This was never documented or officially
       supported.
 
+   .. versionchanged:: 3.10
+      Python now uses ``SSL_read_ex`` and ``SSL_write_ex`` internally. The
+      functions support reading and writing of data larger than 2 GB. Writing
+      zero-length data no longer fails with a protocol violation error.
+
 SSL sockets also have the following additional methods and attributes:
 
 .. method:: SSLSocket.read(len=1024, buffer=None)
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
index 403261dda9680..7b70979026dcf 100644
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -1110,6 +1110,17 @@ def test_connect_ex_error(self):
         )
         self.assertIn(rc, errors)
 
+    def test_read_write_zero(self):
+        # empty reads and writes now work, bpo-42854, bpo-31711
+        client_context, server_context, hostname = testing_context()
+        server = ThreadedEchoServer(context=server_context)
+        with server:
+            with client_context.wrap_socket(socket.socket(),
+                                            server_hostname=hostname) as s:
+                s.connect((HOST, server.port))
+                self.assertEqual(s.recv(0), b"")
+                self.assertEqual(s.send(b""), 0)
+
 
 class ContextTests(unittest.TestCase):
 
diff --git a/Misc/NEWS.d/next/Library/2021-04-19-03-54-29.bpo-42854.Y4M7Tv.rst b/Misc/NEWS.d/next/Library/2021-04-19-03-54-29.bpo-42854.Y4M7Tv.rst
new file mode 100644
index 0000000000000..3941fd85635f0
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2021-04-19-03-54-29.bpo-42854.Y4M7Tv.rst
@@ -0,0 +1,4 @@
+The :mod:`ssl` module now uses ``SSL_read_ex`` and ``SSL_write_ex``
+internally. The functions support reading and writing of data larger
+than 2 GB. Writing zero-length data no longer fails with a protocol
+violation error.
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
index 376d3bb11a40b..f371d4210a488 100644
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -2186,7 +2186,8 @@ static PyObject *
 _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b)
 /*[clinic end generated code: output=aa7a6be5527358d8 input=77262d994fe5100a]*/
 {
-    int len;
+    size_t count = 0;
+    int retval;
     int sockstate;
     _PySSLError err;
     int nonblocking;
@@ -2204,12 +2205,6 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b)
         Py_INCREF(sock);
     }
 
-    if (b->len > INT_MAX) {
-        PyErr_Format(PyExc_OverflowError,
-                     "string longer than %d bytes", INT_MAX);
-        goto error;
-    }
-
     if (sock != NULL) {
         /* just in case the blocking state of the socket has been changed */
         nonblocking = (sock->sock_timeout >= 0);
@@ -2239,8 +2234,8 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b)
 
     do {
         PySSL_BEGIN_ALLOW_THREADS
-        len = SSL_write(self->ssl, b->buf, (int)b->len);
-        err = _PySSL_errno(len <= 0, self->ssl, len);
+        retval = SSL_write_ex(self->ssl, b->buf, (int)b->len, &count);
+        err = _PySSL_errno(retval == 0, self->ssl, retval);
         PySSL_END_ALLOW_THREADS
         self->err = err;
 
@@ -2273,11 +2268,11 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b)
              err.ssl == SSL_ERROR_WANT_WRITE);
 
     Py_XDECREF(sock);
-    if (len <= 0)
-        return PySSL_SetError(self, len, __FILE__, __LINE__);
+    if (retval == 0)
+        return PySSL_SetError(self, retval, __FILE__, __LINE__);
     if (PySSL_ChainExceptions(self) < 0)
         return NULL;
-    return PyLong_FromLong(len);
+    return PyLong_FromSize_t(count);
 error:
     Py_XDECREF(sock);
     PySSL_ChainExceptions(self);
@@ -2327,7 +2322,8 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, int len, int group_right_1,
 {
     PyObject *dest = NULL;
     char *mem;
-    int count;
+    size_t count = 0;
+    int retval;
     int sockstate;
     _PySSLError err;
     int nonblocking;
@@ -2390,8 +2386,8 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, int len, int group_right_1,
 
     do {
         PySSL_BEGIN_ALLOW_THREADS
-        count = SSL_read(self->ssl, mem, len);
-        err = _PySSL_errno(count <= 0, self->ssl, count);
+        retval = SSL_read_ex(self->ssl, mem, len, &count);
+        err = _PySSL_errno(retval == 0, self->ssl, retval);
         PySSL_END_ALLOW_THREADS
         self->err = err;
 
@@ -2424,8 +2420,8 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, int len, int group_right_1,
     } while (err.ssl == SSL_ERROR_WANT_READ ||
              err.ssl == SSL_ERROR_WANT_WRITE);
 
-    if (count <= 0) {
-        PySSL_SetError(self, count, __FILE__, __LINE__);
+    if (retval == 0) {
+        PySSL_SetError(self, retval, __FILE__, __LINE__);
         goto error;
     }
     if (self->exc_type != NULL)
@@ -2438,7 +2434,7 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, int len, int group_right_1,
         return dest;
     }
     else {
-        return PyLong_FromLong(count);
+        return PyLong_FromSize_t(count);
     }
 
 error:



More information about the Python-checkins mailing list