changeset 1659:a434ee49b5a6

uppercased modulenames below MoinMoin.server (aka 'The joy of relative imports' :), fixes wrong import for twisted server
author Thomas Waldmann <tw AT waldmann-edv DOT de>
date Wed, 01 Nov 2006 19:12:16 +0100
parents 0dee8ba737af
children 00f6b442348a
files MoinMoin/server/CGI.py MoinMoin/server/STANDALONE.py MoinMoin/server/TWISTED.py MoinMoin/server/WSGI.py MoinMoin/server/cgi.py MoinMoin/server/standalone.py MoinMoin/server/twistedmoin.py MoinMoin/server/wsgi.py moin.py wiki/server/moin.cgi wiki/server/mointwisted.py wiki/server/moinwsgi.py
diffstat 12 files changed, 958 insertions(+), 958 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/server/CGI.py	Wed Nov 01 19:12:16 2006 +0100
@@ -0,0 +1,69 @@
+# -*- coding: iso-8859-1 -*-
+"""
+    MoinMoin - CGI pseudo Server
+
+    This is not really a server, it is just so that CGI stuff (the real
+    server is likely Apache or IIS or some other std. CGI server) looks
+    similar to what we have for Twisted and standalone server.
+
+    Minimal usage:
+
+        from MoinMoin.server.CGI import CgiConfig, run
+        
+        class Config(CgiConfig):
+            pass
+
+        run(Config)
+        
+    See more options in CgiConfig class.
+
+    @copyright: 2006 MoinMoin:ThomasWaldmann
+    @license: GNU GPL, see COPYING for details.
+"""
+
+import os, sys, time, socket, errno, shutil
+
+from MoinMoin import version, wikiutil
+from MoinMoin.server import Config
+from MoinMoin.request import CGI
+
+# Server globals
+config = None
+
+# ------------------------------------------------------------------------
+# Public interface
+
+class CgiConfig(Config):
+    """ CGI default config """
+
+    name = 'moin'
+    properties = {}
+    logPath = None
+
+    # Development options
+    hotshotProfile = None # e.g. "moin.prof"
+
+
+def run(configClass):
+    """ Create and run a Cgi Request
+    
+    See CgiConfig for available options
+    
+    @param configClass: config class
+    """
+
+    config = configClass()
+
+    if config.hotshotProfile:
+        import hotshot
+        config.hotshotProfile = hotshot.Profile(config.hotshotProfile)
+        config.hotshotProfile.start()
+
+    from MoinMoin.request import CGI
+    request = CGI.Request(properties=config.properties)
+    request.run()
+
+    if config.hotshotProfile:
+        config.hotshotProfile.close()
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/server/STANDALONE.py	Wed Nov 01 19:12:16 2006 +0100
@@ -0,0 +1,586 @@
+# -*- coding: iso-8859-1 -*-
+"""
+    MoinMoin - Stand-alone HTTP Server
+
+    This is a simple, fast and very easy to install server. Its
+    recommended for personal wikis or public wikis with little load.
+
+    It is not well tested in public wikis with heavy load. In these case
+    you might want to use twisted, fast cgi or mod python, or if you
+    can't use those, cgi.
+        
+    Minimal usage:
+
+        from MoinMoin.server.STANDALONE import StandaloneConfig, run
+        
+        class Config(StandaloneConfig):
+            docs = '/usr/share/moin/wiki/htdocs'
+            user = 'www-data'
+            group = 'www-data'
+            
+        run(Config)
+        
+    See more options in StandaloneConfig class.
+
+    For security, the server will not run as root. If you try to run it
+    as root, it will run as the user and group in the config. If you run
+    it as a normal user, it will run with your regular user and group.
+
+    Significant contributions to this module by R. Church <rc@ghostbitch.org>
+
+    @copyright: 2001-2004 MoinMoin:JürgenHermann
+    @copyright: 2005      MoinMoin:AlexanderSchremmer
+    @copyright: 2005      MoinMoin:NirSoffer
+    @license: GNU GPL, see COPYING for details.
+"""
+
+import os, sys, time, socket, errno, shutil, logging
+import BaseHTTPServer, SimpleHTTPServer, SocketServer
+
+from MoinMoin import version, wikiutil
+from MoinMoin.server import Config, switchUID
+from MoinMoin.request import STANDALONE
+from MoinMoin.util import timefuncs
+
+# Server globals
+httpd = None
+config = None
+
+
+class SimpleServer(BaseHTTPServer.HTTPServer):
+    """ Simplest server, serving one request after another
+    
+    This server is good for personal wiki, or when lowest memory
+    footprint is needed.
+    """
+    use_threads = False
+
+    def __init__(self, config):
+        self.htdocs = config.docs
+        self.request_queue_size = config.requestQueueSize
+        self._abort = 0
+        address = (config.interface, config.port)
+        BaseHTTPServer.HTTPServer.__init__(self, address, MoinRequestHandler)
+
+    def server_activate(self):
+        BaseHTTPServer.HTTPServer.server_activate(self)
+        logging.info("Serving on %s:%d" % self.server_address)
+
+    def serve_forever(self):
+        """Handle one request at a time until we die """
+        while not self._abort:
+            self.handle_request()
+
+    def die(self):
+        """Abort this server instance's serving loop """
+        # Close hotshot profiler
+        if config.hotshotProfile:
+            config.hotshotProfile.close()
+
+        # Set abort flag, then make request to wake the server
+        self._abort = 1
+        try:
+            import httplib
+            addr = self.server_address
+            if not addr[0]:
+                addr = ("localhost", addr[1])
+            req = httplib.HTTP('%s:%d' % addr)
+            req.connect()
+            req.putrequest('DIE', '/')
+            req.endheaders()
+            del req
+        except socket.error, err:
+            # Ignore certain errors
+            if err.args[0] not in [errno.EADDRNOTAVAIL, ]:
+                raise
+
+
+class ThreadingServer(SimpleServer):
+    """ Serve each request in a new thread 
+    
+    This server is used since release 1.3 and seems to work nice with
+    little load.
+    
+    From release 1.3.5 there is a thread limit, that should help to
+    limit the load on the server.
+    """
+    use_threads = True
+
+    def __init__(self, config):
+        self.thread_limit = config.threadLimit
+        from threading import Condition
+        self.lock = Condition()
+        SimpleServer.__init__(self, config)
+
+    def process_request(self, request, client_address):
+        """ Start a new thread to process the request
+        
+        If the thread limit has been reached, wait on the lock. The
+        next thread will notify when finished.
+        """
+        from threading import Thread, activeCount
+        self.lock.acquire()
+        try:
+            if activeCount() > self.thread_limit:
+                self.lock.wait()
+            if self._abort:
+                return
+            t = Thread(target=self.process_request_thread,
+                       args=(request, client_address))
+            t.start()
+        finally:
+            self.lock.release()
+
+    def process_request_thread(self, request, client_address):
+        """ Called for each request on a new thread 
+        
+        Notify the main thread on the end of each request.
+        """
+        try:
+            self.finish_request(request, client_address)
+        except:
+            self.handle_error(request, client_address)
+        self.close_request(request)
+        self.lock.acquire()
+        try:
+            # Main thread might be waiting
+            self.lock.notify()
+        finally:
+            self.lock.release()
+
+
+class ThreadPoolServer(SimpleServer):
+    """ Threading server using a pool of threads 
+
+    This is a new experimental server, using a pool of threads instead
+    of creating new thread for each request. This is similar to Apache
+    worker mpm, with a simpler constant thread pool.
+
+    This server is 5 times faster than ThreadingServer for static
+    files, and about the same for wiki pages.
+    
+    TODO: sometimes the server won't exit on Conrol-C, and continue to
+    run with few threads (you can kill it with kill -9). Same problem
+    exist with the twisted server. When the problem is finally solved,
+    remove the commented debug prints.
+    """
+    use_threads = True
+
+    def __init__(self, config):
+        self.queue = []
+        # The size of the queue need more testing
+        self.queueSize = config.threadLimit * 2
+        self.poolSize = config.threadLimit
+        from threading import Condition
+        self.lock = Condition()
+        SimpleServer.__init__(self, config)
+
+    def serve_forever(self):
+        """ Create a thread pool then invoke base class method """
+        from threading import Thread
+        for i in range(self.poolSize):
+            t = Thread(target=self.serve_forever_thread)
+            t.start()
+        SimpleServer.serve_forever(self)
+
+    def process_request(self, request, client_address):
+        """ Called for each request 
+        
+        Insert the request into the queue. If the queue is full, wait
+        until one of the request threads pop a request. During the wait,
+        new connections might be dropped.
+        """
+        self.lock.acquire()
+        try:
+            if len(self.queue) >= self.queueSize:
+                self.lock.wait()
+            if self._abort:
+                return
+            self.queue.insert(0, (request, client_address))
+            self.lock.notify()
+        finally:
+            self.lock.release()
+
+    def serve_forever_thread(self):
+        """ The main loop of request threads 
+        
+        Pop a request from the queue and process it.
+        """
+        while not self._abort:
+            request, client_address = self.pop_request()
+            try:
+                self.finish_request(request, client_address)
+            except:
+                self.handle_error(request, client_address)
+            self.close_request(request)
+        # sys.stderr.write('thread exiting...\n')
+
+    def pop_request(self):
+        """ Pop a request from the queue 
+        
+        If the queue is empty, wait for notification. If the queue was
+        full, notify the main thread which may be waiting.
+        """
+        self.lock.acquire()
+        try:
+            while not self._abort:
+                try:
+                    item = self.queue.pop()
+                    if len(self.queue) == self.queueSize - 1:
+                        # Queue was full - main thread might be waiting
+                        self.lock.notify()
+                    return item
+                except IndexError:
+                    self.lock.wait()
+        finally:
+            self.lock.release()
+        # sys.stderr.write('thread exiting...\n')
+        sys.exit()
+
+    def die(self):
+        """ Wake all threads then invoke base class die
+
+        Threads should exist when _abort is True.
+        """
+        self._abort = True
+        self.wake_all_threads()
+        time.sleep(0.1)
+        SimpleServer.die(self)
+
+    def wake_all_threads(self):
+        self.lock.acquire()
+        try:
+            # sys.stderr.write('waking up all threads...\n')
+            self.lock.notifyAll()
+        finally:
+            self.lock.release()
+
+
+class ForkingServer(SocketServer.ForkingMixIn, SimpleServer):
+    """ Serve each request in a new process 
+    
+    This is new untested server, first tests show rather pathetic cgi
+    like performance. No data is cached between requests.
+    
+    The mixin has its own process limit.
+    """
+    max_children = 10
+
+
+class MoinRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
+
+    bufferSize = 8 * 1024 # used to serve static files
+    staticExpire = 365 * 24 * 3600 # 1 year expiry for static files
+
+    def __init__(self, request, client_address, server):
+        self.server_version = "MoinMoin %s %s" % (version.revision,
+                                                  server.__class__.__name__)
+        self.expires = 0
+        SimpleHTTPServer.SimpleHTTPRequestHandler.__init__(self, request,
+            client_address, server)
+
+    def log_message(self, format, *args):
+        logging.info("%s %s" % (self.address_string(), format % args))
+
+    # -------------------------------------------------------------------
+    # do_METHOD dispatchers - called for each request
+
+    def do_DIE(self):
+        if self.server._abort:
+            self.log_error("Shutting down")
+
+    def do_ALL(self):
+        """ Handle requests (request type GET/HEAD/POST is in self.command)
+
+        Separate between wiki pages and css and image url by similar
+        system as cgi and twisted, the url_prefix_static prefix.
+        """
+        prefix = config.url_prefix_static
+        if self.path.startswith(prefix + '/'):
+            self.path = self.path[len(prefix):]
+            self.serve_static_file()
+        elif self.path in ['/favicon.ico', '/robots.txt']:
+            self.serve_static_file()
+        else:
+            self.serve_moin()
+
+    do_POST = do_ALL
+    do_GET = do_ALL
+    do_HEAD = do_ALL
+
+    # -------------------------------------------------------------------    
+    # Serve methods
+
+    def serve_static_file(self):
+        """ Serve files from the htdocs directory """
+        self.expires = self.staticExpire
+        path = self.path.split("?", 1)
+        if len(path) > 1:
+            self.path = path[0] # XXX ?params
+
+        try:
+            fn = getattr(SimpleHTTPServer.SimpleHTTPRequestHandler, 'do_' + self.command)
+            fn(self)
+        except socket.error, err:
+            # Ignore certain errors
+            if err.args[0] not in [errno.EPIPE, errno.ECONNABORTED]:
+                raise
+
+    def serve_moin(self):
+        """ Serve a request using moin """
+        # don't make an Expires header for wiki pages
+        self.expires = 0
+
+        try:
+            req = STANDALONE.Request(self, properties=config.properties)
+            req.run()
+        except socket.error, err:
+            # Ignore certain errors
+            if err.args[0] not in [errno.EPIPE, errno.ECONNABORTED]:
+                raise
+
+    def translate_path(self, uri):
+        """ Translate a /-separated PATH to the local filename syntax.
+
+        Components that mean special things to the local file system
+        (e.g. drive or directory names) are ignored.
+        """
+        file = wikiutil.url_unquote(uri, want_unicode=False)
+        file.replace('\\', '/')
+        words = file.split('/')
+        words = filter(None, words)
+
+        path = self.server.htdocs
+        bad_uri = 0
+        for word in words:
+            drive, word = os.path.splitdrive(word)
+            if drive:
+                bad_uri = 1
+            head, word = os.path.split(word)
+            if word in (os.curdir, os.pardir):
+                bad_uri = 1
+                continue
+            path = os.path.join(path, word)
+
+        if bad_uri:
+            self.log_error("Detected bad request URI '%s', translated to '%s'"
+                           % (uri, path,))
+        return path
+
+    def end_headers(self):
+        """overload the default end_headers, inserting expires header"""
+        if self.expires:
+            now = time.time()
+            expires = now + self.expires
+            self.send_header('Expires', timefuncs.formathttpdate(expires))
+        SimpleHTTPServer.SimpleHTTPRequestHandler.end_headers(self)
+
+    def copyfile(self, source, outputfile):
+        """Copy all data between two file objects.
+        
+        Modify the base class method to change the buffer size. Test
+        shows that for the typical static files we serve, 8K buffer is
+        faster than the default 16K buffer.
+        """
+        shutil.copyfileobj(source, outputfile, length=self.bufferSize)
+
+
+try:
+    from tlslite.api import TLSSocketServerMixIn, X509, X509CertChain, SessionCache, parsePEMKey, TLSError
+    from tlslite.TLSConnection import TLSConnection
+except ImportError:
+    pass
+else:
+    class SecureRequestRedirect(BaseHTTPServer.BaseHTTPRequestHandler):
+        def handle(self):
+            self.close_connection = 1
+            try:
+                self.raw_requestline = self.rfile.readline()
+            except socket.error:
+                return
+            if self.parse_request():
+                host = self.headers.get('Host', socket.gethostname())
+                path = self.path
+            else:
+                host = '%s:%s' % (socket.gethostname(),
+                        self.request.getsockname()[1])
+                path = '/'
+
+            self.requestline = 'ERROR: Redirecting to https://%s%s' % (host, path)
+            self.request_version = 'HTTP/1.1'
+            self.command = 'GET'
+            self.send_response(301, 'Document Moved')
+            self.send_header('Date', self.date_time_string())
+            self.send_header('Location', 'https://%s%s' % (host, path))
+            self.send_header('Connection', 'close')
+            self.send_header('Content-Length', '0')
+            self.wfile.write('\r\n')
+
+    class SecureThreadPoolServer(TLSSocketServerMixIn, ThreadPoolServer):
+        def __init__(self, config):
+            ThreadPoolServer.__init__(self, config)
+
+            cert = open(config.ssl_certificate).read()
+            x509 = X509()
+            x509.parse(cert)
+            self.certChain = X509CertChain([x509])
+
+            priv = open(config.ssl_privkey).read()
+            self.privateKey = parsePEMKey(priv, private=True)
+
+            self.sessionCache = SessionCache()
+
+        def finish_request(self, sock, client_address):
+            # Peek into the packet, if it starts with GET or POS(T) then
+            # redirect, otherwise let TLSLite handle the connection.
+            peek = sock.recv(3, socket.MSG_PEEK).lower()
+            if peek == 'get' or peek == 'pos':
+                SecureRequestRedirect(sock, client_address, self)
+                return
+            tls_connection = TLSConnection(sock)
+            if self.handshake(tls_connection):
+                self.RequestHandlerClass(tls_connection, client_address, self)
+            else:
+                # This will probably fail because the TLSConnection has 
+                # already written SSL stuff to the socket. But not sure what
+                # else we should do.
+                SecureRequestRedirect(sock, client_address, self)
+
+        def handshake(self, tls_connection):
+            try:
+                tls_connection.handshakeServer(certChain=self.certChain,
+                                               privateKey=self.privateKey,
+                                               sessionCache=self.sessionCache)
+                tls_connection.ignoreAbruptClose = True
+                return True
+            except:
+                return False
+
+
+def memoryProfileDecorator(func, profile):
+    """ Return a profiled function """
+    def profiledFunction(*args, **kw):
+        profile.addRequest()
+        return func(*args, **kw)
+    return profiledFunction
+
+
+def hotshotProfileDecorator(func, profile):
+    """ Return a profiled function """
+    profile.moin_requests_done = 0
+    def profiledFunction(*args, **kw):
+        profile.moin_requests_done += 1
+        if profile.moin_requests_done == 1:
+            # Don't profile first request, its not interesting
+            return func(*args, **kw)
+        return profile.runcall(func, *args, **kw)
+
+    return profiledFunction
+
+
+def quit(signo, stackframe):
+    """ Signal handler for aborting signals """
+    global httpd
+    logging.info("Thanks for using MoinMoin!")
+    if httpd:
+        httpd.die()
+
+
+def registerSignalHandlers(func):
+    """ Register signal handlers on platforms that support it """
+    try:
+        import signal
+        signal.signal(signal.SIGABRT, func)
+        signal.signal(signal.SIGINT, func)
+        signal.signal(signal.SIGTERM, func)
+    except ImportError:
+        pass
+
+
+def makeServer(config):
+    """ Create a new server, based on the the platform capabilities 
+    
+    Try to create the server class specified in the config. If threads
+    are not available, fallback to ForkingServer. If fork is not
+    available, fallback to a SimpleServer.
+    """
+    serverClass = globals()[config.serverClass]
+    if serverClass.use_threads:
+        try:
+            import threading
+        except ImportError:
+            serverClass = ForkingServer
+    if serverClass is ForkingServer and not hasattr(os, "fork"):
+        serverClass = SimpleServer
+    if serverClass.__name__ != config.serverClass:
+        logging.error('%s is not available on this platform, falling back '
+                      'to %s\n' % (config.serverClass, serverClass.__name__))
+
+    from MoinMoin import config as _config
+    _config.use_threads = serverClass.use_threads
+    return serverClass(config)
+
+# ------------------------------------------------------------------------
+# Public interface
+
+class StandaloneConfig(Config):
+    """ Standalone server default config """
+
+    name = 'moin'
+    properties = {}
+    docs = '/usr/share/moin/htdocs'
+    user = 'www-data'
+    group = 'www-data'
+    port = 8000
+    interface = 'localhost'
+    logPath = None
+
+    # Advanced options
+    serverClass = 'ThreadPoolServer'
+    threadLimit = 10
+    # The size of the listen backlog. Twisted uses a default of 50.
+    # Tests on Mac OS X show many failed request with backlog of 5 or 10.
+    requestQueueSize = 50
+
+    # Development options
+    memoryProfile = None
+    hotshotProfile = None
+
+
+def run(configClass):
+    """ Create and run a moin server
+    
+    See StandaloneConfig for available options
+    
+    @param configClass: config class
+    """
+    # Run only once!
+    global httpd, config
+    if httpd is not None:
+        raise RuntimeError("You can run only one server per process!")
+
+    config = configClass()
+
+    # Install hotshot profiled serve_moin method. To compare with other
+    # servers, we profile the part that create and run the request.
+    if config.hotshotProfile:
+        import hotshot
+        config.hotshotProfile = hotshot.Profile(config.hotshotProfile)
+        MoinRequestHandler.serve_moin = hotshotProfileDecorator(
+            MoinRequestHandler.serve_moin, config.hotshotProfile)
+
+    # Install a memory profiled serve_moin method
+    if config.memoryProfile:
+        config.memoryProfile.sample()
+        MoinRequestHandler.serve_moin = memoryProfileDecorator(
+            MoinRequestHandler.serve_moin, config.memoryProfile)
+
+    registerSignalHandlers(quit)
+    httpd = makeServer(config)
+
+    # Run as a safe user (posix only)
+    if os.name == 'posix' and os.getuid() == 0:
+        switchUID(config.uid, config.gid)
+
+    httpd.serve_forever()
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/server/TWISTED.py	Wed Nov 01 19:12:16 2006 +0100
@@ -0,0 +1,284 @@
+# -*- coding: iso-8859-1 -*-
+"""
+    MoinMoin.server.twistedmoin
+
+    Create standalone twisted based server.
+
+    Minimal usage:
+
+        from MoinMoin.server.TWISTED import TwistedConfig, makeApp
+        
+        class Config(TwistedConfig):
+            docs = '/usr/share/moin/wiki/htdocs'
+            user = 'www-data'
+            group = 'www-data'
+            
+        application = makeApp(Config)
+
+    Then run this code with twistd -y yourcode.py. See moin_twisted script.
+
+    @copyright: 2004 by Thomas Waldmann, Oliver Graf, Nir Soffer
+    @license: GNU GPL, see COPYING for details.
+"""
+
+from twisted.application import internet, service
+from twisted.web import script, static, server, vhost, resource, util
+from twisted.internet import threads, reactor
+
+try:
+    from twisted.internet import ssl
+except ImportError:
+    ssl = None
+
+# Enable threads
+from twisted.python import threadable
+threadable.init(1)
+
+# MoinMoin imports
+from MoinMoin.request import TWISTED
+from MoinMoin.server import Config
+
+# Set threads flag, so other code can use proper locking
+from MoinMoin import config
+config.use_threads = True
+del config
+
+# Server globals
+config = None
+
+
+class WikiResource(resource.Resource):
+    """ Wiki resource """
+    isLeaf = 1
+
+    def render(self, request):
+        return server.NOT_DONE_YET
+
+
+class WikiRoot(resource.Resource):
+    """ Wiki root resource """
+
+    def getChild(self, name, request):
+        # Serve images and css from url_prefix_static
+        if request.prepath == [] and name == config.url_prefix_static[1:]:
+            return resource.Resource.getChild(self, name, request)
+
+        # Serve special 'root' files from url_prefix_static
+        elif name in ['favicon.ico', 'robots.txt'] and request.postpath == []:
+            return self.children[config.url_prefix_static[1:]].getChild(name, request)
+
+        # All other through moin
+
+        # TODO: fix profile code to include the request init and ignore
+        # first request. I'm not doing this now since its better done
+        # with the new twisted code waiting in fix branch. --Nir
+        else:
+            if config.memoryProfile:
+                config.memoryProfile.addRequest()
+            req = TWISTED.Request(request, name, reactor, properties=config.properties)
+            if config.hotshotProfile:
+                threads.deferToThread(config.hotshotProfile.runcall, req.run)
+            else:
+                threads.deferToThread(req.run)
+            return WikiResource()
+
+
+class MoinRequest(server.Request):
+    """ MoinMoin request
+
+    Enable passing of file-upload filenames
+    """
+
+    def requestReceived(self, command, path, version):
+        """ Called by channel when all data has been received.
+
+        Override server.Request method for POST requests, to fix file
+        uploads issue.
+        """
+        if command == 'POST':
+            self.requestReceivedPOST(path, version)
+        else:
+            server.Request.requestReceived(self, command, path, version)
+
+    def requestReceivedPOST(self, path, version):
+        """ Handle POST requests
+
+        This is a modified copy of server.Request.requestRecived,
+        modified to use cgi.FieldStorage to handle file uploads
+        correctly.
+
+        Creates an extra member extended_args which also has
+        filenames of file uploads ( FIELDNAME__filename__ ).
+        """
+        import cgi
+
+        self.content.seek(0, 0)
+        self.args = {}
+        self.extended_args = {}
+        self.stack = []
+
+        self.method = 'POST'
+        self.uri = path
+        self.clientproto = version
+        x = self.uri.split('?')
+
+        argstring = ""
+        if len(x) == 1:
+            self.path = self.uri
+        else:
+            if len(x) != 2:
+                from twisted.python import log
+                log.msg("May ignore parts of this invalid URI: %s"
+                        % repr(self.uri))
+            self.path, argstring = x[0], x[1]
+
+        # cache the client and server information, we'll need this later to be
+        # serialized and sent with the request so CGIs will work remotely
+        self.client = self.channel.transport.getPeer()
+        self.host = self.channel.transport.getHost()
+
+        # create dummy env for cgi.FieldStorage
+        env = {
+            'REQUEST_METHOD': self.method,
+            'QUERY_STRING': argstring,
+            }
+        form = cgi.FieldStorage(fp=self.content,
+                                environ=env,
+                                headers=self.received_headers)
+
+        # Argument processing
+
+        args = self.args
+        try:
+            keys = form.keys()
+        except TypeError:
+            pass
+        else:
+            for key in keys:
+                values = form[key]
+                if not isinstance(values, list):
+                    values = [values]
+                fixedResult = []
+                for i in values:
+                    if isinstance(i, cgi.MiniFieldStorage):
+                        fixedResult.append(i.value)
+                    elif isinstance(i, cgi.FieldStorage):
+                        fixedResult.append(i.value)
+                        # multiple uploads to same form field are stupid!
+                        if i.filename:
+                            args[key + '__filename__'] = i.filename
+                args[key] = fixedResult
+
+        self.process()
+
+
+class MoinSite(server.Site):
+    """ Moin site """
+    requestFactory = MoinRequest
+
+    def startFactory(self):
+        """ Setup before starting """
+        # Memory profile
+        if config.memoryProfile:
+            config.memoryProfile.sample()
+
+        # hotshot profile
+        if config.hotshotProfile:
+            import hotshot
+            config.hotshotProfile = hotshot.Profile(config.hotshotProfile)
+        server.Site.startFactory(self)
+
+    def stopFactory(self):
+        """ Cleaup before stoping """
+        server.Site.stopFactory(self)
+        if config.hotshotProfile:
+            config.hotshotProfile.close()
+
+
+class TwistedConfig(Config):
+    """ Twisted server default config """
+
+    name = 'mointwisted'
+    properties = {}
+    docs = '/usr/share/moin/htdocs'
+    user = 'www-data'
+    group = 'www-data'
+    port = 8080
+    interfaces = ['']
+    threads = 10
+    logPath = None # moin log file
+    logPath_twisted = None # Twisted log file
+    virtualHosts = None
+    memoryProfile = None
+    hotshotProfile = None
+
+    # sslcert = ('/whereever/cert/sitekey.pem', '/whereever/cert/sitecert.pem')
+    sslcert = None
+
+    def __init__(self):
+        Config.__init__(self)
+
+        # Check for '' in interfaces, then ignore other
+        if '' in self.interfaces:
+            self.interfaces = ['']
+
+
+def makeApp(ConfigClass):
+    """ Generate and return an application
+
+    See MoinMoin.server.Config for config options
+
+    @param ConfigClass: config class
+    @rtype: application object
+    @return twisted application, needed by twistd
+    """
+    # Create config instance (raise RuntimeError if config invalid)
+    global config
+    config = ConfigClass()
+
+    # Set number of threads
+    reactor.suggestThreadPoolSize(config.threads)
+
+    # The root of the HTTP hierarchy
+    default = WikiRoot()
+
+    # Here is where img and css and some special files come from
+    default.putChild(config.url_prefix_static[1:], static.File(config.docs))
+
+    # Generate the Site factory
+    # TODO: Maybe we can use WikiRoot instead of this
+    # ----------------------------------------------
+    root = vhost.NameVirtualHost()
+    root.default = default
+    # ----------------------------------------------
+    site = MoinSite(root, logPath=config.logPath_twisted, timeout=2*60) # 2 minutes timeout
+
+    # Make application
+    application = service.Application("web", uid=config.uid, gid=config.gid)
+    sc = service.IServiceCollection(application)
+
+    # Listen to all interfaces in config.interfaces
+    for entry in config.interfaces:
+        # Add a TCPServer for each interface.
+
+        # This is an hidden experimantal feature: each entry in
+        # interface may contain a port, using 'ip:port'.
+        # Note: the format is subject to change!
+        try:
+            interface, port = entry.split(':', 1)
+        except ValueError:
+            interface, port = entry, config.port
+
+        # Might raise ValueError if not integer.
+        # TODO: check if we can use string port, like 'http'
+        port = int(port)
+
+        if port == 443 and ssl and ssl.supported and config.sslcert:
+            sslContext = ssl.DefaultOpenSSLContextFactory(*config.sslcert)
+            s = internet.SSLServer(port, site, sslContext, interface=interface)
+        else:
+            s = internet.TCPServer(port, site, interface=interface)
+        s.setServiceParent(sc)
+
+    return application
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/server/WSGI.py	Wed Nov 01 19:12:16 2006 +0100
@@ -0,0 +1,15 @@
+"""
+    MoinMoin - WSGI application
+
+    @copyright: 2005 by Anakim Border <akborder@gmail.com>
+    @license: GNU GPL, see COPYING for details.
+"""
+
+from MoinMoin.request import WSGI
+
+def moinmoinApp(environ, start_response):
+    request = WSGI.Request(environ)
+    request.run()
+    start_response(request.status, request.headers)
+    return [request.output()]
+
--- a/MoinMoin/server/cgi.py	Wed Nov 01 17:49:27 2006 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-    MoinMoin - CGI pseudo Server
-
-    This is not really a server, it is just so that CGI stuff (the real
-    server is likely Apache or IIS or some other std. CGI server) looks
-    similar to what we have for Twisted and standalone server.
-
-    Minimal usage:
-
-        from MoinMoin.server.cgi import CgiConfig, run
-        
-        class Config(CgiConfig):
-            pass
-
-        run(Config)
-        
-    See more options in CgiConfig class.
-
-    @copyright: 2006 MoinMoin:ThomasWaldmann
-    @license: GNU GPL, see COPYING for details.
-"""
-
-import os, sys, time, socket, errno, shutil
-
-from MoinMoin import version, wikiutil
-from MoinMoin.server import Config
-from MoinMoin.request import CGI
-
-# Server globals
-config = None
-
-# ------------------------------------------------------------------------
-# Public interface
-
-class CgiConfig(Config):
-    """ CGI default config """
-
-    name = 'moin'
-    properties = {}
-    logPath = None
-
-    # Development options
-    hotshotProfile = None # e.g. "moin.prof"
-
-
-def run(configClass):
-    """ Create and run a Cgi Request
-    
-    See CgiConfig for available options
-    
-    @param configClass: config class
-    """
-
-    config = configClass()
-
-    if config.hotshotProfile:
-        import hotshot
-        config.hotshotProfile = hotshot.Profile(config.hotshotProfile)
-        config.hotshotProfile.start()
-
-    from MoinMoin.request import CGI
-    request = CGI.Request(properties=config.properties)
-    request.run()
-
-    if config.hotshotProfile:
-        config.hotshotProfile.close()
-
-
--- a/MoinMoin/server/standalone.py	Wed Nov 01 17:49:27 2006 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,586 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-    MoinMoin - Stand-alone HTTP Server
-
-    This is a simple, fast and very easy to install server. Its
-    recommended for personal wikis or public wikis with little load.
-
-    It is not well tested in public wikis with heavy load. In these case
-    you might want to use twisted, fast cgi or mod python, or if you
-    can't use those, cgi.
-        
-    Minimal usage:
-
-        from MoinMoin.server.standalone import StandaloneConfig, run
-        
-        class Config(StandaloneConfig):
-            docs = '/usr/share/moin/wiki/htdocs'
-            user = 'www-data'
-            group = 'www-data'
-            
-        run(Config)
-        
-    See more options in StandaloneConfig class.
-
-    For security, the server will not run as root. If you try to run it
-    as root, it will run as the user and group in the config. If you run
-    it as a normal user, it will run with your regular user and group.
-
-    Significant contributions to this module by R. Church <rc@ghostbitch.org>
-
-    @copyright: 2001-2004 MoinMoin:JürgenHermann
-    @copyright: 2005      MoinMoin:AlexanderSchremmer
-    @copyright: 2005      MoinMoin:NirSoffer
-    @license: GNU GPL, see COPYING for details.
-"""
-
-import os, sys, time, socket, errno, shutil, logging
-import BaseHTTPServer, SimpleHTTPServer, SocketServer
-
-from MoinMoin import version, wikiutil
-from MoinMoin.server import Config, switchUID
-from MoinMoin.request import STANDALONE
-from MoinMoin.util import timefuncs
-
-# Server globals
-httpd = None
-config = None
-
-
-class SimpleServer(BaseHTTPServer.HTTPServer):
-    """ Simplest server, serving one request after another
-    
-    This server is good for personal wiki, or when lowest memory
-    footprint is needed.
-    """
-    use_threads = False
-
-    def __init__(self, config):
-        self.htdocs = config.docs
-        self.request_queue_size = config.requestQueueSize
-        self._abort = 0
-        address = (config.interface, config.port)
-        BaseHTTPServer.HTTPServer.__init__(self, address, MoinRequestHandler)
-
-    def server_activate(self):
-        BaseHTTPServer.HTTPServer.server_activate(self)
-        logging.info("Serving on %s:%d" % self.server_address)
-
-    def serve_forever(self):
-        """Handle one request at a time until we die """
-        while not self._abort:
-            self.handle_request()
-
-    def die(self):
-        """Abort this server instance's serving loop """
-        # Close hotshot profiler
-        if config.hotshotProfile:
-            config.hotshotProfile.close()
-
-        # Set abort flag, then make request to wake the server
-        self._abort = 1
-        try:
-            import httplib
-            addr = self.server_address
-            if not addr[0]:
-                addr = ("localhost", addr[1])
-            req = httplib.HTTP('%s:%d' % addr)
-            req.connect()
-            req.putrequest('DIE', '/')
-            req.endheaders()
-            del req
-        except socket.error, err:
-            # Ignore certain errors
-            if err.args[0] not in [errno.EADDRNOTAVAIL, ]:
-                raise
-
-
-class ThreadingServer(SimpleServer):
-    """ Serve each request in a new thread 
-    
-    This server is used since release 1.3 and seems to work nice with
-    little load.
-    
-    From release 1.3.5 there is a thread limit, that should help to
-    limit the load on the server.
-    """
-    use_threads = True
-
-    def __init__(self, config):
-        self.thread_limit = config.threadLimit
-        from threading import Condition
-        self.lock = Condition()
-        SimpleServer.__init__(self, config)
-
-    def process_request(self, request, client_address):
-        """ Start a new thread to process the request
-        
-        If the thread limit has been reached, wait on the lock. The
-        next thread will notify when finished.
-        """
-        from threading import Thread, activeCount
-        self.lock.acquire()
-        try:
-            if activeCount() > self.thread_limit:
-                self.lock.wait()
-            if self._abort:
-                return
-            t = Thread(target=self.process_request_thread,
-                       args=(request, client_address))
-            t.start()
-        finally:
-            self.lock.release()
-
-    def process_request_thread(self, request, client_address):
-        """ Called for each request on a new thread 
-        
-        Notify the main thread on the end of each request.
-        """
-        try:
-            self.finish_request(request, client_address)
-        except:
-            self.handle_error(request, client_address)
-        self.close_request(request)
-        self.lock.acquire()
-        try:
-            # Main thread might be waiting
-            self.lock.notify()
-        finally:
-            self.lock.release()
-
-
-class ThreadPoolServer(SimpleServer):
-    """ Threading server using a pool of threads 
-
-    This is a new experimental server, using a pool of threads instead
-    of creating new thread for each request. This is similar to Apache
-    worker mpm, with a simpler constant thread pool.
-
-    This server is 5 times faster than ThreadingServer for static
-    files, and about the same for wiki pages.
-    
-    TODO: sometimes the server won't exit on Conrol-C, and continue to
-    run with few threads (you can kill it with kill -9). Same problem
-    exist with the twisted server. When the problem is finally solved,
-    remove the commented debug prints.
-    """
-    use_threads = True
-
-    def __init__(self, config):
-        self.queue = []
-        # The size of the queue need more testing
-        self.queueSize = config.threadLimit * 2
-        self.poolSize = config.threadLimit
-        from threading import Condition
-        self.lock = Condition()
-        SimpleServer.__init__(self, config)
-
-    def serve_forever(self):
-        """ Create a thread pool then invoke base class method """
-        from threading import Thread
-        for i in range(self.poolSize):
-            t = Thread(target=self.serve_forever_thread)
-            t.start()
-        SimpleServer.serve_forever(self)
-
-    def process_request(self, request, client_address):
-        """ Called for each request 
-        
-        Insert the request into the queue. If the queue is full, wait
-        until one of the request threads pop a request. During the wait,
-        new connections might be dropped.
-        """
-        self.lock.acquire()
-        try:
-            if len(self.queue) >= self.queueSize:
-                self.lock.wait()
-            if self._abort:
-                return
-            self.queue.insert(0, (request, client_address))
-            self.lock.notify()
-        finally:
-            self.lock.release()
-
-    def serve_forever_thread(self):
-        """ The main loop of request threads 
-        
-        Pop a request from the queue and process it.
-        """
-        while not self._abort:
-            request, client_address = self.pop_request()
-            try:
-                self.finish_request(request, client_address)
-            except:
-                self.handle_error(request, client_address)
-            self.close_request(request)
-        # sys.stderr.write('thread exiting...\n')
-
-    def pop_request(self):
-        """ Pop a request from the queue 
-        
-        If the queue is empty, wait for notification. If the queue was
-        full, notify the main thread which may be waiting.
-        """
-        self.lock.acquire()
-        try:
-            while not self._abort:
-                try:
-                    item = self.queue.pop()
-                    if len(self.queue) == self.queueSize - 1:
-                        # Queue was full - main thread might be waiting
-                        self.lock.notify()
-                    return item
-                except IndexError:
-                    self.lock.wait()
-        finally:
-            self.lock.release()
-        # sys.stderr.write('thread exiting...\n')
-        sys.exit()
-
-    def die(self):
-        """ Wake all threads then invoke base class die
-
-        Threads should exist when _abort is True.
-        """
-        self._abort = True
-        self.wake_all_threads()
-        time.sleep(0.1)
-        SimpleServer.die(self)
-
-    def wake_all_threads(self):
-        self.lock.acquire()
-        try:
-            # sys.stderr.write('waking up all threads...\n')
-            self.lock.notifyAll()
-        finally:
-            self.lock.release()
-
-
-class ForkingServer(SocketServer.ForkingMixIn, SimpleServer):
-    """ Serve each request in a new process 
-    
-    This is new untested server, first tests show rather pathetic cgi
-    like performance. No data is cached between requests.
-    
-    The mixin has its own process limit.
-    """
-    max_children = 10
-
-
-class MoinRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
-
-    bufferSize = 8 * 1024 # used to serve static files
-    staticExpire = 365 * 24 * 3600 # 1 year expiry for static files
-
-    def __init__(self, request, client_address, server):
-        self.server_version = "MoinMoin %s %s" % (version.revision,
-                                                  server.__class__.__name__)
-        self.expires = 0
-        SimpleHTTPServer.SimpleHTTPRequestHandler.__init__(self, request,
-            client_address, server)
-
-    def log_message(self, format, *args):
-        logging.info("%s %s" % (self.address_string(), format % args))
-
-    # -------------------------------------------------------------------
-    # do_METHOD dispatchers - called for each request
-
-    def do_DIE(self):
-        if self.server._abort:
-            self.log_error("Shutting down")
-
-    def do_ALL(self):
-        """ Handle requests (request type GET/HEAD/POST is in self.command)
-
-        Separate between wiki pages and css and image url by similar
-        system as cgi and twisted, the url_prefix_static prefix.
-        """
-        prefix = config.url_prefix_static
-        if self.path.startswith(prefix + '/'):
-            self.path = self.path[len(prefix):]
-            self.serve_static_file()
-        elif self.path in ['/favicon.ico', '/robots.txt']:
-            self.serve_static_file()
-        else:
-            self.serve_moin()
-
-    do_POST = do_ALL
-    do_GET = do_ALL
-    do_HEAD = do_ALL
-
-    # -------------------------------------------------------------------    
-    # Serve methods
-
-    def serve_static_file(self):
-        """ Serve files from the htdocs directory """
-        self.expires = self.staticExpire
-        path = self.path.split("?", 1)
-        if len(path) > 1:
-            self.path = path[0] # XXX ?params
-
-        try:
-            fn = getattr(SimpleHTTPServer.SimpleHTTPRequestHandler, 'do_' + self.command)
-            fn(self)
-        except socket.error, err:
-            # Ignore certain errors
-            if err.args[0] not in [errno.EPIPE, errno.ECONNABORTED]:
-                raise
-
-    def serve_moin(self):
-        """ Serve a request using moin """
-        # don't make an Expires header for wiki pages
-        self.expires = 0
-
-        try:
-            req = STANDALONE.Request(self, properties=config.properties)
-            req.run()
-        except socket.error, err:
-            # Ignore certain errors
-            if err.args[0] not in [errno.EPIPE, errno.ECONNABORTED]:
-                raise
-
-    def translate_path(self, uri):
-        """ Translate a /-separated PATH to the local filename syntax.
-
-        Components that mean special things to the local file system
-        (e.g. drive or directory names) are ignored.
-        """
-        file = wikiutil.url_unquote(uri, want_unicode=False)
-        file.replace('\\', '/')
-        words = file.split('/')
-        words = filter(None, words)
-
-        path = self.server.htdocs
-        bad_uri = 0
-        for word in words:
-            drive, word = os.path.splitdrive(word)
-            if drive:
-                bad_uri = 1
-            head, word = os.path.split(word)
-            if word in (os.curdir, os.pardir):
-                bad_uri = 1
-                continue
-            path = os.path.join(path, word)
-
-        if bad_uri:
-            self.log_error("Detected bad request URI '%s', translated to '%s'"
-                           % (uri, path,))
-        return path
-
-    def end_headers(self):
-        """overload the default end_headers, inserting expires header"""
-        if self.expires:
-            now = time.time()
-            expires = now + self.expires
-            self.send_header('Expires', timefuncs.formathttpdate(expires))
-        SimpleHTTPServer.SimpleHTTPRequestHandler.end_headers(self)
-
-    def copyfile(self, source, outputfile):
-        """Copy all data between two file objects.
-        
-        Modify the base class method to change the buffer size. Test
-        shows that for the typical static files we serve, 8K buffer is
-        faster than the default 16K buffer.
-        """
-        shutil.copyfileobj(source, outputfile, length=self.bufferSize)
-
-
-try:
-    from tlslite.api import TLSSocketServerMixIn, X509, X509CertChain, SessionCache, parsePEMKey, TLSError
-    from tlslite.TLSConnection import TLSConnection
-except ImportError:
-    pass
-else:
-    class SecureRequestRedirect(BaseHTTPServer.BaseHTTPRequestHandler):
-        def handle(self):
-            self.close_connection = 1
-            try:
-                self.raw_requestline = self.rfile.readline()
-            except socket.error:
-                return
-            if self.parse_request():
-                host = self.headers.get('Host', socket.gethostname())
-                path = self.path
-            else:
-                host = '%s:%s' % (socket.gethostname(),
-                        self.request.getsockname()[1])
-                path = '/'
-
-            self.requestline = 'ERROR: Redirecting to https://%s%s' % (host, path)
-            self.request_version = 'HTTP/1.1'
-            self.command = 'GET'
-            self.send_response(301, 'Document Moved')
-            self.send_header('Date', self.date_time_string())
-            self.send_header('Location', 'https://%s%s' % (host, path))
-            self.send_header('Connection', 'close')
-            self.send_header('Content-Length', '0')
-            self.wfile.write('\r\n')
-
-    class SecureThreadPoolServer(TLSSocketServerMixIn, ThreadPoolServer):
-        def __init__(self, config):
-            ThreadPoolServer.__init__(self, config)
-
-            cert = open(config.ssl_certificate).read()
-            x509 = X509()
-            x509.parse(cert)
-            self.certChain = X509CertChain([x509])
-
-            priv = open(config.ssl_privkey).read()
-            self.privateKey = parsePEMKey(priv, private=True)
-
-            self.sessionCache = SessionCache()
-
-        def finish_request(self, sock, client_address):
-            # Peek into the packet, if it starts with GET or POS(T) then
-            # redirect, otherwise let TLSLite handle the connection.
-            peek = sock.recv(3, socket.MSG_PEEK).lower()
-            if peek == 'get' or peek == 'pos':
-                SecureRequestRedirect(sock, client_address, self)
-                return
-            tls_connection = TLSConnection(sock)
-            if self.handshake(tls_connection):
-                self.RequestHandlerClass(tls_connection, client_address, self)
-            else:
-                # This will probably fail because the TLSConnection has 
-                # already written SSL stuff to the socket. But not sure what
-                # else we should do.
-                SecureRequestRedirect(sock, client_address, self)
-
-        def handshake(self, tls_connection):
-            try:
-                tls_connection.handshakeServer(certChain=self.certChain,
-                                               privateKey=self.privateKey,
-                                               sessionCache=self.sessionCache)
-                tls_connection.ignoreAbruptClose = True
-                return True
-            except:
-                return False
-
-
-def memoryProfileDecorator(func, profile):
-    """ Return a profiled function """
-    def profiledFunction(*args, **kw):
-        profile.addRequest()
-        return func(*args, **kw)
-    return profiledFunction
-
-
-def hotshotProfileDecorator(func, profile):
-    """ Return a profiled function """
-    profile.moin_requests_done = 0
-    def profiledFunction(*args, **kw):
-        profile.moin_requests_done += 1
-        if profile.moin_requests_done == 1:
-            # Don't profile first request, its not interesting
-            return func(*args, **kw)
-        return profile.runcall(func, *args, **kw)
-
-    return profiledFunction
-
-
-def quit(signo, stackframe):
-    """ Signal handler for aborting signals """
-    global httpd
-    logging.info("Thanks for using MoinMoin!")
-    if httpd:
-        httpd.die()
-
-
-def registerSignalHandlers(func):
-    """ Register signal handlers on platforms that support it """
-    try:
-        import signal
-        signal.signal(signal.SIGABRT, func)
-        signal.signal(signal.SIGINT, func)
-        signal.signal(signal.SIGTERM, func)
-    except ImportError:
-        pass
-
-
-def makeServer(config):
-    """ Create a new server, based on the the platform capabilities 
-    
-    Try to create the server class specified in the config. If threads
-    are not available, fallback to ForkingServer. If fork is not
-    available, fallback to a SimpleServer.
-    """
-    serverClass = globals()[config.serverClass]
-    if serverClass.use_threads:
-        try:
-            import threading
-        except ImportError:
-            serverClass = ForkingServer
-    if serverClass is ForkingServer and not hasattr(os, "fork"):
-        serverClass = SimpleServer
-    if serverClass.__name__ != config.serverClass:
-        logging.error('%s is not available on this platform, falling back '
-                      'to %s\n' % (config.serverClass, serverClass.__name__))
-
-    from MoinMoin import config as _config
-    _config.use_threads = serverClass.use_threads
-    return serverClass(config)
-
-# ------------------------------------------------------------------------
-# Public interface
-
-class StandaloneConfig(Config):
-    """ Standalone server default config """
-
-    name = 'moin'
-    properties = {}
-    docs = '/usr/share/moin/htdocs'
-    user = 'www-data'
-    group = 'www-data'
-    port = 8000
-    interface = 'localhost'
-    logPath = None
-
-    # Advanced options
-    serverClass = 'ThreadPoolServer'
-    threadLimit = 10
-    # The size of the listen backlog. Twisted uses a default of 50.
-    # Tests on Mac OS X show many failed request with backlog of 5 or 10.
-    requestQueueSize = 50
-
-    # Development options
-    memoryProfile = None
-    hotshotProfile = None
-
-
-def run(configClass):
-    """ Create and run a moin server
-    
-    See StandaloneConfig for available options
-    
-    @param configClass: config class
-    """
-    # Run only once!
-    global httpd, config
-    if httpd is not None:
-        raise RuntimeError("You can run only one server per process!")
-
-    config = configClass()
-
-    # Install hotshot profiled serve_moin method. To compare with other
-    # servers, we profile the part that create and run the request.
-    if config.hotshotProfile:
-        import hotshot
-        config.hotshotProfile = hotshot.Profile(config.hotshotProfile)
-        MoinRequestHandler.serve_moin = hotshotProfileDecorator(
-            MoinRequestHandler.serve_moin, config.hotshotProfile)
-
-    # Install a memory profiled serve_moin method
-    if config.memoryProfile:
-        config.memoryProfile.sample()
-        MoinRequestHandler.serve_moin = memoryProfileDecorator(
-            MoinRequestHandler.serve_moin, config.memoryProfile)
-
-    registerSignalHandlers(quit)
-    httpd = makeServer(config)
-
-    # Run as a safe user (posix only)
-    if os.name == 'posix' and os.getuid() == 0:
-        switchUID(config.uid, config.gid)
-
-    httpd.serve_forever()
-
--- a/MoinMoin/server/twistedmoin.py	Wed Nov 01 17:49:27 2006 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,284 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-    MoinMoin.server.twistedmoin
-
-    Create standalone twisted based server.
-
-    Minimal usage:
-
-        from MoinMoin.server.twistedmoin import TwistedConfig, makeApp
-        
-        class Config(TwistedConfig):
-            docs = '/usr/share/moin/wiki/htdocs'
-            user = 'www-data'
-            group = 'www-data'
-            
-        application = makeApp(Config)
-
-    Then run this code with twistd -y yourcode.py. See moin_twisted script.
-
-    @copyright: 2004 by Thomas Waldmann, Oliver Graf, Nir Soffer
-    @license: GNU GPL, see COPYING for details.
-"""
-
-from twisted.application import internet, service
-from twisted.web import script, static, server, vhost, resource, util
-from twisted.internet import threads, reactor
-
-try:
-    from twisted.internet import ssl
-except ImportError:
-    ssl = None
-
-# Enable threads
-from twisted.python import threadable
-threadable.init(1)
-
-# MoinMoin imports
-from MoinMoin.request import TWISTED
-from MoinMoin.server import Config
-
-# Set threads flag, so other code can use proper locking
-from MoinMoin import config
-config.use_threads = True
-del config
-
-# Server globals
-config = None
-
-
-class WikiResource(resource.Resource):
-    """ Wiki resource """
-    isLeaf = 1
-
-    def render(self, request):
-        return server.NOT_DONE_YET
-
-
-class WikiRoot(resource.Resource):
-    """ Wiki root resource """
-
-    def getChild(self, name, request):
-        # Serve images and css from url_prefix_static
-        if request.prepath == [] and name == config.url_prefix_static[1:]:
-            return resource.Resource.getChild(self, name, request)
-
-        # Serve special 'root' files from url_prefix_static
-        elif name in ['favicon.ico', 'robots.txt'] and request.postpath == []:
-            return self.children[config.url_prefix_static[1:]].getChild(name, request)
-
-        # All other through moin
-
-        # TODO: fix profile code to include the request init and ignore
-        # first request. I'm not doing this now since its better done
-        # with the new twisted code waiting in fix branch. --Nir
-        else:
-            if config.memoryProfile:
-                config.memoryProfile.addRequest()
-            req = TWISTED.Request(request, name, reactor, properties=config.properties)
-            if config.hotshotProfile:
-                threads.deferToThread(config.hotshotProfile.runcall, req.run)
-            else:
-                threads.deferToThread(req.run)
-            return WikiResource()
-
-
-class MoinRequest(server.Request):
-    """ MoinMoin request
-
-    Enable passing of file-upload filenames
-    """
-
-    def requestReceived(self, command, path, version):
-        """ Called by channel when all data has been received.
-
-        Override server.Request method for POST requests, to fix file
-        uploads issue.
-        """
-        if command == 'POST':
-            self.requestReceivedPOST(path, version)
-        else:
-            server.Request.requestReceived(self, command, path, version)
-
-    def requestReceivedPOST(self, path, version):
-        """ Handle POST requests
-
-        This is a modified copy of server.Request.requestRecived,
-        modified to use cgi.FieldStorage to handle file uploads
-        correctly.
-
-        Creates an extra member extended_args which also has
-        filenames of file uploads ( FIELDNAME__filename__ ).
-        """
-        import cgi
-
-        self.content.seek(0, 0)
-        self.args = {}
-        self.extended_args = {}
-        self.stack = []
-
-        self.method = 'POST'
-        self.uri = path
-        self.clientproto = version
-        x = self.uri.split('?')
-
-        argstring = ""
-        if len(x) == 1:
-            self.path = self.uri
-        else:
-            if len(x) != 2:
-                from twisted.python import log
-                log.msg("May ignore parts of this invalid URI: %s"
-                        % repr(self.uri))
-            self.path, argstring = x[0], x[1]
-
-        # cache the client and server information, we'll need this later to be
-        # serialized and sent with the request so CGIs will work remotely
-        self.client = self.channel.transport.getPeer()
-        self.host = self.channel.transport.getHost()
-
-        # create dummy env for cgi.FieldStorage
-        env = {
-            'REQUEST_METHOD': self.method,
-            'QUERY_STRING': argstring,
-            }
-        form = cgi.FieldStorage(fp=self.content,
-                                environ=env,
-                                headers=self.received_headers)
-
-        # Argument processing
-
-        args = self.args
-        try:
-            keys = form.keys()
-        except TypeError:
-            pass
-        else:
-            for key in keys:
-                values = form[key]
-                if not isinstance(values, list):
-                    values = [values]
-                fixedResult = []
-                for i in values:
-                    if isinstance(i, cgi.MiniFieldStorage):
-                        fixedResult.append(i.value)
-                    elif isinstance(i, cgi.FieldStorage):
-                        fixedResult.append(i.value)
-                        # multiple uploads to same form field are stupid!
-                        if i.filename:
-                            args[key + '__filename__'] = i.filename
-                args[key] = fixedResult
-
-        self.process()
-
-
-class MoinSite(server.Site):
-    """ Moin site """
-    requestFactory = MoinRequest
-
-    def startFactory(self):
-        """ Setup before starting """
-        # Memory profile
-        if config.memoryProfile:
-            config.memoryProfile.sample()
-
-        # hotshot profile
-        if config.hotshotProfile:
-            import hotshot
-            config.hotshotProfile = hotshot.Profile(config.hotshotProfile)
-        server.Site.startFactory(self)
-
-    def stopFactory(self):
-        """ Cleaup before stoping """
-        server.Site.stopFactory(self)
-        if config.hotshotProfile:
-            config.hotshotProfile.close()
-
-
-class TwistedConfig(Config):
-    """ Twisted server default config """
-
-    name = 'mointwisted'
-    properties = {}
-    docs = '/usr/share/moin/htdocs'
-    user = 'www-data'
-    group = 'www-data'
-    port = 8080
-    interfaces = ['']
-    threads = 10
-    logPath = None # moin log file
-    logPath_twisted = None # Twisted log file
-    virtualHosts = None
-    memoryProfile = None
-    hotshotProfile = None
-
-    # sslcert = ('/whereever/cert/sitekey.pem', '/whereever/cert/sitecert.pem')
-    sslcert = None
-
-    def __init__(self):
-        Config.__init__(self)
-
-        # Check for '' in interfaces, then ignore other
-        if '' in self.interfaces:
-            self.interfaces = ['']
-
-
-def makeApp(ConfigClass):
-    """ Generate and return an application
-
-    See MoinMoin.server.Config for config options
-
-    @param ConfigClass: config class
-    @rtype: application object
-    @return twisted application, needed by twistd
-    """
-    # Create config instance (raise RuntimeError if config invalid)
-    global config
-    config = ConfigClass()
-
-    # Set number of threads
-    reactor.suggestThreadPoolSize(config.threads)
-
-    # The root of the HTTP hierarchy
-    default = WikiRoot()
-
-    # Here is where img and css and some special files come from
-    default.putChild(config.url_prefix_static[1:], static.File(config.docs))
-
-    # Generate the Site factory
-    # TODO: Maybe we can use WikiRoot instead of this
-    # ----------------------------------------------
-    root = vhost.NameVirtualHost()
-    root.default = default
-    # ----------------------------------------------
-    site = MoinSite(root, logPath=config.logPath_twisted, timeout=2*60) # 2 minutes timeout
-
-    # Make application
-    application = service.Application("web", uid=config.uid, gid=config.gid)
-    sc = service.IServiceCollection(application)
-
-    # Listen to all interfaces in config.interfaces
-    for entry in config.interfaces:
-        # Add a TCPServer for each interface.
-
-        # This is an hidden experimantal feature: each entry in
-        # interface may contain a port, using 'ip:port'.
-        # Note: the format is subject to change!
-        try:
-            interface, port = entry.split(':', 1)
-        except ValueError:
-            interface, port = entry, config.port
-
-        # Might raise ValueError if not integer.
-        # TODO: check if we can use string port, like 'http'
-        port = int(port)
-
-        if port == 443 and ssl and ssl.supported and config.sslcert:
-            sslContext = ssl.DefaultOpenSSLContextFactory(*config.sslcert)
-            s = internet.SSLServer(port, site, sslContext, interface=interface)
-        else:
-            s = internet.TCPServer(port, site, interface=interface)
-        s.setServiceParent(sc)
-
-    return application
-
--- a/MoinMoin/server/wsgi.py	Wed Nov 01 17:49:27 2006 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-"""
-    MoinMoin - WSGI application
-
-    @copyright: 2005 by Anakim Border <akborder@gmail.com>
-    @license: GNU GPL, see COPYING for details.
-"""
-
-from MoinMoin.request import WSGI
-
-def moinmoinApp(environ, start_response):
-    request = WSGI.Request(environ)
-    request.run()
-    start_response(request.status, request.headers)
-    return [request.output()]
-
--- a/moin.py	Wed Nov 01 17:49:27 2006 +0100
+++ b/moin.py	Wed Nov 01 19:12:16 2006 +0100
@@ -43,7 +43,7 @@
 ## import os
 ## os.environ['MOIN_DEBUG'] = '1'
 
-from MoinMoin.server.standalone import StandaloneConfig, run
+from MoinMoin.server.STANDALONE import StandaloneConfig, run
 from MoinMoin.version import project, release, revision
 
 print "%s - %s [%s]" % (project, release, revision)
--- a/wiki/server/moin.cgi	Wed Nov 01 17:49:27 2006 +0100
+++ b/wiki/server/moin.cgi	Wed Nov 01 19:12:16 2006 +0100
@@ -26,7 +26,7 @@
 ## import os
 ## os.environ['MOIN_DEBUG'] = '1'
 
-from MoinMoin.server.cgi import CgiConfig, run
+from MoinMoin.server.CGI import CgiConfig, run
 
 class Config(CgiConfig):
     # Server name
--- a/wiki/server/mointwisted.py	Wed Nov 01 17:49:27 2006 +0100
+++ b/wiki/server/mointwisted.py	Wed Nov 01 19:12:16 2006 +0100
@@ -27,7 +27,7 @@
 ## import os
 ## os.environ['MOIN_DEBUG'] = '1'
 
-from MoinMoin.server.twistedmoin import TwistedConfig, makeApp
+from MoinMoin.server.TWISTED import TwistedConfig, makeApp
 
 
 class Config(TwistedConfig):
--- a/wiki/server/moinwsgi.py	Wed Nov 01 17:49:27 2006 +0100
+++ b/wiki/server/moinwsgi.py	Wed Nov 01 19:12:16 2006 +0100
@@ -14,7 +14,7 @@
 del config
 
 from flup.server.fcgi import WSGIServer
-from MoinMoin.server.wsgi import moinmoinApp
+from MoinMoin.server.WSGI import moinmoinApp
 import os
 
 if __name__ == '__main__':