Skip to content

Commit 8419d89

Browse files
Revert "Revert "bpo-42854: Use SSL_read/write_ex() (pythonGH-25468)""
This reverts commit fde82b2.
1 parent 2a87fb4 commit 8419d89

3 files changed

Lines changed: 30 additions & 18 deletions

File tree

Doc/library/ssl.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1157,6 +1157,11 @@ SSL Sockets
11571157
to create instances directly. This was never documented or officially
11581158
supported.
11591159

1160+
.. versionchanged:: 3.10
1161+
Python now uses ``SSL_read_ex`` and ``SSL_write_ex`` internally. The
1162+
functions support reading and writing of data larger than 2 GB. Writing
1163+
zero-length data no longer fails with a protocol violation error.
1164+
11601165
SSL sockets also have the following additional methods and attributes:
11611166

11621167
.. method:: SSLSocket.read(len=1024, buffer=None)

Lib/test/test_ssl.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,6 +1130,17 @@ def test_connect_ex_error(self):
11301130
)
11311131
self.assertIn(rc, errors)
11321132

1133+
def test_read_write_zero(self):
1134+
# empty reads and writes now work, bpo-42854, bpo-31711
1135+
client_context, server_context, hostname = testing_context()
1136+
server = ThreadedEchoServer(context=server_context)
1137+
with server:
1138+
with client_context.wrap_socket(socket.socket(),
1139+
server_hostname=hostname) as s:
1140+
s.connect((HOST, server.port))
1141+
self.assertEqual(s.recv(0), b"")
1142+
self.assertEqual(s.send(b""), 0)
1143+
11331144

11341145
class ContextTests(unittest.TestCase):
11351146

Modules/_ssl.c

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2352,7 +2352,8 @@ static PyObject *
23522352
_ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b)
23532353
/*[clinic end generated code: output=aa7a6be5527358d8 input=77262d994fe5100a]*/
23542354
{
2355-
int len;
2355+
size_t count = 0;
2356+
int retval;
23562357
int sockstate;
23572358
_PySSLError err;
23582359
int nonblocking;
@@ -2370,12 +2371,6 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b)
23702371
Py_INCREF(sock);
23712372
}
23722373

2373-
if (b->len > INT_MAX) {
2374-
PyErr_Format(PyExc_OverflowError,
2375-
"string longer than %d bytes", INT_MAX);
2376-
goto error;
2377-
}
2378-
23792374
if (sock != NULL) {
23802375
/* just in case the blocking state of the socket has been changed */
23812376
nonblocking = (sock->sock_timeout >= 0);
@@ -2405,8 +2400,8 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b)
24052400

24062401
do {
24072402
PySSL_BEGIN_ALLOW_THREADS
2408-
len = SSL_write(self->ssl, b->buf, (int)b->len);
2409-
err = _PySSL_errno(len <= 0, self->ssl, len);
2403+
retval = SSL_write_ex(self->ssl, b->buf, (size_t)b->len, &count);
2404+
err = _PySSL_errno(retval == 0, self->ssl, retval);
24102405
PySSL_END_ALLOW_THREADS
24112406
self->err = err;
24122407

@@ -2439,11 +2434,11 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b)
24392434
err.ssl == SSL_ERROR_WANT_WRITE);
24402435

24412436
Py_XDECREF(sock);
2442-
if (len <= 0)
2443-
return PySSL_SetError(self, len, __FILE__, __LINE__);
2437+
if (retval == 0)
2438+
return PySSL_SetError(self, retval, __FILE__, __LINE__);
24442439
if (PySSL_ChainExceptions(self) < 0)
24452440
return NULL;
2446-
return PyLong_FromLong(len);
2441+
return PyLong_FromSize_t(count);
24472442
error:
24482443
Py_XDECREF(sock);
24492444
PySSL_ChainExceptions(self);
@@ -2493,7 +2488,8 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, Py_ssize_t len,
24932488
{
24942489
PyObject *dest = NULL;
24952490
char *mem;
2496-
int count;
2491+
size_t count = 0;
2492+
int retval;
24972493
int sockstate;
24982494
_PySSLError err;
24992495
int nonblocking;
@@ -2556,8 +2552,8 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, Py_ssize_t len,
25562552

25572553
do {
25582554
PySSL_BEGIN_ALLOW_THREADS
2559-
count = SSL_read(self->ssl, mem, len);
2560-
err = _PySSL_errno(count <= 0, self->ssl, count);
2555+
retval = SSL_read_ex(self->ssl, mem, (size_t)len, &count);
2556+
err = _PySSL_errno(retval == 0, self->ssl, retval);
25612557
PySSL_END_ALLOW_THREADS
25622558
self->err = err;
25632559

@@ -2590,8 +2586,8 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, Py_ssize_t len,
25902586
} while (err.ssl == SSL_ERROR_WANT_READ ||
25912587
err.ssl == SSL_ERROR_WANT_WRITE);
25922588

2593-
if (count <= 0) {
2594-
PySSL_SetError(self, count, __FILE__, __LINE__);
2589+
if (retval == 0) {
2590+
PySSL_SetError(self, retval, __FILE__, __LINE__);
25952591
goto error;
25962592
}
25972593
if (self->exc_type != NULL)
@@ -2604,7 +2600,7 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, Py_ssize_t len,
26042600
return dest;
26052601
}
26062602
else {
2607-
return PyLong_FromLong(count);
2603+
return PyLong_FromSize_t(count);
26082604
}
26092605

26102606
error:

0 commit comments

Comments
 (0)