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
This commit is contained in:
Jakub Stasiak
2014-10-06 00:38:32 +01:00
parent 02a23c8bd7
commit 6cbd4846ab
16 changed files with 312 additions and 243 deletions

1
NEWS
View File

@@ -2,6 +2,7 @@
========================= =========================
* removed deprecated modules: api, most of coros, pool, proc, processes and util * removed deprecated modules: api, most of coros, pool, proc, processes and util
* improved Python 3 compatibility
0.15.2 0.15.2
====== ======

View File

@@ -7,7 +7,7 @@ import sys
import eventlet import eventlet
from eventlet import hubs from eventlet import hubs
from eventlet.support import greenlets, get_errno, six from eventlet.support import greenlets, get_errno
try: try:
sys.ps1 sys.ps1
@@ -30,13 +30,11 @@ class FileProxy(object):
pass pass
def write(self, data, *a, **kw): def write(self, data, *a, **kw):
data = six.b(data)
self.f.write(data, *a, **kw) self.f.write(data, *a, **kw)
self.f.flush() self.f.flush()
def readline(self, *a): def readline(self, *a):
line = self.f.readline(*a).replace(b'\r\n', b'\n') return self.f.readline(*a).replace('\r\n', '\n')
return six.u(line)
def __getattr__(self, attr): def __getattr__(self, attr):
return getattr(self.f, attr) return getattr(self.f, attr)

View File

