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()