Removed Green_fileobject and moved its contents to GreenPipe. Removed higher_order_send and higher_order_recv, integrating their contents with the appropriate methods on GreenSocket and GreenPipe. Fixed up callsites that were depending on various aspects of Green_fileobject's behavior. Added a backdoor unit test.
This commit is contained in:
@@ -3,7 +3,7 @@ import sys
|
|||||||
import errno
|
import errno
|
||||||
from code import InteractiveConsole
|
from code import InteractiveConsole
|
||||||
|
|
||||||
from eventlet import api
|
from eventlet import api, hubs
|
||||||
from eventlet.support import greenlets
|
from eventlet.support import greenlets
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -16,25 +16,34 @@ except AttributeError:
|
|||||||
sys.ps2 = '... '
|
sys.ps2 = '... '
|
||||||
|
|
||||||
|
|
||||||
|
class FileProxy(object):
|
||||||
|
def __init__(self, f):
|
||||||
|
self.f = f
|
||||||
|
def writeflush(*a, **kw):
|
||||||
|
f.write(*a, **kw)
|
||||||
|
f.flush()
|
||||||
|
self.fixups = {
|
||||||
|
'softspace': 0,
|
||||||
|
'isatty': lambda: True,
|
||||||
|
'flush': lambda: None,
|
||||||
|
'write': writeflush,
|
||||||
|
'readline': lambda *a: f.readline(*a).replace('\r\n', '\n'),
|
||||||
|
}
|
||||||
|
|
||||||
|
def __getattr__(self, attr):
|
||||||
|
fixups = object.__getattribute__(self, 'fixups')
|
||||||
|
if attr in fixups:
|
||||||
|
return fixups[attr]
|
||||||
|
f = object.__getattribute__(self, 'f')
|
||||||
|
return getattr(f, attr)
|
||||||
|
|
||||||
|
|
||||||
class SocketConsole(greenlets.greenlet):
|
class SocketConsole(greenlets.greenlet):
|
||||||
def __init__(self, desc, hostport, locals):
|
def __init__(self, desc, hostport, locals):
|
||||||
self.hostport = hostport
|
self.hostport = hostport
|
||||||
self.locals = locals
|
self.locals = locals
|
||||||
# mangle the socket
|
# mangle the socket
|
||||||
self.desc = desc
|
self.desc = FileProxy(desc)
|
||||||
readline = desc.readline
|
|
||||||
self.old = {}
|
|
||||||
self.fixups = {
|
|
||||||
'softspace': 0,
|
|
||||||
'isatty': lambda: True,
|
|
||||||
'flush': lambda: None,
|
|
||||||
'readline': lambda *a: readline(*a).replace('\r\n', '\n'),
|
|
||||||
}
|
|
||||||
for key, value in self.fixups.iteritems():
|
|
||||||
if hasattr(desc, key):
|
|
||||||
self.old[key] = getattr(desc, key)
|
|
||||||
setattr(desc, key, value)
|
|
||||||
|
|
||||||
greenlets.greenlet.__init__(self)
|
greenlets.greenlet.__init__(self)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
@@ -55,15 +64,6 @@ class SocketConsole(greenlets.greenlet):
|
|||||||
|
|
||||||
def finalize(self):
|
def finalize(self):
|
||||||
# restore the state of the socket
|
# restore the state of the socket
|
||||||
for key in self.fixups:
|
|
||||||
try:
|
|
||||||
value = self.old[key]
|
|
||||||
except KeyError:
|
|
||||||
delattr(self.desc, key)
|
|
||||||
else:
|
|
||||||
setattr(self.desc, key, value)
|
|
||||||
self.fixups.clear()
|
|
||||||
self.old.clear()
|
|
||||||
self.desc = None
|
self.desc = None
|
||||||
print "backdoor closed to %s:%s" % self.hostport
|
print "backdoor closed to %s:%s" % self.hostport
|
||||||
|
|
||||||
@@ -73,18 +73,18 @@ def backdoor_server(sock, locals=None):
|
|||||||
accepting connections and running backdoor consoles for each client that
|
accepting connections and running backdoor consoles for each client that
|
||||||
connects.
|
connects.
|
||||||
"""
|
"""
|
||||||
print "backdoor server listening on %s:%s" % server.getsockname()
|
print "backdoor server listening on %s:%s" % sock.getsockname()
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
socketpair = server.accept()
|
socketpair = sock.accept()
|
||||||
backdoor(socketpair, locals)
|
backdoor(socketpair, locals)
|
||||||
except socket.error, e:
|
except socket.error, e:
|
||||||
# Broken pipe means it was shutdown
|
# Broken pipe means it was shutdown
|
||||||
if e[0] != errno.EPIPE:
|
if e[0] != errno.EPIPE:
|
||||||
raise
|
raise
|
||||||
finally:
|
finally:
|
||||||
server.close()
|
sock.close()
|
||||||
|
|
||||||
|
|
||||||
def backdoor((conn, addr), locals=None):
|
def backdoor((conn, addr), locals=None):
|
||||||
@@ -95,8 +95,7 @@ def backdoor((conn, addr), locals=None):
|
|||||||
"""
|
"""
|
||||||
host, port = addr
|
host, port = addr
|
||||||
print "backdoor to %s:%s" % (host, port)
|
print "backdoor to %s:%s" % (host, port)
|
||||||
fl = conn.makeGreenFile("rw")
|
fl = conn.makefile("rw")
|
||||||
fl.newlines = '\n'
|
|
||||||
console = SocketConsole(fl, (host, port), locals)
|
console = SocketConsole(fl, (host, port), locals)
|
||||||
hub = hubs.get_hub()
|
hub = hubs.get_hub()
|
||||||
hub.schedule_call_global(0, console.switch)
|
hub.schedule_call_global(0, console.switch)
|
||||||
|
@@ -15,56 +15,11 @@ import warnings
|
|||||||
from errno import EWOULDBLOCK, EAGAIN
|
from errno import EWOULDBLOCK, EAGAIN
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['GreenSocket', 'GreenPipe']
|
__all__ = ['GreenSocket', 'GreenPipe', 'shutdown_safe']
|
||||||
|
|
||||||
def higher_order_recv(recv_func):
|
CONNECT_ERR = set((errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK))
|
||||||
def recv(self, buflen, flags=0):
|
CONNECT_SUCCESS = set((0, errno.EISCONN))
|
||||||
if self.act_non_blocking:
|
|
||||||
return self.fd.recv(buflen, flags)
|
|
||||||
buf = self.recvbuffer
|
|
||||||
if buf:
|
|
||||||
chunk, self.recvbuffer = buf[:buflen], buf[buflen:]
|
|
||||||
return chunk
|
|
||||||
fd = self.fd
|
|
||||||
bytes = recv_func(fd, buflen, flags)
|
|
||||||
if self.gettimeout():
|
|
||||||
end = time.time()+self.gettimeout()
|
|
||||||
else:
|
|
||||||
end = None
|
|
||||||
timeout = None
|
|
||||||
while bytes is None:
|
|
||||||
try:
|
|
||||||
if end:
|
|
||||||
timeout = end - time.time()
|
|
||||||
trampoline(fd, read=True, timeout=timeout, timeout_exc=socket.timeout)
|
|
||||||
except socket.timeout:
|
|
||||||
raise
|
|
||||||
except socket.error, e:
|
|
||||||
if e[0] == errno.EPIPE:
|
|
||||||
bytes = ''
|
|
||||||
else:
|
|
||||||
raise
|
|
||||||
else:
|
|
||||||
bytes = recv_func(fd, buflen, flags)
|
|
||||||
self.recvcount += len(bytes)
|
|
||||||
return bytes
|
|
||||||
return recv
|
|
||||||
|
|
||||||
|
|
||||||
def higher_order_send(send_func):
|
|
||||||
def send(self, data, flags=0):
|
|
||||||
if self.act_non_blocking:
|
|
||||||
return self.fd.send(data, flags)
|
|
||||||
count = send_func(self.fd, data, flags)
|
|
||||||
if not count:
|
|
||||||
return 0
|
|
||||||
self.sendcount += count
|
|
||||||
return count
|
|
||||||
return send
|
|
||||||
|
|
||||||
|
|
||||||
CONNECT_ERR = (errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK)
|
|
||||||
CONNECT_SUCCESS = (0, errno.EISCONN)
|
|
||||||
def socket_connect(descriptor, address):
|
def socket_connect(descriptor, address):
|
||||||
err = descriptor.connect_ex(address)
|
err = descriptor.connect_ex(address)
|
||||||
if err in CONNECT_ERR:
|
if err in CONNECT_ERR:
|
||||||
@@ -83,60 +38,15 @@ def socket_accept(descriptor):
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
def socket_send(descriptor, data, flags=0):
|
|
||||||
try:
|
|
||||||
return descriptor.send(data, flags)
|
|
||||||
except socket.error, e:
|
|
||||||
if e[0] == errno.EWOULDBLOCK or e[0] == errno.ENOTCONN:
|
|
||||||
return 0
|
|
||||||
raise
|
|
||||||
|
|
||||||
if sys.platform[:3]=="win":
|
if sys.platform[:3]=="win":
|
||||||
# winsock sometimes throws ENOTCONN
|
# winsock sometimes throws ENOTCONN
|
||||||
SOCKET_BLOCKING = (errno.EWOULDBLOCK,)
|
SOCKET_BLOCKING = set((errno.EWOULDBLOCK,))
|
||||||
SOCKET_CLOSED = (errno.ECONNRESET, errno.ENOTCONN, errno.ESHUTDOWN)
|
SOCKET_CLOSED = set((errno.ECONNRESET, errno.ENOTCONN, errno.ESHUTDOWN))
|
||||||
else:
|
else:
|
||||||
# oddly, on linux/darwin, an unconnected socket is expected to block,
|
# oddly, on linux/darwin, an unconnected socket is expected to block,
|
||||||
# so we treat ENOTCONN the same as EWOULDBLOCK
|
# so we treat ENOTCONN the same as EWOULDBLOCK
|
||||||
SOCKET_BLOCKING = (errno.EWOULDBLOCK, errno.ENOTCONN)
|
SOCKET_BLOCKING = set((errno.EWOULDBLOCK, errno.ENOTCONN))
|
||||||
SOCKET_CLOSED = (errno.ECONNRESET, errno.ESHUTDOWN)
|
SOCKET_CLOSED = set((errno.ECONNRESET, errno.ESHUTDOWN, errno.EPIPE))
|
||||||
def socket_recv(descriptor, buflen, flags=0):
|
|
||||||
try:
|
|
||||||
return descriptor.recv(buflen, flags)
|
|
||||||
except socket.error, e:
|
|
||||||
if e[0] in SOCKET_BLOCKING:
|
|
||||||
return None
|
|
||||||
if e[0] in SOCKET_CLOSED:
|
|
||||||
return ''
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
def file_recv(fd, buflen, flags=0):
|
|
||||||
try:
|
|
||||||
return fd.read(buflen)
|
|
||||||
except IOError, e:
|
|
||||||
if e[0] == EAGAIN:
|
|
||||||
return None
|
|
||||||
return ''
|
|
||||||
except socket.error, e:
|
|
||||||
if e[0] == errno.EPIPE:
|
|
||||||
return ''
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
def file_send(fd, data, flags=0):
|
|
||||||
try:
|
|
||||||
fd.write(data)
|
|
||||||
fd.flush()
|
|
||||||
return len(data)
|
|
||||||
except IOError, e:
|
|
||||||
if e[0] == EAGAIN:
|
|
||||||
return 0
|
|
||||||
except ValueError, e:
|
|
||||||
written = 0
|
|
||||||
except socket.error, e:
|
|
||||||
if e[0] == errno.EPIPE:
|
|
||||||
written = 0
|
|
||||||
|
|
||||||
|
|
||||||
def set_nonblocking(fd):
|
def set_nonblocking(fd):
|
||||||
@@ -176,9 +86,6 @@ class GreenSocket(object):
|
|||||||
set_nonblocking(fd)
|
set_nonblocking(fd)
|
||||||
self.fd = fd
|
self.fd = fd
|
||||||
self._fileno = fd.fileno()
|
self._fileno = fd.fileno()
|
||||||
self.sendcount = 0
|
|
||||||
self.recvcount = 0
|
|
||||||
self.recvbuffer = ''
|
|
||||||
self.closed = False
|
self.closed = False
|
||||||
self.timeout = socket.getdefaulttimeout()
|
self.timeout = socket.getdefaulttimeout()
|
||||||
|
|
||||||
@@ -303,9 +210,28 @@ class GreenSocket(object):
|
|||||||
return socket._fileobject(self.dup(), mode, bufsize)
|
return socket._fileobject(self.dup(), mode, bufsize)
|
||||||
|
|
||||||
def makeGreenFile(self, mode='r', bufsize=-1):
|
def makeGreenFile(self, mode='r', bufsize=-1):
|
||||||
return Green_fileobject(self.dup())
|
warnings.warn("makeGreenFile has been deprecated, please use "
|
||||||
|
"makefile instead", DeprecationWarning, stacklevel=2)
|
||||||
|
return self.makefile(mode, bufsize)
|
||||||
|
|
||||||
recv = higher_order_recv(socket_recv)
|
def recv(self, buflen, flags=0):
|
||||||
|
fd = self.fd
|
||||||
|
if self.act_non_blocking:
|
||||||
|
return fd.recv(buflen, flags)
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
return fd.recv(buflen, flags)
|
||||||
|
except socket.error, e:
|
||||||
|
if e[0] in SOCKET_BLOCKING:
|
||||||
|
pass
|
||||||
|
elif e[0] in SOCKET_CLOSED:
|
||||||
|
return ''
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
trampoline(fd,
|
||||||
|
read=True,
|
||||||
|
timeout=self.gettimeout(),
|
||||||
|
timeout_exc=socket.timeout)
|
||||||
|
|
||||||
def recvfrom(self, *args):
|
def recvfrom(self, *args):
|
||||||
if not self.act_non_blocking:
|
if not self.act_non_blocking:
|
||||||
@@ -322,13 +248,25 @@ class GreenSocket(object):
|
|||||||
trampoline(self.fd, read=True, timeout=self.gettimeout(), timeout_exc=socket.timeout)
|
trampoline(self.fd, read=True, timeout=self.gettimeout(), timeout_exc=socket.timeout)
|
||||||
return self.fd.recv_into(*args)
|
return self.fd.recv_into(*args)
|
||||||
|
|
||||||
send = higher_order_send(socket_send)
|
def send(self, data, flags=0):
|
||||||
|
fd = self.fd
|
||||||
|
if self.act_non_blocking:
|
||||||
|
return fd.send(data, flags)
|
||||||
|
try:
|
||||||
|
return fd.send(data, flags)
|
||||||
|
except socket.error, e:
|
||||||
|
if e[0] in SOCKET_BLOCKING:
|
||||||
|
return 0
|
||||||
|
raise
|
||||||
|
|
||||||
def sendall(self, data, flags=0):
|
def sendall(self, data, flags=0):
|
||||||
fd = self.fd
|
fd = self.fd
|
||||||
tail = self.send(data, flags)
|
tail = self.send(data, flags)
|
||||||
while tail < len(data):
|
while tail < len(data):
|
||||||
trampoline(self.fd, write=True, timeout_exc=socket.timeout)
|
trampoline(fd,
|
||||||
|
write=True,
|
||||||
|
timeout=self.gettimeout(),
|
||||||
|
timeout_exc=socket.timeout)
|
||||||
tail += self.send(data[tail:], flags)
|
tail += self.send(data[tail:], flags)
|
||||||
|
|
||||||
def sendto(self, *args):
|
def sendto(self, *args):
|
||||||
@@ -371,47 +309,78 @@ class GreenSocket(object):
|
|||||||
return self.timeout
|
return self.timeout
|
||||||
|
|
||||||
|
|
||||||
class Green_fileobject(object):
|
class GreenPipe(object):
|
||||||
"""Green version of socket._fileobject, for use only with regular
|
|
||||||
sockets."""
|
|
||||||
newlines = '\r\n'
|
newlines = '\r\n'
|
||||||
mode = 'wb+'
|
|
||||||
|
|
||||||
def __init__(self, fd):
|
def __init__(self, fd):
|
||||||
if isinstance(fd, GreenSocket):
|
set_nonblocking(fd)
|
||||||
set_nonblocking(fd.fd)
|
self.fd = fd
|
||||||
else:
|
|
||||||
set_nonblocking(fd)
|
|
||||||
self.sock = fd
|
|
||||||
self.closed = False
|
self.closed = False
|
||||||
|
self.recvbuffer = ''
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self.sock.close()
|
self.fd.close()
|
||||||
self.closed = True
|
self.closed = True
|
||||||
|
|
||||||
def fileno(self):
|
def fileno(self):
|
||||||
return self.sock.fileno()
|
return self.fd.fileno()
|
||||||
|
|
||||||
# TODO next
|
def read(self, buflen, flags=0):
|
||||||
|
fd = self.fd
|
||||||
|
if buflen is None:
|
||||||
|
buflen = BUFFER_SIZE
|
||||||
|
buf = self.recvbuffer
|
||||||
|
if buf:
|
||||||
|
chunk, self.recvbuffer = buf[:buflen], buf[buflen:]
|
||||||
|
return chunk
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
return fd.read(buflen)
|
||||||
|
except IOError, e:
|
||||||
|
if e[0] != EAGAIN:
|
||||||
|
return ''
|
||||||
|
except socket.error, e:
|
||||||
|
if e[0] == errno.EPIPE:
|
||||||
|
return ''
|
||||||
|
raise
|
||||||
|
trampoline(fd, read=True)
|
||||||
|
|
||||||
|
def write(self, data, flags=0):
|
||||||
|
fd = self.fd
|
||||||
|
tail = 0
|
||||||
|
len_data = len(data)
|
||||||
|
while tail < len_data:
|
||||||
|
tosend = data[tail:]
|
||||||
|
try:
|
||||||
|
fd.write(tosend)
|
||||||
|
fd.flush()
|
||||||
|
tail += len(tosend)
|
||||||
|
if tail == len_data:
|
||||||
|
return len_data
|
||||||
|
except IOError, e:
|
||||||
|
if e[0] != EAGAIN:
|
||||||
|
raise
|
||||||
|
except ValueError, e:
|
||||||
|
pass
|
||||||
|
except socket.error, e:
|
||||||
|
if e[0] != errno.EPIPE:
|
||||||
|
raise
|
||||||
|
trampoline(fd, write=True)
|
||||||
|
|
||||||
def flush(self):
|
def flush(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def write(self, data):
|
|
||||||
return self.sock.sendall(data)
|
|
||||||
|
|
||||||
def readuntil(self, terminator, size=None):
|
def readuntil(self, terminator, size=None):
|
||||||
buf, self.sock.recvbuffer = self.sock.recvbuffer, ''
|
buf, self.recvbuffer = self.recvbuffer, ''
|
||||||
checked = 0
|
checked = 0
|
||||||
if size is None:
|
if size is None:
|
||||||
while True:
|
while True:
|
||||||
found = buf.find(terminator, checked)
|
found = buf.find(terminator, checked)
|
||||||
if found != -1:
|
if found != -1:
|
||||||
found += len(terminator)
|
found += len(terminator)
|
||||||
chunk, self.sock.recvbuffer = buf[:found], buf[found:]
|
chunk, self.recvbuffer = buf[:found], buf[found:]
|
||||||
return chunk
|
return chunk
|
||||||
checked = max(0, len(buf) - (len(terminator) - 1))
|
checked = max(0, len(buf) - (len(terminator) - 1))
|
||||||
d = self.sock.recv(BUFFER_SIZE)
|
d = self.fd.read(BUFFER_SIZE)
|
||||||
if not d:
|
if not d:
|
||||||
break
|
break
|
||||||
buf += d
|
buf += d
|
||||||
@@ -420,14 +389,14 @@ class Green_fileobject(object):
|
|||||||
found = buf.find(terminator, checked)
|
found = buf.find(terminator, checked)
|
||||||
if found != -1:
|
if found != -1:
|
||||||
found += len(terminator)
|
found += len(terminator)
|
||||||
chunk, self.sock.recvbuffer = buf[:found], buf[found:]
|
chunk, self.recvbuffer = buf[:found], buf[found:]
|
||||||
return chunk
|
return chunk
|
||||||
checked = len(buf)
|
checked = len(buf)
|
||||||
d = self.sock.recv(BUFFER_SIZE)
|
d = self.fd.read(BUFFER_SIZE)
|
||||||
if not d:
|
if not d:
|
||||||
break
|
break
|
||||||
buf += d
|
buf += d
|
||||||
chunk, self.sock.recvbuffer = buf[:size], buf[size:]
|
chunk, self.recvbuffer = buf[:size], buf[size:]
|
||||||
return chunk
|
return chunk
|
||||||
|
|
||||||
def readline(self, size=None):
|
def readline(self, size=None):
|
||||||
@@ -436,9 +405,6 @@ class Green_fileobject(object):
|
|||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return self.xreadlines()
|
return self.xreadlines()
|
||||||
|
|
||||||
def readlines(self, size=None):
|
|
||||||
return list(self.xreadlines(size=size))
|
|
||||||
|
|
||||||
def xreadlines(self, size=None):
|
def xreadlines(self, size=None):
|
||||||
if size is None:
|
if size is None:
|
||||||
while True:
|
while True:
|
||||||
@@ -458,61 +424,6 @@ class Green_fileobject(object):
|
|||||||
for line in lines:
|
for line in lines:
|
||||||
self.write(line)
|
self.write(line)
|
||||||
|
|
||||||
def read(self, size=None):
|
|
||||||
if size is not None and not isinstance(size, (int, long)):
|
|
||||||
raise TypeError('Expecting an int or long for size, got %s: %s' % (type(size), repr(size)))
|
|
||||||
buf, self.sock.recvbuffer = self.sock.recvbuffer, ''
|
|
||||||
lst = [buf]
|
|
||||||
if size is None:
|
|
||||||
while True:
|
|
||||||
d = self.sock.recv(BUFFER_SIZE)
|
|
||||||
if not d:
|
|
||||||
break
|
|
||||||
lst.append(d)
|
|
||||||
else:
|
|
||||||
buflen = len(buf)
|
|
||||||
while buflen < size:
|
|
||||||
d = self.sock.recv(BUFFER_SIZE)
|
|
||||||
if not d:
|
|
||||||
break
|
|
||||||
buflen += len(d)
|
|
||||||
lst.append(d)
|
|
||||||
else:
|
|
||||||
d = lst[-1]
|
|
||||||
overbite = buflen - size
|
|
||||||
if overbite:
|
|
||||||
lst[-1], self.sock.recvbuffer = d[:-overbite], d[-overbite:]
|
|
||||||
else:
|
|
||||||
lst[-1], self.sock.recvbuffer = d, ''
|
|
||||||
return ''.join(lst)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class GreenPipeSocket(GreenSocket):
|
|
||||||
""" This is a weird class that looks like a socket but expects a file descriptor as an argument instead of a socket.
|
|
||||||
"""
|
|
||||||
recv = higher_order_recv(file_recv)
|
|
||||||
|
|
||||||
send = higher_order_send(file_send)
|
|
||||||
|
|
||||||
|
|
||||||
class GreenPipe(Green_fileobject):
|
|
||||||
def __init__(self, fd):
|
|
||||||
set_nonblocking(fd)
|
|
||||||
self.fd = GreenPipeSocket(fd)
|
|
||||||
super(GreenPipe, self).__init__(self.fd)
|
|
||||||
|
|
||||||
def recv(self, *args, **kw):
|
|
||||||
fn = self.recv = self.fd.recv
|
|
||||||
return fn(*args, **kw)
|
|
||||||
|
|
||||||
def send(self, *args, **kw):
|
|
||||||
fn = self.send = self.fd.send
|
|
||||||
return fn(*args, **kw)
|
|
||||||
|
|
||||||
def flush(self):
|
|
||||||
self.fd.fd.flush()
|
|
||||||
|
|
||||||
|
|
||||||
# import SSL module here so we can refer to greenio.SSL.exceptionclass
|
# import SSL module here so we can refer to greenio.SSL.exceptionclass
|
||||||
try:
|
try:
|
||||||
|
29
tests/backdoor_test.py
Normal file
29
tests/backdoor_test.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import eventlet
|
||||||
|
from eventlet import backdoor
|
||||||
|
from eventlet.green import socket
|
||||||
|
|
||||||
|
from tests import LimitedTestCase, main
|
||||||
|
|
||||||
|
class BackdoorTest(LimitedTestCase):
|
||||||
|
def test_server(self):
|
||||||
|
listener = socket.socket()
|
||||||
|
listener.bind(('localhost', 0))
|
||||||
|
listener.listen(50)
|
||||||
|
serv = eventlet.spawn(backdoor.backdoor_server, listener)
|
||||||
|
client = socket.socket()
|
||||||
|
client.connect(('localhost', listener.getsockname()[1]))
|
||||||
|
f = client.makefile()
|
||||||
|
self.assert_('Python' in f.readline())
|
||||||
|
f.readline() # build info
|
||||||
|
f.readline() # help info
|
||||||
|
self.assert_('InteractiveConsole' in f.readline())
|
||||||
|
self.assertEquals('>>> ', f.read(4))
|
||||||
|
f.write('print "hi"\n')
|
||||||
|
f.flush()
|
||||||
|
self.assertEquals('hi\n', f.readline())
|
||||||
|
self.assertEquals('>>> ', f.read(4))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
@@ -47,11 +47,15 @@ class TestGreenIo(LimitedTestCase):
|
|||||||
# by closing the socket prior to using the made file
|
# by closing the socket prior to using the made file
|
||||||
try:
|
try:
|
||||||
conn, addr = listener.accept()
|
conn, addr = listener.accept()
|
||||||
fd = conn.makeGreenFile()
|
fd = conn.makefile()
|
||||||
conn.close()
|
conn.close()
|
||||||
fd.write('hello\n')
|
fd.write('hello\n')
|
||||||
fd.close()
|
fd.close()
|
||||||
self.assertRaises(socket.error, fd.write, 'a')
|
# socket._fileobjects are odd: writes don't check
|
||||||
|
# whether the socket is closed or not, and you get an
|
||||||
|
# AttributeError during flush if it is closed
|
||||||
|
fd.write('a')
|
||||||
|
self.assertRaises(Exception, fd.flush)
|
||||||
self.assertRaises(socket.error, conn.send, 'b')
|
self.assertRaises(socket.error, conn.send, 'b')
|
||||||
finally:
|
finally:
|
||||||
listener.close()
|
listener.close()
|
||||||
@@ -61,19 +65,20 @@ class TestGreenIo(LimitedTestCase):
|
|||||||
# by closing the made file and then sending a character
|
# by closing the made file and then sending a character
|
||||||
try:
|
try:
|
||||||
conn, addr = listener.accept()
|
conn, addr = listener.accept()
|
||||||
fd = conn.makeGreenFile()
|
fd = conn.makefile()
|
||||||
fd.write('hello')
|
fd.write('hello')
|
||||||
fd.close()
|
fd.close()
|
||||||
conn.send('\n')
|
conn.send('\n')
|
||||||
conn.close()
|
conn.close()
|
||||||
self.assertRaises(socket.error, fd.write, 'a')
|
fd.write('a')
|
||||||
|
self.assertRaises(Exception, fd.flush)
|
||||||
self.assertRaises(socket.error, conn.send, 'b')
|
self.assertRaises(socket.error, conn.send, 'b')
|
||||||
finally:
|
finally:
|
||||||
listener.close()
|
listener.close()
|
||||||
|
|
||||||
def did_it_work(server):
|
def did_it_work(server):
|
||||||
client = api.connect_tcp(('127.0.0.1', server.getsockname()[1]))
|
client = api.connect_tcp(('127.0.0.1', server.getsockname()[1]))
|
||||||
fd = client.makeGreenFile()
|
fd = client.makefile()
|
||||||
client.close()
|
client.close()
|
||||||
assert fd.readline() == 'hello\n'
|
assert fd.readline() == 'hello\n'
|
||||||
assert fd.read() == ''
|
assert fd.read() == ''
|
||||||
@@ -96,16 +101,17 @@ class TestGreenIo(LimitedTestCase):
|
|||||||
# closing the file object should close everything
|
# closing the file object should close everything
|
||||||
try:
|
try:
|
||||||
conn, addr = listener.accept()
|
conn, addr = listener.accept()
|
||||||
conn = conn.makeGreenFile()
|
conn = conn.makefile()
|
||||||
conn.write('hello\n')
|
conn.write('hello\n')
|
||||||
conn.close()
|
conn.close()
|
||||||
self.assertRaises(socket.error, conn.write, 'a')
|
conn.write('a')
|
||||||
|
self.assertRaises(Exception, conn.flush)
|
||||||
finally:
|
finally:
|
||||||
listener.close()
|
listener.close()
|
||||||
server = api.tcp_listener(('0.0.0.0', 0))
|
server = api.tcp_listener(('0.0.0.0', 0))
|
||||||
killer = coros.execute(accept_once, server)
|
killer = coros.execute(accept_once, server)
|
||||||
client = api.connect_tcp(('127.0.0.1', server.getsockname()[1]))
|
client = api.connect_tcp(('127.0.0.1', server.getsockname()[1]))
|
||||||
fd = client.makeGreenFile()
|
fd = client.makefile()
|
||||||
client.close()
|
client.close()
|
||||||
assert fd.read() == 'hello\n'
|
assert fd.read() == 'hello\n'
|
||||||
assert fd.read() == ''
|
assert fd.read() == ''
|
||||||
|
@@ -83,7 +83,7 @@ class ConnectionClosed(Exception):
|
|||||||
|
|
||||||
|
|
||||||
def read_http(sock):
|
def read_http(sock):
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makefile()
|
||||||
try:
|
try:
|
||||||
response_line = fd.readline()
|
response_line = fd.readline()
|
||||||
except socket.error, exc:
|
except socket.error, exc:
|
||||||
@@ -92,11 +92,19 @@ def read_http(sock):
|
|||||||
raise
|
raise
|
||||||
if not response_line:
|
if not response_line:
|
||||||
raise ConnectionClosed
|
raise ConnectionClosed
|
||||||
raw_headers = fd.readuntil('\r\n\r\n').strip()
|
|
||||||
#print "R", response_line, raw_headers
|
header_lines = []
|
||||||
|
while True:
|
||||||
|
line = fd.readline()
|
||||||
|
if line == '\r\n':
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
header_lines.append(line)
|
||||||
headers = dict()
|
headers = dict()
|
||||||
for x in raw_headers.split('\r\n'):
|
for x in header_lines:
|
||||||
#print "X", x
|
x = x.strip()
|
||||||
|
if not x:
|
||||||
|
continue
|
||||||
key, value = x.split(': ', 1)
|
key, value = x.split(': ', 1)
|
||||||
headers[key.lower()] = value
|
headers[key.lower()] = value
|
||||||
|
|
||||||
@@ -134,8 +142,9 @@ class TestHttpd(LimitedTestCase):
|
|||||||
sock = api.connect_tcp(
|
sock = api.connect_tcp(
|
||||||
('localhost', self.port))
|
('localhost', self.port))
|
||||||
|
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makefile()
|
||||||
fd.write('GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
|
fd.write('GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
|
||||||
|
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
|
||||||
@@ -146,10 +155,12 @@ class TestHttpd(LimitedTestCase):
|
|||||||
sock = api.connect_tcp(
|
sock = api.connect_tcp(
|
||||||
('localhost', self.port))
|
('localhost', self.port))
|
||||||
|
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makefile()
|
||||||
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
||||||
|
fd.flush()
|
||||||
read_http(sock)
|
read_http(sock)
|
||||||
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
||||||
|
fd.flush()
|
||||||
read_http(sock)
|
read_http(sock)
|
||||||
fd.close()
|
fd.close()
|
||||||
|
|
||||||
@@ -158,8 +169,9 @@ class TestHttpd(LimitedTestCase):
|
|||||||
sock = api.connect_tcp(
|
sock = api.connect_tcp(
|
||||||
('localhost', self.port))
|
('localhost', self.port))
|
||||||
|
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makefile()
|
||||||
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
||||||
|
fd.flush()
|
||||||
cancel = api.exc_after(1, RuntimeError)
|
cancel = api.exc_after(1, RuntimeError)
|
||||||
self.assertRaises(TypeError, fd.read, "This shouldn't work")
|
self.assertRaises(TypeError, fd.read, "This shouldn't work")
|
||||||
cancel.cancel()
|
cancel.cancel()
|
||||||
@@ -169,12 +181,15 @@ class TestHttpd(LimitedTestCase):
|
|||||||
sock = api.connect_tcp(
|
sock = api.connect_tcp(
|
||||||
('localhost', self.port))
|
('localhost', self.port))
|
||||||
|
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makefile()
|
||||||
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
||||||
|
fd.flush()
|
||||||
read_http(sock)
|
read_http(sock)
|
||||||
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
|
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
|
||||||
|
fd.flush()
|
||||||
read_http(sock)
|
read_http(sock)
|
||||||
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
||||||
|
fd.flush()
|
||||||
self.assertRaises(ConnectionClosed, read_http, sock)
|
self.assertRaises(ConnectionClosed, read_http, sock)
|
||||||
fd.close()
|
fd.close()
|
||||||
|
|
||||||
@@ -194,8 +209,9 @@ class TestHttpd(LimitedTestCase):
|
|||||||
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
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makefile()
|
||||||
fd.write(request)
|
fd.write(request)
|
||||||
|
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,
|
||||||
@@ -220,8 +236,9 @@ class TestHttpd(LimitedTestCase):
|
|||||||
'Content-Length: 3',
|
'Content-Length: 3',
|
||||||
'',
|
'',
|
||||||
'a=a'))
|
'a=a'))
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makefile()
|
||||||
fd.write(request)
|
fd.write(request)
|
||||||
|
fd.flush()
|
||||||
|
|
||||||
# send some junk after the actual request
|
# send some junk after the actual request
|
||||||
fd.write('01234567890123456789')
|
fd.write('01234567890123456789')
|
||||||
@@ -233,12 +250,15 @@ class TestHttpd(LimitedTestCase):
|
|||||||
sock = api.connect_tcp(
|
sock = api.connect_tcp(
|
||||||
('localhost', self.port))
|
('localhost', self.port))
|
||||||
|
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makefile()
|
||||||
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
||||||
|
fd.flush()
|
||||||
response_line_200,_,_ = read_http(sock)
|
response_line_200,_,_ = read_http(sock)
|
||||||
fd.write('GET /notexist HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
fd.write('GET /notexist HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
||||||
|
fd.flush()
|
||||||
response_line_404,_,_ = read_http(sock)
|
response_line_404,_,_ = read_http(sock)
|
||||||
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
|
||||||
|
fd.flush()
|
||||||
response_line_test,_,_ = read_http(sock)
|
response_line_test,_,_ = read_http(sock)
|
||||||
self.assertEqual(response_line_200,response_line_test)
|
self.assertEqual(response_line_200,response_line_test)
|
||||||
fd.close()
|
fd.close()
|
||||||
@@ -248,8 +268,9 @@ class TestHttpd(LimitedTestCase):
|
|||||||
sock = api.connect_tcp(
|
sock = api.connect_tcp(
|
||||||
('localhost', self.port))
|
('localhost', self.port))
|
||||||
|
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makefile()
|
||||||
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
|
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
|
||||||
|
fd.flush()
|
||||||
self.assert_('Transfer-Encoding: chunked' in fd.read())
|
self.assert_('Transfer-Encoding: chunked' in fd.read())
|
||||||
|
|
||||||
def test_010_no_chunked_http_1_0(self):
|
def test_010_no_chunked_http_1_0(self):
|
||||||
@@ -257,8 +278,9 @@ class TestHttpd(LimitedTestCase):
|
|||||||
sock = api.connect_tcp(
|
sock = api.connect_tcp(
|
||||||
('localhost', self.port))
|
('localhost', self.port))
|
||||||
|
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makefile()
|
||||||
fd.write('GET / HTTP/1.0\r\nHost: localhost\r\nConnection: close\r\n\r\n')
|
fd.write('GET / HTTP/1.0\r\nHost: localhost\r\nConnection: close\r\n\r\n')
|
||||||
|
fd.flush()
|
||||||
self.assert_('Transfer-Encoding: chunked' not in fd.read())
|
self.assert_('Transfer-Encoding: chunked' not in fd.read())
|
||||||
|
|
||||||
def test_011_multiple_chunks(self):
|
def test_011_multiple_chunks(self):
|
||||||
@@ -266,9 +288,16 @@ class TestHttpd(LimitedTestCase):
|
|||||||
sock = api.connect_tcp(
|
sock = api.connect_tcp(
|
||||||
('localhost', self.port))
|
('localhost', self.port))
|
||||||
|
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makefile()
|
||||||
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
|
fd.write('GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
|
||||||
headers = fd.readuntil('\r\n\r\n')
|
fd.flush()
|
||||||
|
headers = ''
|
||||||
|
while True:
|
||||||
|
line = fd.readline()
|
||||||
|
if line == '\r\n':
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
headers += line
|
||||||
self.assert_('Transfer-Encoding: chunked' in headers)
|
self.assert_('Transfer-Encoding: chunked' in headers)
|
||||||
chunks = 0
|
chunks = 0
|
||||||
chunklen = int(fd.readline(), 16)
|
chunklen = int(fd.readline(), 16)
|
||||||
@@ -316,43 +345,54 @@ class TestHttpd(LimitedTestCase):
|
|||||||
def test_014_chunked_post(self):
|
def test_014_chunked_post(self):
|
||||||
self.site.application = chunked_post
|
self.site.application = chunked_post
|
||||||
sock = api.connect_tcp(('localhost', self.port))
|
sock = api.connect_tcp(('localhost', self.port))
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makefile()
|
||||||
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')
|
'2\r\noh\r\n4\r\n hai\r\n0\r\n\r\n')
|
||||||
fd.readuntil('\r\n\r\n')
|
fd.flush()
|
||||||
|
while True:
|
||||||
|
if fd.readline() == '\r\n':
|
||||||
|
break
|
||||||
response = fd.read()
|
response = fd.read()
|
||||||
self.assert_(response == 'oh hai', 'invalid response %s' % response)
|
self.assert_(response == 'oh hai', 'invalid response %s' % response)
|
||||||
|
|
||||||
sock = api.connect_tcp(('localhost', self.port))
|
sock = api.connect_tcp(('localhost', self.port))
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makefile()
|
||||||
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')
|
'2\r\noh\r\n4\r\n hai\r\n0\r\n\r\n')
|
||||||
fd.readuntil('\r\n\r\n')
|
fd.flush()
|
||||||
|
while True:
|
||||||
|
if fd.readline() == '\r\n':
|
||||||
|
break
|
||||||
response = fd.read()
|
response = fd.read()
|
||||||
self.assert_(response == 'oh hai', 'invalid response %s' % response)
|
self.assert_(response == 'oh hai', 'invalid response %s' % response)
|
||||||
|
|
||||||
sock = api.connect_tcp(('localhost', self.port))
|
sock = api.connect_tcp(('localhost', self.port))
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makefile()
|
||||||
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')
|
'2\r\noh\r\n4\r\n hai\r\n0\r\n\r\n')
|
||||||
fd.readuntil('\r\n\r\n')
|
fd.flush()
|
||||||
|
while True:
|
||||||
|
if fd.readline() == '\r\n':
|
||||||
|
break
|
||||||
response = fd.read(8192)
|
response = fd.read(8192)
|
||||||
self.assert_(response == 'oh hai', 'invalid response %s' % response)
|
self.assert_(response == '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 = api.connect_tcp(('localhost', self.port))
|
sock = api.connect_tcp(('localhost', self.port))
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makefile()
|
||||||
fd.write('GET /a HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
|
fd.write('GET /a HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
|
||||||
|
fd.flush()
|
||||||
response_line, headers, body = read_http(sock)
|
response_line, headers, body = read_http(sock)
|
||||||
self.assert_('content-length' in headers)
|
self.assert_('content-length' in headers)
|
||||||
|
|
||||||
sock = api.connect_tcp(('localhost', self.port))
|
sock = api.connect_tcp(('localhost', self.port))
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makefile()
|
||||||
fd.write('GET /b HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
|
fd.write('GET /b HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
|
||||||
|
fd.flush()
|
||||||
response_line, headers, body = read_http(sock)
|
response_line, headers, body = read_http(sock)
|
||||||
self.assert_('transfer-encoding' in headers)
|
self.assert_('transfer-encoding' in headers)
|
||||||
self.assert_(headers['transfer-encoding'] == 'chunked')
|
self.assert_(headers['transfer-encoding'] == 'chunked')
|
||||||
@@ -367,10 +407,17 @@ class TestHttpd(LimitedTestCase):
|
|||||||
return ['testing']
|
return ['testing']
|
||||||
self.site.application = wsgi_app
|
self.site.application = wsgi_app
|
||||||
sock = api.connect_tcp(('localhost', self.port))
|
sock = api.connect_tcp(('localhost', self.port))
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makefile()
|
||||||
fd.write('GET /a HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
|
fd.write('GET /a HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
|
||||||
headerlines = fd.readuntil('\r\n\r\n').splitlines()
|
fd.flush()
|
||||||
self.assertEquals(1, len([l for l in headerlines
|
header_lines = []
|
||||||
|
while True:
|
||||||
|
line = fd.readline()
|
||||||
|
if line == '\r\n':
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
header_lines.append(line)
|
||||||
|
self.assertEquals(1, len([l for l in header_lines
|
||||||
if l.lower().startswith('content-length')]))
|
if l.lower().startswith('content-length')]))
|
||||||
|
|
||||||
def test_017_ssl_zeroreturnerror(self):
|
def test_017_ssl_zeroreturnerror(self):
|
||||||
@@ -413,14 +460,19 @@ class TestHttpd(LimitedTestCase):
|
|||||||
sock = api.connect_tcp(
|
sock = api.connect_tcp(
|
||||||
('localhost', self.port))
|
('localhost', self.port))
|
||||||
|
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makefile()
|
||||||
fd.write('GET / HTTP/1.0\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n')
|
fd.write('GET / HTTP/1.0\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n')
|
||||||
self.assert_('connection: keep-alive' in
|
fd.flush()
|
||||||
fd.readuntil('\r\n\r\n').lower())
|
|
||||||
|
response_line, headers, body = read_http(sock)
|
||||||
|
self.assert_('connection' in headers)
|
||||||
|
self.assertEqual('keep-alive', headers['connection'])
|
||||||
# repeat request to verify connection is actually still open
|
# repeat request to verify connection is actually still open
|
||||||
fd.write('GET / HTTP/1.0\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n')
|
fd.write('GET / HTTP/1.0\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n')
|
||||||
self.assert_('connection: keep-alive' in
|
fd.flush()
|
||||||
fd.readuntil('\r\n\r\n').lower())
|
response_line, headers, body = read_http(sock)
|
||||||
|
self.assert_('connection' in headers)
|
||||||
|
self.assertEqual('keep-alive', headers['connection'])
|
||||||
|
|
||||||
def test_019_fieldstorage_compat(self):
|
def test_019_fieldstorage_compat(self):
|
||||||
def use_fieldstorage(environ, start_response):
|
def use_fieldstorage(environ, start_response):
|
||||||
@@ -434,13 +486,14 @@ class TestHttpd(LimitedTestCase):
|
|||||||
sock = api.connect_tcp(
|
sock = api.connect_tcp(
|
||||||
('localhost', self.port))
|
('localhost', self.port))
|
||||||
|
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makefile()
|
||||||
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'
|
||||||
'Transfer-Encoding: chunked\r\n\r\n'
|
'Transfer-Encoding: chunked\r\n\r\n'
|
||||||
'2\r\noh\r\n'
|
'2\r\noh\r\n'
|
||||||
'4\r\n hai\r\n0\r\n\r\n')
|
'4\r\n hai\r\n0\r\n\r\n')
|
||||||
|
fd.flush()
|
||||||
self.assert_('hello!' in fd.read())
|
self.assert_('hello!' in fd.read())
|
||||||
|
|
||||||
def test_020_x_forwarded_for(self):
|
def test_020_x_forwarded_for(self):
|
||||||
@@ -484,11 +537,12 @@ class TestHttpd(LimitedTestCase):
|
|||||||
return []
|
return []
|
||||||
self.site.application = clobberin_time
|
self.site.application = clobberin_time
|
||||||
sock = api.connect_tcp(('localhost', self.port))
|
sock = api.connect_tcp(('localhost', self.port))
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makefile()
|
||||||
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')
|
'\r\n\r\n')
|
||||||
|
fd.flush()
|
||||||
self.assert_('200 OK' in fd.read())
|
self.assert_('200 OK' in fd.read())
|
||||||
|
|
||||||
def test_022_custom_pool(self):
|
def test_022_custom_pool(self):
|
||||||
@@ -511,8 +565,9 @@ class TestHttpd(LimitedTestCase):
|
|||||||
# 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 = api.connect_tcp(
|
sock = api.connect_tcp(
|
||||||
('localhost', self.port))
|
('localhost', self.port))
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makefile()
|
||||||
fd.write('GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
|
fd.write('GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
|
||||||
|
fd.flush()
|
||||||
result = fd.read()
|
result = fd.read()
|
||||||
fd.close()
|
fd.close()
|
||||||
self.assert_(result.startswith('HTTP'), result)
|
self.assert_(result.startswith('HTTP'), result)
|
||||||
@@ -521,8 +576,9 @@ class TestHttpd(LimitedTestCase):
|
|||||||
def test_023_bad_content_length(self):
|
def test_023_bad_content_length(self):
|
||||||
sock = api.connect_tcp(
|
sock = api.connect_tcp(
|
||||||
('localhost', self.port))
|
('localhost', self.port))
|
||||||
fd = sock.makeGreenFile()
|
fd = sock.makefile()
|
||||||
fd.write('GET / HTTP/1.0\r\nHost: localhost\r\nContent-length: argh\r\n\r\n')
|
fd.write('GET / HTTP/1.0\r\nHost: localhost\r\nContent-length: argh\r\n\r\n')
|
||||||
|
fd.flush()
|
||||||
result = fd.read()
|
result = fd.read()
|
||||||
fd.close()
|
fd.close()
|
||||||
self.assert_(result.startswith('HTTP'), result)
|
self.assert_(result.startswith('HTTP'), result)
|
||||||
|
Reference in New Issue
Block a user