diff options
author | Jakub Stasiak <jakub@stasiak.at> | 2014-10-06 00:38:32 +0100 |
---|---|---|
committer | Jakub Stasiak <jakub@stasiak.at> | 2014-10-10 09:17:41 +0100 |
commit | 6cbd4846ab2f12b1c18c38b570293c0bb05d28a7 (patch) | |
tree | 900c16e1c3da70e0aa58e2e88e84489db8e8249a | |
parent | 02a23c8bd78b3b923faed3e9c62c7664c7e6a6cd (diff) | |
download | eventlet-6cbd4846ab2f12b1c18c38b570293c0bb05d28a7.tar.gz |
Python 3 compat: Improve various bits
This includes changes to WSGI, websocket, bytes/str/unicode handling,
SSL, backdoor, greenio and tests.
Some comments and conditionals (PY2/PY3) were added for clarity
GH issues:
Closes #106
Closes #111
Closes #118
Closes #141
Incidentally should also close #135 (reopen if didn't)
cc #6
-rw-r--r-- | NEWS | 1 | ||||
-rw-r--r-- | eventlet/backdoor.py | 6 | ||||
-rw-r--r-- | eventlet/green/ssl.py | 63 | ||||
-rw-r--r-- | eventlet/greenio.py | 30 | ||||
-rw-r--r-- | eventlet/websocket.py | 50 | ||||
-rw-r--r-- | eventlet/wsgi.py | 48 | ||||
-rw-r--r-- | tests/api_test.py | 10 | ||||
-rw-r--r-- | tests/backdoor_test.py | 12 | ||||
-rw-r--r-- | tests/convenience_test.py | 4 | ||||
-rw-r--r-- | tests/env_test.py | 1 | ||||
-rw-r--r-- | tests/greenio_test.py | 12 | ||||
-rw-r--r-- | tests/mysqldb_test_monkey_patch.py | 4 | ||||
-rw-r--r-- | tests/patcher_test.py | 23 | ||||
-rw-r--r-- | tests/websocket_new_test.py | 36 | ||||
-rw-r--r-- | tests/wsgi_test.py | 253 | ||||
-rw-r--r-- | tests/wsgi_test_conntimeout.py | 2 |
16 files changed, 312 insertions, 243 deletions
@@ -2,6 +2,7 @@ ========================= * removed deprecated modules: api, most of coros, pool, proc, processes and util +* improved Python 3 compatibility 0.15.2 ====== diff --git a/eventlet/backdoor.py b/eventlet/backdoor.py index 5994035..2067772 100644 --- a/eventlet/backdoor.py +++ b/eventlet/backdoor.py @@ -7,7 +7,7 @@ import sys import eventlet from eventlet import hubs -from eventlet.support import greenlets, get_errno, six +from eventlet.support import greenlets, get_errno try: sys.ps1 @@ -30,13 +30,11 @@ class FileProxy(object): pass def write(self, data, *a, **kw): - data = six.b(data) self.f.write(data, *a, **kw) self.f.flush() def readline(self, *a): - line = self.f.readline(*a).replace(b'\r\n', b'\n') - return six.u(line) + return self.f.readline(*a).replace('\r\n', '\n') def __getattr__(self, attr): return getattr(self.f, attr) diff --git a/eventlet/green/ssl.py b/eventlet/green/ssl.py index ba5e6c2..b76ce38 100644 --- a/eventlet/green/ssl.py +++ b/eventlet/green/ssl.py @@ -7,7 +7,7 @@ import sys import errno time = __import__('time') -from eventlet.support import get_errno +from eventlet.support import get_errno, six from eventlet.hubs import trampoline, IOClosed from eventlet.greenio import set_nonblocking, GreenSocket, SOCKET_CLOSED, CONNECT_ERR, CONNECT_SUCCESS orig_socket = __import__('socket') @@ -21,9 +21,10 @@ else: __patched__ = ['SSLSocket', 'wrap_socket', 'sslwrap_simple'] +_original_sslsocket = __ssl.SSLSocket -class GreenSSLSocket(__ssl.SSLSocket): +class GreenSSLSocket(_original_sslsocket): """ This is a green version of the SSLSocket class from the ssl module added in 2.6. For documentation on it, please see the Python standard documentation. @@ -40,23 +41,49 @@ class GreenSSLSocket(__ssl.SSLSocket): # we are inheriting from SSLSocket because its constructor calls # do_handshake whose behavior we wish to override - def __init__(self, sock, *args, **kw): + def __init__(self, sock, keyfile=None, certfile=None, + server_side=False, cert_reqs=CERT_NONE, + ssl_version=PROTOCOL_SSLv23, ca_certs=None, + do_handshake_on_connect=True, *args, **kw): if not isinstance(sock, GreenSocket): sock = GreenSocket(sock) self.act_non_blocking = sock.act_non_blocking - self._timeout = sock.gettimeout() - super(GreenSSLSocket, self).__init__(sock.fd, *args, **kw) + + if six.PY2: + # On Python 2 SSLSocket constructor queries the timeout, it'd break without + # this assignment + self._timeout = sock.gettimeout() + + # nonblocking socket handshaking on connect got disabled so let's pretend it's disabled + # even when it's on + super(GreenSSLSocket, self).__init__( + sock.fd, keyfile, certfile, server_side,cert_reqs, ssl_version, + ca_certs, do_handshake_on_connect and six.PY2, *args, **kw) # the superclass initializer trashes the methods so we remove # the local-object versions of them and let the actual class # methods shine through + # Note: This for Python 2 try: for fn in orig_socket._delegate_methods: delattr(self, fn) except AttributeError: pass + if six.PY3: + # Python 3 SSLSocket construction process overwrites the timeout so restore it + self._timeout = sock.gettimeout() + + # it also sets timeout to None internally apparently (tested with 3.4.2) + _original_sslsocket.settimeout(self, 0.0) + assert _original_sslsocket.gettimeout(self) == 0.0 + + # see note above about handshaking + self.do_handshake_on_connect = do_handshake_on_connect + if do_handshake_on_connect and self._connected: + self.do_handshake() + def settimeout(self, timeout): self._timeout = timeout @@ -98,14 +125,14 @@ class GreenSSLSocket(__ssl.SSLSocket): return self._call_trampolining( super(GreenSSLSocket, self).write, data) - def read(self, len=1024): + def read(self, *args, **kwargs): """Read up to LEN bytes and return them. Return zero-length string on EOF.""" try: return self._call_trampolining( - super(GreenSSLSocket, self).read, len) + super(GreenSSLSocket, self).read, *args, **kwargs) except IOClosed: - return '' + return b'' def send(self, data, flags=0): if self._sslobj: @@ -174,9 +201,9 @@ class GreenSSLSocket(__ssl.SSLSocket): trampoline(self, read=True, timeout=self.gettimeout(), timeout_exc=timeout_exc('timed out')) except IOClosed: - return '' + return b'' if get_errno(e) in SOCKET_CLOSED: - return '' + return b'' raise def recv_into(self, buffer, nbytes=None, flags=0): @@ -245,14 +272,16 @@ class GreenSSLSocket(__ssl.SSLSocket): if self._sslobj: raise ValueError("attempt to connect already-connected SSLSocket!") self._socket_connect(addr) - if has_ciphers: - self._sslobj = _ssl.sslwrap(self._sock, False, self.keyfile, self.certfile, - self.cert_reqs, self.ssl_version, - self.ca_certs, self.ciphers) + server_side = False + try: + sslwrap = _ssl.sslwrap + except AttributeError: + # sslwrap was removed in 2.7.9 + self._sslobj = self._context._wrap_socket(self, server_side) else: - self._sslobj = _ssl.sslwrap(self._sock, False, self.keyfile, self.certfile, - self.cert_reqs, self.ssl_version, - self.ca_certs) + self._sslobj = sslwrap(self._sock, server_side, self.keyfile, self.certfile, + self.cert_reqs, self.ssl_version, + self.ca_certs, *([self.ciphers] if has_ciphers else [])) if self.do_handshake_on_connect: self.do_handshake() diff --git a/eventlet/greenio.py b/eventlet/greenio.py index 38e8168..cd521b3 100644 --- a/eventlet/greenio.py +++ b/eventlet/greenio.py @@ -160,6 +160,15 @@ class GreenSocket(object): def _sock(self): return self + if six.PY3: + def _get_io_refs(self): + return self.fd._io_refs + + def _set_io_refs(self, value): + self.fd._io_refs = value + + _io_refs = property(_get_io_refs, _set_io_refs) + # Forward unknown attributes to fd, cache the value for future use. # I do not see any simple attribute which could be changed # so caching everything in self is fine. @@ -275,12 +284,16 @@ class GreenSocket(object): newsock.settimeout(self.gettimeout()) return newsock - def makefile(self, *args, **kw): - dupped = self.dup() - res = _fileobject(dupped, *args, **kw) - if hasattr(dupped, "_drop"): - dupped._drop() - return res + if six.PY3: + def makefile(self, *args, **kwargs): + return _original_socket.makefile(self, *args, **kwargs) + else: + def makefile(self, *args, **kwargs): + dupped = self.dup() + res = _fileobject(dupped, *args, **kwargs) + if hasattr(dupped, "_drop"): + dupped._drop() + return res def makeGreenFile(self, *args, **kw): warnings.warn("makeGreenFile has been deprecated, please use " @@ -457,11 +470,12 @@ class _SocketDuckForFd(object): def send(self, data): while True: try: - os.write(self._fileno, data) + return os.write(self._fileno, data) except OSError as e: if get_errno(e) not in SOCKET_BLOCKING: raise IOError(*e.args) - trampoline(self, write=True) + else: + trampoline(self, write=True) def sendall(self, data): len_data = len(data) diff --git a/eventlet/websocket.py b/eventlet/websocket.py index 64514c2..10c868d 100644 --- a/eventlet/websocket.py +++ b/eventlet/websocket.py @@ -37,15 +37,17 @@ for _mod in ('wsaccel.utf8validator', 'autobahn.utf8validator'): ACCEPTABLE_CLIENT_ERRORS = set((errno.ECONNRESET, errno.EPIPE)) __all__ = ["WebSocketWSGI", "WebSocket"] -PROTOCOL_GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11' -VALID_CLOSE_STATUS = (range(1000, 1004) - + range(1007, 1012) - # 3000-3999: reserved for use by libraries, frameworks, - # and applications - + range(3000, 4000) - # 4000-4999: reserved for private use and thus can't - # be registered - + range(4000, 5000)) +PROTOCOL_GUID = b'258EAFA5-E914-47DA-95CA-C5AB0DC85B11' +VALID_CLOSE_STATUS = set( + list(range(1000, 1004)) + + list(range(1007, 1012)) + + # 3000-3999: reserved for use by libraries, frameworks, + # and applications + list(range(3000, 4000)) + + # 4000-4999: reserved for private use and thus can't + # be registered + list(range(4000, 5000)) +) class BadRequest(Exception): @@ -115,7 +117,7 @@ class WebSocketWSGI(object): raise BadRequest() except BadRequest as e: status = e.status - body = e.body or '' + body = e.body or b'' headers = e.headers or [] start_response(status, [('Connection', 'close'), ] + headers) @@ -219,15 +221,14 @@ class WebSocketWSGI(object): # extensions = [i.strip() for i in extensions.split(',')] key = environ['HTTP_SEC_WEBSOCKET_KEY'] - response = base64.b64encode(sha1(key + PROTOCOL_GUID).digest()) - handshake_reply = ["HTTP/1.1 101 Switching Protocols", - "Upgrade: websocket", - "Connection: Upgrade", - "Sec-WebSocket-Accept: %s" % (response, )] + response = base64.b64encode(sha1(six.b(key) + PROTOCOL_GUID).digest()) + handshake_reply = [b"HTTP/1.1 101 Switching Protocols", + b"Upgrade: websocket", + b"Connection: Upgrade", + b"Sec-WebSocket-Accept: " + response] if negotiated_protocol: - handshake_reply.append("Sec-WebSocket-Protocol: %s" - % (negotiated_protocol, )) - sock.sendall('\r\n'.join(handshake_reply) + '\r\n\r\n') + handshake_reply.append(b"Sec-WebSocket-Protocol: " + six.b(negotiated_protocol)) + sock.sendall(b'\r\n'.join(handshake_reply) + b'\r\n\r\n') return RFC6455WebSocket(sock, environ, self.protocol_version, protocol=negotiated_protocol) @@ -425,7 +426,7 @@ class RFC6455WebSocket(WebSocket): return self.decoder.decode(data, final) def _get_bytes(self, numbytes): - data = '' + data = b'' while len(data) < numbytes: d = self.socket.recv(numbytes - len(data)) if not d: @@ -447,14 +448,14 @@ class RFC6455WebSocket(WebSocket): self.data.append(data) def getvalue(self): - return ''.join(self.data) + return ('' if self.decoder else b'').join(self.data) @staticmethod def _apply_mask(data, mask, length=None, offset=0): if length is None: length = len(data) cnt = range(length) - return ''.join(chr(ord(data[i]) ^ mask[(offset + i) % 4]) for i in cnt) + return b''.join(six.int2byte(six.indexbytes(data, i) ^ mask[(offset + i) % 4]) for i in cnt) def _handle_control_frame(self, opcode, data): if opcode == 8: # connection close @@ -609,12 +610,13 @@ class RFC6455WebSocket(WebSocket): # NOTE: RFC6455 states: # A server MUST NOT mask any frames that it sends to the client rand = Random(time.time()) - mask = map(rand.getrandbits, (8, ) * 4) + mask = [rand.getrandbits(8) for _ in six.moves.xrange(4)] message = RFC6455WebSocket._apply_mask(message, mask, length) maskdata = struct.pack('!BBBB', *mask) else: - maskdata = '' - return ''.join((header, lengthdata, maskdata, message)) + maskdata = b'' + + return b''.join((header, lengthdata, maskdata, message)) def wait(self): for i in self.iterator: diff --git a/eventlet/wsgi.py b/eventlet/wsgi.py index 94a2405..2f89cbb 100644 --- a/eventlet/wsgi.py +++ b/eventlet/wsgi.py @@ -116,11 +116,11 @@ class Input(object): if length and length > self.content_length - self.position: length = self.content_length - self.position if not length: - return '' + return b'' try: read = reader(length) except greenio.SSL.ZeroReturnError: - read = '' + read = b'' self.position += len(read) return read @@ -189,7 +189,7 @@ class Input(object): return self._do_read(self.rfile.readlines, hint) def __iter__(self): - return iter(self.read, '') + return iter(self.read, b'') def get_socket(self): return self.rfile._sock @@ -226,7 +226,7 @@ class FileObjectForHeaders(object): if size < 0: sz = MAX_HEADER_LINE rv = self.fp.readline(sz) - if size < 0 and len(rv) >= MAX_HEADER_LINE: + if len(rv) >= MAX_HEADER_LINE: raise HeaderLineTooLong() self.total_header_size += len(rv) if self.total_header_size > MAX_TOTAL_HEADER_SIZE: @@ -267,8 +267,8 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler): self.raw_requestline = self.rfile.readline(self.server.url_length_limit) if len(self.raw_requestline) == self.server.url_length_limit: self.wfile.write( - "HTTP/1.0 414 Request URI Too Long\r\n" - "Connection: close\r\nContent-length: 0\r\n\r\n") + b"HTTP/1.0 414 Request URI Too Long\r\n" + b"Connection: close\r\nContent-length: 0\r\n\r\n") self.close_connection = 1 return except greenio.SSL.ZeroReturnError: @@ -289,14 +289,14 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler): return except HeaderLineTooLong: self.wfile.write( - "HTTP/1.0 400 Header Line Too Long\r\n" - "Connection: close\r\nContent-length: 0\r\n\r\n") + b"HTTP/1.0 400 Header Line Too Long\r\n" + b"Connection: close\r\nContent-length: 0\r\n\r\n") self.close_connection = 1 return except HeadersTooLarge: self.wfile.write( - "HTTP/1.0 400 Headers Too Large\r\n" - "Connection: close\r\nContent-length: 0\r\n\r\n") + b"HTTP/1.0 400 Headers Too Large\r\n" + b"Connection: close\r\nContent-length: 0\r\n\r\n") self.close_connection = 1 return finally: @@ -308,8 +308,8 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler): int(content_length) except ValueError: self.wfile.write( - "HTTP/1.0 400 Bad Request\r\n" - "Connection: close\r\nContent-length: 0\r\n\r\n") + b"HTTP/1.0 400 Bad Request\r\n" + b"Connection: close\r\nContent-length: 0\r\n\r\n") self.close_connection = 1 return @@ -345,13 +345,13 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler): status, response_headers = headers_set headers_sent.append(1) header_list = [header[0].lower() for header in response_headers] - towrite.append('%s %s\r\n' % (self.protocol_version, status)) + towrite.append(six.b('%s %s\r\n' % (self.protocol_version, status))) for header in response_headers: - towrite.append('%s: %s\r\n' % header) + towrite.append(six.b('%s: %s\r\n' % header)) # send Date header? if 'date' not in header_list: - towrite.append('Date: %s\r\n' % (format_date_time(time.time()),)) + towrite.append(six.b('Date: %s\r\n' % (format_date_time(time.time()),))) client_conn = self.headers.get('Connection', '').lower() send_keep_alive = False @@ -369,21 +369,21 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler): if 'content-length' not in header_list: if self.request_version == 'HTTP/1.1': use_chunked[0] = True - towrite.append('Transfer-Encoding: chunked\r\n') + towrite.append(b'Transfer-Encoding: chunked\r\n') elif 'content-length' not in header_list: # client is 1.0 and therefore must read to EOF self.close_connection = 1 if self.close_connection: - towrite.append('Connection: close\r\n') + towrite.append(b'Connection: close\r\n') elif send_keep_alive: - towrite.append('Connection: keep-alive\r\n') - towrite.append('\r\n') + towrite.append(b'Connection: keep-alive\r\n') + towrite.append(b'\r\n') # end of header writing if use_chunked[0]: # Write the chunked encoding - towrite.append("%x\r\n%s\r\n" % (len(data), data)) + towrite.append(six.b("%x" % (len(data),)) + b"\r\n" + data + b"\r\n") else: towrite.append(data) try: @@ -450,15 +450,15 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler): towrite.append(data) towrite_size += len(data) if towrite_size >= minimum_write_chunk_size: - write(''.join(towrite)) + write(b''.join(towrite)) towrite = [] just_written_size = towrite_size towrite_size = 0 if towrite: just_written_size = towrite_size - write(''.join(towrite)) + write(b''.join(towrite)) if not headers_sent or (use_chunked[0] and just_written_size): - write('') + write(b'') except Exception: self.close_connection = 1 tb = traceback.format_exc() @@ -476,7 +476,7 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler): result.close() if (self.environ['eventlet.input'].chunked_input or self.environ['eventlet.input'].position - < self.environ['eventlet.input'].content_length): + < self.environ['eventlet.input'].content_length or 0): # Read and discard body if there was no pending 100-continue if not self.environ['eventlet.input'].wfile: # NOTE: MINIMUM_CHUNK_SIZE is used here for purpose different than chunking. diff --git a/tests/api_test.py b/tests/api_test.py index 8cb7410..e63dbd2 100644 --- a/tests/api_test.py +++ b/tests/api_test.py @@ -1,7 +1,8 @@ import os -import socket from unittest import TestCase, main +from nose.tools import eq_ + import eventlet from eventlet import greenio, hubs, greenthread, spawn from eventlet.green import ssl @@ -51,9 +52,8 @@ class TestApi(TestCase): client = eventlet.connect(('127.0.0.1', server.getsockname()[1])) fd = client.makefile('rb') client.close() - assert fd.readline() == b'hello\n' - - assert fd.read() == b'' + eq_(fd.readline(), b'hello\n') + eq_(fd.read(), b'') fd.close() check_hub() @@ -80,7 +80,7 @@ class TestApi(TestCase): raw_client = eventlet.connect(('127.0.0.1', server.getsockname()[1])) client = ssl.wrap_socket(raw_client) - fd = socket._fileobject(client, 'rb', 8192) + fd = client.makefile('rb', 8192) assert fd.readline() == b'hello\r\n' try: diff --git a/tests/backdoor_test.py b/tests/backdoor_test.py index f304d3f..6facffe 100644 --- a/tests/backdoor_test.py +++ b/tests/backdoor_test.py @@ -14,15 +14,15 @@ class BackdoorTest(LimitedTestCase): client = socket.socket() client.connect(('localhost', listener.getsockname()[1])) f = client.makefile('rw') - assert b'Python' in f.readline() + assert 'Python' in f.readline() f.readline() # build info f.readline() # help info - assert b'InteractiveConsole' in f.readline() - self.assertEqual(b'>>> ', f.read(4)) - f.write(b'print("hi")\n') + assert 'InteractiveConsole' in f.readline() + self.assertEqual('>>> ', f.read(4)) + f.write('print("hi")\n') f.flush() - self.assertEqual(b'hi\n', f.readline()) - self.assertEqual(b'>>> ', f.read(4)) + self.assertEqual('hi\n', f.readline()) + self.assertEqual('>>> ', f.read(4)) f.close() client.close() serv.kill() diff --git a/tests/convenience_test.py b/tests/convenience_test.py index 83726bc..194699c 100644 --- a/tests/convenience_test.py +++ b/tests/convenience_test.py @@ -125,8 +125,8 @@ class TestServe(LimitedTestCase): eventlet.spawn(eventlet.serve, server, handle) client = eventlet.wrap_ssl(eventlet.connect(('localhost', port))) - client.sendall("echo") - self.assertEqual("echo", client.recv(1024)) + client.sendall(b"echo") + self.assertEqual(b"echo", client.recv(1024)) def test_socket_reuse(self): lsock1 = eventlet.listen(('localhost', 0)) diff --git a/tests/env_test.py b/tests/env_test.py index 4888e9d..f8931c1 100644 --- a/tests/env_test.py +++ b/tests/env_test.py @@ -1,4 +1,5 @@ import os +from eventlet.support import six from tests.patcher_test import ProcessBase from tests import skip_with_pyevent diff --git a/tests/greenio_test.py b/tests/greenio_test.py index c56b946..ba3a826 100644 --- a/tests/greenio_test.py +++ b/tests/greenio_test.py @@ -450,7 +450,7 @@ class TestGreenSocket(LimitedTestCase): def sender(evt): s2, addr = server.accept() - wrap_wfile = s2.makefile('w') + wrap_wfile = s2.makefile('wb') eventlet.sleep(0.02) wrap_wfile.write(b'hi') @@ -627,7 +627,7 @@ class TestGreenPipe(LimitedTestCase): wf = greenio.GreenPipe(w, 'w', 0) def sender(f, content): - for ch in content: + for ch in map(six.int2byte, six.iterbytes(content)): eventlet.sleep(0.0001) f.write(ch) f.close() @@ -638,7 +638,7 @@ class TestGreenPipe(LimitedTestCase): line = rf.readline() eventlet.sleep(0.01) self.assertEqual(line, one_line) - self.assertEqual(rf.readline(), '') + self.assertEqual(rf.readline(), b'') def test_pipe_read(self): # ensure that 'readline' works properly on GreenPipes when data is not @@ -663,10 +663,10 @@ class TestGreenPipe(LimitedTestCase): eventlet.sleep(0) line = r.readline() - self.assertEqual(line, 'line\n') + self.assertEqual(line, b'line\n') line = r.readline() - self.assertEqual(line, 'line\r\n') + self.assertEqual(line, b'line\r\n') gt.wait() @@ -676,7 +676,7 @@ class TestGreenPipe(LimitedTestCase): r = greenio.GreenPipe(r) w = greenio.GreenPipe(w, 'w') - large_message = b"".join([1024 * chr(i) for i in range(65)]) + large_message = b"".join([1024 * six.int2byte(i) for i in range(65)]) def writer(): w.write(large_message) diff --git a/tests/mysqldb_test_monkey_patch.py b/tests/mysqldb_test_monkey_patch.py index 2d9c0e7..a76178e 100644 --- a/tests/mysqldb_test_monkey_patch.py +++ b/tests/mysqldb_test_monkey_patch.py @@ -1,12 +1,12 @@ from __future__ import print_function -import MySQLdb as m from eventlet import patcher -from eventlet.green import MySQLdb as gm # no standard tests in this file, ignore __test__ = False if __name__ == '__main__': + import MySQLdb as m + from eventlet.green import MySQLdb as gm patcher.monkey_patch(all=True, MySQLdb=True) print("mysqltest {0}".format(",".join(sorted(patcher.already_patched.keys())))) print("connect {0}".format(m.connect == gm.connect)) diff --git a/tests/patcher_test.py b/tests/patcher_test.py index c575a80..f80b589 100644 --- a/tests/patcher_test.py +++ b/tests/patcher_test.py @@ -3,12 +3,16 @@ import shutil import sys import tempfile +from eventlet.support import six from tests import LimitedTestCase, main, run_python, skip_with_pyevent base_module_contents = """ import socket -import urllib +try: + import urllib.request as urllib +except ImportError: + import urllib print("base {0} {1}".format(socket, urllib)) """ @@ -45,14 +49,18 @@ class ProcessBase(LimitedTestCase): filename = os.path.join(self.tempdir, name) if not filename.endswith('.py'): filename = filename + '.py' - fd = open(filename, "wb") - fd.write(contents) - fd.close() + with open(filename, "w") as fd: + fd.write(contents) def launch_subprocess(self, filename): path = os.path.join(self.tempdir, filename) output = run_python(path) - lines = output.split("\n") + if six.PY3: + output = output.decode('utf-8') + separator = '\n' + else: + separator = b'\n' + lines = output.split(separator) return output, lines def run_script(self, contents, modname=None): @@ -98,7 +106,10 @@ class MonkeyPatch(ProcessBase): from eventlet import patcher patcher.monkey_patch() import socket -import urllib +try: + import urllib.request as urllib +except ImportError: + import urllib print("newmod {0} {1}".format(socket.socket, urllib.socket.socket)) """ self.write_to_tempfile("newmod", new_mod) diff --git a/tests/websocket_new_test.py b/tests/websocket_new_test.py index ec29fc6..95d36b5 100644 --- a/tests/websocket_new_test.py +++ b/tests/websocket_new_test.py @@ -1,11 +1,15 @@ import errno import struct +from nose.tools import eq_ + import eventlet from eventlet import event from eventlet import websocket from eventlet.green import httplib from eventlet.green import socket +from eventlet import websocket +from eventlet.support import six from tests.wsgi_test import _TestBase @@ -51,7 +55,7 @@ class TestWebSocket(_TestBase): self.assertEqual(resp.status, 400) self.assertEqual(resp.getheader('connection'), 'close') - self.assertEqual(resp.read(), '') + self.assertEqual(resp.read(), b'') # Now, miss off key headers = dict(kv.split(': ') for kv in [ @@ -67,7 +71,7 @@ class TestWebSocket(_TestBase): self.assertEqual(resp.status, 400) self.assertEqual(resp.getheader('connection'), 'close') - self.assertEqual(resp.read(), '') + self.assertEqual(resp.read(), b'') # No Upgrade now headers = dict(kv.split(': ') for kv in [ @@ -82,7 +86,7 @@ class TestWebSocket(_TestBase): self.assertEqual(resp.status, 400) self.assertEqual(resp.getheader('connection'), 'close') - self.assertEqual(resp.read(), '') + self.assertEqual(resp.read(), b'') def test_correct_upgrade_request_13(self): for http_connection in ['Upgrade', 'UpGrAdE', 'keep-alive, Upgrade']: @@ -97,16 +101,16 @@ class TestWebSocket(_TestBase): ] sock = eventlet.connect(('localhost', self.port)) - sock.sendall('\r\n'.join(connect) + '\r\n\r\n') + sock.sendall(six.b('\r\n'.join(connect) + '\r\n\r\n')) result = sock.recv(1024) # The server responds the correct Websocket handshake print('Connection string: %r' % http_connection) - self.assertEqual(result, '\r\n'.join([ + self.assertEqual(result, six.b('\r\n'.join([ 'HTTP/1.1 101 Switching Protocols', 'Upgrade: websocket', 'Connection: Upgrade', 'Sec-WebSocket-Accept: ywSyWXCPNsDxLrQdQrn5RFNRfBU=\r\n\r\n', - ])) + ]))) def test_send_recv_13(self): connect = [ @@ -121,15 +125,15 @@ class TestWebSocket(_TestBase): sock = eventlet.connect( ('localhost', self.port)) - sock.sendall('\r\n'.join(connect) + '\r\n\r\n') + sock.sendall(six.b('\r\n'.join(connect) + '\r\n\r\n')) sock.recv(1024) ws = websocket.RFC6455WebSocket(sock, {}, client=True) - ws.send('hello') - assert ws.wait() == 'hello' - ws.send('hello world!\x01') + ws.send(b'hello') + eq_(ws.wait(), b'hello') + ws.send(b'hello world!\x01') ws.send(u'hello world again!') - assert ws.wait() == 'hello world!\x01' - assert ws.wait() == u'hello world again!' + eq_(ws.wait(), b'hello world!\x01') + eq_(ws.wait(), u'hello world again!') ws.close() eventlet.sleep(0.01) @@ -160,7 +164,7 @@ class TestWebSocket(_TestBase): ] sock = eventlet.connect( ('localhost', self.port)) - sock.sendall('\r\n'.join(connect) + '\r\n\r\n') + sock.sendall(six.b('\r\n'.join(connect) + '\r\n\r\n')) sock.recv(1024) # get the headers sock.close() # close while the app is running done_with_request.wait() @@ -193,7 +197,7 @@ class TestWebSocket(_TestBase): ] sock = eventlet.connect( ('localhost', self.port)) - sock.sendall('\r\n'.join(connect) + '\r\n\r\n') + sock.sendall(six.b('\r\n'.join(connect) + '\r\n\r\n')) sock.recv(1024) # get the headers closeframe = struct.pack('!BBIH', 1 << 7 | 8, 1 << 7 | 2, 0, 1000) sock.sendall(closeframe) # "Close the connection" packet. @@ -227,8 +231,8 @@ class TestWebSocket(_TestBase): ] sock = eventlet.connect( ('localhost', self.port)) - sock.sendall('\r\n'.join(connect) + '\r\n\r\n') + sock.sendall(six.b('\r\n'.join(connect) + '\r\n\r\n')) sock.recv(1024) # get the headers - sock.sendall('\x07\xff') # Weird packet. + sock.sendall(b'\x07\xff') # Weird packet. done_with_request.wait() assert not error_detected[0] diff --git a/tests/wsgi_test.py b/tests/wsgi_test.py index 4ebf136..9765076 100644 --- a/tests/wsgi_test.py +++ b/tests/wsgi_test.py @@ -27,6 +27,13 @@ import tests certificate_file = os.path.join(os.path.dirname(__file__), 'test_server.crt') private_key_file = os.path.join(os.path.dirname(__file__), 'test_server.key') +if six.PY3: + def bytes_to_str(b): + return b.decode() +else: + def bytes_to_str(b): + return b + HttpReadResult = collections.namedtuple( 'HttpReadResult', @@ -36,17 +43,17 @@ HttpReadResult = collections.namedtuple( def hello_world(env, start_response): if env['PATH_INFO'] == 'notexist': start_response('404 Not Found', [('Content-type', 'text/plain')]) - return ["not found"] + return [b"not found"] start_response('200 OK', [('Content-type', 'text/plain')]) - return ["hello world"] + return [b"hello world"] def chunked_app(env, start_response): start_response('200 OK', [('Content-type', 'text/plain')]) - yield "this" - yield "is" - yield "chunked" + yield b"this" + yield b"is" + yield b"chunked" def chunked_fail_app(environ, start_response): @@ -56,8 +63,8 @@ def chunked_fail_app(environ, start_response): start_response('200 OK', headers) # We start streaming data just fine. - yield "The dwarves of yore made mighty spells," - yield "While hammers fell like ringing bells" + yield b"The dwarves of yore made mighty spells," + yield b"While hammers fell like ringing bells" # Then the back-end fails! try: @@ -67,13 +74,13 @@ def chunked_fail_app(environ, start_response): return # So rest of the response data is not available. - yield "In places deep, where dark things sleep," - yield "In hollow halls beneath the fells." + yield b"In places deep, where dark things sleep," + yield b"In hollow halls beneath the fells." def big_chunks(env, start_response): start_response('200 OK', [('Content-type', 'text/plain')]) - line = 'a' * 8192 + line = b'a' * 8192 for x in range(10): yield line @@ -150,11 +157,13 @@ class ConnectionClosed(Exception): def read_http(sock): - fd = sock.makefile() + fd = sock.makefile('rb') try: - response_line = fd.readline().rstrip('\r\n') + response_line = bytes_to_str(fd.readline().rstrip(b'\r\n')) except socket.error as exc: - if support.get_errno(exc) == 10053: + # TODO find out whether 54 is ok here or not, I see it when running tests + # on Python 3 + if support.get_errno(exc) in (10053, 54): raise ConnectionClosed raise if not response_line: @@ -163,7 +172,7 @@ def read_http(sock): header_lines = [] while True: line = fd.readline() - if line == '\r\n': + if line == b'\r\n': break else: header_lines.append(line) @@ -174,7 +183,7 @@ def read_http(sock): x = x.strip() if not x: continue - key, value = x.split(':', 1) + key, value = bytes_to_str(x).split(':', 1) key = key.rstrip() value = value.lstrip() key_lower = key.lower() @@ -256,20 +265,20 @@ class TestHttpd(_TestBase): sock = eventlet.connect( ('localhost', self.port)) - fd = sock.makefile('rw') + fd = sock.makefile('rwb') fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n') fd.flush() result = fd.read() fd.close() # The server responds with the maximum version it supports - assert result.startswith('HTTP'), result - assert result.endswith('hello world'), result + assert result.startswith(b'HTTP'), result + assert result.endswith(b'hello world'), result def test_002_keepalive(self): sock = eventlet.connect( ('localhost', self.port)) - fd = sock.makefile('w') + fd = sock.makefile('wb') fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n') fd.flush() read_http(sock) @@ -284,7 +293,7 @@ class TestHttpd(_TestBase): sock = eventlet.connect( ('localhost', self.port)) - fd = sock.makefile('rw') + fd = sock.makefile('rwb') fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n') fd.flush() cancel = eventlet.Timeout(1, RuntimeError) @@ -296,7 +305,7 @@ class TestHttpd(_TestBase): sock = eventlet.connect( ('localhost', self.port)) - fd = sock.makefile('w') + fd = sock.makefile('wb') fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n') fd.flush() read_http(sock) @@ -323,8 +332,8 @@ class TestHttpd(_TestBase): for ii in range(3000): path_parts.append('path') path = '/'.join(path_parts) - request = 'GET /%s HTTP/1.0\r\nHost: localhost\r\n\r\n' % path - fd = sock.makefile('rw') + request = ('GET /%s HTTP/1.0\r\nHost: localhost\r\n\r\n' % path).encode() + fd = sock.makefile('rwb') fd.write(request) fd.flush() result = fd.readline() @@ -352,8 +361,8 @@ class TestHttpd(_TestBase): 'Content-Length: 3', '', 'a=a')) - fd = sock.makefile('w') - fd.write(request) + fd = sock.makefile('wb') + fd.write(request.encode()) fd.flush() # send some junk after the actual request @@ -365,7 +374,7 @@ class TestHttpd(_TestBase): def test_008_correctresponse(self): sock = eventlet.connect(('localhost', self.port)) - fd = sock.makefile('w') + fd = sock.makefile('wb') fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n') fd.flush() result_200 = read_http(sock) @@ -384,37 +393,37 @@ class TestHttpd(_TestBase): sock = eventlet.connect( ('localhost', self.port)) - fd = sock.makefile('rw') + fd = sock.makefile('rwb') fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n') fd.flush() - assert 'Transfer-Encoding: chunked' in fd.read() + assert b'Transfer-Encoding: chunked' in fd.read() def test_010_no_chunked_http_1_0(self): self.site.application = chunked_app sock = eventlet.connect( ('localhost', self.port)) - fd = sock.makefile('rw') + fd = sock.makefile('rwb') fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\nConnection: close\r\n\r\n') fd.flush() - assert 'Transfer-Encoding: chunked' not in fd.read() + assert b'Transfer-Encoding: chunked' not in fd.read() def test_011_multiple_chunks(self): self.site.application = big_chunks sock = eventlet.connect( ('localhost', self.port)) - fd = sock.makefile('rw') + fd = sock.makefile('rwb') fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n') fd.flush() - headers = '' + headers = b'' while True: line = fd.readline() - if line == '\r\n': + if line == b'\r\n': break else: headers += line - assert 'Transfer-Encoding: chunked' in headers + assert b'Transfer-Encoding: chunked' in headers chunks = 0 chunklen = int(fd.readline(), 16) while chunklen: @@ -473,52 +482,52 @@ class TestHttpd(_TestBase): def test_014_chunked_post(self): self.site.application = chunked_post sock = eventlet.connect(('localhost', self.port)) - fd = sock.makefile('rw') + fd = sock.makefile('rwb') fd.write('PUT /a HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n' 'Transfer-Encoding: chunked\r\n\r\n' '2\r\noh\r\n4\r\n hai\r\n0\r\n\r\n'.encode()) fd.flush() while True: - if fd.readline() == '\r\n': + if fd.readline() == b'\r\n': break response = fd.read() - assert response == 'oh hai', 'invalid response %s' % response + assert response == b'oh hai', 'invalid response %s' % response sock = eventlet.connect(('localhost', self.port)) - fd = sock.makefile('rw') + fd = sock.makefile('rwb') fd.write('PUT /b HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n' 'Transfer-Encoding: chunked\r\n\r\n' '2\r\noh\r\n4\r\n hai\r\n0\r\n\r\n'.encode()) fd.flush() while True: - if fd.readline() == '\r\n': + if fd.readline() == b'\r\n': break response = fd.read() - assert response == 'oh hai', 'invalid response %s' % response + assert response == b'oh hai', 'invalid response %s' % response sock = eventlet.connect(('localhost', self.port)) - fd = sock.makefile('rw') + fd = sock.makefile('rwb') fd.write('PUT /c HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n' 'Transfer-Encoding: chunked\r\n\r\n' '2\r\noh\r\n4\r\n hai\r\n0\r\n\r\n'.encode()) fd.flush() while True: - if fd.readline() == '\r\n': + if fd.readline() == b'\r\n': break response = fd.read(8192) - assert response == 'oh hai', 'invalid response %s' % response + assert response == b'oh hai', 'invalid response %s' % response def test_015_write(self): self.site.application = use_write sock = eventlet.connect(('localhost', self.port)) - fd = sock.makefile('w') + fd = sock.makefile('wb') fd.write(b'GET /a HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n') fd.flush() result1 = read_http(sock) assert 'content-length' in result1.headers_lower sock = eventlet.connect(('localhost', self.port)) - fd = sock.makefile('w') + fd = sock.makefile('wb') fd.write(b'GET /b HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n') fd.flush() result2 = read_http(sock) @@ -531,21 +540,21 @@ class TestHttpd(_TestBase): """ def wsgi_app(environ, start_response): start_response('200 OK', [('Content-Length', '7')]) - return ['testing'] + return [b'testing'] self.site.application = wsgi_app sock = eventlet.connect(('localhost', self.port)) - fd = sock.makefile('rw') + fd = sock.makefile('rwb') fd.write(b'GET /a HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n') fd.flush() header_lines = [] while True: line = fd.readline() - if line == '\r\n': + if line == b'\r\n': break else: header_lines.append(line) self.assertEqual(1, len( - [l for l in header_lines if l.lower().startswith('content-length')])) + [l for l in header_lines if l.lower().startswith(b'content-length')])) @tests.skip_if_no_ssl def test_017_ssl_zeroreturnerror(self): @@ -588,7 +597,7 @@ class TestHttpd(_TestBase): sock = eventlet.connect( ('localhost', self.port)) - fd = sock.makefile('w') + fd = sock.makefile('wb') fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n') fd.flush() @@ -607,13 +616,13 @@ class TestHttpd(_TestBase): def use_fieldstorage(environ, start_response): cgi.FieldStorage(fp=environ['wsgi.input'], environ=environ) start_response('200 OK', [('Content-type', 'text/plain')]) - return ['hello!'] + return [b'hello!'] self.site.application = use_fieldstorage sock = eventlet.connect( ('localhost', self.port)) - fd = sock.makefile('rw') + fd = sock.makefile('rwb') fd.write('POST / HTTP/1.1\r\n' 'Host: localhost\r\n' 'Connection: close\r\n' @@ -621,7 +630,7 @@ class TestHttpd(_TestBase): '2\r\noh\r\n' '4\r\n hai\r\n0\r\n\r\n'.encode()) fd.flush() - assert 'hello!' in fd.read() + assert b'hello!' in fd.read() def test_020_x_forwarded_for(self): request_bytes = ( @@ -654,13 +663,13 @@ class TestHttpd(_TestBase): self.spawn_server(sock=server_sock_2) # do a single req/response to verify it's up sock = eventlet.connect(('localhost', self.port)) - fd = sock.makefile('rw') + fd = sock.makefile('rwb') fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n') fd.flush() result = fd.read(1024) fd.close() - assert result.startswith('HTTP'), result - assert result.endswith('hello world') + assert result.startswith(b'HTTP'), result + assert result.endswith(b'hello world'), result # shut down the server and verify the server_socket fd is still open, # but the actual socketobject passed in to wsgi.server is closed @@ -673,13 +682,13 @@ class TestHttpd(_TestBase): self.assertEqual(support.get_errno(exc), errno.EBADF) self.spawn_server(sock=server_sock) sock = eventlet.connect(('localhost', self.port)) - fd = sock.makefile('rw') + fd = sock.makefile('rwb') fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n') fd.flush() result = fd.read(1024) fd.close() - assert result.startswith('HTTP'), result - assert result.endswith('hello world') + assert result.startswith(b'HTTP'), result + assert result.endswith(b'hello world'), result def test_021_environ_clobbering(self): def clobberin_time(environ, start_response): @@ -695,13 +704,13 @@ class TestHttpd(_TestBase): return [] self.site.application = clobberin_time sock = eventlet.connect(('localhost', self.port)) - fd = sock.makefile('rw') + fd = sock.makefile('rwb') fd.write('GET / HTTP/1.1\r\n' 'Host: localhost\r\n' 'Connection: close\r\n' '\r\n\r\n'.encode()) fd.flush() - assert '200 OK' in fd.read() + assert b'200 OK' in fd.read() def test_022_custom_pool(self): # just test that it accepts the parameter for now @@ -713,44 +722,44 @@ class TestHttpd(_TestBase): # this stuff is copied from test_001_server, could be better factored sock = eventlet.connect( ('localhost', self.port)) - fd = sock.makefile('rw') + fd = sock.makefile('rwb') fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n') fd.flush() result = fd.read() fd.close() - assert result.startswith('HTTP'), result - assert result.endswith('hello world') + assert result.startswith(b'HTTP'), result + assert result.endswith(b'hello world'), result def test_023_bad_content_length(self): sock = eventlet.connect( ('localhost', self.port)) - fd = sock.makefile('rw') + fd = sock.makefile('rwb') fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\nContent-length: argh\r\n\r\n') fd.flush() result = fd.read() fd.close() - assert result.startswith('HTTP'), result - assert '400 Bad Request' in result - assert '500' not in result + assert result.startswith(b'HTTP'), result + assert b'400 Bad Request' in result, result + assert b'500' not in result, result def test_024_expect_100_continue(self): def wsgi_app(environ, start_response): if int(environ['CONTENT_LENGTH']) > 1024: start_response('417 Expectation Failed', [('Content-Length', '7')]) - return ['failure'] + return [b'failure'] else: text = environ['wsgi.input'].read() start_response('200 OK', [('Content-Length', str(len(text)))]) return [text] self.site.application = wsgi_app sock = eventlet.connect(('localhost', self.port)) - fd = sock.makefile('rw') + fd = sock.makefile('rwb') fd.write(b'PUT / HTTP/1.1\r\nHost: localhost\r\nContent-length: 1025\r\n' b'Expect: 100-continue\r\n\r\n') fd.flush() result = read_http(sock) self.assertEqual(result.status, 'HTTP/1.1 417 Expectation Failed') - self.assertEqual(result.body, 'failure') + self.assertEqual(result.body, b'failure') fd.write( b'PUT / HTTP/1.1\r\nHost: localhost\r\nContent-length: 7\r\n' b'Expect: 100-continue\r\n\r\ntesting') @@ -758,7 +767,7 @@ class TestHttpd(_TestBase): header_lines = [] while True: line = fd.readline() - if line == '\r\n': + if line == b'\r\n': break else: header_lines.append(line) @@ -766,12 +775,12 @@ class TestHttpd(_TestBase): header_lines = [] while True: line = fd.readline() - if line == '\r\n': + if line == b'\r\n': break else: header_lines.append(line) assert header_lines[0].startswith('HTTP/1.1 200 OK') - self.assertEqual(fd.read(7), 'testing') + assert fd.read(7) == b'testing' fd.close() sock.close() @@ -871,7 +880,7 @@ class TestHttpd(_TestBase): result = read_http(sock) self.assertEqual(result.headers_lower['connection'], 'close') self.assertNotEqual(result.headers_lower.get('transfer-encoding'), 'chunked') - self.assertEqual(result.body, "thisischunked") + self.assertEqual(result.body, b"thisischunked") def test_minimum_chunk_size_parameter_leaves_httpprotocol_class_member_intact(self): start_size = wsgi.HttpProtocol.minimum_chunk_size @@ -902,7 +911,7 @@ class TestHttpd(_TestBase): self.assertEqual(result.body, expected_body) # verify that socket is closed by server - self.assertEqual(sock.recv(1), '') + self.assertEqual(sock.recv(1), b'') def test_026_http_10_nokeepalive(self): # verify that if an http/1.0 client sends connection: keep-alive @@ -918,7 +927,7 @@ class TestHttpd(_TestBase): def test_027_keepalive_chunked(self): self.site.application = chunked_post sock = eventlet.connect(('localhost', self.port)) - fd = sock.makefile('w') + fd = sock.makefile('wb') common_suffix = ( b'Host: localhost\r\nTransfer-Encoding: chunked\r\n\r\n' + b'10\r\n0123456789abcdef\r\n0\r\n\r\n') @@ -995,13 +1004,13 @@ class TestHttpd(_TestBase): env['eventlet.posthooks'].append( (posthook1, (2,), {'multiplier': 3})) start_response('200 OK', [('Content-Type', 'text/plain')]) - yield '' + yield b'' self.site.application = one_posthook_app sock = eventlet.connect(('localhost', self.port)) - fp = sock.makefile('rw') + fp = sock.makefile('rwb') fp.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n') fp.flush() - self.assertEqual(fp.readline(), 'HTTP/1.1 200 OK\r\n') + self.assertEqual(fp.readline(), b'HTTP/1.1 200 OK\r\n') fp.close() sock.close() self.assertEqual(posthook1_count[0], 6) @@ -1018,13 +1027,13 @@ class TestHttpd(_TestBase): env['eventlet.posthooks'].append( (posthook2, (100,), {'divisor': 4})) start_response('200 OK', [('Content-Type', 'text/plain')]) - yield '' + yield b'' self.site.application = two_posthook_app sock = eventlet.connect(('localhost', self.port)) - fp = sock.makefile('rw') + fp = sock.makefile('rwb') fp.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n') fp.flush() - self.assertEqual(fp.readline(), 'HTTP/1.1 200 OK\r\n') + self.assertEqual(fp.readline(), b'HTTP/1.1 200 OK\r\n') fp.close() sock.close() self.assertEqual(posthook1_count[0], 26) @@ -1034,7 +1043,7 @@ class TestHttpd(_TestBase): sock = eventlet.connect(('localhost', self.port)) request = 'GET / HTTP/1.0\r\nHost: localhost\r\nLong: %s\r\n\r\n' % \ ('a' * 10000) - fd = sock.makefile('rw') + fd = sock.makefile('rwb') fd.write(request.encode()) fd.flush() result = read_http(sock) @@ -1065,7 +1074,7 @@ class TestHttpd(_TestBase): yield chunk self.site.application = echo_by_iterating - upload_data = '123456789abcdef' * 100 + upload_data = b'123456789abcdef' * 100 request = ( 'POST / HTTP/1.0\r\n' 'Host: localhost\r\n' @@ -1089,20 +1098,20 @@ class TestHttpd(_TestBase): sock = eventlet.connect( ('localhost', self.port)) - fd = sock.makefile('rw') + fd = sock.makefile('rwb') fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n') fd.flush() - response = fd.read().split('\r\n') + response = fd.read().split(b'\r\n') headers = [] while True: h = response.pop(0) headers.append(h) if h == '': break - assert 'Transfer-Encoding: chunked' in ''.join(headers) + assert b'Transfer-Encoding: chunked' in ''.join(headers) # should only be one chunk of zero size with two blank lines # (one terminates the chunk, one terminates the body) - self.assertEqual(response, ['0', '', '']) + self.assertEqual(response, [b'0', b'', b'']) def test_configurable_url_length_limit(self): self.spawn_server(url_length_limit=20000) @@ -1110,15 +1119,15 @@ class TestHttpd(_TestBase): ('localhost', self.port)) path = 'x' * 15000 request = 'GET /%s HTTP/1.0\r\nHost: localhost\r\n\r\n' % path - fd = sock.makefile('rw') - fd.write(request) + fd = sock.makefile('rwb') + fd.write(request.encode()) fd.flush() result = fd.readline() if result: # windows closes the socket before the data is flushed, # so we never get anything back - status = result.split(' ')[1] - self.assertEqual(status, '200') + status = result.split(b' ')[1] + self.assertEqual(status, b'200') fd.close() def test_aborted_chunked_post(self): @@ -1130,7 +1139,7 @@ class TestHttpd(_TestBase): content = env['wsgi.input'].read(1024) except IOError: blew_up[0] = True - content = 'ok' + content = b'ok' read_content.send(content) start_response('200 OK', [('Content-Type', 'text/plain')]) return [content] @@ -1147,7 +1156,7 @@ class TestHttpd(_TestBase): sock.close() # the test passes if we successfully get here, and read all the data # in spite of the early close - self.assertEqual(read_content.wait(), 'ok') + self.assertEqual(read_content.wait(), b'ok') assert blew_up[0] def test_exceptions_close_connection(self): @@ -1155,7 +1164,7 @@ class TestHttpd(_TestBase): raise RuntimeError("intentional error") self.site.application = wsgi_app sock = eventlet.connect(('localhost', self.port)) - fd = sock.makefile('rw') + fd = sock.makefile('rwb') fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n') fd.flush() result = read_http(sock) @@ -1170,13 +1179,13 @@ class TestHttpd(_TestBase): yield u"non-encodable unicode: \u0230" self.site.application = wsgi_app sock = eventlet.connect(('localhost', self.port)) - fd = sock.makefile('rw') + fd = sock.makefile('rwb') fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n') fd.flush() result = read_http(sock) self.assertEqual(result.status, 'HTTP/1.1 500 Internal Server Error') self.assertEqual(result.headers_lower['connection'], 'close') - assert 'unicode' in result.body + assert b'unicode' in result.body def test_path_info_decoding(self): def wsgi_app(environ, start_response): @@ -1185,13 +1194,13 @@ class TestHttpd(_TestBase): yield "raw: %s" % environ['RAW_PATH_INFO'] self.site.application = wsgi_app sock = eventlet.connect(('localhost', self.port)) - fd = sock.makefile('rw') + fd = sock.makefile('rwb') fd.write(b'GET /a*b@%40%233 HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n') fd.flush() result = read_http(sock) self.assertEqual(result.status, 'HTTP/1.1 200 OK') - assert 'decoded: /a*b@@#3' in result.body - assert 'raw: /a*b@%40%233' in result.body + assert b'decoded: /a*b@@#3' in result.body + assert b'raw: /a*b@%40%233' in result.body def test_ipv6(self): try: @@ -1224,12 +1233,12 @@ class TestHttpd(_TestBase): self.site.application = crasher sock = eventlet.connect(('localhost', self.port)) - fd = sock.makefile('w') + fd = sock.makefile('wb') fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n') fd.flush() result1 = read_http(sock) self.assertEqual(result1.status, 'HTTP/1.1 500 Internal Server Error') - self.assertEqual(result1.body, '') + self.assertEqual(result1.body, b'') self.assertEqual(result1.headers_lower['connection'], 'close') assert 'transfer-encoding' not in result1.headers_lower @@ -1237,14 +1246,14 @@ class TestHttpd(_TestBase): self.spawn_server(debug=True) self.site.application = crasher sock = eventlet.connect(('localhost', self.port)) - fd = sock.makefile('w') + fd = sock.makefile('wb') fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n') fd.flush() result2 = read_http(sock) self.assertEqual(result2.status, 'HTTP/1.1 500 Internal Server Error') - assert 'intentional crash' in result2.body - assert 'RuntimeError' in result2.body - assert 'Traceback' in result2.body + assert b'intentional crash' in result2.body, result2.body + assert b'RuntimeError' in result2.body, result2.body + assert b'Traceback' in result2.body, result2.body self.assertEqual(result2.headers_lower['connection'], 'close') assert 'transfer-encoding' not in result2.headers_lower @@ -1253,7 +1262,7 @@ class TestHttpd(_TestBase): """ def long_response(environ, start_response): start_response('200 OK', [('Content-Length', '9876')]) - yield 'a' * 9876 + yield b'a' * 9876 server_sock = eventlet.listen(('localhost', 0)) self.port = server_sock.getsockname()[1] @@ -1366,7 +1375,7 @@ class IterableAlreadyHandledTest(_TestBase): sock = eventlet.connect( ('localhost', self.port)) - fd = sock.makefile('rw') + fd = sock.makefile('rwb') fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n') fd.flush() @@ -1378,7 +1387,7 @@ class IterableAlreadyHandledTest(_TestBase): result = read_http(sock) self.assertEqual(result.status, 'HTTP/1.1 200 OK') self.assertEqual(result.headers_lower.get('transfer-encoding'), 'chunked') - self.assertEqual(result.body, '0\r\n\r\n') # Still coming back chunked + self.assertEqual(result.body, b'0\r\n\r\n') # Still coming back chunked class ProxiedIterableAlreadyHandledTest(IterableAlreadyHandledTest): @@ -1418,13 +1427,13 @@ class TestChunkedInput(_TestBase): self.yield_next_space = False def response_iter(): - yield ' ' + yield b' ' num_sleeps = 0 while not self.yield_next_space and num_sleeps < 200: eventlet.sleep(.01) num_sleeps += 1 - yield ' ' + yield b' ' start_response('200 OK', [('Content-Type', 'text/plain'), @@ -1467,7 +1476,7 @@ class TestChunkedInput(_TestBase): fd = self.connect() fd.sendall(req.encode()) - self.assertEqual(read_http(fd).body, "this is ch") + self.assertEqual(read_http(fd).body, b"this is ch") self.ping(fd) fd.close() @@ -1478,7 +1487,7 @@ class TestChunkedInput(_TestBase): "Content-Length:0\r\n\r\n" + body fd = self.connect() fd.sendall(req.encode()) - self.assertEqual(read_http(fd).body, "this is ch") + self.assertEqual(read_http(fd).body, b"this is ch") self.ping(fd) fd.close() @@ -1489,7 +1498,7 @@ class TestChunkedInput(_TestBase): fd = self.connect() fd.sendall(req.encode()) - self.assertEqual(read_http(fd).body, "this is ch") + self.assertEqual(read_http(fd).body, b"this is ch") self.ping(fd) fd.close() @@ -1500,7 +1509,7 @@ class TestChunkedInput(_TestBase): fd = self.connect() fd.sendall(req.encode()) - self.assertEqual(read_http(fd).body, "pong") + self.assertEqual(read_http(fd).body, b"pong") self.ping(fd) fd.close() @@ -1512,7 +1521,7 @@ class TestChunkedInput(_TestBase): fd = self.connect() fd.sendall(req.encode()) - self.assertEqual(read_http(fd).body, 'this is chunked\nline 2\nline3') + self.assertEqual(read_http(fd).body, b'this is chunked\nline 2\nline3') fd.close() def test_chunked_readline_wsgi_override_minimum_chunk_size(self): @@ -1527,7 +1536,7 @@ class TestChunkedInput(_TestBase): resp_so_far += one_byte if resp_so_far.endswith('\r\n\r\n'): break - self.assertEqual(fd.recv(1), ' ') + self.assertEqual(fd.recv(1), b' ') try: with eventlet.Timeout(.1): fd.recv(1) @@ -1538,22 +1547,22 @@ class TestChunkedInput(_TestBase): self.yield_next_space = True with eventlet.Timeout(.1): - self.assertEqual(fd.recv(1), ' ') + self.assertEqual(fd.recv(1), b' ') def test_chunked_readline_wsgi_not_override_minimum_chunk_size(self): fd = self.connect() fd.sendall(b"POST /yield_spaces HTTP/1.1\r\nContent-Length: 0\r\n\r\n") - resp_so_far = '' + resp_so_far = b'' try: with eventlet.Timeout(.1): while True: one_byte = fd.recv(1) resp_so_far += one_byte - if resp_so_far.endswith('\r\n\r\n'): + if resp_so_far.endswith(b'\r\n\r\n'): break - self.assertEqual(fd.recv(1), ' ') + self.assertEqual(fd.recv(1), b' ') except eventlet.Timeout: pass else: diff --git a/tests/wsgi_test_conntimeout.py b/tests/wsgi_test_conntimeout.py index 91a690f..d925a04 100644 --- a/tests/wsgi_test_conntimeout.py +++ b/tests/wsgi_test_conntimeout.py @@ -136,7 +136,7 @@ if __name__ == '__main__': # req #1 - normal sock1 = eventlet.connect(server_addr) sock1.settimeout(0.1) - fd1 = sock1.makefile('rw') + fd1 = sock1.makefile('rwb') fd1.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n') fd1.flush() tests.wsgi_test.read_http(sock1) |