durusmail: quixote-users: Quixote server on top of Twisted Python
Quixote server on top of Twisted Python
2002-03-19
Quixote server on top of Twisted Python
Andrew Kuchling
2002-03-19
As an experiment, I wrote a demo server that uses Twisted Python's
HTTP support to serve a Quixote application; the code is below in case
any one is interested in trying it.  (Mikhail Sobolev posted a similar
server earlier this month that doesn't use Twisted.)

Note that there's one bug I've been unable to pin down; the
redirection for a trailing slash doesn't work.  Try 'lynx -dump -head
http://localhost:8080/14 ' to see the problem.  A half hour of tedious
tracing didn't find the error, and I didn't want to spend the time on
figuring it out.

--amk                                                             (www.amk.ca)
  "It doesn't work."
  " You astound me."
    -- The Doctor and the Brigadier, in "The Time Monster"


"""qserv

Demo of an HTTP server built on top of Twisted Python that serves a
Quixote application, and also supports an SMTP interface.

"""

# created 2002/03/19, AMK

__revision__ = "$Id$"

import string, cStringIO

from quixote.http_request import HTTPRequest
from quixote.publish import Publisher

from twisted.cred.service import Service
from twisted.internet.app import Application
from twisted.mail import mail
from twisted.protocols import protocol, smtp
from twisted.web import server

# Ports this server will listen on
HTTP_PORT = 8080
SMTP_PORT = 8081

import quixote
quixote.enable_ptl()

publisher = Publisher('quixote.demo')
publisher.read_config('quixote.conf')
publisher.setup_logs()

class QuixoteTWRequest (server.Request):
    def process(self):
        factory = self.factory
        environ = self.create_environment()
        stdin = cStringIO.StringIO(self.content)
        request = HTTPRequest(stdin, environ)
        stdout = cStringIO.StringIO()
        stderr = cStringIO.StringIO()

        publisher.publish(stdin, stdout, stderr, environ)
        output = stdout.getvalue()

        self.setResponseCode(request.response.status_code)
        for hdr, value in request.response.headers.items():
            self.setHeader(hdr, value)
        self.write(output)
        self.finish()

    def create_environment (self):
        host = self.getHeader('host') or self.getHost()
        if ':' in host:
            serverName = string.split(host, ':')[0]
        else:
            serverName = host
        content_type = self.getHeader('content-type')
        typ, remote_addr, remote_port = self.transport.getPeer()

        env = {
               "PATH_INFO":         self.path,
               "SERVER_SOFTWARE":   server.version,
               "SERVER_NAME":       serverName,
               "GATEWAY_INTERFACE": "CGI/1.1",
               "REMOTE_ADDR":       remote_addr,
               "REMOTE_PORT":       str(remote_port),
               "SERVER_PROTOCOL":   self.clientproto,
               "SERVER_PORT":       str(HTTP_PORT),
               "REQUEST_METHOD":    self.method,
               "SCRIPT_NAME":       "",
               "SCRIPT_FILENAME":   "",
               "REQUEST_URI":       self.uri,
               "CONTENT_TYPE":      content_type,
               }
        return env

class DemoSMTP (smtp.SMTP):
    def validateTo (self, user, success, failure):
        print user
        success(user)

    def handleMessage(self, users, message, success, failure):
        for user in users:
            print 'received', user, message
#            self.factory.domains[user.domain].saveMessage(user, message)
        success()


class QuixoteFactory (protocol.ServerFactory):
    def buildProtocol (self, addr):
        r = QuixoteTWRequest()
        r.factory = self
        return r

def run ():
    app = Application('Quixote')
    app.listenTCP(HTTP_PORT, QuixoteFactory())
    app.listenTCP(SMTP_PORT, mail.createDomainsFactory(DemoSMTP,
                                                       {'example.com':None}))
    app.run()


if __name__ == '__main__':
    run()


reply