#!/usr/bin/env python

"""
twist -- Demo of an HTTP server built on top of Twisted Python.
"""

__revision__ = "$Id: medusa_http.py 21221 2003-03-20 16:02:41Z akuchlin $"

# 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
#
# version 0.2 -- 2003.03.24 11:07 PM
#   adds missing support for session management, and for
#   standard Quixote response headers (expires, date)


from twisted.internet.app import Application
from twisted.protocols import http
from twisted.web import server

import quixote
quixote.enable_ptl()
from quixote import errors
from quixote.publish import Publisher
from quixote.http_response import Stream

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)
        resp = qxrequest.response
        self.setResponseCode(resp.status_code)
        for hdr, value in resp.generate_headers():
            self.setHeader(hdr, value)
        if resp.body is not None:
            self.write(resp.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)
            # needed for session management!
            pub.finish_successful_request(qxrequest)
        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:
            if isinstance(output, Stream):
                # XXX a Twisted person needs to add support for streams
                output = ''.join(map(str, output))
            qxrequest.response.set_body(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

        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 ():
    import quixote.demo
    # 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()
