I took a stab at fixing the earlier attempts made to write a Twisted driver for Quixote. This one seems quite stable, and apepars to solve the problems encountered in earlier versions posted to the list (redirects not working, headers munged into the body, ...). I side-stepped the Publisher.publish method (similar to the approach taken in medusa_http) -- this may require some rework if you have overridden that method in your custom Publishers. Lastly, I moved the publisher and http_port out of the global namespace (the approach in the orignal versions), and into the run() function -- so this ought to work nicely as a basis for a quixote.server module... Tested using quixote.demo, on Win32, Quixote 0.65b, Twisted 0.18.0. Your mileage may vary (though I hope it doesn't!). Regards, -- Graham """ twist -- Demo of an HTTP server built on top of Twisted Python. """ # based on qserv, created 2002/03/19, AMK # last mod 2003.03.24, Graham Fawcett # tested on Win32 / Twisted 0.18.0 / Quixote 0.6b5 import quixote quixote.enable_ptl() import quixote.demo from quixote import errors from quixote.publish import Publisher from twisted.internet.app import Application from twisted.protocols import http from twisted.web import server class QuixoteTWRequest(server.Request): def process(self): self.publisher = self.channel.factory.publisher environ = self.create_environment() ## this seek is important, it doesnt work without it self.content.seek(0,0) qxrequest = self.publisher.create_request(self.content, environ) self.quixote_publish(qxrequest, environ) self.setResponseCode(qxrequest.response.status_code) for hdr, value in qxrequest.response.headers.items(): self.setHeader(hdr, value) self.write(qxrequest.response.body) self.finish() def quixote_publish(self, qxrequest, env): """ Warning, this sidesteps the Publisher.publish method, Hope you didn't override it... """ pub = self.publisher try: pub.parse_request(qxrequest) output = pub.process_request(qxrequest, env) except errors.PublishError, exc: # Exit the publishing loop and return a result right away. output = pub.finish_interrupted_request(qxrequest, exc) except: # other exception, generate error messages to logs, etc. output = pub.finish_failed_request(qxrequest) # don't write out the output, just set the response body # the calling method will do the rest. if output: qxrequest.response.set_body(str(output)) pub._clear_request() def create_environment(self): """ Borrowed heavily from twisted.web.twcgi """ serverName = self.getRequestHostname().split(':')[0] env = {"SERVER_SOFTWARE": server.version, "SERVER_NAME": serverName, "GATEWAY_INTERFACE": "CGI/1.1", "SERVER_PROTOCOL": self.clientproto, "SERVER_PORT": str(self.getHost()[2]), "REQUEST_METHOD": self.method, "SCRIPT_NAME": '', "SCRIPT_FILENAME": '', "REQUEST_URI": self.uri, } client = self.getClient() if client is not None: env['REMOTE_HOST'] = client ip = self.getClientIP() if ip is not None: env['REMOTE_ADDR'] = ip xx, xx, remote_port = self.transport.getPeer() env['REMOTE_PORT'] = remote_port env["PATH_INFO"] = self.path qindex = self.uri.find('?') if qindex != -1: env['QUERY_STRING'] = self.uri[qindex+1:] else: env['QUERY_STRING'] = '' # Propogate HTTP headers for title, header in self.getAllHeaders().items(): envname = title.replace('-', '_').upper() if title not in ('content-type', 'content-length'): envname = "HTTP_" + envname env[envname] = header print envname, header return env class QuixoteFactory (http.HTTPFactory): def __init__(self, publisher): self.publisher = publisher http.HTTPFactory.__init__(self, None) def buildProtocol (self, addr): h = http.HTTPChannel() h.requestFactory = QuixoteTWRequest h.factory = self return h def run (): # Ports this server will listen on http_port = 8080 namespace = quixote.demo app = Application('Quixote') publisher = Publisher(namespace) publisher.setup_logs() qf = QuixoteFactory(publisher) app.listenTCP(http_port, qf) app.run(save=0) if __name__ == '__main__': run()