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
* improved Python 3 compatibility
0.15.2
======

View File

@@ -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)

View File

@@ -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
if six.PY2:
# On Python 2 SSLSocket constructor queries the timeout, it'd break without
# this assignment
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 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._sslobj = sslwrap(self._sock, server_side, self.keyfile, self.certfile,
self.cert_reqs, self.ssl_version,
self.ca_certs)
self.ca_certs, *([self.ciphers] if has_ciphers else []))
if self.do_handshake_on_connect:
self.do_handshake()

View File

@@ -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,9 +284,13 @@ class GreenSocket(object):
newsock.settimeout(self.gettimeout())
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()
res = _fileobject(dupped, *args, **kw)
res = _fileobject(dupped, *args, **kwargs)
if hasattr(dupped, "_drop"):
dupped._drop()
return res
@@ -457,10 +470,11 @@ 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)
else:
trampoline(self, write=True)
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))
__all__ = ["WebSocketWSGI", "WebSocket"]
PROTOCOL_GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
VALID_CLOSE_STATUS = (range(1000, 1004)
+ range(1007, 1012)
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
+ range(3000, 4000)
list(range(3000, 4000)) +
# 4000-4999: reserved for private use and thus can't
# be registered
+ range(4000, 5000))
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:

View File

@@ -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.

View File

@@ -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:

View File

@@ -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()

View File

@@ -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))

View File

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

View File

@@ -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)

View File

@@ -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))

View File

@@ -3,11 +3,15 @@ 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
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")
with open(filename, "w") as fd:
fd.write(contents)
fd.close()
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,6 +106,9 @@ class MonkeyPatch(ProcessBase):
from eventlet import patcher
patcher.monkey_patch()
import socket
try:
import urllib.request as urllib
except ImportError:
import urllib
print("newmod {0} {1}".format(socket.socket, urllib.socket.socket))
"""

View File

@@ -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]

View File

@@ -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:

View File

@@ -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)