@@ -7,7 +7,7 @@ import sys
import errno import errno
time = __import__('time') time = __import__('time')
from eventlet.support import get_errno from eventlet.support import get_errno, six
from eventlet.hubs import trampoline, IOClosed from eventlet.hubs import trampoline, IOClosed
from eventlet.greenio import set_nonblocking, GreenSocket, SOCKET_CLOSED, CONNECT_ERR, CONNECT_SUCCESS from eventlet.greenio import set_nonblocking, GreenSocket, SOCKET_CLOSED, CONNECT_ERR, CONNECT_SUCCESS
orig_socket = __import__('socket') orig_socket = __import__('socket')
@@ -21,9 +21,10 @@ else:
__patched__ = ['SSLSocket', 'wrap_socket', 'sslwrap_simple'] __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 """ 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 in 2.6. For documentation on it, please see the Python standard
documentation. documentation.
@@ -40,23 +41,49 @@ class GreenSSLSocket(__ssl.SSLSocket):
# we are inheriting from SSLSocket because its constructor calls # we are inheriting from SSLSocket because its constructor calls
# do_handshake whose behavior we wish to override # 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): if not isinstance(sock, GreenSocket):
sock = GreenSocket(sock) sock = GreenSocket(sock)
self.act_non_blocking = sock.act_non_blocking self.act_non_blocking = sock.act_non_blocking
if six.PY2:
# On Python 2 SSLSocket constructor queries the timeout, it'd break without
# this assignment
self._timeout = sock.gettimeout() self._timeout = sock.gettimeout()
super(GreenSSLSocket, self).__init__(sock.fd, *args, **kw)
# 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 superclass initializer trashes the methods so we remove
# the local-object versions of them and let the actual class # the local-object versions of them and let the actual class
# methods shine through # methods shine through
# Note: This for Python 2
try: try:
for fn in orig_socket._delegate_methods: for fn in orig_socket._delegate_methods:
delattr(self, fn) delattr(self, fn)
except AttributeError: except AttributeError:
pass 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): def settimeout(self, timeout):
self._timeout = timeout self._timeout = timeout
@@ -98,14 +125,14 @@ class GreenSSLSocket(__ssl.SSLSocket):
return self._call_trampolining( return self._call_trampolining(
super(GreenSSLSocket, self).write, data) super(GreenSSLSocket, self).write, data)
def read(self, len=1024): def read(self, *args, **kwargs):
"""Read up to LEN bytes and return them. """Read up to LEN bytes and return them.
Return zero-length string on EOF.""" Return zero-length string on EOF."""
try: try:
return self._call_trampolining( return self._call_trampolining(
super(GreenSSLSocket, self).read, len) super(GreenSSLSocket, self).read, *args, **kwargs)
except IOClosed: except IOClosed:
return '' return b''
def send(self, data, flags=0): def send(self, data, flags=0):
if self._sslobj: if self._sslobj:
@@ -174,9 +201,9 @@ class GreenSSLSocket(__ssl.SSLSocket):
trampoline(self, read=True, trampoline(self, read=True,
timeout=self.gettimeout(), timeout_exc=timeout_exc('timed out')) timeout=self.gettimeout(), timeout_exc=timeout_exc('timed out'))
except IOClosed: except IOClosed:
return '' return b''
if get_errno(e) in SOCKET_CLOSED: if get_errno(e) in SOCKET_CLOSED:
return '' return b''
raise raise
def recv_into(self, buffer, nbytes=None, flags=0): def recv_into(self, buffer, nbytes=None, flags=0):
@@ -245,14 +272,16 @@ class GreenSSLSocket(__ssl.SSLSocket):
if self._sslobj: if self._sslobj:
raise ValueError("attempt to connect already-connected SSLSocket!") raise ValueError("attempt to connect already-connected SSLSocket!")
self._socket_connect(addr) self._socket_connect(addr)
if has_ciphers: server_side = False
self._sslobj = _ssl.sslwrap(self._sock, False, self.keyfile, self.certfile, try:
self.cert_reqs, self.ssl_version, sslwrap = _ssl.sslwrap
self.ca_certs, self.ciphers) except AttributeError:
# sslwrap was removed in 2.7.9
self._sslobj = self._context._wrap_socket(self, server_side)
else: else:
self._sslobj = _ssl.sslwrap(self._sock, False, self.keyfile, self.certfile, self._sslobj = sslwrap(self._sock, server_side, self.keyfile, self.certfile,
self.cert_reqs, self.ssl_version, self.cert_reqs, self.ssl_version,
self.ca_certs) self.ca_certs, *([self.ciphers] if has_ciphers else []))
if self.do_handshake_on_connect: if self.do_handshake_on_connect:
self.do_handshake() self.do_handshake()

View File

@@ -160,6 +160,15 @@ class GreenSocket(object):
def _sock(self): def _sock(self):
return 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. # Forward unknown attributes to fd, cache the value for future use.
# I do not see any simple attribute which could be changed # I do not see any simple attribute which could be changed
# so caching everything in self is fine. # so caching everything in self is fine.
@@ -275,9 +284,13 @@ class GreenSocket(object):
newsock.settimeout(self.gettimeout()) newsock.settimeout(self.gettimeout())
return newsock return newsock
def makefile(self, *args, **kw): if six.PY3:
def makefile(self, *args, **kwargs):
return _original_socket.makefile(self, *args, **kwargs)
else:
def makefile(self, *args, **kwargs):
dupped = self.dup() dupped = self.dup()
res = _fileobject(dupped, *args, **kw) res = _fileobject(dupped, *args, **kwargs)
if hasattr(dupped, "_drop"): if hasattr(dupped, "_drop"):
dupped._drop() dupped._drop()
return res return res
@@ -457,10 +470,11 @@ class _SocketDuckForFd(object):
def send(self, data): def send(self, data):
while True: while True:
try: try:
os.write(self._fileno, data) return os.write(self._fileno, data)
except OSError as e: except OSError as e:
if get_errno(e) not in SOCKET_BLOCKING: if get_errno(e) not in SOCKET_BLOCKING:
raise IOError(*e.args) raise IOError(*e.args)
else:
trampoline(self, write=True) trampoline(self, write=True)
def sendall(self, data): def sendall(self, data):

View File

@@ -37,15 +37,17 @@ for _mod in ('wsaccel.utf8validator', 'autobahn.utf8validator'):
ACCEPTABLE_CLIENT_ERRORS = set((errno.ECONNRESET, errno.EPIPE)) ACCEPTABLE_CLIENT_ERRORS = set((errno.ECONNRESET, errno.EPIPE))
__all__ = ["WebSocketWSGI", "WebSocket"] __all__ = ["WebSocketWSGI", "WebSocket"]
PROTOCOL_GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11' PROTOCOL_GUID = b'258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
VALID_CLOSE_STATUS = (range(1000, 1004) VALID_CLOSE_STATUS = set(
+ range(1007, 1012) list(range(1000, 1004)) +
list(range(1007, 1012)) +
# 3000-3999: reserved for use by libraries, frameworks, # 3000-3999: reserved for use by libraries, frameworks,
# and applications # and applications
+ range(3000, 4000) list(range(3000, 4000)) +
# 4000-4999: reserved for private use and thus can't # 4000-4999: reserved for private use and thus can't
# be registered # be registered
+ range(4000, 5000)) list(range(4000, 5000))
)
class BadRequest(Exception): class BadRequest(Exception):
@@ -115,7 +117,7 @@ class WebSocketWSGI(object):
raise BadRequest() raise BadRequest()
except BadRequest as e: except BadRequest as e:
status = e.status status = e.status
body = e.body or '' body = e.body or b''
headers = e.headers or [] headers = e.headers or []
start_response(status, start_response(status,
[('Connection', 'close'), ] + headers) [('Connection', 'close'), ] + headers)
@@ -219,15 +221,14 @@ class WebSocketWSGI(object):
# extensions = [i.strip() for i in extensions.split(',')] # extensions = [i.strip() for i in extensions.split(',')]
key = environ['HTTP_SEC_WEBSOCKET_KEY'] key = environ['HTTP_SEC_WEBSOCKET_KEY']
response = base64.b64encode(sha1(key + PROTOCOL_GUID).digest()) response = base64.b64encode(sha1(six.b(key) + PROTOCOL_GUID).digest())
handshake_reply = ["HTTP/1.1 101 Switching Protocols", handshake_reply = [b"HTTP/1.1 101 Switching Protocols",
"Upgrade: websocket", b"Upgrade: websocket",
"Connection: Upgrade", b"Connection: Upgrade",
"Sec-WebSocket-Accept: %s" % (response, )] b"Sec-WebSocket-Accept: " + response]
if negotiated_protocol: if negotiated_protocol:
handshake_reply.append("Sec-WebSocket-Protocol: %s" handshake_reply.append(b"Sec-WebSocket-Protocol: " + six.b(negotiated_protocol))
% (negotiated_protocol, )) sock.sendall(b'\r\n'.join(handshake_reply) + b'\r\n\r\n')
sock.sendall('\r\n'.join(handshake_reply) + '\r\n\r\n')
return RFC6455WebSocket(sock, environ, self.protocol_version, return RFC6455WebSocket(sock, environ, self.protocol_version,
protocol=negotiated_protocol) protocol=negotiated_protocol)
@@ -425,7 +426,7 @@ class RFC6455WebSocket(WebSocket):
return self.decoder.decode(data, final) return self.decoder.decode(data, final)
def _get_bytes(self, numbytes): def _get_bytes(self, numbytes):
data = '' data = b''
while len(data) < numbytes: while len(data) < numbytes:
d = self.socket.recv(numbytes - len(data)) d = self.socket.recv(numbytes - len(data))
if not d: if not d:
@@ -447,14 +448,14 @@ class RFC6455WebSocket(WebSocket):
self.data.append(data) self.data.append(data)
def getvalue(self): def getvalue(self):
return ''.join(self.data) return ('' if self.decoder else b'').join(self.data)
@staticmethod @staticmethod
def _apply_mask(data, mask, length=None, offset=0): def _apply_mask(data, mask, length=None, offset=0):
if length is None: if length is None:
length = len(data) length = len(data)
cnt = range(length) 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): def _handle_control_frame(self, opcode, data):
if opcode == 8: # connection close if opcode == 8: # connection close
@@ -609,12 +610,13 @@ class RFC6455WebSocket(WebSocket):
# NOTE: RFC6455 states: # NOTE: RFC6455 states:
# A server MUST NOT mask any frames that it sends to the client # A server MUST NOT mask any frames that it sends to the client
rand = Random(time.time()) 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) message = RFC6455WebSocket._apply_mask(message, mask, length)
maskdata = struct.pack('!BBBB', *mask) maskdata = struct.pack('!BBBB', *mask)
else: else:
maskdata = '' maskdata = b''
return ''.join((header, lengthdata, maskdata, message))
return b''.join((header, lengthdata, maskdata, message))
def wait(self): def wait(self):
for i in self.iterator: for i in self.iterator:

View File

@@ -116,11 +116,11 @@ class Input(object):
if length and length > self.content_length - self.position: if length and length > self.content_length - self.position:
length = self.content_length - self.position length = self.content_length - self.position
if not length: if not length:
return '' return b''
try: try:
read = reader(length) read = reader(length)
except greenio.SSL.ZeroReturnError: except greenio.SSL.ZeroReturnError:
read = '' read = b''
self.position += len(read) self.position += len(read)
return read return read
@@ -189,7 +189,7 @@ class Input(object):
return self._do_read(self.rfile.readlines, hint) return self._do_read(self.rfile.readlines, hint)
def __iter__(self): def __iter__(self):
return iter(self.read, '') return iter(self.read, b'')
def get_socket(self): def get_socket(self):
return self.rfile._sock return self.rfile._sock
@@ -226,7 +226,7 @@ class FileObjectForHeaders(object):
if size < 0: if size < 0:
sz = MAX_HEADER_LINE sz = MAX_HEADER_LINE
rv = self.fp.readline(sz) rv = self.fp.readline(sz)
if size < 0 and len(rv) >= MAX_HEADER_LINE: if len(rv) >= MAX_HEADER_LINE:
raise HeaderLineTooLong() raise HeaderLineTooLong()
self.total_header_size += len(rv) self.total_header_size += len(rv)
if self.total_header_size > MAX_TOTAL_HEADER_SIZE: 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) self.raw_requestline = self.rfile.readline(self.server.url_length_limit)
if len(self.raw_requestline) == self.server.url_length_limit: if len(self.raw_requestline) == self.server.url_length_limit:
self.wfile.write( self.wfile.write(
"HTTP/1.0 414 Request URI Too Long\r\n" b"HTTP/1.0 414 Request URI Too Long\r\n"
"Connection: close\r\nContent-length: 0\r\n\r\n") b"Connection: close\r\nContent-length: 0\r\n\r\n")
self.close_connection = 1 self.close_connection = 1
return return
except greenio.SSL.ZeroReturnError: except greenio.SSL.ZeroReturnError:
@@ -289,14 +289,14 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
return return
except HeaderLineTooLong: except HeaderLineTooLong:
self.wfile.write( self.wfile.write(
"HTTP/1.0 400 Header Line Too Long\r\n" b"HTTP/1.0 400 Header Line Too Long\r\n"
"Connection: close\r\nContent-length: 0\r\n\r\n") b"Connection: close\r\nContent-length: 0\r\n\r\n")
self.close_connection = 1 self.close_connection = 1
return return
except HeadersTooLarge: except HeadersTooLarge:
self.wfile.write( self.wfile.write(
"HTTP/1.0 400 Headers Too Large\r\n" b"HTTP/1.0 400 Headers Too Large\r\n"
"Connection: close\r\nContent-length: 0\r\n\r\n") b"Connection: close\r\nContent-length: 0\r\n\r\n")
self.close_connection = 1 self.close_connection = 1
return return
finally: finally:
@@ -308,8 +308,8 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
int(content_length) int(content_length)
except ValueError: except ValueError:
self.wfile.write( self.wfile.write(
"HTTP/1.0 400 Bad Request\r\n" b"HTTP/1.0 400 Bad Request\r\n"
"Connection: close\r\nContent-length: 0\r\n\r\n") b"Connection: close\r\nContent-length: 0\r\n\r\n")
self.close_connection = 1 self.close_connection = 1
return return
@@ -345,13 +345,13 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
status, response_headers = headers_set status, response_headers = headers_set
headers_sent.append(1) headers_sent.append(1)
header_list = [header[0].lower() for header in response_headers] 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: for header in response_headers:
towrite.append('%s: %s\r\n' % header) towrite.append(six.b('%s: %s\r\n' % header))
# send Date header? # send Date header?
if 'date' not in header_list: 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() client_conn = self.headers.get('Connection', '').lower()
send_keep_alive = False send_keep_alive = False
@@ -369,21 +369,21 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
if 'content-length' not in header_list: if 'content-length' not in header_list:
if self.request_version == 'HTTP/1.1': if self.request_version == 'HTTP/1.1':
use_chunked[0] = True 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: elif 'content-length' not in header_list:
# client is 1.0 and therefore must read to EOF # client is 1.0 and therefore must read to EOF
self.close_connection = 1 self.close_connection = 1
if self.close_connection: if self.close_connection:
towrite.append('Connection: close\r\n') towrite.append(b'Connection: close\r\n')
elif send_keep_alive: elif send_keep_alive:
towrite.append('Connection: keep-alive\r\n') towrite.append(b'Connection: keep-alive\r\n')
towrite.append('\r\n') towrite.append(b'\r\n')
# end of header writing # end of header writing
if use_chunked[0]: if use_chunked[0]:
# Write the chunked encoding # 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: else:
towrite.append(data) towrite.append(data)
try: try:
@@ -450,15 +450,15 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
towrite.append(data) towrite.append(data)
towrite_size += len(data) towrite_size += len(data)
if towrite_size >= minimum_write_chunk_size: if towrite_size >= minimum_write_chunk_size:
write(''.join(towrite)) write(b''.join(towrite))
towrite = [] towrite = []
just_written_size = towrite_size just_written_size = towrite_size
towrite_size = 0 towrite_size = 0
if towrite: if towrite:
just_written_size = towrite_size just_written_size = towrite_size
write(''.join(towrite)) write(b''.join(towrite))
if not headers_sent or (use_chunked[0] and just_written_size): if not headers_sent or (use_chunked[0] and just_written_size):
write('') write(b'')
except Exception: except Exception:
self.close_connection = 1 self.close_connection = 1
tb = traceback.format_exc() tb = traceback.format_exc()
@@ -476,7 +476,7 @@ class HttpProtocol(BaseHTTPServer.BaseHTTPRequestHandler):
result.close() result.close()
if (self.environ['eventlet.input'].chunked_input or if (self.environ['eventlet.input'].chunked_input or
self.environ['eventlet.input'].position 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 # Read and discard body if there was no pending 100-continue
if not self.environ['eventlet.input'].wfile: if not self.environ['eventlet.input'].wfile:
# NOTE: MINIMUM_CHUNK_SIZE is used here for purpose different than chunking. # NOTE: MINIMUM_CHUNK_SIZE is used here for purpose different than chunking.

View File

@@ -1,7 +1,8 @@
import os import os
import socket
from unittest import TestCase, main from unittest import TestCase, main
from nose.tools import eq_
import eventlet import eventlet
from eventlet import greenio, hubs, greenthread, spawn from eventlet import greenio, hubs, greenthread, spawn
from eventlet.green import ssl from eventlet.green import ssl
@@ -51,9 +52,8 @@ class TestApi(TestCase):
client = eventlet.connect(('127.0.0.1', server.getsockname()[1])) client = eventlet.connect(('127.0.0.1', server.getsockname()[1]))
fd = client.makefile('rb') fd = client.makefile('rb')
client.close() client.close()
assert fd.readline() == b'hello\n' eq_(fd.readline(), b'hello\n')
eq_(fd.read(), b'')
assert fd.read() == b''
fd.close() fd.close()
check_hub() check_hub()
@@ -80,7 +80,7 @@ class TestApi(TestCase):
raw_client = eventlet.connect(('127.0.0.1', server.getsockname()[1])) raw_client = eventlet.connect(('127.0.0.1', server.getsockname()[1]))
client = ssl.wrap_socket(raw_client) client = ssl.wrap_socket(raw_client)
fd = socket._fileobject(client, 'rb', 8192) fd = client.makefile('rb', 8192)
assert fd.readline() == b'hello\r\n' assert fd.readline() == b'hello\r\n'
try: try:

View File

@@ -14,15 +14,15 @@ class BackdoorTest(LimitedTestCase):
client = socket.socket() client = socket.socket()
client.connect(('localhost', listener.getsockname()[1])) client.connect(('localhost', listener.getsockname()[1]))
f = client.makefile('rw') f = client.makefile('rw')
assert b'Python' in f.readline() assert 'Python' in f.readline()
f.readline() # build info f.readline() # build info
f.readline() # help info f.readline() # help info
assert b'InteractiveConsole' in f.readline() assert 'InteractiveConsole' in f.readline()
self.assertEqual(b'>>> ', f.read(4)) self.assertEqual('>>> ', f.read(4))
f.write(b'print("hi")\n') f.write('print("hi")\n')
f.flush() f.flush()
self.assertEqual(b'hi\n', f.readline()) self.assertEqual('hi\n', f.readline())
self.assertEqual(b'>>> ', f.read(4)) self.assertEqual('>>> ', f.read(4))
f.close() f.close()
client.close() client.close()
serv.kill() serv.kill()

View File

@@ -125,8 +125,8 @@ class TestServe(LimitedTestCase):
eventlet.spawn(eventlet.serve, server, handle) eventlet.spawn(eventlet.serve, server, handle)
client = eventlet.wrap_ssl(eventlet.connect(('localhost', port))) client = eventlet.wrap_ssl(eventlet.connect(('localhost', port)))
client.sendall("echo") client.sendall(b"echo")
self.assertEqual("echo", client.recv(1024)) self.assertEqual(b"echo", client.recv(1024))
def test_socket_reuse(self): def test_socket_reuse(self):
lsock1 = eventlet.listen(('localhost', 0)) lsock1 = eventlet.listen(('localhost', 0))

View File

@@ -1,4 +1,5 @@
import os import os
from eventlet.support import six
from tests.patcher_test import ProcessBase from tests.patcher_test import ProcessBase
from tests import skip_with_pyevent from tests import skip_with_pyevent

View File

@@ -450,7 +450,7 @@ class TestGreenSocket(LimitedTestCase):
def sender(evt): def sender(evt):
s2, addr = server.accept() s2, addr = server.accept()
wrap_wfile = s2.makefile('w') wrap_wfile = s2.makefile('wb')
eventlet.sleep(0.02) eventlet.sleep(0.02)
wrap_wfile.write(b'hi') wrap_wfile.write(b'hi')
@@ -627,7 +627,7 @@ class TestGreenPipe(LimitedTestCase):
wf = greenio.GreenPipe(w, 'w', 0) wf = greenio.GreenPipe(w, 'w', 0)
def sender(f, content): def sender(f, content):
for ch in content: for ch in map(six.int2byte, six.iterbytes(content)):
eventlet.sleep(0.0001) eventlet.sleep(0.0001)
f.write(ch) f.write(ch)
f.close() f.close()
@@ -638,7 +638,7 @@ class TestGreenPipe(LimitedTestCase):
line = rf.readline() line = rf.readline()
eventlet.sleep(0.01) eventlet.sleep(0.01)
self.assertEqual(line, one_line) self.assertEqual(line, one_line)
self.assertEqual(rf.readline(), '') self.assertEqual(rf.readline(), b'')
def test_pipe_read(self): def test_pipe_read(self):
# ensure that 'readline' works properly on GreenPipes when data is not # ensure that 'readline' works properly on GreenPipes when data is not
@@ -663,10 +663,10 @@ class TestGreenPipe(LimitedTestCase):
eventlet.sleep(0) eventlet.sleep(0)
line = r.readline() line = r.readline()
self.assertEqual(line, 'line\n') self.assertEqual(line, b'line\n')
line = r.readline() line = r.readline()
self.assertEqual(line, 'line\r\n') self.assertEqual(line, b'line\r\n')
gt.wait() gt.wait()
@@ -676,7 +676,7 @@ class TestGreenPipe(LimitedTestCase):
r = greenio.GreenPipe(r) r = greenio.GreenPipe(r)
w = greenio.GreenPipe(w, 'w') 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(): def writer():
w.write(large_message) w.write(large_message)

View File

@@ -1,12 +1,12 @@
from __future__ import print_function from __future__ import print_function
import MySQLdb as m
from eventlet import patcher from eventlet import patcher
from eventlet.green import MySQLdb as gm
# no standard tests in this file, ignore # no standard tests in this file, ignore
__test__ = False __test__ = False
if __name__ == '__main__': if __name__ == '__main__':
import MySQLdb as m
from eventlet.green import MySQLdb as gm
patcher.monkey_patch(all=True, MySQLdb=True) patcher.monkey_patch(all=True, MySQLdb=True)
print("mysqltest {0}".format(",".join(sorted(patcher.already_patched.keys())))) print("mysqltest {0}".format(",".join(sorted(patcher.already_patched.keys()))))
print("connect {0}".format(m.connect == gm.connect)) print("connect {0}".format(m.connect == gm.connect))

View File

@@ -3,11 +3,15 @@ import shutil
import sys import sys
import tempfile import tempfile
from eventlet.support import six
from tests import LimitedTestCase, main, run_python, skip_with_pyevent from tests import LimitedTestCase, main, run_python, skip_with_pyevent
base_module_contents = """ base_module_contents = """
import socket import socket
try:
import urllib.request as urllib
except ImportError:
import urllib import urllib
print("base {0} {1}".format(socket, urllib)) print("base {0} {1}".format(socket, urllib))
""" """
@@ -45,14 +49,18 @@ class ProcessBase(LimitedTestCase):
filename = os.path.join(self.tempdir, name) filename = os.path.join(self.tempdir, name)
if not filename.endswith('.py'): if not filename.endswith('.py'):
filename = filename + '.py' filename = filename + '.py'
fd = open(filename, "wb") with open(filename, "w") as fd:
fd.write(contents) fd.write(contents)
fd.close()
def launch_subprocess(self, filename): def launch_subprocess(self, filename):
path = os.path.join(self.tempdir, filename) path = os.path.join(self.tempdir, filename)
output = run_python(path) 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 return output, lines
def run_script(self, contents, modname=None): def run_script(self, contents, modname=None):
@@ -98,6 +106,9 @@ class MonkeyPatch(ProcessBase):
from eventlet import patcher from eventlet import patcher
patcher.monkey_patch() patcher.monkey_patch()
import socket import socket
try:
import urllib.request as urllib
except ImportError:
import urllib import urllib
print("newmod {0} {1}".format(socket.socket, urllib.socket.socket)) print("newmod {0} {1}".format(socket.socket, urllib.socket.socket))
""" """

View File

@@ -1,11 +1,15 @@
import errno import errno
import struct import struct
from nose.tools import eq_
import eventlet import eventlet
from eventlet import event from eventlet import event
from eventlet import websocket from eventlet import websocket
from eventlet.green import httplib from eventlet.green import httplib
from eventlet.green import socket from eventlet.green import socket
from eventlet import websocket
from eventlet.support import six
from tests.wsgi_test import _TestBase from tests.wsgi_test import _TestBase
@@ -51,7 +55,7 @@ class TestWebSocket(_TestBase):
self.assertEqual(resp.status, 400) self.assertEqual(resp.status, 400)
self.assertEqual(resp.getheader('connection'), 'close') self.assertEqual(resp.getheader('connection'), 'close')
self.assertEqual(resp.read(), '') self.assertEqual(resp.read(), b'')
# Now, miss off key # Now, miss off key
headers = dict(kv.split(': ') for kv in [ headers = dict(kv.split(': ') for kv in [
@@ -67,7 +71,7 @@ class TestWebSocket(_TestBase):
self.assertEqual(resp.status, 400) self.assertEqual(resp.status, 400)
self.assertEqual(resp.getheader('connection'), 'close') self.assertEqual(resp.getheader('connection'), 'close')
self.assertEqual(resp.read(), '') self.assertEqual(resp.read(), b'')
# No Upgrade now # No Upgrade now
headers = dict(kv.split(': ') for kv in [ headers = dict(kv.split(': ') for kv in [
@@ -82,7 +86,7 @@ class TestWebSocket(_TestBase):
self.assertEqual(resp.status, 400) self.assertEqual(resp.status, 400)
self.assertEqual(resp.getheader('connection'), 'close') self.assertEqual(resp.getheader('connection'), 'close')
self.assertEqual(resp.read(), '') self.assertEqual(resp.read(), b'')
def test_correct_upgrade_request_13(self): def test_correct_upgrade_request_13(self):
for http_connection in ['Upgrade', 'UpGrAdE', 'keep-alive, Upgrade']: for http_connection in ['Upgrade', 'UpGrAdE', 'keep-alive, Upgrade']:
@@ -97,16 +101,16 @@ class TestWebSocket(_TestBase):
] ]
sock = eventlet.connect(('localhost', self.port)) 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) result = sock.recv(1024)
# The server responds the correct Websocket handshake # The server responds the correct Websocket handshake
print('Connection string: %r' % http_connection) 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', 'HTTP/1.1 101 Switching Protocols',
'Upgrade: websocket', 'Upgrade: websocket',
'Connection: Upgrade', 'Connection: Upgrade',
'Sec-WebSocket-Accept: ywSyWXCPNsDxLrQdQrn5RFNRfBU=\r\n\r\n', 'Sec-WebSocket-Accept: ywSyWXCPNsDxLrQdQrn5RFNRfBU=\r\n\r\n',
])) ])))
def test_send_recv_13(self): def test_send_recv_13(self):
connect = [ connect = [
@@ -121,15 +125,15 @@ class TestWebSocket(_TestBase):
sock = eventlet.connect( sock = eventlet.connect(
('localhost', self.port)) ('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) sock.recv(1024)
ws = websocket.RFC6455WebSocket(sock, {}, client=True) ws = websocket.RFC6455WebSocket(sock, {}, client=True)
ws.send('hello') ws.send(b'hello')
assert ws.wait() == 'hello' eq_(ws.wait(), b'hello')
ws.send('hello world!\x01') ws.send(b'hello world!\x01')
ws.send(u'hello world again!') ws.send(u'hello world again!')
assert ws.wait() == 'hello world!\x01' eq_(ws.wait(), b'hello world!\x01')
assert ws.wait() == u'hello world again!' eq_(ws.wait(), u'hello world again!')
ws.close() ws.close()
eventlet.sleep(0.01) eventlet.sleep(0.01)
@@ -160,7 +164,7 @@ class TestWebSocket(_TestBase):
] ]
sock = eventlet.connect( sock = eventlet.connect(
('localhost', self.port)) ('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.recv(1024) # get the headers
sock.close() # close while the app is running sock.close() # close while the app is running
done_with_request.wait() done_with_request.wait()
@@ -193,7 +197,7 @@ class TestWebSocket(_TestBase):
] ]
sock = eventlet.connect( sock = eventlet.connect(
('localhost', self.port)) ('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.recv(1024) # get the headers
closeframe = struct.pack('!BBIH', 1 << 7 | 8, 1 << 7 | 2, 0, 1000) closeframe = struct.pack('!BBIH', 1 << 7 | 8, 1 << 7 | 2, 0, 1000)
sock.sendall(closeframe) # "Close the connection" packet. sock.sendall(closeframe) # "Close the connection" packet.
@@ -227,8 +231,8 @@ class TestWebSocket(_TestBase):
] ]
sock = eventlet.connect( sock = eventlet.connect(
('localhost', self.port)) ('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.recv(1024) # get the headers
sock.sendall('\x07\xff') # Weird packet. sock.sendall(b'\x07\xff') # Weird packet.
done_with_request.wait() done_with_request.wait()
assert not error_detected[0] assert not error_detected[0]

View File

@@ -27,6 +27,13 @@ import tests
certificate_file = os.path.join(os.path.dirname(__file__), 'test_server.crt') 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') 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 = collections.namedtuple(
'HttpReadResult', 'HttpReadResult',
@@ -36,17 +43,17 @@ HttpReadResult = collections.namedtuple(
def hello_world(env, start_response): def hello_world(env, start_response):
if env['PATH_INFO'] == 'notexist': if env['PATH_INFO'] == 'notexist':
start_response('404 Not Found', [('Content-type', 'text/plain')]) start_response('404 Not Found', [('Content-type', 'text/plain')])
return ["not found"] return [b"not found"]
start_response('200 OK', [('Content-type', 'text/plain')]) start_response('200 OK', [('Content-type', 'text/plain')])
return ["hello world"] return [b"hello world"]
def chunked_app(env, start_response): def chunked_app(env, start_response):
start_response('200 OK', [('Content-type', 'text/plain')]) start_response('200 OK', [('Content-type', 'text/plain')])
yield "this" yield b"this"
yield "is" yield b"is"
yield "chunked" yield b"chunked"
def chunked_fail_app(environ, start_response): def chunked_fail_app(environ, start_response):
@@ -56,8 +63,8 @@ def chunked_fail_app(environ, start_response):
start_response('200 OK', headers) start_response('200 OK', headers)
# We start streaming data just fine. # We start streaming data just fine.
yield "The dwarves of yore made mighty spells," yield b"The dwarves of yore made mighty spells,"
yield "While hammers fell like ringing bells" yield b"While hammers fell like ringing bells"
# Then the back-end fails! # Then the back-end fails!
try: try:
@@ -67,13 +74,13 @@ def chunked_fail_app(environ, start_response):
return return
# So rest of the response data is not available. # So rest of the response data is not available.
yield "In places deep, where dark things sleep," yield b"In places deep, where dark things sleep,"
yield "In hollow halls beneath the fells." yield b"In hollow halls beneath the fells."
def big_chunks(env, start_response): def big_chunks(env, start_response):
start_response('200 OK', [('Content-type', 'text/plain')]) start_response('200 OK', [('Content-type', 'text/plain')])
line = 'a' * 8192 line = b'a' * 8192
for x in range(10): for x in range(10):
yield line yield line
@@ -150,11 +157,13 @@ class ConnectionClosed(Exception):
def read_http(sock): def read_http(sock):
fd = sock.makefile() fd = sock.makefile('rb')
try: try:
response_line = fd.readline().rstrip('\r\n') response_line = bytes_to_str(fd.readline().rstrip(b'\r\n'))
except socket.error as exc: 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 ConnectionClosed
raise raise
if not response_line: if not response_line:
@@ -163,7 +172,7 @@ def read_http(sock):
header_lines = [] header_lines = []
while True: while True:
line = fd.readline() line = fd.readline()
if line == '\r\n': if line == b'\r\n':
break break
else: else:
header_lines.append(line) header_lines.append(line)
@@ -174,7 +183,7 @@ def read_http(sock):
x = x.strip() x = x.strip()
if not x: if not x:
continue continue
key, value = x.split(':', 1) key, value = bytes_to_str(x).split(':', 1)
key = key.rstrip() key = key.rstrip()
value = value.lstrip() value = value.lstrip()
key_lower = key.lower() key_lower = key.lower()
@@ -256,20 +265,20 @@ class TestHttpd(_TestBase):
sock = eventlet.connect( sock = eventlet.connect(
('localhost', self.port)) ('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.write(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
fd.flush() fd.flush()
result = fd.read() result = fd.read()
fd.close() fd.close()
# The server responds with the maximum version it supports # The server responds with the maximum version it supports
assert result.startswith('HTTP'), result assert result.startswith(b'HTTP'), result
assert result.endswith('hello world'), result assert result.endswith(b'hello world'), result
def test_002_keepalive(self): def test_002_keepalive(self):
sock = eventlet.connect( sock = eventlet.connect(
('localhost', self.port)) ('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.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
fd.flush() fd.flush()
read_http(sock) read_http(sock)
@@ -284,7 +293,7 @@ class TestHttpd(_TestBase):
sock = eventlet.connect( sock = eventlet.connect(
('localhost', self.port)) ('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.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
fd.flush() fd.flush()
cancel = eventlet.Timeout(1, RuntimeError) cancel = eventlet.Timeout(1, RuntimeError)
@@ -296,7 +305,7 @@ class TestHttpd(_TestBase):
sock = eventlet.connect( sock = eventlet.connect(
('localhost', self.port)) ('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.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
fd.flush() fd.flush()
read_http(sock) read_http(sock)
@@ -323,8 +332,8 @@ class TestHttpd(_TestBase):
for ii in range(3000): for ii in range(3000):
path_parts.append('path') path_parts.append('path')
path = '/'.join(path_parts) path = '/'.join(path_parts)
request = 'GET /%s HTTP/1.0\r\nHost: localhost\r\n\r\n' % path request = ('GET /%s HTTP/1.0\r\nHost: localhost\r\n\r\n' % path).encode()
fd = sock.makefile('rw') fd = sock.makefile('rwb')
fd.write(request) fd.write(request)
fd.flush() fd.flush()
result = fd.readline() result = fd.readline()
@@ -352,8 +361,8 @@ class TestHttpd(_TestBase):
'Content-Length: 3', 'Content-Length: 3',
'', '',
'a=a')) 'a=a'))
fd = sock.makefile('w') fd = sock.makefile('wb')
fd.write(request) fd.write(request.encode())
fd.flush() fd.flush()
# send some junk after the actual request # send some junk after the actual request
@@ -365,7 +374,7 @@ class TestHttpd(_TestBase):
def test_008_correctresponse(self): def test_008_correctresponse(self):
sock = eventlet.connect(('localhost', self.port)) 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.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
fd.flush() fd.flush()
result_200 = read_http(sock) result_200 = read_http(sock)
@@ -384,37 +393,37 @@ class TestHttpd(_TestBase):
sock = eventlet.connect( sock = eventlet.connect(
('localhost', self.port)) ('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.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
fd.flush() 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): def test_010_no_chunked_http_1_0(self):
self.site.application = chunked_app self.site.application = chunked_app
sock = eventlet.connect( sock = eventlet.connect(
('localhost', self.port)) ('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.write(b'GET / HTTP/1.0\r\nHost: localhost\r\nConnection: close\r\n\r\n')
fd.flush() 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): def test_011_multiple_chunks(self):
self.site.application = big_chunks self.site.application = big_chunks
sock = eventlet.connect( sock = eventlet.connect(
('localhost', self.port)) ('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.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
fd.flush() fd.flush()
headers = '' headers = b''
while True: while True:
line = fd.readline() line = fd.readline()
if line == '\r\n': if line == b'\r\n':
break break
else: else:
headers += line headers += line
assert 'Transfer-Encoding: chunked' in headers assert b'Transfer-Encoding: chunked' in headers
chunks = 0 chunks = 0
chunklen = int(fd.readline(), 16) chunklen = int(fd.readline(), 16)
while chunklen: while chunklen:
@@ -473,52 +482,52 @@ class TestHttpd(_TestBase):
def test_014_chunked_post(self): def test_014_chunked_post(self):
self.site.application = chunked_post self.site.application = chunked_post
sock = eventlet.connect(('localhost', self.port)) 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' fd.write('PUT /a HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n'
'Transfer-Encoding: chunked\r\n\r\n' 'Transfer-Encoding: chunked\r\n\r\n'
'2\r\noh\r\n4\r\n hai\r\n0\r\n\r\n'.encode()) '2\r\noh\r\n4\r\n hai\r\n0\r\n\r\n'.encode())
fd.flush() fd.flush()
while True: while True:
if fd.readline() == '\r\n': if fd.readline() == b'\r\n':
break break
response = fd.read() 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)) 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' fd.write('PUT /b HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n'
'Transfer-Encoding: chunked\r\n\r\n' 'Transfer-Encoding: chunked\r\n\r\n'
'2\r\noh\r\n4\r\n hai\r\n0\r\n\r\n'.encode()) '2\r\noh\r\n4\r\n hai\r\n0\r\n\r\n'.encode())
fd.flush() fd.flush()
while True: while True:
if fd.readline() == '\r\n': if fd.readline() == b'\r\n':
break break
response = fd.read() 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)) 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' fd.write('PUT /c HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n'
'Transfer-Encoding: chunked\r\n\r\n' 'Transfer-Encoding: chunked\r\n\r\n'
'2\r\noh\r\n4\r\n hai\r\n0\r\n\r\n'.encode()) '2\r\noh\r\n4\r\n hai\r\n0\r\n\r\n'.encode())
fd.flush() fd.flush()
while True: while True:
if fd.readline() == '\r\n': if fd.readline() == b'\r\n':
break break
response = fd.read(8192) 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): def test_015_write(self):
self.site.application = use_write self.site.application = use_write
sock = eventlet.connect(('localhost', self.port)) 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.write(b'GET /a HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
fd.flush() fd.flush()
result1 = read_http(sock) result1 = read_http(sock)
assert 'content-length' in result1.headers_lower assert 'content-length' in result1.headers_lower
sock = eventlet.connect(('localhost', self.port)) 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.write(b'GET /b HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
fd.flush() fd.flush()
result2 = read_http(sock) result2 = read_http(sock)
@@ -531,21 +540,21 @@ class TestHttpd(_TestBase):
""" """
def wsgi_app(environ, start_response): def wsgi_app(environ, start_response):
start_response('200 OK', [('Content-Length', '7')]) start_response('200 OK', [('Content-Length', '7')])
return ['testing'] return [b'testing']
self.site.application = wsgi_app self.site.application = wsgi_app
sock = eventlet.connect(('localhost', self.port)) 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.write(b'GET /a HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
fd.flush() fd.flush()
header_lines = [] header_lines = []
while True: while True:
line = fd.readline() line = fd.readline()
if line == '\r\n': if line == b'\r\n':
break break
else: else:
header_lines.append(line) header_lines.append(line)
self.assertEqual(1, len( 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 @tests.skip_if_no_ssl
def test_017_ssl_zeroreturnerror(self): def test_017_ssl_zeroreturnerror(self):
@@ -588,7 +597,7 @@ class TestHttpd(_TestBase):
sock = eventlet.connect( sock = eventlet.connect(
('localhost', self.port)) ('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.write(b'GET / HTTP/1.0\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n')
fd.flush() fd.flush()
@@ -607,13 +616,13 @@ class TestHttpd(_TestBase):
def use_fieldstorage(environ, start_response): def use_fieldstorage(environ, start_response):
cgi.FieldStorage(fp=environ['wsgi.input'], environ=environ) cgi.FieldStorage(fp=environ['wsgi.input'], environ=environ)
start_response('200 OK', [('Content-type', 'text/plain')]) start_response('200 OK', [('Content-type', 'text/plain')])
return ['hello!'] return [b'hello!']
self.site.application = use_fieldstorage self.site.application = use_fieldstorage
sock = eventlet.connect( sock = eventlet.connect(
('localhost', self.port)) ('localhost', self.port))
fd = sock.makefile('rw') fd = sock.makefile('rwb')
fd.write('POST / HTTP/1.1\r\n' fd.write('POST / HTTP/1.1\r\n'
'Host: localhost\r\n' 'Host: localhost\r\n'
'Connection: close\r\n' 'Connection: close\r\n'
@@ -621,7 +630,7 @@ class TestHttpd(_TestBase):
'2\r\noh\r\n' '2\r\noh\r\n'
'4\r\n hai\r\n0\r\n\r\n'.encode()) '4\r\n hai\r\n0\r\n\r\n'.encode())
fd.flush() fd.flush()
assert 'hello!' in fd.read() assert b'hello!' in fd.read()
def test_020_x_forwarded_for(self): def test_020_x_forwarded_for(self):
request_bytes = ( request_bytes = (
@@ -654,13 +663,13 @@ class TestHttpd(_TestBase):
self.spawn_server(sock=server_sock_2) self.spawn_server(sock=server_sock_2)
# do a single req/response to verify it's up # do a single req/response to verify it's up
sock = eventlet.connect(('localhost', self.port)) 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.write(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
fd.flush() fd.flush()
result = fd.read(1024) result = fd.read(1024)
fd.close() fd.close()
assert result.startswith('HTTP'), result assert result.startswith(b'HTTP'), result
assert result.endswith('hello world') assert result.endswith(b'hello world'), result
# shut down the server and verify the server_socket fd is still open, # shut down the server and verify the server_socket fd is still open,
# but the actual socketobject passed in to wsgi.server is closed # 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.assertEqual(support.get_errno(exc), errno.EBADF)
self.spawn_server(sock=server_sock) self.spawn_server(sock=server_sock)
sock = eventlet.connect(('localhost', self.port)) 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.write(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
fd.flush() fd.flush()
result = fd.read(1024) result = fd.read(1024)
fd.close() fd.close()
assert result.startswith('HTTP'), result assert result.startswith(b'HTTP'), result
assert result.endswith('hello world') assert result.endswith(b'hello world'), result
def test_021_environ_clobbering(self): def test_021_environ_clobbering(self):
def clobberin_time(environ, start_response): def clobberin_time(environ, start_response):
@@ -695,13 +704,13 @@ class TestHttpd(_TestBase):
return [] return []
self.site.application = clobberin_time self.site.application = clobberin_time
sock = eventlet.connect(('localhost', self.port)) sock = eventlet.connect(('localhost', self.port))
fd = sock.makefile('rw') fd = sock.makefile('rwb')
fd.write('GET / HTTP/1.1\r\n' fd.write('GET / HTTP/1.1\r\n'
'Host: localhost\r\n' 'Host: localhost\r\n'
'Connection: close\r\n' 'Connection: close\r\n'
'\r\n\r\n'.encode()) '\r\n\r\n'.encode())
fd.flush() fd.flush()
assert '200 OK' in fd.read() assert b'200 OK' in fd.read()
def test_022_custom_pool(self): def test_022_custom_pool(self):
# just test that it accepts the parameter for now # 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 # this stuff is copied from test_001_server, could be better factored
sock = eventlet.connect( sock = eventlet.connect(
('localhost', self.port)) ('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.write(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
fd.flush() fd.flush()
result = fd.read() result = fd.read()
fd.close() fd.close()
assert result.startswith('HTTP'), result assert result.startswith(b'HTTP'), result
assert result.endswith('hello world') assert result.endswith(b'hello world'), result
def test_023_bad_content_length(self): def test_023_bad_content_length(self):
sock = eventlet.connect( sock = eventlet.connect(
('localhost', self.port)) ('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.write(b'GET / HTTP/1.0\r\nHost: localhost\r\nContent-length: argh\r\n\r\n')
fd.flush() fd.flush()
result = fd.read() result = fd.read()
fd.close() fd.close()
assert result.startswith('HTTP'), result assert result.startswith(b'HTTP'), result
assert '400 Bad Request' in result assert b'400 Bad Request' in result, result
assert '500' not in result assert b'500' not in result, result
def test_024_expect_100_continue(self): def test_024_expect_100_continue(self):
def wsgi_app(environ, start_response): def wsgi_app(environ, start_response):
if int(environ['CONTENT_LENGTH']) > 1024: if int(environ['CONTENT_LENGTH']) > 1024:
start_response('417 Expectation Failed', [('Content-Length', '7')]) start_response('417 Expectation Failed', [('Content-Length', '7')])
return ['failure'] return [b'failure']
else: else:
text = environ['wsgi.input'].read() text = environ['wsgi.input'].read()
start_response('200 OK', [('Content-Length', str(len(text)))]) start_response('200 OK', [('Content-Length', str(len(text)))])
return [text] return [text]
self.site.application = wsgi_app self.site.application = wsgi_app
sock = eventlet.connect(('localhost', self.port)) 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' fd.write(b'PUT / HTTP/1.1\r\nHost: localhost\r\nContent-length: 1025\r\n'
b'Expect: 100-continue\r\n\r\n') b'Expect: 100-continue\r\n\r\n')
fd.flush() fd.flush()
result = read_http(sock) result = read_http(sock)
self.assertEqual(result.status, 'HTTP/1.1 417 Expectation Failed') self.assertEqual(result.status, 'HTTP/1.1 417 Expectation Failed')
self.assertEqual(result.body, 'failure') self.assertEqual(result.body, b'failure')
fd.write( fd.write(
b'PUT / HTTP/1.1\r\nHost: localhost\r\nContent-length: 7\r\n' b'PUT / HTTP/1.1\r\nHost: localhost\r\nContent-length: 7\r\n'
b'Expect: 100-continue\r\n\r\ntesting') b'Expect: 100-continue\r\n\r\ntesting')
@@ -758,7 +767,7 @@ class TestHttpd(_TestBase):
header_lines = [] header_lines = []
while True: while True:
line = fd.readline() line = fd.readline()
if line == '\r\n': if line == b'\r\n':
break break
else: else:
header_lines.append(line) header_lines.append(line)
@@ -766,12 +775,12 @@ class TestHttpd(_TestBase):
header_lines = [] header_lines = []
while True: while True:
line = fd.readline() line = fd.readline()
if line == '\r\n': if line == b'\r\n':
break break
else: else:
header_lines.append(line) header_lines.append(line)
assert header_lines[0].startswith('HTTP/1.1 200 OK') assert header_lines[0].startswith('HTTP/1.1 200 OK')
self.assertEqual(fd.read(7), 'testing') assert fd.read(7) == b'testing'
fd.close() fd.close()
sock.close() sock.close()
@@ -871,7 +880,7 @@ class TestHttpd(_TestBase):
result = read_http(sock) result = read_http(sock)
self.assertEqual(result.headers_lower['connection'], 'close') self.assertEqual(result.headers_lower['connection'], 'close')
self.assertNotEqual(result.headers_lower.get('transfer-encoding'), 'chunked') 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): def test_minimum_chunk_size_parameter_leaves_httpprotocol_class_member_intact(self):
start_size = wsgi.HttpProtocol.minimum_chunk_size start_size = wsgi.HttpProtocol.minimum_chunk_size
@@ -902,7 +911,7 @@ class TestHttpd(_TestBase):
self.assertEqual(result.body, expected_body) self.assertEqual(result.body, expected_body)
# verify that socket is closed by server # 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): def test_026_http_10_nokeepalive(self):
# verify that if an http/1.0 client sends connection: keep-alive # 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): def test_027_keepalive_chunked(self):
self.site.application = chunked_post self.site.application = chunked_post
sock = eventlet.connect(('localhost', self.port)) sock = eventlet.connect(('localhost', self.port))
fd = sock.makefile('w') fd = sock.makefile('wb')
common_suffix = ( common_suffix = (
b'Host: localhost\r\nTransfer-Encoding: chunked\r\n\r\n' + b'Host: localhost\r\nTransfer-Encoding: chunked\r\n\r\n' +
b'10\r\n0123456789abcdef\r\n0\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( env['eventlet.posthooks'].append(
(posthook1, (2,), {'multiplier': 3})) (posthook1, (2,), {'multiplier': 3}))
start_response('200 OK', [('Content-Type', 'text/plain')]) start_response('200 OK', [('Content-Type', 'text/plain')])
yield '' yield b''
self.site.application = one_posthook_app self.site.application = one_posthook_app
sock = eventlet.connect(('localhost', self.port)) 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.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
fp.flush() 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() fp.close()
sock.close() sock.close()
self.assertEqual(posthook1_count[0], 6) self.assertEqual(posthook1_count[0], 6)
@@ -1018,13 +1027,13 @@ class TestHttpd(_TestBase):
env['eventlet.posthooks'].append( env['eventlet.posthooks'].append(
(posthook2, (100,), {'divisor': 4})) (posthook2, (100,), {'divisor': 4}))
start_response('200 OK', [('Content-Type', 'text/plain')]) start_response('200 OK', [('Content-Type', 'text/plain')])
yield '' yield b''
self.site.application = two_posthook_app self.site.application = two_posthook_app
sock = eventlet.connect(('localhost', self.port)) 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.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
fp.flush() 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() fp.close()
sock.close() sock.close()
self.assertEqual(posthook1_count[0], 26) self.assertEqual(posthook1_count[0], 26)
@@ -1034,7 +1043,7 @@ class TestHttpd(_TestBase):
sock = eventlet.connect(('localhost', self.port)) sock = eventlet.connect(('localhost', self.port))
request = 'GET / HTTP/1.0\r\nHost: localhost\r\nLong: %s\r\n\r\n' % \ request = 'GET / HTTP/1.0\r\nHost: localhost\r\nLong: %s\r\n\r\n' % \
('a' * 10000) ('a' * 10000)
fd = sock.makefile('rw') fd = sock.makefile('rwb')
fd.write(request.encode()) fd.write(request.encode())
fd.flush() fd.flush()
result = read_http(sock) result = read_http(sock)
@@ -1065,7 +1074,7 @@ class TestHttpd(_TestBase):
yield chunk yield chunk
self.site.application = echo_by_iterating self.site.application = echo_by_iterating
upload_data = '123456789abcdef' * 100 upload_data = b'123456789abcdef' * 100
request = ( request = (
'POST / HTTP/1.0\r\n' 'POST / HTTP/1.0\r\n'
'Host: localhost\r\n' 'Host: localhost\r\n'
@@ -1089,20 +1098,20 @@ class TestHttpd(_TestBase):
sock = eventlet.connect( sock = eventlet.connect(
('localhost', self.port)) ('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.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
fd.flush() fd.flush()
response = fd.read().split('\r\n') response = fd.read().split(b'\r\n')
headers = [] headers = []
while True: while True:
h = response.pop(0) h = response.pop(0)
headers.append(h) headers.append(h)
if h == '': if h == '':
break 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 # should only be one chunk of zero size with two blank lines
# (one terminates the chunk, one terminates the body) # (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): def test_configurable_url_length_limit(self):
self.spawn_server(url_length_limit=20000) self.spawn_server(url_length_limit=20000)
@@ -1110,15 +1119,15 @@ class TestHttpd(_TestBase):
('localhost', self.port)) ('localhost', self.port))
path = 'x' * 15000 path = 'x' * 15000
request = 'GET /%s HTTP/1.0\r\nHost: localhost\r\n\r\n' % path request = 'GET /%s HTTP/1.0\r\nHost: localhost\r\n\r\n' % path
fd = sock.makefile('rw') fd = sock.makefile('rwb')
fd.write(request) fd.write(request.encode())
fd.flush() fd.flush()
result = fd.readline() result = fd.readline()
if result: if result:
# windows closes the socket before the data is flushed, # windows closes the socket before the data is flushed,
# so we never get anything back # so we never get anything back
status = result.split(' ')[1] status = result.split(b' ')[1]
self.assertEqual(status, '200') self.assertEqual(status, b'200')
fd.close() fd.close()
def test_aborted_chunked_post(self): def test_aborted_chunked_post(self):
@@ -1130,7 +1139,7 @@ class TestHttpd(_TestBase):
content = env['wsgi.input'].read(1024) content = env['wsgi.input'].read(1024)
except IOError: except IOError:
blew_up[0] = True blew_up[0] = True
content = 'ok' content = b'ok'
read_content.send(content) read_content.send(content)
start_response('200 OK', [('Content-Type', 'text/plain')]) start_response('200 OK', [('Content-Type', 'text/plain')])
return [content] return [content]
@@ -1147,7 +1156,7 @@ class TestHttpd(_TestBase):
sock.close() sock.close()
# the test passes if we successfully get here, and read all the data # the test passes if we successfully get here, and read all the data
# in spite of the early close # in spite of the early close
self.assertEqual(read_content.wait(), 'ok') self.assertEqual(read_content.wait(), b'ok')
assert blew_up[0] assert blew_up[0]
def test_exceptions_close_connection(self): def test_exceptions_close_connection(self):
@@ -1155,7 +1164,7 @@ class TestHttpd(_TestBase):
raise RuntimeError("intentional error") raise RuntimeError("intentional error")
self.site.application = wsgi_app self.site.application = wsgi_app
sock = eventlet.connect(('localhost', self.port)) 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.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
fd.flush() fd.flush()
result = read_http(sock) result = read_http(sock)
@@ -1170,13 +1179,13 @@ class TestHttpd(_TestBase):
yield u"non-encodable unicode: \u0230" yield u"non-encodable unicode: \u0230"
self.site.application = wsgi_app self.site.application = wsgi_app
sock = eventlet.connect(('localhost', self.port)) 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.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
fd.flush() fd.flush()
result = read_http(sock) result = read_http(sock)
self.assertEqual(result.status, 'HTTP/1.1 500 Internal Server Error') self.assertEqual(result.status, 'HTTP/1.1 500 Internal Server Error')
self.assertEqual(result.headers_lower['connection'], 'close') 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 test_path_info_decoding(self):
def wsgi_app(environ, start_response): def wsgi_app(environ, start_response):
@@ -1185,13 +1194,13 @@ class TestHttpd(_TestBase):
yield "raw: %s" % environ['RAW_PATH_INFO'] yield "raw: %s" % environ['RAW_PATH_INFO']
self.site.application = wsgi_app self.site.application = wsgi_app
sock = eventlet.connect(('localhost', self.port)) 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.write(b'GET /a*b@%40%233 HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
fd.flush() fd.flush()
result = read_http(sock) result = read_http(sock)
self.assertEqual(result.status, 'HTTP/1.1 200 OK') self.assertEqual(result.status, 'HTTP/1.1 200 OK')
assert 'decoded: /a*b@@#3' in result.body assert b'decoded: /a*b@@#3' in result.body
assert 'raw: /a*b@%40%233' in result.body assert b'raw: /a*b@%40%233' in result.body
def test_ipv6(self): def test_ipv6(self):
try: try:
@@ -1224,12 +1233,12 @@ class TestHttpd(_TestBase):
self.site.application = crasher self.site.application = crasher
sock = eventlet.connect(('localhost', self.port)) 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.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
fd.flush() fd.flush()
result1 = read_http(sock) result1 = read_http(sock)
self.assertEqual(result1.status, 'HTTP/1.1 500 Internal Server Error') 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') self.assertEqual(result1.headers_lower['connection'], 'close')
assert 'transfer-encoding' not in result1.headers_lower assert 'transfer-encoding' not in result1.headers_lower
@@ -1237,14 +1246,14 @@ class TestHttpd(_TestBase):
self.spawn_server(debug=True) self.spawn_server(debug=True)
self.site.application = crasher self.site.application = crasher
sock = eventlet.connect(('localhost', self.port)) 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.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
fd.flush() fd.flush()
result2 = read_http(sock) result2 = read_http(sock)
self.assertEqual(result2.status, 'HTTP/1.1 500 Internal Server Error') self.assertEqual(result2.status, 'HTTP/1.1 500 Internal Server Error')
assert 'intentional crash' in result2.body assert b'intentional crash' in result2.body, result2.body
assert 'RuntimeError' in result2.body assert b'RuntimeError' in result2.body, result2.body
assert 'Traceback' in result2.body assert b'Traceback' in result2.body, result2.body
self.assertEqual(result2.headers_lower['connection'], 'close') self.assertEqual(result2.headers_lower['connection'], 'close')
assert 'transfer-encoding' not in result2.headers_lower assert 'transfer-encoding' not in result2.headers_lower
@@ -1253,7 +1262,7 @@ class TestHttpd(_TestBase):
""" """
def long_response(environ, start_response): def long_response(environ, start_response):
start_response('200 OK', [('Content-Length', '9876')]) start_response('200 OK', [('Content-Length', '9876')])
yield 'a' * 9876 yield b'a' * 9876
server_sock = eventlet.listen(('localhost', 0)) server_sock = eventlet.listen(('localhost', 0))
self.port = server_sock.getsockname()[1] self.port = server_sock.getsockname()[1]
@@ -1366,7 +1375,7 @@ class IterableAlreadyHandledTest(_TestBase):
sock = eventlet.connect( sock = eventlet.connect(
('localhost', self.port)) ('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.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
fd.flush() fd.flush()
@@ -1378,7 +1387,7 @@ class IterableAlreadyHandledTest(_TestBase):
result = read_http(sock) result = read_http(sock)
self.assertEqual(result.status, 'HTTP/1.1 200 OK') self.assertEqual(result.status, 'HTTP/1.1 200 OK')
self.assertEqual(result.headers_lower.get('transfer-encoding'), 'chunked') 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): class ProxiedIterableAlreadyHandledTest(IterableAlreadyHandledTest):
@@ -1418,13 +1427,13 @@ class TestChunkedInput(_TestBase):
self.yield_next_space = False self.yield_next_space = False
def response_iter(): def response_iter():
yield ' ' yield b' '
num_sleeps = 0 num_sleeps = 0
while not self.yield_next_space and num_sleeps < 200: while not self.yield_next_space and num_sleeps < 200:
eventlet.sleep(.01) eventlet.sleep(.01)
num_sleeps += 1 num_sleeps += 1
yield ' ' yield b' '
start_response('200 OK', start_response('200 OK',
[('Content-Type', 'text/plain'), [('Content-Type', 'text/plain'),
@@ -1467,7 +1476,7 @@ class TestChunkedInput(_TestBase):
fd = self.connect() fd = self.connect()
fd.sendall(req.encode()) 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) self.ping(fd)
fd.close() fd.close()
@@ -1478,7 +1487,7 @@ class TestChunkedInput(_TestBase):
"Content-Length:0\r\n\r\n" + body "Content-Length:0\r\n\r\n" + body
fd = self.connect() fd = self.connect()
fd.sendall(req.encode()) 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) self.ping(fd)
fd.close() fd.close()
@@ -1489,7 +1498,7 @@ class TestChunkedInput(_TestBase):
fd = self.connect() fd = self.connect()
fd.sendall(req.encode()) 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) self.ping(fd)
fd.close() fd.close()
@@ -1500,7 +1509,7 @@ class TestChunkedInput(_TestBase):
fd = self.connect() fd = self.connect()
fd.sendall(req.encode()) fd.sendall(req.encode())
self.assertEqual(read_http(fd).body, "pong") self.assertEqual(read_http(fd).body, b"pong")
self.ping(fd) self.ping(fd)
fd.close() fd.close()
@@ -1512,7 +1521,7 @@ class TestChunkedInput(_TestBase):
fd = self.connect() fd = self.connect()
fd.sendall(req.encode()) 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() fd.close()
def test_chunked_readline_wsgi_override_minimum_chunk_size(self): def test_chunked_readline_wsgi_override_minimum_chunk_size(self):
@@ -1527,7 +1536,7 @@ class TestChunkedInput(_TestBase):
resp_so_far += one_byte resp_so_far += one_byte
if resp_so_far.endswith('\r\n\r\n'): if resp_so_far.endswith('\r\n\r\n'):
break break
self.assertEqual(fd.recv(1), ' ') self.assertEqual(fd.recv(1), b' ')
try: try:
with eventlet.Timeout(.1): with eventlet.Timeout(.1):
fd.recv(1) fd.recv(1)
@@ -1538,22 +1547,22 @@ class TestChunkedInput(_TestBase):
self.yield_next_space = True self.yield_next_space = True
with eventlet.Timeout(.1): 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): def test_chunked_readline_wsgi_not_override_minimum_chunk_size(self):
fd = self.connect() fd = self.connect()
fd.sendall(b"POST /yield_spaces HTTP/1.1\r\nContent-Length: 0\r\n\r\n") 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: try:
with eventlet.Timeout(.1): with eventlet.Timeout(.1):
while True: while True:
one_byte = fd.recv(1) one_byte = fd.recv(1)
resp_so_far += one_byte 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 break
self.assertEqual(fd.recv(1), ' ') self.assertEqual(fd.recv(1), b' ')
except eventlet.Timeout: except eventlet.Timeout:
pass pass
else: else:

View File

@@ -136,7 +136,7 @@ if __name__ == '__main__':
# req #1 - normal # req #1 - normal
sock1 = eventlet.connect(server_addr) sock1 = eventlet.connect(server_addr)
sock1.settimeout(0.1) 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.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
fd1.flush() fd1.flush()
tests.wsgi_test.read_http(sock1) tests.wsgi_test.read_http(sock1)