changeset 4902:6049883eb89e

updated flup to 1.0.2+ (http://hg.saddi.com/flup-server changeset 100:af072c39193e)
author Reimar Bauer <rb.proj AT googlemail DOT com>
date Fri, 24 Jul 2009 20:50:22 +0200
parents 6c8aa68b803c
children 4eea6a2856dd
files MoinMoin/support/flup/ChangeLog MoinMoin/support/flup/NOTES.moin MoinMoin/support/flup/server/__init__.py MoinMoin/support/flup/server/ajp.py MoinMoin/support/flup/server/ajp_base.py MoinMoin/support/flup/server/ajp_fork.py MoinMoin/support/flup/server/fcgi.py MoinMoin/support/flup/server/fcgi_base.py MoinMoin/support/flup/server/fcgi_fork.py MoinMoin/support/flup/server/fcgi_single.py MoinMoin/support/flup/server/paste_factory.py MoinMoin/support/flup/server/preforkserver.py MoinMoin/support/flup/server/scgi.py MoinMoin/support/flup/server/scgi_base.py MoinMoin/support/flup/server/scgi_fork.py MoinMoin/support/flup/server/threadedserver.py MoinMoin/support/flup/server/threadpool.py
diffstat 17 files changed, 557 insertions(+), 286 deletions(-) [+]
line wrap: on
line diff
--- a/MoinMoin/support/flup/ChangeLog	Fri Jul 24 16:34:27 2009 +0200
+++ b/MoinMoin/support/flup/ChangeLog	Fri Jul 24 20:50:22 2009 +0200
@@ -1,3 +1,52 @@
+2009-06-05  Allan Saddi  <allan@saddi.com>
+
+	* Fix bug in scgi servers that occurs when SCRIPT_NAME is missing.
+	  Thanks to Jon Nelson for finding the problem!
+
+2009-05-29  Allan Saddi  <allan@saddi.com>
+
+	* Let all the active requests to finish before quitting. Thanks
+	  to Anand Chitipothu for the patch!
+
+2009-05-26  Allan Saddi  <allan@saddi.com>
+
+	* Release 1.0.2
+
+2009-05-18  Allan Saddi  <allan@saddi.com>
+
+	* Import Paste factories (and dependencies...) from PasteScript
+
+2009-05-04  Allan Saddi  <allan@saddi.com>
+
+	* Be tolerant of EAGAIN when sending messages to parent process.
+
+2009-02-02  Allan Saddi  <allan@saddi.com>
+
+	* Add forceCGI keyword argument to FastCGI servers to
+	  programmatically force CGI behavior.
+
+	* Merge Tommi Virtanen's "single server" (sequential server)
+	  patch.
+
+2008-12-03  Allan Saddi  <allan@saddi.com>
+
+	* Update ez_setup.py.
+
+2008-09-26  Allan Saddi  <allan@saddi.com>
+
+	* Re-seed random module after each fork.
+
+2008-09-11  Allan Saddi  <allan@saddi.com>
+
+	* Add an indication as to which header fails assertion when
+	  passing in non-string header names and/or values.
+
+2008-08-20  Allan Saddi  <allan@saddi.com>
+
+	* Add support for setting umask for UNIX domain sockets from
+	  paste.server_factory implementations. Thanks to Michal Suszko
+	  for the patch.
+
 2008-07-23  Allan Saddi  <allan@saddi.com>
 
 	* Add support for configuring UNIX domain sockets (for servers that
--- a/MoinMoin/support/flup/NOTES.moin	Fri Jul 24 16:34:27 2009 +0200
+++ b/MoinMoin/support/flup/NOTES.moin	Fri Jul 24 20:50:22 2009 +0200
@@ -1,17 +1,12 @@
 NOTES for bundled flup:
 =======================
-This directory contains the flup WSGI adapter package. It has been
-patched to support completely singlethreaded non-forking servers for
-deployment in webservers, that have their own process spawning strategy.
+This directory contains the flup WSGI adapter package. 
 
 The shipped version is available via mercurial checkout:
 
-hg clone -r aa983e43105e http://hg.saddi.com/flup-server
-
-The singlethreaded server patch was provided via a trac bugreport
-(http://trac.saddi.com/flup/ticket/22) and is provided in this directory
-as singleserver.diff for convenience. It has already been applied.
+hg clone -r af072c39193e http://hg.saddi.com/flup-server
 
 Thanks to Allan Saddi <allan@saddi.com> for writing flup and to
 the unnamed contributor <tv@inoi.fi> for the single-thread patch.
 
+
--- a/MoinMoin/support/flup/server/__init__.py	Fri Jul 24 16:34:27 2009 +0200
+++ b/MoinMoin/support/flup/server/__init__.py	Fri Jul 24 20:50:22 2009 +0200
@@ -1,1 +1,5 @@
 #
+class NoDefault(object):
+    pass
+
+__all__ = [ 'NoDefault', ]
--- a/MoinMoin/support/flup/server/ajp.py	Fri Jul 24 16:34:27 2009 +0200
+++ b/MoinMoin/support/flup/server/ajp.py	Fri Jul 24 20:50:22 2009 +0200
@@ -1,39 +1,45 @@
-# Copyright (c) 2005, 2006 Allan Saddi <allan@saddi.com>
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-#    notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-#    notice, this list of conditions and the following disclaimer in the
-#    documentation and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-# SUCH DAMAGE.
-#
-# $Id$
+"""
+.. highlight:: python
+   :linenothreshold: 5
 
-"""
+.. highlight:: bash
+   :linenothreshold: 5
+
 ajp - an AJP 1.3/WSGI gateway.
 
+:copyright: Copyright (c) 2005, 2006 Allan Saddi <allan@saddi.com>
+  All rights reserved.
+:license:
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS **AS IS** AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
 For more information about AJP and AJP connectors for your web server, see
-<http://jakarta.apache.org/tomcat/connectors-doc/>.
+http://jakarta.apache.org/tomcat/connectors-doc/.
 
 For more information about the Web Server Gateway Interface, see
-<http://www.python.org/peps/pep-0333.html>.
+http://www.python.org/peps/pep-0333.html.
 
-Example usage:
+Example usage::
 
   #!/usr/bin/env python
   import sys
@@ -50,7 +56,7 @@
 re-run. When a SIGINT or SIGTERM is received, the script exits with status
 code 0, possibly indicating a normal exit.
 
-Example wrapper script:
+Example wrapper script::
 
   #!/bin/sh
   STATUS=42
@@ -59,14 +65,14 @@
     STATUS=$?
   done
 
-Example workers.properties (for mod_jk):
+Example workers.properties (for mod_jk)::
 
   worker.list=foo
   worker.foo.port=8009
   worker.foo.host=localhost
   worker.foo.type=ajp13
 
-Example httpd.conf (for mod_jk):
+Example httpd.conf (for mod_jk)::
 
   JkWorkersFile /path/to/workers.properties
   JkMount /* foo
@@ -98,12 +104,12 @@
     implement. :)
 
     Of course you will need an AJP1.3 connector for your webserver (e.g.
-    mod_jk) - see <http://jakarta.apache.org/tomcat/connectors-doc/>.
+    mod_jk) - see http://jakarta.apache.org/tomcat/connectors-doc/.
     """
     def __init__(self, application, scriptName='', environ=None,
                  multithreaded=True, multiprocess=False,
                  bindAddress=('localhost', 8009), allowedServers=None,
-                 loggingLevel=logging.INFO, debug=True, **kw):
+                 loggingLevel=logging.INFO, debug=False, **kw):
         """
         scriptName is the initial portion of the URL path that "belongs"
         to your application. It is used to determine PATH_INFO (which doesn't
@@ -156,16 +162,16 @@
         ret = ThreadedServer.run(self, sock)
 
         self._cleanupSocket(sock)
+        # AJP connections are more or less persistent. .shutdown() will
+        # not return until the web server lets go. So don't bother calling
+        # it...
+        #self.shutdown()
 
         self.logger.info('%s shutting down%s', self.__class__.__name__,
                          self._hupReceived and ' (reload requested)' or '')
 
         return ret
 
-def factory(global_conf, host=None, port=None, **local):
-    import paste_factory
-    return paste_factory.helper(WSGIServer, global_conf, host, port, **local)
-
 if __name__ == '__main__':
     def test_app(environ, start_response):
         """Probably not the most efficient example."""
--- a/MoinMoin/support/flup/server/ajp_base.py	Fri Jul 24 16:34:27 2009 +0200
+++ b/MoinMoin/support/flup/server/ajp_base.py	Fri Jul 24 20:50:22 2009 +0200
@@ -41,10 +41,9 @@
 import thread
 import threading
 
-__all__ = ['BaseAJPServer']
+from flup.server import NoDefault
 
-class NoDefault(object):
-    pass
+__all__ = ['BaseAJPServer']
 
 # Packet header prefixes.
 SERVER_PREFIX = '\x12\x34'
@@ -752,7 +751,7 @@
     def __init__(self, application, scriptName='', environ=None,
                  multithreaded=True, multiprocess=False,
                  bindAddress=('localhost', 8009), allowedServers=NoDefault,
-                 loggingLevel=logging.INFO, debug=True):
+                 loggingLevel=logging.INFO, debug=False):
         """
         scriptName is the initial portion of the URL path that "belongs"
         to your application. It is used to determine PATH_INFO (which doesn't
@@ -886,8 +885,8 @@
             assert type(response_headers) is list, 'Headers must be a list'
             if __debug__:
                 for name,val in response_headers:
-                    assert type(name) is str, 'Header names must be strings'
-                    assert type(val) is str, 'Header values must be strings'
+                    assert type(name) is str, 'Header name "%s" must be a string' % name
+                    assert type(val) is str, 'Value of header "%s" must be a string' % name
 
             headers_set[:] = [status, response_headers]
             return write
--- a/MoinMoin/support/flup/server/ajp_fork.py	Fri Jul 24 16:34:27 2009 +0200
+++ b/MoinMoin/support/flup/server/ajp_fork.py	Fri Jul 24 20:50:22 2009 +0200
@@ -1,37 +1,43 @@
-# Copyright (c) 2005, 2006 Allan Saddi <allan@saddi.com>
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-#    notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-#    notice, this list of conditions and the following disclaimer in the
-#    documentation and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-# SUCH DAMAGE.
-#
-# $Id$
+"""
+.. highlight:: python
+   :linenothreshold: 5
 
-"""
+.. highlight:: bash
+   :linenothreshold: 5
+
 ajp - an AJP 1.3/WSGI gateway.
 
+:copyright: Copyright (c) 2005, 2006 Allan Saddi <allan@saddi.com>
+  All rights reserved.
+:license:
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS **AS IS** AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
 For more information about AJP and AJP connectors for your web server, see
-<http://jakarta.apache.org/tomcat/connectors-doc/>.
+http://jakarta.apache.org/tomcat/connectors-doc/.
 
 For more information about the Web Server Gateway Interface, see
-<http://www.python.org/peps/pep-0333.html>.
+http://www.python.org/peps/pep-0333.html.
 
 Example usage:
 
@@ -50,7 +56,7 @@
 re-run. When a SIGINT or SIGTERM is received, the script exits with status
 code 0, possibly indicating a normal exit.
 
-Example wrapper script:
+Example wrapper script::
 
   #!/bin/sh
   STATUS=42
@@ -59,14 +65,14 @@
     STATUS=$?
   done
 
-Example workers.properties (for mod_jk):
+Example workers.properties (for mod_jk)::
 
   worker.list=foo
   worker.foo.port=8009
   worker.foo.host=localhost
   worker.foo.type=ajp13
 
-Example httpd.conf (for mod_jk):
+Example httpd.conf (for mod_jk)::
 
   JkWorkersFile /path/to/workers.properties
   JkMount /* foo
@@ -98,11 +104,11 @@
     implement. :)
 
     Of course you will need an AJP1.3 connector for your webserver (e.g.
-    mod_jk) - see <http://jakarta.apache.org/tomcat/connectors-doc/>.
+    mod_jk) - see http://jakarta.apache.org/tomcat/connectors-doc/.
     """
     def __init__(self, application, scriptName='', environ=None,
                  bindAddress=('localhost', 8009), allowedServers=None,
-                 loggingLevel=logging.INFO, debug=True, **kw):
+                 loggingLevel=logging.INFO, debug=False, **kw):
         """
         scriptName is the initial portion of the URL path that "belongs"
         to your application. It is used to determine PATH_INFO (which doesn't
@@ -160,10 +166,6 @@
 
         return ret
 
-def factory(global_conf, host=None, port=None, **local):
-    import paste_factory
-    return paste_factory.helper(WSGIServer, global_conf, host, port, **local)
-
 if __name__ == '__main__':
     def test_app(environ, start_response):
         """Probably not the most efficient example."""
--- a/MoinMoin/support/flup/server/fcgi.py	Fri Jul 24 16:34:27 2009 +0200
+++ b/MoinMoin/support/flup/server/fcgi.py	Fri Jul 24 20:50:22 2009 +0200
@@ -64,7 +64,7 @@
     def __init__(self, application, environ=None,
                  multithreaded=True, multiprocess=False,
                  bindAddress=None, umask=None, multiplexed=False,
-                 debug=True, roles=(FCGI_RESPONDER,), **kw):
+                 debug=False, roles=(FCGI_RESPONDER,), forceCGI=False, **kw):
         """
         environ, if present, must be a dictionary-like object. Its
         contents will be copied into application's environ. Useful
@@ -87,7 +87,8 @@
                                 umask=umask,
                                 multiplexed=multiplexed,
                                 debug=debug,
-                                roles=roles)
+                                roles=roles,
+                                forceCGI=forceCGI)
         for key in ('jobClass', 'jobArgs'):
             if kw.has_key(key):
                 del kw[key]
@@ -113,13 +114,10 @@
         ret = ThreadedServer.run(self, sock)
 
         self._cleanupSocket(sock)
+        self.shutdown()
 
         return ret
 
-def factory(global_conf, host=None, port=None, **local):
-    import paste_factory
-    return paste_factory.helper(WSGIServer, global_conf, host, port, **local)
-
 if __name__ == '__main__':
     def test_app(environ, start_response):
         """Probably not the most efficient example."""
--- a/MoinMoin/support/flup/server/fcgi_base.py	Fri Jul 24 16:34:27 2009 +0200
+++ b/MoinMoin/support/flup/server/fcgi_base.py	Fri Jul 24 20:50:22 2009 +0200
@@ -902,7 +902,8 @@
     def __init__(self, application, environ=None,
                  multithreaded=True, multiprocess=False,
                  bindAddress=None, umask=None, multiplexed=False,
-                 debug=True, roles=(FCGI_RESPONDER,)):
+                 debug=False, roles=(FCGI_RESPONDER,),
+                 forceCGI=False):
         """
         bindAddress, if present, must either be a string or a 2-tuple. If
         present, run() will open its own listening socket. You would use
@@ -934,6 +935,7 @@
         self.multiprocess = multiprocess
         self.debug = debug
         self.roles = roles
+        self.forceCGI = forceCGI
 
         self._bindAddress = bindAddress
         self._umask = umask
@@ -989,7 +991,7 @@
             # if you want to run your app as a simple CGI. (You can do
             # this with Apache's mod_env [not loaded by default in OS X
             # client, ha ha] and the SetEnv directive.)
-            if not isFCGI or \
+            if not isFCGI or self.forceCGI or \
                os.environ.get('FCGI_FORCE_CGI', 'N').upper().startswith('Y'):
                 req = self.cgirequest_class(self)
                 req.run()
@@ -1103,8 +1105,8 @@
             assert type(response_headers) is list, 'Headers must be a list'
             if __debug__:
                 for name,val in response_headers:
-                    assert type(name) is str, 'Header names must be strings'
-                    assert type(val) is str, 'Header values must be strings'
+                    assert type(name) is str, 'Header name "%s" must be a string' % name
+                    assert type(val) is str, 'Value of header "%s" must be a string' % name
 
             headers_set[:] = [status, response_headers]
             return write
--- a/MoinMoin/support/flup/server/fcgi_fork.py	Fri Jul 24 16:34:27 2009 +0200
+++ b/MoinMoin/support/flup/server/fcgi_fork.py	Fri Jul 24 20:50:22 2009 +0200
@@ -1,38 +1,44 @@
-# Copyright (c) 2005, 2006 Allan Saddi <allan@saddi.com>
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-#    notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-#    notice, this list of conditions and the following disclaimer in the
-#    documentation and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-# SUCH DAMAGE.
-#
-# $Id$
+"""
+.. highlight:: python
+   :linenothreshold: 5
 
-"""
+.. highlight:: bash
+   :linenothreshold: 5
+
 fcgi - a FastCGI/WSGI gateway.
 
-For more information about FastCGI, see <http://www.fastcgi.com/>.
+:copyright: Copyright (c) 2005, 2006 Allan Saddi <allan@saddi.com>
+  All rights reserved.
+:license:
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS **AS IS** AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+For more information about FastCGI, see http://www.fastcgi.com/.
 
 For more information about the Web Server Gateway Interface, see
-<http://www.python.org/peps/pep-0333.html>.
+http://www.python.org/peps/pep-0333.html.
 
-Example usage:
+Example usage::
 
   #!/usr/bin/env python
   from myapplication import app # Assume app is your WSGI application object
@@ -51,7 +57,7 @@
 
 import os
 
-from flup.server.fcgi_base import BaseFCGIServer, \
+from flup.server.fcgi_base import BaseFCGIServer, FCGI_RESPONDER, \
      FCGI_MAX_CONNS, FCGI_MAX_REQS, FCGI_MPXS_CONNS
 from flup.server.preforkserver import PreforkServer
 
@@ -60,11 +66,11 @@
 class WSGIServer(BaseFCGIServer, PreforkServer):
     """
     FastCGI server that supports the Web Server Gateway Interface. See
-    <http://www.python.org/peps/pep-0333.html>.
+    http://www.python.org/peps/pep-0333.html.
     """
     def __init__(self, application, environ=None,
                  bindAddress=None, umask=None, multiplexed=False,
-                 debug=True, **kw):
+                 debug=False, roles=(FCGI_RESPONDER,), forceCGI=False, **kw):
         """
         environ, if present, must be a dictionary-like object. Its
         contents will be copied into application's environ. Useful
@@ -86,7 +92,9 @@
                                 bindAddress=bindAddress,
                                 umask=umask,
                                 multiplexed=multiplexed,
-                                debug=debug)
+                                debug=debug,
+                                roles=roles,
+                                forceCGI=forceCGI)
         for key in ('multithreaded', 'multiprocess', 'jobClass', 'jobArgs'):
             if kw.has_key(key):
                 del kw[key]
@@ -134,10 +142,6 @@
 
         return ret
 
-def factory(global_conf, host=None, port=None, **local):
-    import paste_factory
-    return paste_factory.helper(WSGIServer, global_conf, host, port, **local)
-
 if __name__ == '__main__':
     def test_app(environ, start_response):
         """Probably not the most efficient example."""
--- a/MoinMoin/support/flup/server/fcgi_single.py	Fri Jul 24 16:34:27 2009 +0200
+++ b/MoinMoin/support/flup/server/fcgi_single.py	Fri Jul 24 20:50:22 2009 +0200
@@ -64,7 +64,7 @@
     """
     def __init__(self, application, environ=None,
                  bindAddress=None, umask=None, multiplexed=False,
-                 debug=True, roles=(FCGI_RESPONDER,), **kw):
+                 debug=False, roles=(FCGI_RESPONDER,), forceCGI=False, **kw):
         """
         environ, if present, must be a dictionary-like object. Its
         contents will be copied into application's environ. Useful
@@ -87,7 +87,8 @@
                                 umask=umask,
                                 multiplexed=multiplexed,
                                 debug=debug,
-                                roles=roles)
+                                roles=roles,
+                                forceCGI=forceCGI)
         for key in ('jobClass', 'jobArgs'):
             if kw.has_key(key):
                 del kw[key]
@@ -121,10 +122,6 @@
 
         return ret
 
-def factory(global_conf, host=None, port=None, **local):
-    import paste_factory
-    return paste_factory.helper(WSGIServer, global_conf, host, port, **local)
-
 if __name__ == '__main__':
     def test_app(environ, start_response):
         """Probably not the most efficient example."""
--- a/MoinMoin/support/flup/server/paste_factory.py	Fri Jul 24 16:34:27 2009 +0200
+++ b/MoinMoin/support/flup/server/paste_factory.py	Fri Jul 24 20:50:22 2009 +0200
@@ -1,16 +1,151 @@
-def helper(wsgiServerClass, global_conf, host, port, **local_conf):
-    # I think I can't write a tuple for bindAddress in .ini file
-    host = host or global_conf.get('host', 'localhost')
-    port = port or global_conf.get('port', 4000)
+# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
+# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
 
-    if 'socket' in local_conf:
-        local_conf['bindAddress'] = local_conf['socket']
-        del local_conf['socket']
+from flup.server import NoDefault
+
+def asbool(obj):
+    if isinstance(obj, (str, unicode)):
+        obj = obj.strip().lower()
+        if obj in ['true', 'yes', 'on', 'y', 't', '1']:
+            return True
+        elif obj in ['false', 'no', 'off', 'n', 'f', '0']:
+            return False
+        else:
+            raise ValueError(
+                "String is not true/false: %r" % obj)
+    return bool(obj)
+
+def aslist(obj, sep=None, strip=True):
+    if isinstance(obj, (str, unicode)):
+        lst = obj.split(sep)
+        if strip:
+            lst = [v.strip() for v in lst]
+        return lst
+    elif isinstance(obj, (list, tuple)):
+        return obj
+    elif obj is None:
+        return []
     else:
-        local_conf['bindAddress'] = (host, int(port))
-    
-    def server(application):
-        server = wsgiServerClass(application, **local_conf)
-        server.run()
+        return [obj]
 
-    return server
+def run_ajp_thread(wsgi_app, global_conf,
+                   scriptName='', host='localhost', port='8009',
+                   allowedServers='127.0.0.1', debug=NoDefault):
+    import flup.server.ajp
+    addr = (host, int(port))
+    if debug is NoDefault:
+        debug = global_conf.get('debug', False)
+    debug = asbool(debug)
+    s = flup.server.ajp.WSGIServer(
+        wsgi_app,
+        scriptName=scriptName,
+        bindAddress=addr,
+        allowedServers=aslist(allowedServers),
+        debug=debug,
+        )
+    s.run()
+
+def run_ajp_fork(wsgi_app, global_conf,
+                 scriptName='', host='localhost', port='8009',
+                 allowedServers='127.0.0.1', debug=NoDefault):
+    import flup.server.ajp_fork
+    addr = (host, int(port))
+    if debug is NoDefault:
+        debug = global_conf.get('debug', False)
+    debug = asbool(debug)
+    s = flup.server.ajp_fork.WSGIServer(
+        wsgi_app,
+        scriptName=scriptName,
+        bindAddress=addr,
+        allowedServers=aslist(allowedServers),
+        debug=debug,
+        )
+    s.run()
+
+def run_fcgi_thread(wsgi_app, global_conf,
+                    host=None, port=None,
+                    socket=None, umask=None,
+                    multiplexed=False, debug=NoDefault):
+    import flup.server.fcgi
+    if socket:
+        assert host is None and port is None
+        sock = socket
+    elif host:
+        assert host is not None and port is not None
+        sock = (host, int(port))
+    else:
+        sock = None
+    if umask is not None:
+        umask = int(umask)
+    if debug is NoDefault:
+        debug = global_conf.get('debug', False)
+    debug = asbool(debug)
+    s = flup.server.fcgi.WSGIServer(
+        wsgi_app,
+        bindAddress=sock, umask=umask,
+        multiplexed=asbool(multiplexed),
+        debug=debug)
+    s.run()
+
+def run_fcgi_fork(wsgi_app, global_conf,
+                  host=None, port=None,
+                  socket=None, umask=None,
+                  multiplexed=False,
+                  debug=NoDefault):
+    import flup.server.fcgi_fork
+    if socket:
+        assert host is None and port is None
+        sock = socket
+    elif host:
+        assert host is not None and port is not None
+        sock = (host, int(port))
+    else:
+        sock = None
+    if umask is not None:
+        umask = int(umask)
+    if debug is NoDefault:
+        debug = global_conf.get('debug', False)
+    debug = asbool(debug)
+    s = flup.server.fcgi_fork.WSGIServer(
+        wsgi_app,
+        bindAddress=sock, umask=umask,
+        multiplexed=asbool(multiplexed),
+        debug=debug)
+    s.run()
+
+def run_scgi_thread(wsgi_app, global_conf,
+                    scriptName=NoDefault, host='localhost', port='4000',
+                    allowedServers='127.0.0.1',
+                    debug=NoDefault):
+    import flup.server.scgi
+    addr = (host, int(port))
+    if debug is NoDefault:
+        debug = global_conf.get('debug', False)
+    debug = asbool(debug)
+    s = flup.server.scgi.WSGIServer(
+        wsgi_app,
+        scriptName=scriptName,
+        bindAddress=addr,
+        allowedServers=aslist(allowedServers),
+        debug=debug,
+        )
+    s.run()
+
+def run_scgi_fork(wsgi_app, global_conf,
+                  scriptName=NoDefault, host='localhost', port='4000',
+                  allowedServers='127.0.0.1',
+                  debug=NoDefault):
+    import flup.server.scgi_fork
+    addr = (host, int(port))
+    if debug is NoDefault:
+        debug = global_conf.get('debug', False)
+    debug = asbool(debug)
+    s = flup.server.scgi_fork.WSGIServer(
+        wsgi_app,
+        scriptName=scriptName,
+        bindAddress=addr,
+        allowedServers=aslist(allowedServers),
+        debug=debug,
+        )
+    s.run()
+
--- a/MoinMoin/support/flup/server/preforkserver.py	Fri Jul 24 16:34:27 2009 +0200
+++ b/MoinMoin/support/flup/server/preforkserver.py	Fri Jul 24 20:50:22 2009 +0200
@@ -33,6 +33,8 @@
 import select
 import errno
 import signal
+import random
+import time
 
 try:
     import fcntl
@@ -97,6 +99,9 @@
         # free to process requests.
         self._children = {}
 
+        self._children_to_purge = []
+        self._last_purge = 0
+
     def run(self, sock):
         """
         The main loop. Pass a socket that is ready to accept() client
@@ -124,15 +129,17 @@
             r = [x['file'] for x in self._children.values()
                  if x['file'] is not None]
 
-            if len(r) == len(self._children):
+            if len(r) == len(self._children) and not self._children_to_purge:
                 timeout = None
             else:
                 # There are dead children that need to be reaped, ensure
-                # that they are by timing out, if necessary.
+                # that they are by timing out, if necessary. Or there are some
+                # children that need to die.
                 timeout = 2
 
+            w = (time.time() > self._last_purge + 10) and self._children_to_purge or []
             try:
-                r, w, e = select.select(r, [], [], timeout)
+                r, w, e = select.select(r, w, [], timeout)
             except select.error, e:
                 if e[0] != errno.EINTR:
                     raise
@@ -161,6 +168,20 @@
                             d['file'] = None
                             d['avail'] = False
 
+            for child in w:
+                # purging child
+                child.send('bye, bye')
+                del self._children_to_purge[self._children_to_purge.index(child)]
+                self._last_purge = time.time()
+
+                # Try to match it with a child. (Do we need a reverse map?)
+                for pid,d in self._children.items():
+                    if child is d['file']:
+                        d['file'].close()
+                        d['file'] = None
+                        d['avail'] = False
+                break
+
             # Reap children.
             self._reapChildren()
 
@@ -307,10 +328,37 @@
         """Override to provide access control."""
         return True
 
+    def _notifyParent(self, parent, msg):
+        """Send message to parent, ignoring EPIPE and retrying on EAGAIN"""
+        while True:
+            try:
+                parent.send(msg)
+                return True
+            except socket.error, e:
+                if e[0] == errno.EPIPE:
+                    return False # Parent is gone
+                if e[0] == errno.EAGAIN:
+                    # Wait for socket change before sending again
+                    select.select([], [parent], [])
+                else:
+                    raise
+                
     def _child(self, sock, parent):
         """Main loop for children."""
         requestCount = 0
-        
+
+        # Re-seed random module
+        preseed = ''
+        # urandom only exists in Python >= 2.4
+        if hasattr(os, 'urandom'):
+            try:
+                preseed = os.urandom(16)
+            except NotImplementedError:
+                pass
+        # Have doubts about this. random.seed will just hash the string
+        random.seed('%s%s%s' % (preseed, os.getpid(), time.time()))
+        del preseed
+
         while True:
             # Wait for any activity on the main socket or parent socket.
             r, w, e = select.select([sock, parent], [], [])
@@ -339,12 +387,7 @@
                 continue
 
             # Notify parent we're no longer available.
-            try:
-                parent.send('\x00')
-            except socket.error, e:
-                # If parent is gone, finish up this request.
-                if e[0] != errno.EPIPE:
-                    raise
+            self._notifyParent(parent, '\x00')
 
             # Do the job.
             self._jobClass(clientSock, addr, *self._jobArgs).run()
@@ -356,13 +399,8 @@
                     break
                 
             # Tell parent we're free again.
-            try:
-                parent.send('\xff')
-            except socket.error, e:
-                if e[0] == errno.EPIPE:
-                    # Parent is gone.
-                    return
-                raise
+            if not self._notifyParent(parent, '\xff'):
+                return # Parent is gone.
 
     # Signal handlers
 
@@ -377,16 +415,24 @@
         # Do nothing (breaks us out of select and allows us to reap children).
         pass
 
+    def _usr1Handler(self, signum, frame):
+        self._children_to_purge = [x['file'] for x in self._children.values()
+                                   if x['file'] is not None]
+
     def _installSignalHandlers(self):
         supportedSignals = [signal.SIGINT, signal.SIGTERM]
         if hasattr(signal, 'SIGHUP'):
             supportedSignals.append(signal.SIGHUP)
+        if hasattr(signal, 'SIGUSR1'):
+            supportedSignals.append(signal.SIGUSR1)
 
         self._oldSIGs = [(x,signal.getsignal(x)) for x in supportedSignals]
 
         for sig in supportedSignals:
             if hasattr(signal, 'SIGHUP') and sig == signal.SIGHUP:
                 signal.signal(sig, self._hupHandler)
+            elif hasattr(signal, 'SIGUSR1') and sig == signal.SIGUSR1:
+                signal.signal(sig, self._usr1Handler)
             else:
                 signal.signal(sig, self._intHandler)
 
--- a/MoinMoin/support/flup/server/scgi.py	Fri Jul 24 16:34:27 2009 +0200
+++ b/MoinMoin/support/flup/server/scgi.py	Fri Jul 24 20:50:22 2009 +0200
@@ -1,39 +1,45 @@
-# Copyright (c) 2005, 2006 Allan Saddi <allan@saddi.com>
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-#    notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-#    notice, this list of conditions and the following disclaimer in the
-#    documentation and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-# SUCH DAMAGE.
-#
-# $Id$
+"""
+.. highlight:: python
+   :linenothreshold: 5
 
-"""
+.. highlight:: bash
+   :linenothreshold: 5
+
 scgi - an SCGI/WSGI gateway.
 
+:copyright: Copyright (c) 2005, 2006 Allan Saddi <allan@saddi.com>
+  All rights reserved.
+:license:
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS **AS IS** AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
 For more information about SCGI and mod_scgi for Apache1/Apache2, see
-<http://www.mems-exchange.org/software/scgi/>.
+http://www.mems-exchange.org/software/scgi/.
 
 For more information about the Web Server Gateway Interface, see
-<http://www.python.org/peps/pep-0333.html>.
+http://www.python.org/peps/pep-0333.html.
 
-Example usage:
+Example usage::
 
   #!/usr/bin/env python
   import sys
@@ -50,7 +56,7 @@
 re-run. When a SIGINT or SIGTERM is received, the script exits with status
 code 0, possibly indicating a normal exit.
 
-Example wrapper script:
+Example wrapper script::
 
   #!/bin/sh
   STATUS=42
@@ -66,7 +72,8 @@
 import logging
 import socket
 
-from flup.server.scgi_base import BaseSCGIServer, Connection, NoDefault
+from flup.server import NoDefault
+from flup.server.scgi_base import BaseSCGIServer, Connection
 from flup.server.threadedserver import ThreadedServer
 
 __all__ = ['WSGIServer']
@@ -74,9 +81,9 @@
 class WSGIServer(BaseSCGIServer, ThreadedServer):
     """
     SCGI/WSGI server. For information about SCGI (Simple Common Gateway
-    Interface), see <http://www.mems-exchange.org/software/scgi/>.
+    Interface), see http://www.mems-exchange.org/software/scgi/.
 
-    This server is similar to SWAP <http://www.idyll.org/~t/www-tools/wsgi/>,
+    This server is similar to SWAP http://www.idyll.org/~t/www-tools/wsgi/,
     another SCGI/WSGI server.
 
     It differs from SWAP in that it isn't based on scgi.scgi_server and
@@ -91,7 +98,7 @@
                  multithreaded=True, multiprocess=False,
                  bindAddress=('localhost', 4000), umask=None,
                  allowedServers=None,
-                 loggingLevel=logging.INFO, debug=True, **kw):
+                 loggingLevel=logging.INFO, debug=False, **kw):
         """
         scriptName is the initial portion of the URL path that "belongs"
         to your application. It is used to determine PATH_INFO (which doesn't
@@ -111,7 +118,7 @@
         the umask is to be changed to before the socket is created in the
         filesystem. After the socket is created, the previous umask is
         restored.
-        
+
         allowedServers must be None or a list of strings representing the
         IPv4 addresses of servers allowed to connect. None means accept
         connections from anywhere.
@@ -151,16 +158,13 @@
         ret = ThreadedServer.run(self, sock)
 
         self._cleanupSocket(sock)
+        self.shutdown()
 
         self.logger.info('%s shutting down%s', self.__class__.__name__,
                          self._hupReceived and ' (reload requested)' or '')
 
         return ret
 
-def factory(global_conf, host=None, port=None, **local):
-    import paste_factory
-    return paste_factory.helper(WSGIServer, global_conf, host, port, **local)
-
 if __name__ == '__main__':
     def test_app(environ, start_response):
         """Probably not the most efficient example."""
--- a/MoinMoin/support/flup/server/scgi_base.py	Fri Jul 24 16:34:27 2009 +0200
+++ b/MoinMoin/support/flup/server/scgi_base.py	Fri Jul 24 20:50:22 2009 +0200
@@ -45,8 +45,7 @@
 
 __all__ = ['BaseSCGIServer']
 
-class NoDefault(object):
-    pass
+from flup.server import NoDefault
 
 # The main classes use this name for logging.
 LoggerName = 'scgi-wsgi'
@@ -278,7 +277,7 @@
                  multithreaded=True, multiprocess=False,
                  bindAddress=('localhost', 4000), umask=None,
                  allowedServers=NoDefault,
-                 loggingLevel=logging.INFO, debug=True):
+                 loggingLevel=logging.INFO, debug=False):
         """
         scriptName is the initial portion of the URL path that "belongs"
         to your application. It is used to determine PATH_INFO (which doesn't
@@ -443,8 +442,8 @@
             assert type(response_headers) is list, 'Headers must be a list'
             if __debug__:
                 for name,val in response_headers:
-                    assert type(name) is str, 'Header names must be strings'
-                    assert type(val) is str, 'Header values must be strings'
+                    assert type(name) is str, 'Header name "%s" must be a string' % name
+                    assert type(val) is str, 'Value of header "%s" must be a string' % name
 
             headers_set[:] = [status, response_headers]
             return write
@@ -501,7 +500,7 @@
         if scriptName is NoDefault:
             # Pull SCRIPT_NAME/PATH_INFO from environment, with empty defaults
             if not environ.has_key('SCRIPT_NAME'):
-                environ['SCRIPT_INFO'] = ''
+                environ['SCRIPT_NAME'] = ''
             if not environ.has_key('PATH_INFO') or not environ['PATH_INFO']:
                 if reqUri is not None:
                     environ['PATH_INFO'] = reqUri[0]
--- a/MoinMoin/support/flup/server/scgi_fork.py	Fri Jul 24 16:34:27 2009 +0200
+++ b/MoinMoin/support/flup/server/scgi_fork.py	Fri Jul 24 20:50:22 2009 +0200
@@ -1,39 +1,45 @@
-# Copyright (c) 2005, 2006 Allan Saddi <allan@saddi.com>
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-#    notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-#    notice, this list of conditions and the following disclaimer in the
-#    documentation and/or other materials provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-# SUCH DAMAGE.
-#
-# $Id$
+"""
+.. highlight:: python
+   :linenothreshold: 5
 
-"""
+.. highlight:: bash
+   :linenothreshold: 5
+
 scgi - an SCGI/WSGI gateway.
 
+:copyright: Copyright (c) 2005, 2006 Allan Saddi <allan@saddi.com>
+  All rights reserved.
+:license:
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS **AS IS** AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
 For more information about SCGI and mod_scgi for Apache1/Apache2, see
-<http://www.mems-exchange.org/software/scgi/>.
+http://www.mems-exchange.org/software/scgi/.
 
 For more information about the Web Server Gateway Interface, see
-<http://www.python.org/peps/pep-0333.html>.
+http://www.python.org/peps/pep-0333.html.
 
-Example usage:
+Example usage::
 
   #!/usr/bin/env python
   import sys
@@ -50,7 +56,7 @@
 re-run. When a SIGINT or SIGTERM is received, the script exits with status
 code 0, possibly indicating a normal exit.
 
-Example wrapper script:
+Example wrapper script::
 
   #!/bin/sh
   STATUS=42
@@ -66,7 +72,8 @@
 import logging
 import socket
 
-from flup.server.scgi_base import BaseSCGIServer, Connection, NoDefault
+from flup.server import NoDefault
+from flup.server.scgi_base import BaseSCGIServer, Connection
 from flup.server.preforkserver import PreforkServer
 
 __all__ = ['WSGIServer']
@@ -74,9 +81,9 @@
 class WSGIServer(BaseSCGIServer, PreforkServer):
     """
     SCGI/WSGI server. For information about SCGI (Simple Common Gateway
-    Interface), see <http://www.mems-exchange.org/software/scgi/>.
+    Interface), see http://www.mems-exchange.org/software/scgi/.
 
-    This server is similar to SWAP <http://www.idyll.org/~t/www-tools/wsgi/>,
+    This server is similar to SWAP http://www.idyll.org/~t/www-tools/wsgi/,
     another SCGI/WSGI server.
 
     It differs from SWAP in that it isn't based on scgi.scgi_server and
@@ -90,7 +97,7 @@
     def __init__(self, application, scriptName=NoDefault, environ=None,
                  bindAddress=('localhost', 4000), umask=None,
                  allowedServers=None,
-                 loggingLevel=logging.INFO, debug=True, **kw):
+                 loggingLevel=logging.INFO, debug=False, **kw):
         """
         scriptName is the initial portion of the URL path that "belongs"
         to your application. It is used to determine PATH_INFO (which doesn't
@@ -110,7 +117,7 @@
         the umask is to be changed to before the socket is created in the
         filesystem. After the socket is created, the previous umask is
         restored.
-        
+
         allowedServers must be None or a list of strings representing the
         IPv4 addresses of servers allowed to connect. None means accept
         connections from anywhere.
@@ -155,10 +162,6 @@
 
         return ret
 
-def factory(global_conf, host=None, port=None, **local):
-    import paste_factory
-    return paste_factory.helper(WSGIServer, global_conf, host, port, **local)
-
 if __name__ == '__main__':
     def test_app(environ, start_response):
         """Probably not the most efficient example."""
--- a/MoinMoin/support/flup/server/threadedserver.py	Fri Jul 24 16:34:27 2009 +0200
+++ b/MoinMoin/support/flup/server/threadedserver.py	Fri Jul 24 20:50:22 2009 +0200
@@ -109,6 +109,10 @@
 
         # Return bool based on whether or not SIGHUP was received.
         return self._hupReceived
+        
+    def shutdown(self):
+        """Wait for running threads to finish."""
+        self._threadPool.shutdown()
 
     def _mainloopPeriodic(self):
         """
--- a/MoinMoin/support/flup/server/threadpool.py	Fri Jul 24 16:34:27 2009 +0200
+++ b/MoinMoin/support/flup/server/threadpool.py	Fri Jul 24 20:50:22 2009 +0200
@@ -28,7 +28,6 @@
 __version__ = '$Revision$'
 
 import sys
-import thread
 import threading
 
 class ThreadPool(object):
@@ -47,9 +46,30 @@
         self._workQueue = []
         self._idleCount = self._workerCount = maxSpare
 
+        self._threads = []
+        self._stop = False
+
         # Start the minimum number of worker threads.
         for i in range(maxSpare):
-            thread.start_new_thread(self._worker, ())
+            self._start_new_thread()
+            
+    def _start_new_thread(self):
+        t = threading.Thread(target=self._worker)
+        self._threads.append(t)
+        t.setDaemon(True)
+        t.start()
+        return t
+        
+    def shutdown(self):
+        """shutdown all workers."""
+        self._lock.acquire()
+        self._stop = True
+        self._lock.notifyAll()
+        self._lock.release()
+
+        # wait for all threads to finish
+        for t in self._threads:
+            t.join()
 
     def addJob(self, job, allowQueuing=True):
         """
@@ -71,7 +91,7 @@
                   self._workerCount < self._maxThreads:
                 self._workerCount += 1
                 self._idleCount += 1
-                thread.start_new_thread(self._worker, ())
+                self._start_new_thread()
 
             # Hand off the job.
             if self._idleCount or allowQueuing:
@@ -88,34 +108,38 @@
         Worker thread routine. Waits for a job, executes it, repeat.
         """
         self._lock.acquire()
-        while True:
-            while not self._workQueue:
-                self._lock.wait()
-
-            # We have a job to do...
-            job = self._workQueue.pop(0)
-
-            assert self._idleCount > 0
-            self._idleCount -= 1
-
-            self._lock.release()
+        try:
+            while True:
+                while not self._workQueue and not self._stop:
+                    self._lock.wait()
+                
+                if self._stop:
+                    return
 
-            try:
-                job.run()
-            except:
-                # FIXME: This should really be reported somewhere.
-                # But we can't simply report it to stderr because of fcgi
-                pass
-
-            self._lock.acquire()
+                # We have a job to do...
+                job = self._workQueue.pop(0)
 
-            if self._idleCount == self._maxSpare:
-                break # NB: lock still held
-            self._idleCount += 1
-            assert self._idleCount <= self._maxSpare
+                assert self._idleCount > 0
+                self._idleCount -= 1
 
-        # Die off...
-        assert self._workerCount > self._maxSpare
-        self._workerCount -= 1
+                self._lock.release()
 
-        self._lock.release()
+                try:
+                    job.run()
+                except:
+                    # FIXME: This should really be reported somewhere.
+                    # But we can't simply report it to stderr because of fcgi
+                    pass
+
+                self._lock.acquire()
+
+                if self._idleCount == self._maxSpare:
+                    break # NB: lock still held
+                self._idleCount += 1
+                assert self._idleCount <= self._maxSpare
+
+            # Die off...
+            assert self._workerCount > self._maxSpare
+            self._workerCount -= 1
+        finally:
+            self._lock.release()