mirror of
https://github.com/python/cpython.git
synced 2025-11-11 14:44:57 +00:00
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@python.org>
This commit is contained in:
parent
49fdf118ae
commit
89d1550d14
4 changed files with 34 additions and 18 deletions
|
|
@ -1122,6 +1122,11 @@ SSL Sockets
|
||||||
to create instances directly. This was never documented or officially
|
to create instances directly. This was never documented or officially
|
||||||
supported.
|
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:
|
SSL sockets also have the following additional methods and attributes:
|
||||||
|
|
||||||
.. method:: SSLSocket.read(len=1024, buffer=None)
|
.. method:: SSLSocket.read(len=1024, buffer=None)
|
||||||
|
|
|
||||||
|
|
@ -1110,6 +1110,17 @@ class BasicSocketTests(unittest.TestCase):
|
||||||
)
|
)
|
||||||
self.assertIn(rc, errors)
|
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):
|
class ContextTests(unittest.TestCase):
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
@ -2186,7 +2186,8 @@ static PyObject *
|
||||||
_ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b)
|
_ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b)
|
||||||
/*[clinic end generated code: output=aa7a6be5527358d8 input=77262d994fe5100a]*/
|
/*[clinic end generated code: output=aa7a6be5527358d8 input=77262d994fe5100a]*/
|
||||||
{
|
{
|
||||||
int len;
|
size_t count = 0;
|
||||||
|
int retval;
|
||||||
int sockstate;
|
int sockstate;
|
||||||
_PySSLError err;
|
_PySSLError err;
|
||||||
int nonblocking;
|
int nonblocking;
|
||||||
|
|
@ -2204,12 +2205,6 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b)
|
||||||
Py_INCREF(sock);
|
Py_INCREF(sock);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (b->len > INT_MAX) {
|
|
||||||
PyErr_Format(PyExc_OverflowError,
|
|
||||||
"string longer than %d bytes", INT_MAX);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sock != NULL) {
|
if (sock != NULL) {
|
||||||
/* just in case the blocking state of the socket has been changed */
|
/* just in case the blocking state of the socket has been changed */
|
||||||
nonblocking = (sock->sock_timeout >= 0);
|
nonblocking = (sock->sock_timeout >= 0);
|
||||||
|
|
@ -2239,8 +2234,8 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b)
|
||||||
|
|
||||||
do {
|
do {
|
||||||
PySSL_BEGIN_ALLOW_THREADS
|
PySSL_BEGIN_ALLOW_THREADS
|
||||||
len = SSL_write(self->ssl, b->buf, (int)b->len);
|
retval = SSL_write_ex(self->ssl, b->buf, (int)b->len, &count);
|
||||||
err = _PySSL_errno(len <= 0, self->ssl, len);
|
err = _PySSL_errno(retval == 0, self->ssl, retval);
|
||||||
PySSL_END_ALLOW_THREADS
|
PySSL_END_ALLOW_THREADS
|
||||||
self->err = err;
|
self->err = err;
|
||||||
|
|
||||||
|
|
@ -2273,11 +2268,11 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b)
|
||||||
err.ssl == SSL_ERROR_WANT_WRITE);
|
err.ssl == SSL_ERROR_WANT_WRITE);
|
||||||
|
|
||||||
Py_XDECREF(sock);
|
Py_XDECREF(sock);
|
||||||
if (len <= 0)
|
if (retval == 0)
|
||||||
return PySSL_SetError(self, len, __FILE__, __LINE__);
|
return PySSL_SetError(self, retval, __FILE__, __LINE__);
|
||||||
if (PySSL_ChainExceptions(self) < 0)
|
if (PySSL_ChainExceptions(self) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
return PyLong_FromLong(len);
|
return PyLong_FromSize_t(count);
|
||||||
error:
|
error:
|
||||||
Py_XDECREF(sock);
|
Py_XDECREF(sock);
|
||||||
PySSL_ChainExceptions(self);
|
PySSL_ChainExceptions(self);
|
||||||
|
|
@ -2327,7 +2322,8 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, int len, int group_right_1,
|
||||||
{
|
{
|
||||||
PyObject *dest = NULL;
|
PyObject *dest = NULL;
|
||||||
char *mem;
|
char *mem;
|
||||||
int count;
|
size_t count = 0;
|
||||||
|
int retval;
|
||||||
int sockstate;
|
int sockstate;
|
||||||
_PySSLError err;
|
_PySSLError err;
|
||||||
int nonblocking;
|
int nonblocking;
|
||||||
|
|
@ -2390,8 +2386,8 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, int len, int group_right_1,
|
||||||
|
|
||||||
do {
|
do {
|
||||||
PySSL_BEGIN_ALLOW_THREADS
|
PySSL_BEGIN_ALLOW_THREADS
|
||||||
count = SSL_read(self->ssl, mem, len);
|
retval = SSL_read_ex(self->ssl, mem, len, &count);
|
||||||
err = _PySSL_errno(count <= 0, self->ssl, count);
|
err = _PySSL_errno(retval == 0, self->ssl, retval);
|
||||||
PySSL_END_ALLOW_THREADS
|
PySSL_END_ALLOW_THREADS
|
||||||
self->err = err;
|
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 ||
|
} while (err.ssl == SSL_ERROR_WANT_READ ||
|
||||||
err.ssl == SSL_ERROR_WANT_WRITE);
|
err.ssl == SSL_ERROR_WANT_WRITE);
|
||||||
|
|
||||||
if (count <= 0) {
|
if (retval == 0) {
|
||||||
PySSL_SetError(self, count, __FILE__, __LINE__);
|
PySSL_SetError(self, retval, __FILE__, __LINE__);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (self->exc_type != NULL)
|
if (self->exc_type != NULL)
|
||||||
|
|
@ -2438,7 +2434,7 @@ done:
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return PyLong_FromLong(count);
|
return PyLong_FromSize_t(count);
|
||||||
}
|
}
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue