summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHelmut Grohne <helmut@subdivi.de>2012-06-29 07:41:56 +0200
committerHelmut Grohne <helmut@subdivi.de>2012-06-29 19:18:54 +0200
commiteba0855c881bea9f533a8d4b359f8711125e5037 (patch)
tree2549936b60a28e2368a3106c8beba0a9777611a6
parentd43d3d8947964392644b84ec1bce76c6f4193bea (diff)
downloadwsgitools-eba0855c881bea9f533a8d4b359f8711125e5037.tar.gz
make scgi.forkpool work with py3k
Note that the construction of the header moved from our internal sendheaders function to the start_response function. This way users supplying unicode characters no representable in iso-8859-1 will get a UnicodeEncodeError back from start_response, which is more useful than failing later while yielding bytes.
-rw-r--r--wsgitools/scgi/forkpool.py71
1 files changed, 35 insertions, 36 deletions
diff --git a/wsgitools/scgi/forkpool.py b/wsgitools/scgi/forkpool.py
index 7cc6d18..88f64be 100644
--- a/wsgitools/scgi/forkpool.py
+++ b/wsgitools/scgi/forkpool.py
@@ -12,6 +12,7 @@ import sys
import errno
import signal
+from wsgitools.internal import bytes2str, str2bytes
from wsgitools.scgi import _convert_environ, FileWrapper
if sys.version_info[0] >= 3:
@@ -28,22 +29,22 @@ class SocketFileWrapper:
def __init__(self, sock, toread):
"""@param sock: is a C{socket.socket()}"""
self.sock = sock
- self.buff = ""
+ self.buff = b""
self.toread = toread
def _recv(self, size=4096):
"""
internal method for receiving and counting incoming data
- @raise socket.error:
+ @raises socket.error:
"""
toread = min(size, self.toread)
if not toread:
- return ""
+ return b""
try:
data = self.sock.recv(toread)
except socket.error as why:
if why[0] in (errno.ECONNRESET, errno.ENOTCONN, errno.ESHUTDOWN):
- data = ""
+ data = b""
else:
raise
self.toread -= len(data)
@@ -63,12 +64,12 @@ class SocketFileWrapper:
def read(self, size=None):
"""
see pep333
- @raise socket.error:
+ @raises socket.error:
"""
if size is None:
retl = []
data = self.buff
- self.buff = ""
+ self.buff = b""
while True:
retl.append(data)
try:
@@ -77,7 +78,7 @@ class SocketFileWrapper:
break
if not data:
break
- return "".join(retl)
+ return b"".join(retl)
datalist = [self.buff]
datalen = len(self.buff)
while datalen < size:
@@ -89,22 +90,22 @@ class SocketFileWrapper:
break
datalist.append(data)
datalen += len(data)
- self.buff = "".join(datalist)
+ self.buff = b"".join(datalist)
if size <= len(self.buff):
ret, self.buff = self.buff[:size], self.buff[size:]
return ret
- ret, self.buff = self.buff, ""
+ ret, self.buff = self.buff, b""
return ret
def readline(self, size=None):
"""
see pep333
- @raise socket.error:
+ @raises socket.error:
"""
while True:
try:
- split = self.buff.index('\n') + 1
+ split = self.buff.index(b'\n') + 1
if size is not None and split > size:
split = size
ret, self.buff = self.buff[:split], self.buff[split:]
@@ -119,14 +120,14 @@ class SocketFileWrapper:
else:
data = self._recv(4096)
if not data:
- ret, self.buff = self.buff, ""
+ ret, self.buff = self.buff, b""
return ret
self.buff += data
def readlines(self):
"""
see pep333
- @raise socket.error:
+ @raises socket.error:
"""
data = self.readline()
while data:
@@ -138,7 +139,7 @@ class SocketFileWrapper:
def __next__(self):
"""
see pep333
- @raise socket.error:
+ @raises socket.error:
"""
data = self.read(4096)
if not data:
@@ -151,7 +152,7 @@ class SocketFileWrapper:
pass
def write(self, data):
"""see pep333"""
- assert isinstance(data, str)
+ assert isinstance(data, bytes)
try:
self.sock.sendall(data)
except socket.error:
@@ -261,11 +262,11 @@ class SCGIServer:
data = self.workers[s].sock.recv(1)
except socket.error:
# we cannot handle errors here, so drop the connection.
- data = ''
- if data == '':
+ data = b''
+ if data == b'':
self.workers[s].sock.close()
del self.workers[s]
- elif data in ('0', '1'):
+ elif data in (b'0', b'1'):
self.workers[s].state = int(data)
else:
raise RuntimeError("unexpected data from worker")
@@ -338,14 +339,14 @@ class SCGIServer:
def work(self, worksock):
"""
internal! serves maxrequests times
- @raise socket.error:
+ @raises socket.error:
"""
for _ in range(self.maxrequests):
(con, addr) = self.server.accept()
# we cannot handle socket.errors here.
- worksock.sendall('1') # tell server we're working
+ worksock.sendall(b'1') # tell server we're working
self.process(con)
- worksock.sendall('0') # tell server we've finished
+ worksock.sendall(b'0') # tell server we've finished
def process(self, con):
"""
@@ -362,10 +363,10 @@ class SCGIServer:
except socket.error:
con.close()
return
- if not ':' in data:
+ if not b':' in data:
con.close()
return
- length, data = data.split(':', 1)
+ length, data = data.split(b':', 1)
if not length.isdigit(): # clear protocol violation
con.close()
return
@@ -383,35 +384,32 @@ class SCGIServer:
data += t
# netstrings!
- data = data.split('\0')
+ data = data.split(b'\0')
# the byte beyond has to be a ','.
# and the number of netstrings excluding the final ',' has to be even
- if data.pop() != ',' or len(data) % 2 != 0:
+ if data.pop() != b',' or len(data) % 2 != 0:
con.close()
return
environ = self.config.copy()
while data:
- key = data.pop(0)
- value = data.pop(0)
+ key = bytes2str(data.pop(0))
+ value = bytes2str(data.pop(0))
environ[key] = value
# elements:
# 0 -> None: no headers set
# 0 -> False: set but unsent
# 0 -> True: sent
- # 1 -> status string
- # 2 -> header list
- response_head = [None, None, None]
+ # 1 -> bytes of the complete header
+ response_head = [None, None]
def sendheaders():
assert response_head[0] is not None # headers set
if response_head[0] != True:
response_head[0] = True
try:
- con.sendall('Status: %s\r\n%s\r\n\r\n' % (response_head[1],
- '\r\n'.join(map("%s: %s".__mod__,
- response_head[2]))))
+ con.sendall(response_head[1])
except socket.error:
pass
@@ -429,9 +427,10 @@ class SCGIServer:
finally:
exc_info = None
assert not response_head[0] # unset or not sent
+ headers = "".join(map("%s: %s\r\n".__mod__, headers))
+ full_header = "Status: %s\r\n%s\r\n" % (status, headers)
+ response_head[1] = str2bytes(full_header)
response_head[0] = False # set but nothing sent
- response_head[1] = status
- response_head[2] = headers
return dumbsend
if not environ.get("CONTENT_LENGTH", "bad").isdigit():
@@ -455,7 +454,7 @@ class SCGIServer:
assert response_head[0] is not None
result_iter = iter(result)
for data in result_iter:
- assert isinstance(data, str)
+ assert isinstance(data, bytes)
dumbsend(data)
if response_head[0] != True:
sendheaders()