mirror of https://github.com/python/cpython.git
Revert r79915 (temporary commit to check for buildbots -> the fix was successful)
This commit is contained in:
parent
9c6cd56e91
commit
343314a11c
|
@ -29,7 +29,6 @@
|
||||||
|
|
||||||
|
|
||||||
class DummyDTPHandler(asynchat.async_chat):
|
class DummyDTPHandler(asynchat.async_chat):
|
||||||
dtp_conn_closed = False
|
|
||||||
|
|
||||||
def __init__(self, conn, baseclass):
|
def __init__(self, conn, baseclass):
|
||||||
asynchat.async_chat.__init__(self, conn)
|
asynchat.async_chat.__init__(self, conn)
|
||||||
|
@ -40,13 +39,8 @@ def handle_read(self):
|
||||||
self.baseclass.last_received_data += self.recv(1024)
|
self.baseclass.last_received_data += self.recv(1024)
|
||||||
|
|
||||||
def handle_close(self):
|
def handle_close(self):
|
||||||
# XXX: this method can be called many times in a row for a single
|
self.baseclass.push('226 transfer complete')
|
||||||
# connection, including in clear-text (non-TLS) mode.
|
self.close()
|
||||||
# (behaviour witnessed with test_data_connection)
|
|
||||||
if not self.dtp_conn_closed:
|
|
||||||
self.baseclass.push('226 transfer complete')
|
|
||||||
self.close()
|
|
||||||
self.dtp_conn_closed = True
|
|
||||||
|
|
||||||
|
|
||||||
class DummyFTPHandler(asynchat.async_chat):
|
class DummyFTPHandler(asynchat.async_chat):
|
||||||
|
@ -259,7 +253,6 @@ class SSLConnection(object, asyncore.dispatcher):
|
||||||
"""An asyncore.dispatcher subclass supporting TLS/SSL."""
|
"""An asyncore.dispatcher subclass supporting TLS/SSL."""
|
||||||
|
|
||||||
_ssl_accepting = False
|
_ssl_accepting = False
|
||||||
_ssl_closing = False
|
|
||||||
|
|
||||||
def secure_connection(self):
|
def secure_connection(self):
|
||||||
self.socket = ssl.wrap_socket(self.socket, suppress_ragged_eofs=False,
|
self.socket = ssl.wrap_socket(self.socket, suppress_ragged_eofs=False,
|
||||||
|
@ -284,36 +277,15 @@ def _do_ssl_handshake(self):
|
||||||
else:
|
else:
|
||||||
self._ssl_accepting = False
|
self._ssl_accepting = False
|
||||||
|
|
||||||
def _do_ssl_shutdown(self):
|
|
||||||
self._ssl_closing = True
|
|
||||||
try:
|
|
||||||
self.socket = self.socket.unwrap()
|
|
||||||
except ssl.SSLError, err:
|
|
||||||
if err.args[0] in (ssl.SSL_ERROR_WANT_READ,
|
|
||||||
ssl.SSL_ERROR_WANT_WRITE):
|
|
||||||
return
|
|
||||||
except socket.error, err:
|
|
||||||
# Any "socket error" corresponds to a SSL_ERROR_SYSCALL return
|
|
||||||
# from OpenSSL's SSL_shutdown(), corresponding to a
|
|
||||||
# closed socket condition. See also:
|
|
||||||
# http://www.mail-archive.com/openssl-users@openssl.org/msg60710.html
|
|
||||||
pass
|
|
||||||
self._ssl_closing = False
|
|
||||||
super(SSLConnection, self).close()
|
|
||||||
|
|
||||||
def handle_read_event(self):
|
def handle_read_event(self):
|
||||||
if self._ssl_accepting:
|
if self._ssl_accepting:
|
||||||
self._do_ssl_handshake()
|
self._do_ssl_handshake()
|
||||||
elif self._ssl_closing:
|
|
||||||
self._do_ssl_shutdown()
|
|
||||||
else:
|
else:
|
||||||
super(SSLConnection, self).handle_read_event()
|
super(SSLConnection, self).handle_read_event()
|
||||||
|
|
||||||
def handle_write_event(self):
|
def handle_write_event(self):
|
||||||
if self._ssl_accepting:
|
if self._ssl_accepting:
|
||||||
self._do_ssl_handshake()
|
self._do_ssl_handshake()
|
||||||
elif self._ssl_closing:
|
|
||||||
self._do_ssl_shutdown()
|
|
||||||
else:
|
else:
|
||||||
super(SSLConnection, self).handle_write_event()
|
super(SSLConnection, self).handle_write_event()
|
||||||
|
|
||||||
|
@ -343,9 +315,12 @@ def handle_error(self):
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
if (isinstance(self.socket, ssl.SSLSocket) and
|
try:
|
||||||
self.socket._sslobj is not None):
|
if isinstance(self.socket, ssl.SSLSocket):
|
||||||
self._do_ssl_shutdown()
|
if self.socket._sslobj is not None:
|
||||||
|
self.socket.unwrap()
|
||||||
|
finally:
|
||||||
|
super(SSLConnection, self).close()
|
||||||
|
|
||||||
|
|
||||||
class DummyTLS_DTPHandler(SSLConnection, DummyDTPHandler):
|
class DummyTLS_DTPHandler(SSLConnection, DummyDTPHandler):
|
||||||
|
@ -622,21 +597,21 @@ def test_data_connection(self):
|
||||||
sock = self.client.transfercmd('list')
|
sock = self.client.transfercmd('list')
|
||||||
self.assertNotIsInstance(sock, ssl.SSLSocket)
|
self.assertNotIsInstance(sock, ssl.SSLSocket)
|
||||||
sock.close()
|
sock.close()
|
||||||
self.assertEqual(self.client.voidresp(), "226 transfer complete")
|
self.client.voidresp()
|
||||||
|
|
||||||
# secured, after PROT P
|
# secured, after PROT P
|
||||||
self.client.prot_p()
|
self.client.prot_p()
|
||||||
sock = self.client.transfercmd('list')
|
sock = self.client.transfercmd('list')
|
||||||
self.assertIsInstance(sock, ssl.SSLSocket)
|
self.assertIsInstance(sock, ssl.SSLSocket)
|
||||||
sock.close()
|
sock.close()
|
||||||
self.assertEqual(self.client.voidresp(), "226 transfer complete")
|
self.client.voidresp()
|
||||||
|
|
||||||
# PROT C is issued, the connection must be in cleartext again
|
# PROT C is issued, the connection must be in cleartext again
|
||||||
self.client.prot_c()
|
self.client.prot_c()
|
||||||
sock = self.client.transfercmd('list')
|
sock = self.client.transfercmd('list')
|
||||||
self.assertNotIsInstance(sock, ssl.SSLSocket)
|
self.assertNotIsInstance(sock, ssl.SSLSocket)
|
||||||
sock.close()
|
sock.close()
|
||||||
self.assertEqual(self.client.voidresp(), "226 transfer complete")
|
self.client.voidresp()
|
||||||
|
|
||||||
def test_login(self):
|
def test_login(self):
|
||||||
# login() is supposed to implicitly secure the control connection
|
# login() is supposed to implicitly secure the control connection
|
||||||
|
|
|
@ -1347,7 +1347,7 @@ Read up to len bytes from the SSL socket.");
|
||||||
|
|
||||||
static PyObject *PySSL_SSLshutdown(PySSLObject *self)
|
static PyObject *PySSL_SSLshutdown(PySSLObject *self)
|
||||||
{
|
{
|
||||||
int err, ssl_err, sockstate;
|
int err;
|
||||||
|
|
||||||
/* Guard against closed socket */
|
/* Guard against closed socket */
|
||||||
if (self->Socket->sock_fd < 0) {
|
if (self->Socket->sock_fd < 0) {
|
||||||
|
@ -1356,42 +1356,13 @@ static PyObject *PySSL_SSLshutdown(PySSLObject *self)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
PySSL_BEGIN_ALLOW_THREADS
|
||||||
PySSL_BEGIN_ALLOW_THREADS
|
err = SSL_shutdown(self->ssl);
|
||||||
|
if (err == 0) {
|
||||||
|
/* we need to call it again to finish the shutdown */
|
||||||
err = SSL_shutdown(self->ssl);
|
err = SSL_shutdown(self->ssl);
|
||||||
if (err == 0) {
|
|
||||||
/* we need to call it again to finish the shutdown */
|
|
||||||
err = SSL_shutdown(self->ssl);
|
|
||||||
}
|
|
||||||
PySSL_END_ALLOW_THREADS
|
|
||||||
if (err >= 0)
|
|
||||||
break;
|
|
||||||
/* Possibly retry shutdown until timeout or failure */
|
|
||||||
ssl_err = SSL_get_error(self->ssl, err);
|
|
||||||
if (ssl_err == SSL_ERROR_WANT_READ)
|
|
||||||
sockstate = check_socket_and_wait_for_timeout(self->Socket, 0);
|
|
||||||
else if (ssl_err == SSL_ERROR_WANT_WRITE)
|
|
||||||
sockstate = check_socket_and_wait_for_timeout(self->Socket, 1);
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
if (sockstate == SOCKET_HAS_TIMED_OUT) {
|
|
||||||
if (ssl_err == SSL_ERROR_WANT_READ)
|
|
||||||
PyErr_SetString(PySSLErrorObject,
|
|
||||||
"The read operation timed out");
|
|
||||||
else
|
|
||||||
PyErr_SetString(PySSLErrorObject,
|
|
||||||
"The write operation timed out");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) {
|
|
||||||
PyErr_SetString(PySSLErrorObject,
|
|
||||||
"Underlying socket too large for select().");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
else if (sockstate != SOCKET_OPERATION_OK)
|
|
||||||
/* Retain the SSL error code */
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
PySSL_END_ALLOW_THREADS
|
||||||
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return PySSL_SetError(self, err, __FILE__, __LINE__);
|
return PySSL_SetError(self, err, __FILE__, __LINE__);
|
||||||
|
|
Loading…
Reference in New Issue