diff options
author | James Bowes <jbowes@redhat.com> | 2006-10-23 20:43:39 +0200 |
---|---|---|
committer | Matěj Cepl <mcepl@cepl.eu> | 2015-10-13 12:17:07 +0200 |
commit | 1b5f8bbe04280558dfe577a2df203eaf0600c473 (patch) | |
tree | 280f69477f036623cdf0f44af154e3dbad396153 | |
parent | 49d300db3c331567be7bd86e6d8f92236486f43b (diff) | |
download | m2crypto-1b5f8bbe04280558dfe577a2df203eaf0600c473.tar.gz |
Add support for SSL socket timeouts
See for discussion of this patch
https://bugzilla.redhat.com/show_bug.cgi?id=210966
This patch adds timeout to SSL Operations, but it breaks API. From the
linked bug comment:
This patch seems to change the API, likely breaking any currently
working code that uses nonblocking sockets.
- the patch completely changes the semantics of non-blocking
operations (with timeout==0.0): instead of returning 0L, None or
-1, they would raise exceptions
- although SSL.Connection._{read,write}_{,n}bio uses the "internal
use" naming convention, they are used in the shipped demo and
contrib code, so I wouldn't be surprised if they were used in
applications as well
- SSL.Connection.makefile() supports write-only and read-write file
objects, while SSLFile is supports only reading.
ALSO, BE AWARE THAT THIS BUG USES LINUX SYSTEM CALL POLL() IN ITS
C PART, SO IT IS NOT WORKING ON WINDOWS.
-rw-r--r-- | M2Crypto/SSL/Connection.py | 59 | ||||
-rw-r--r-- | M2Crypto/SSL/__init__.py | 5 | ||||
-rw-r--r-- | SWIG/_ssl.i | 260 | ||||
-rw-r--r-- | tests/test_ssl.py | 93 |
4 files changed, 307 insertions, 110 deletions
diff --git a/M2Crypto/SSL/Connection.py b/M2Crypto/SSL/Connection.py index ef6a2c8..5d2fb96 100644 --- a/M2Crypto/SSL/Connection.py +++ b/M2Crypto/SSL/Connection.py @@ -41,15 +41,17 @@ class Connection: def __init__(self, ctx, sock=None): self.ctx = ctx self.ssl = m2.ssl_new(self.ctx.ctx) - if sock is not None: + if sock is not None: self.socket = sock else: self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self._fileno = self.socket.fileno() - - self.blocking = self.socket.gettimeout() - + + self._timeout = self.socket.gettimeout() + if self._timeout is None: + self._timeout = -1.0 + self.ssl_close_flag = m2.bio_noclose @@ -83,7 +85,7 @@ class Connection: self.socket.bind(addr) def listen(self, qlen=5): - self.socket.listen(qlen) + self.socket.listen(qlen) def ssl_get_error(self, ret): return m2.ssl_get_error(self.ssl, ret) @@ -93,15 +95,15 @@ class Connection: Explicitly set read and write bios """ m2.ssl_set_bio(self.ssl, readbio._ptr(), writebio._ptr()) - + def set_client_CA_list_from_file(self, cafile): """ Set the acceptable client CA list. If the client returns a certificate, it must have been issued by one of the CAs listed in cafile. - + Makes sense only for servers. - + @param cafile: Filename from which to load the CA list. """ m2.ssl_set_client_CA_list_from_file(self.ssl, cafile) @@ -111,7 +113,7 @@ class Connection: Set the acceptable client CA list. If the client returns a certificate, it must have been issued by one of the CAs listed in context. - + Makes sense only for servers. """ m2.ssl_set_client_CA_list_from_context(self.ssl, self.ctx.ctx) @@ -147,7 +149,7 @@ class Connection: m2.ssl_set_accept_state(self.ssl) def accept_ssl(self): - return m2.ssl_accept(self.ssl) + return m2.ssl_accept(self.ssl, self._timeout) def accept(self): """Accept an SSL connection. The return value is a pair (ssl, addr) where @@ -169,7 +171,7 @@ class Connection: m2.ssl_set_connect_state(self.ssl) def connect_ssl(self): - return m2.ssl_connect(self.ssl) + return m2.ssl_connect(self.ssl, self._timeout) def connect(self, addr): self.socket.connect(addr) @@ -191,12 +193,12 @@ class Connection: return m2.ssl_renegotiate(self.ssl) def pending(self): - """Return the numbers of octets that can be read from the + """Return the numbers of octets that can be read from the connection.""" return m2.ssl_pending(self.ssl) def _write_bio(self, data): - return m2.ssl_write(self.ssl, data) + return m2.ssl_write(self.ssl, data, self._timeout) def _write_nbio(self, data): return m2.ssl_write_nbio(self.ssl, data) @@ -204,7 +206,7 @@ class Connection: def _read_bio(self, size=1024): if size <= 0: raise ValueError, 'size <= 0' - return m2.ssl_read(self.ssl, size) + return m2.ssl_read(self.ssl, size, self._timeout) def _read_nbio(self, size=1024): if size <= 0: @@ -212,13 +214,13 @@ class Connection: return m2.ssl_read_nbio(self.ssl, size) def write(self, data): - if self.blocking: + if self._timeout != 0.0: return self._write_bio(data) return self._write_nbio(data) sendall = send = write def read(self, size=1024): - if self.blocking: + if self._timeout != 0.0: return self._read_bio(size) return self._read_nbio(size) recv = read @@ -226,7 +228,17 @@ class Connection: def setblocking(self, mode): """Set this connection's underlying socket to _mode_.""" self.socket.setblocking(mode) - self.blocking = mode + if mode: + self._timeout = -1.0 + else: + self._timeout = 0.0 + + def settimeout(self, timeout): + """Set this connection's underlying socket's timeout to _timeout_.""" + self.socket.settimeout(timeout) + self._timeout = timeout + if self._timeout is None: + self._timeout = -1.0 def fileno(self): return self.socket.fileno() @@ -238,7 +250,7 @@ class Connection: return apply(self.socket.setsockopt, args) def get_context(self): - """Return the SSL.Context object associated with this + """Return the SSL.Context object associated with this connection.""" return m2.ssl_get_ssl_ctx(self.ssl) @@ -308,15 +320,8 @@ class Connection: """Set the cipher suites for this connection.""" return m2.ssl_set_cipher_list(self.ssl, cipher_list) - def makefile(self, mode='rb', bufsize='ignored'): - r = 'r' in mode or '+' in mode - w = 'w' in mode or 'a' in mode or '+' in mode - b = 'b' in mode - m2mode = ['', 'r'][r] + ['', 'w'][w] + ['', 'b'][b] - # XXX Need to dup(). - bio = BIO.BIO(self.sslbio, _close_cb=self.close) - m2.bio_do_handshake(bio._ptr()) - return BIO.IOBuffer(bio, m2mode, _pyfree=0) + def makefile(self, mode='rb', bufsize=-1): + return socket._fileobject(self, mode, bufsize) def getsockname(self): return self.socket.getsockname() diff --git a/M2Crypto/SSL/__init__.py b/M2Crypto/SSL/__init__.py index a013569..00d4e54 100644 --- a/M2Crypto/SSL/__init__.py +++ b/M2Crypto/SSL/__init__.py @@ -2,11 +2,14 @@ Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.""" +import socket + # M2Crypto from M2Crypto import m2 class SSLError(Exception): pass -m2.ssl_init(SSLError) +class SSLTimeoutError(SSLError, socket.timeout): pass +m2.ssl_init(SSLError, SSLTimeoutError) # M2Crypto.SSL from Cipher import Cipher, Cipher_Stack diff --git a/SWIG/_ssl.i b/SWIG/_ssl.i index 28a247c..ccfece9 100644 --- a/SWIG/_ssl.i +++ b/SWIG/_ssl.i @@ -11,10 +11,13 @@ %{ #include <pythread.h> +#include <limits.h> #include <openssl/bio.h> #include <openssl/dh.h> #include <openssl/ssl.h> #include <openssl/x509.h> +#include <poll.h> +#include <sys/time.h> %} %apply Pointer NONNULL { SSL_CTX * }; @@ -155,6 +158,11 @@ extern long SSL_SESSION_set_timeout(SSL_SESSION *, long); %rename(ssl_session_get_timeout) SSL_SESSION_get_timeout; extern long SSL_SESSION_get_timeout(CONST SSL_SESSION *); +extern PyObject *ssl_accept(SSL *ssl, double timeout = -1); +extern PyObject *ssl_connect(SSL *ssl, double timeout = -1); +extern PyObject *ssl_read(SSL *ssl, int num, double timeout = -1); +extern int ssl_write(SSL *ssl, PyObject *blob, double timeout = -1); + %constant int ssl_error_none = SSL_ERROR_NONE; %constant int ssl_error_ssl = SSL_ERROR_SSL; %constant int ssl_error_want_read = SSL_ERROR_WANT_READ; @@ -210,14 +218,19 @@ extern long SSL_SESSION_get_timeout(CONST SSL_SESSION *); %constant int SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER = SSL_MODE_ENABLE_PARTIAL_WRITE; %constant int SSL_MODE_AUTO_RETRY = SSL_MODE_AUTO_RETRY; +%ignore ssl_handle_error; +%ignore ssl_sleep_with_timeout; %inline %{ static PyObject *_ssl_err; +static PyObject *_ssl_timeout_err; -void ssl_init(PyObject *ssl_err) { +void ssl_init(PyObject *ssl_err, PyObject *ssl_timeout_err) { SSL_library_init(); SSL_load_error_strings(); Py_INCREF(ssl_err); + Py_INCREF(ssl_timeout_err); _ssl_err = ssl_err; + _ssl_timeout_err = ssl_timeout_err; } void ssl_ctx_passphrase_callback(SSL_CTX *ctx, PyObject *pyfunc) { @@ -403,36 +416,130 @@ int ssl_set_fd(SSL *ssl, int fd) { return ret; } -PyObject *ssl_accept(SSL *ssl) { +static void ssl_handle_error(int ssl_err, int ret) { + int err; + + switch (ssl_err) { + case SSL_ERROR_SSL: + PyErr_SetString(_ssl_err, + ERR_reason_error_string(ERR_get_error())); + break; + case SSL_ERROR_SYSCALL: + err = ERR_get_error(); + if (err) + PyErr_SetString(_ssl_err, ERR_reason_error_string(err)); + else if (ret == 0) + PyErr_SetString(_ssl_err, "unexpected eof"); + else if (ret == -1) + PyErr_SetFromErrno(_ssl_err); + else + assert(0); + break; + default: + PyErr_SetString(_ssl_err, "unexpected SSL error"); + } +} + +static int ssl_sleep_with_timeout(SSL *ssl, const struct timeval *start, + double timeout, int ssl_err) { + struct pollfd fd; + struct timeval tv; + int ms, tmp; + + assert(timeout > 0); + again: + gettimeofday(&tv, NULL); + /* tv >= start */ + if ((timeout + start->tv_sec - tv.tv_sec) > INT_MAX / 1000) + ms = -1; + else { + int fract; + + ms = ((start->tv_sec + (int)timeout) - tv.tv_sec) * 1000; + fract = (start->tv_usec + (timeout - (int)timeout) * 1000000 + - tv.tv_usec + 999) / 1000; + if (ms > 0 && fract > INT_MAX - ms) + ms = -1; + else { + ms += fract; + if (ms <= 0) + goto timeout; + } + } + switch (ssl_err) { + case SSL_ERROR_WANT_READ: + fd.fd = SSL_get_rfd(ssl); + fd.events = POLLIN; + break; + + case SSL_ERROR_WANT_WRITE: + fd.fd = SSL_get_wfd(ssl); + fd.events = POLLOUT; + break; + + case SSL_ERROR_WANT_X509_LOOKUP: + return 0; /* FIXME: is this correct? */ + + default: + assert(0); + } + if (fd.fd == -1) { + PyErr_SetString(_ssl_err, "timeout on a non-FD SSL"); + return -1; + } + Py_BEGIN_ALLOW_THREADS + tmp = poll(&fd, 1, ms); + Py_END_ALLOW_THREADS + switch (tmp) { + case 1: + return 0; + case 0: + goto timeout; + case -1: + if (errno == EINTR) + goto again; + PyErr_SetFromErrno(_ssl_err); + return -1; + } + return 0; + + timeout: + PyErr_SetString(_ssl_timeout_err, "timed out"); + return -1; +} + +PyObject *ssl_accept(SSL *ssl, double timeout) { PyObject *obj = NULL; - int r, err; + int r, ssl_err; + struct timeval tv; + if (timeout > 0) + gettimeofday(&tv, NULL); + again: Py_BEGIN_ALLOW_THREADS r = SSL_accept(ssl); + ssl_err = SSL_get_error(ssl, r); Py_END_ALLOW_THREADS - switch (SSL_get_error(ssl, r)) { + switch (ssl_err) { case SSL_ERROR_NONE: case SSL_ERROR_ZERO_RETURN: obj = PyInt_FromLong((long)1); break; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: - obj = PyInt_FromLong((long)0); - break; - case SSL_ERROR_SSL: - PyErr_SetString(_ssl_err, ERR_reason_error_string(ERR_get_error())); + if (timeout <= 0) { + obj = PyInt_FromLong((long)0); + break; + } + if (ssl_sleep_with_timeout(ssl, &tv, timeout, ssl_err) == 0) + goto again; obj = NULL; break; + case SSL_ERROR_SSL: case SSL_ERROR_SYSCALL: - err = ERR_get_error(); - if (err) - PyErr_SetString(_ssl_err, ERR_reason_error_string(err)); - else if (r == 0) - PyErr_SetString(_ssl_err, "unexpected eof"); - else if (r == -1) - PyErr_SetFromErrno(_ssl_err); + ssl_handle_error(ssl_err, r); obj = NULL; break; } @@ -441,36 +548,38 @@ PyObject *ssl_accept(SSL *ssl) { return obj; } -PyObject *ssl_connect(SSL *ssl) { +PyObject *ssl_connect(SSL *ssl, double timeout) { PyObject *obj = NULL; - int r, err; + int r, ssl_err; + struct timeval tv; + if (timeout > 0) + gettimeofday(&tv, NULL); + again: Py_BEGIN_ALLOW_THREADS r = SSL_connect(ssl); + ssl_err = SSL_get_error(ssl, r); Py_END_ALLOW_THREADS - switch (SSL_get_error(ssl, r)) { + switch (ssl_err) { case SSL_ERROR_NONE: case SSL_ERROR_ZERO_RETURN: obj = PyInt_FromLong((long)1); break; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: - obj = PyInt_FromLong((long)0); - break; - case SSL_ERROR_SSL: - PyErr_SetString(_ssl_err, ERR_reason_error_string(ERR_get_error())); + if (timeout <= 0) { + obj = PyInt_FromLong((long)0); + break; + } + if (ssl_sleep_with_timeout(ssl, &tv, timeout, ssl_err) == 0) + goto again; obj = NULL; break; + case SSL_ERROR_SSL: case SSL_ERROR_SYSCALL: - err = ERR_get_error(); - if (err) - PyErr_SetString(_ssl_err, ERR_reason_error_string(err)); - else if (r == 0) - PyErr_SetString(_ssl_err, "unexpected eof"); - else if (r == -1) - PyErr_SetFromErrno(_ssl_err); + ssl_handle_error(ssl_err, r); obj = NULL; break; } @@ -483,10 +592,11 @@ void ssl_set_shutdown1(SSL *ssl, int mode) { SSL_set_shutdown(ssl, mode); } -PyObject *ssl_read(SSL *ssl, int num) { +PyObject *ssl_read(SSL *ssl, int num, double timeout) { PyObject *obj = NULL; void *buf; - int r, err; + int r; + struct timeval tv; if (!(buf = PyMem_Malloc(num))) { PyErr_SetString(PyExc_MemoryError, "ssl_read"); @@ -494,37 +604,44 @@ PyObject *ssl_read(SSL *ssl, int num) { } + if (timeout > 0) + gettimeofday(&tv, NULL); + again: Py_BEGIN_ALLOW_THREADS r = SSL_read(ssl, buf, num); Py_END_ALLOW_THREADS - switch (SSL_get_error(ssl, r)) { - case SSL_ERROR_NONE: - case SSL_ERROR_ZERO_RETURN: - buf = PyMem_Realloc(buf, r); - obj = PyString_FromStringAndSize(buf, r); - break; - case SSL_ERROR_WANT_WRITE: - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_X509_LOOKUP: - Py_INCREF(Py_None); - obj = Py_None; - break; - case SSL_ERROR_SSL: - PyErr_SetString(_ssl_err, ERR_reason_error_string(ERR_get_error())); - obj = NULL; - break; - case SSL_ERROR_SYSCALL: - err = ERR_get_error(); - if (err) - PyErr_SetString(_ssl_err, ERR_reason_error_string(err)); - else if (r == 0) - PyErr_SetString(_ssl_err, "unexpected eof"); - else if (r == -1) - PyErr_SetFromErrno(_ssl_err); - obj = NULL; - break; + if (r >= 0) { + buf = PyMem_Realloc(buf, r); + obj = PyString_FromStringAndSize(buf, r); + } else { + int ssl_err; + + ssl_err = SSL_get_error(ssl, r); + switch (ssl_err) { + case SSL_ERROR_NONE: + case SSL_ERROR_ZERO_RETURN: + assert(0); + + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_X509_LOOKUP: + if (timeout <= 0) { + Py_INCREF(Py_None); + obj = Py_None; + break; + } + if (ssl_sleep_with_timeout(ssl, &tv, timeout, ssl_err) == 0) + goto again; + obj = NULL; + break; + case SSL_ERROR_SSL: + case SSL_ERROR_SYSCALL: + ssl_handle_error(ssl_err, r); + obj = NULL; + break; + } } PyMem_Free(buf); @@ -582,22 +699,26 @@ PyObject *ssl_read_nbio(SSL *ssl, int num) { return obj; } -int ssl_write(SSL *ssl, PyObject *blob) { +int ssl_write(SSL *ssl, PyObject *blob, double timeout) { const void *buf; - int len, r, err, ret; + int len, r, ssl_err, ret; + struct timeval tv; if (m2_PyObject_AsReadBufferInt(blob, &buf, &len) == -1) { return -1; } - + if (timeout > 0) + gettimeofday(&tv, NULL); + again: Py_BEGIN_ALLOW_THREADS r = SSL_write(ssl, buf, len); + ssl_err = SSL_get_error(ssl, r); Py_END_ALLOW_THREADS - switch (SSL_get_error(ssl, r)) { + switch (ssl_err) { case SSL_ERROR_NONE: case SSL_ERROR_ZERO_RETURN: ret = r; @@ -605,20 +726,17 @@ int ssl_write(SSL *ssl, PyObject *blob) { case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_X509_LOOKUP: + if (timeout <= 0) { + ret = -1; + break; + } + if (ssl_sleep_with_timeout(ssl, &tv, timeout, ssl_err) == 0) + goto again; ret = -1; break; case SSL_ERROR_SSL: - PyErr_SetString(_ssl_err, ERR_reason_error_string(ERR_get_error())); - ret = -1; - break; case SSL_ERROR_SYSCALL: - err = ERR_get_error(); - if (err) - PyErr_SetString(_ssl_err, ERR_reason_error_string(ERR_get_error())); - else if (r == 0) - PyErr_SetString(_ssl_err, "unexpected eof"); - else if (r == -1) - PyErr_SetFromErrno(_ssl_err); + ssl_handle_error(ssl_err, r); default: ret = -1; } diff --git a/tests/test_ssl.py b/tests/test_ssl.py index 701484d..fc857a8 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -36,7 +36,7 @@ def verify_cb_new_function(ok, store): m2.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, m2.X509_V_ERR_CERT_UNTRUSTED, m2.X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE] - assert store.get_error_depth() == 0 + assert store.get_error_depth() == 0 app_data = m2.x509_store_ctx_get_app_data(store.ctx) assert app_data x509 = store.get_current_cert() @@ -47,7 +47,7 @@ def verify_cb_new_function(ok, store): except AssertionError, e: # If we let exceptions propagate from here the # caller may see strange errors. This is cleaner. - return 0 + return 0 return 1 class VerifyCB: @@ -99,7 +99,7 @@ class BaseSSLClientTestCase(unittest.TestCase): os.waitpid(pid, 0) def http_get(self, s): - s.send('GET / HTTP/1.0\n\n') + s.send('GET / HTTP/1.0\n\n') resp = '' while 1: try: @@ -108,7 +108,7 @@ class BaseSSLClientTestCase(unittest.TestCase): break except SSL.SSLError: # s_server throws an 'unexpected eof'... break - resp = resp + r + resp = resp + r return resp def setUp(self): @@ -716,7 +716,7 @@ class MiscSSLClientTestCase(BaseSSLClientTestCase): self.stop_server(pid) def test_verify_cert_mutual_auth(self): - self.args.extend(['-Verify', '2', '-CAfile', 'ca.pem']) + self.args.extend(['-Verify', '2', '-CAfile', 'ca.pem']) pid = self.start_server(self.args) try: ctx = SSL.Context() @@ -754,7 +754,7 @@ class MiscSSLClientTestCase(BaseSSLClientTestCase): self.failIf(string.find(data, 's_server -quiet -www') == -1) def test_verify_cert_mutual_auth_fail(self): - self.args.extend(['-Verify', '2', '-CAfile', 'ca.pem']) + self.args.extend(['-Verify', '2', '-CAfile', 'ca.pem']) pid = self.start_server(self.args) try: ctx = SSL.Context() @@ -911,7 +911,7 @@ class Urllib2SSLClientTestCase(BaseSSLClientTestCase): from M2Crypto import m2urllib2 opener = m2urllib2.build_opener(ctx) - opener.addheaders = [('Connection', 'close')] + opener.addheaders = [('Connection', 'close')] u = opener.open('https://%s:%s/' % (srv_host, srv_port)) data = u.read() u.close() @@ -972,6 +972,77 @@ class Urllib2SSLClientTestCase(BaseSSLClientTestCase): class TwistedSSLClientTestCase(BaseSSLClientTestCase): + def test_timeout(self): + pid = self.start_server(self.args) + try: + ctx = SSL.Context() + s = SSL.Connection(ctx) + # Just a really small number so we can timeout + s.settimeout(0.000000000000000000000000000001) + self.assertRaises(SSL.SSLTimeoutError, s.connect, self.srv_addr) + s.close() + finally: + self.stop_server(pid) + + def test_makefile_timeout(self): + # httpslib uses makefile to read the response + pid = self.start_server(self.args) + try: + from M2Crypto import httpslib + c = httpslib.HTTPS(srv_host, srv_port) + c.putrequest('GET', '/') + c.putheader('Accept', 'text/html') + c.putheader('Accept', 'text/plain') + c.endheaders() + c._conn.sock.settimeout(100) + err, msg, headers = c.getreply() + assert err == 200, err + f = c.getfile() + data = f.read() + c.close() + finally: + self.stop_server(pid) + self.failIf(string.find(data, 's_server -quiet -www') == -1) + + def test_makefile_timeout_fires(self): + # This is convoluted because (openssl s_server -www) starts writing the + # response as soon as it receives the first line of the request, so it's + # possible for it to send the response before the request is sent and + # there would be no timeout. So, let the server spend time reading from + # an empty pipe + FIFO_NAME = 'test_makefile_timeout_fires_fifo' + os.mkfifo('tests/' + FIFO_NAME) + pipe_pid = os.fork() + try: + if pipe_pid == 0: + try: + f = open('tests/' + FIFO_NAME, 'w') + try: + time.sleep(sleepTime + 1) + f.write('Content\n') + finally: + f.close() + finally: + os._exit(0) + self.args[self.args.index('-www')] = '-WWW' + pid = self.start_server(self.args) + try: + from M2Crypto import httpslib + c = httpslib.HTTPS(srv_host, srv_port) + c.putrequest('GET', '/' + FIFO_NAME) + c.putheader('Accept', 'text/html') + c.putheader('Accept', 'text/plain') + c.endheaders() + c._conn.sock.settimeout(0.0000000001) + self.assertRaises(socket.timeout, c.getreply) + c.close() + finally: + self.stop_server(pid) + finally: + os.kill(pipe_pid, 1) + os.waitpid(pipe_pid, 0) + os.unlink('tests/' + FIFO_NAME) + def test_twisted_wrapper(self): # Test only when twisted and ZopeInterfaces are present try: @@ -1067,12 +1138,12 @@ def suite(): suite.addTest(unittest.makeSuite(TwistedSSLClientTestCase)) except ImportError: pass - return suite - + return suite + def zap_servers(): s = 's_server' - fn = tempfile.mktemp() + fn = tempfile.mktemp() cmd = 'ps | egrep %s > %s' % (s, fn) os.system(cmd) f = open(fn) @@ -1097,7 +1168,7 @@ if __name__ == '__main__': gc.set_debug(gc.DEBUG_LEAK & ~gc.DEBUG_SAVEALL) try: - Rand.load_file('randpool.dat', -1) + Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') finally: |