summaryrefslogtreecommitdiff
path: root/wsgitools/scgi
diff options
context:
space:
mode:
authorHelmut Grohne <helmut@subdivi.de>2008-09-22 22:47:14 +0200
committerHelmut Grohne <helmut@subdivi.de>2008-09-22 22:47:14 +0200
commit592eaf98f851b9fd03206a4cd12ecaad462efa2c (patch)
tree38e31fea40df0c47990536c46b6ee2d9eb34d1ed /wsgitools/scgi
parent0f08962bd848ce9a0fbf71684fc72fd0776da84d (diff)
downloadwsgitools-592eaf98f851b9fd03206a4cd12ecaad462efa2c.tar.gz
make limits in scgi.asynchronous configurable
Diffstat (limited to 'wsgitools/scgi')
-rw-r--r--wsgitools/scgi/asynchronous.py58
1 files changed, 39 insertions, 19 deletions
diff --git a/wsgitools/scgi/asynchronous.py b/wsgitools/scgi/asynchronous.py
index 5d0e43d..338fac9 100644
--- a/wsgitools/scgi/asynchronous.py
+++ b/wsgitools/scgi/asynchronous.py
@@ -10,20 +10,20 @@ except ImportError:
class SCGIConnection(asyncore.dispatcher):
"""SCGI connection class used by WSGISCGIServer."""
- # maximum request size
- MAX_REQUEST_SIZE = 65536
- # maximum post size
- MAX_POST_SIZE = 8 << 20
- # read and write size
- BLOCK_SIZE = 4096
# connection states
NEW = 0*4 | 1 # connection established, waiting for request
HEADER = 1*4 | 1 # the request length was received, waiting for the rest
BODY = 2*4 | 1 # the request header was received, waiting for the body
REQ = 3*4 | 2 # request received, sending response
- def __init__(self, server, connection, addr):
+ def __init__(self, server, connection, addr, maxrequestsize=65536,
+ maxpostsize=8<<20, blocksize=4096):
+ asyncore.dispatcher.__init__(self, connection)
+
self.server = server # WSGISCGIServer instance
self.addr = addr # scgi client address
+ self.maxrequestsize = maxrequestsize
+ self.maxpostsize = maxpostsize
+ self.blocksize = blocksize
self.state = SCGIConnection.NEW # internal state
self.environ = {} # environment passed to wsgi app
self.reqlen = -1 # request length used in two different meanings
@@ -33,7 +33,6 @@ class SCGIConnection(asyncore.dispatcher):
self.outheaders = () # headers to be sent
# () -> unset, (..,..) -> set, True -> sent
self.body = StringIO.StringIO() # request body
- asyncore.dispatcher.__init__(self, connection)
def _wsgi_headers(self):
return {"wsgi.version": (1, 0),
@@ -69,7 +68,7 @@ class SCGIConnection(asyncore.dispatcher):
def handle_read(self):
"""asyncore interface"""
- data = self.recv(self.BLOCK_SIZE)
+ data = self.recv(self.blocksize)
self.inbuff += data
if self.state == SCGIConnection.NEW:
if ':' in self.inbuff:
@@ -78,12 +77,12 @@ class SCGIConnection(asyncore.dispatcher):
self.close()
return # invalid request format
reqlen = long(reqlen)
- if reqlen > self.MAX_REQUEST_SIZE:
+ if reqlen > self.maxrequestsize:
self.close()
return # request too long
self.reqlen = reqlen
self.state = SCGIConnection.HEADER
- elif len(self.inbuff) > self.MAX_REQUEST_SIZE:
+ elif len(self.inbuff) > self.maxrequestsize:
self.close()
return # request too long
@@ -105,7 +104,7 @@ class SCGIConnection(asyncore.dispatcher):
self.close()
return
self.reqlen = long(self.environ["CONTENT_LENGTH"])
- if self.reqlen > self.MAX_POST_SIZE:
+ if self.reqlen > self.maxpostsize:
self.close()
return
self.state = SCGIConnection.BODY
@@ -151,13 +150,13 @@ class SCGIConnection(asyncore.dispatcher):
def handle_write(self):
"""asyncore interface"""
assert self.state >= SCGIConnection.REQ
- if len(self.outbuff) < self.BLOCK_SIZE:
+ if len(self.outbuff) < self.blocksize:
self._try_send_headers()
for data in self.wsgihandler:
assert isinstance(data, str)
if data:
self.outbuff += data
- if len(self.outbuff) >= self.BLOCK_SIZE:
+ if len(self.outbuff) >= self.blocksize:
break
if len(self.outbuff) == 0:
if hasattr(self.wsgihandler, "close"):
@@ -165,7 +164,7 @@ class SCGIConnection(asyncore.dispatcher):
self.close()
return
try:
- sentbytes = self.send(self.outbuff[:self.BLOCK_SIZE])
+ sentbytes = self.send(self.outbuff[:self.blocksize])
except socket.error:
if hasattr(self.wsgihandler, "close"):
self.wsgihandler.close()
@@ -181,20 +180,41 @@ __all__.append("SCGIServer")
class SCGIServer(asyncore.dispatcher):
"""SCGI Server for WSGI applications. It does not use multiple processes or
multiple threads."""
- def __init__(self, wsgiapp, port, interface="localhost", error=sys.stderr):
+ def __init__(self, wsgiapp, port, interface="localhost", error=sys.stderr,
+ maxrequestsize=None, maxpostsize=None, blocksize=None):
"""
@param wsgiapp: is the wsgi application to be run.
- @type port: number
+ @type port: int
@param port: is an int representing the TCP port number to be used.
@type interface: str
@param interface: is a string specifying the network interface to bind
which defaults to "localhost" making the server inaccessible
over network.
@param error: is a file-like object being passed as wsgi.error in the
- environ parameter defaulting to stderr."""
+ environ parameter defaulting to stderr.
+ @type maxrequestsize: int
+ @param maxrequestsize: limit the size of request blocks in scgi
+ connections. Connections are dropped when this limit is hit.
+ @type maxpostsize: int
+ @param maxpostsize: limit the size of post bodies that may be processed
+ by this instance. Connections are dropped when this limit is
+ hit.
+ @type blocksize: int
+ @param blocksize: is amount of data to read or write from or to the
+ network at once
+ """
asyncore.dispatcher.__init__(self)
+
self.wsgiapp = wsgiapp
self.error = error
+ self.conf = {}
+ if maxrequestsize is not None:
+ self.conf["maxrequestsize"] = maxrequestsize
+ if maxpostsize is not None:
+ self.conf["maxpostsize"] = maxpostsize
+ if blocksize is not None:
+ self.conf["blocksize"] = blocksize
+
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.set_reuse_addr()
self.bind((interface, port))
@@ -205,7 +225,7 @@ class SCGIServer(asyncore.dispatcher):
ret = self.accept()
if ret is not None:
conn, addr = ret
- SCGIConnection(self, conn, addr)
+ SCGIConnection(self, conn, addr, **self.conf)
def run(self):
"""Runs the server. It will not return and you can invoke