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:
1
NEWS
1
NEWS
@@ -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
|
||||||
======
|
======
|
||||||
|
@@ -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)
|
||||||
|
@@ -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()
|
||||||
|
|
||||||
|
@@ -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):
|
||||||
|
@@ -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:
|
||||||
|
@@ -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.
|
||||||
|
@@ -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:
|
||||||
|
@@ -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()
|
||||||
|
@@ -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))
|
||||||
|
@@ -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
|
||||||
|
|
||||||
|
@@ -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)
|
||||||
|
@@ -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))
|
||||||
|
@@ -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))
|
||||||
"""
|
"""
|
||||||
|
@@ -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]
|
||||||
|
@@ -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:
|
||||||
|
@@ -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)
|
||||||
|
Reference in New Issue
Block a user