#!/usr/bin/env python

"""quixote.server.medusa_http

An HTTP handler for Medusa that publishes a Quixote application.
"""

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

# A simple HTTP server, using Medusa, that publishes a Quixote application.

import asyncore, rfc822, socket
from StringIO import StringIO
from medusa import http_server, xmlrpc_handler
from quixote.http_request import HTTPRequest
from quixote.publish import Publisher
from quixote.errors import PublishError

class QuixoteHandler:
    def __init__ (self, publisher, server_name, server):
        """QuixoteHandler(publisher:Publisher, server_name:string,
                        server:medusa.http_server.http_server)

        Publish the specified Quixote publisher.  'server_name' will
        be passed as the SERVER_NAME environment variable.
        """
        self.publisher = publisher
        self.server_name = server_name
        self.server = server

    def match (self, request):
        # Always match, since this is the only handler there is.
        return 1

    def handle_request (self, request):
        msg = rfc822.Message(StringIO('\n'.join(request.header)))
        length = int(msg.get('Content-Length', '0'))
        if length:
            request.collector = xmlrpc_handler.collector(self, request)
        else:
            self.continue_request('', request)

    def continue_request (self, data, request):
        msg = rfc822.Message(StringIO('\n'.join(request.header)))
        remote_addr, remote_port = request.channel.addr
        query_string = ''
        if '?' in request.uri:
            [request.uri, query_string] = request.uri.split('?', 1)

        environ = {'REQUEST_METHOD':request.command,
                   'ACCEPT_ENCODING':msg.get('Accept-encoding'),
                   'CONTENT_TYPE': msg.get('Content-type'),
                   'CONTENT_LENGTH':len(data),
                   'HTTP_COOKIE':msg.get('Cookie'),
                   'HTTP_REFERER':msg.get('Referer'),
                   'HTTP_USER_AGENT':msg.get('User-agent'),
                   'PATH_INFO':request.uri,
                   'QUERY_STRING':query_string,
                   'REMOTE_ADDR':remote_addr,
                   'REMOTE_PORT':str(remote_port),
                   'REQUEST_URI':request.uri,
                   'SCRIPT_NAME':'',
                   'SERVER_NAME':self.server.ip or socket.gethostname(),
                   'SERVER_PORT':str(self.server.port),
                   'SERVER_PROTOCOL':'HTTP/1.1',
                   'SERVER_SOFTWARE':self.server_name,
                   }
        for k,v in environ.items():
            if v == None:
                environ[k] = ''

        stdin = StringIO(data)
        qreq = self.publisher.create_request(stdin, environ)
        try:
            self.publisher.parse_request(qreq)
            output = self.publisher.process_request(qreq, environ)
        except PublishError, err:
            output = self.publisher.finish_interrupted_request(qreq, err)
        except:
            output = self.publisher.finish_failed_request(qreq)

        if output:
            qreq.response.set_body(str(output))

        output_file = StringIO()
        qreq.response.write(output_file)
        output_file.seek(0)
        msg = rfc822.Message(output_file)
        msg.rewindbody()
        output = output_file.read()

        # Copy headers from Quixote's HTTP response
        for hdr in msg.keys():
            values = msg.getheaders(hdr)
            # XXX Medusa's HTTP request is buggy, and only allows unique
            # headers.
            for v in values:
                request[hdr.title()] = v

        request.response(qreq.response.status_code)

        # XXX should we set a default Last-Modified time?
        request['Content-Length'] = '0'
        if output:
            request.push(output)
            request['Content-Length'] = str(len(output))

        request.done()

def main ():
    from quixote import enable_ptl
    enable_ptl()

    print 'Now serving the Quixote demo on port 8080'
    server = http_server.http_server('', 8080)
    publisher = Publisher('quixote.demo')

    # When initializing the Publisher in your own driver script,
    # you'll want to parse a configuration file.
    ##publisher.read_config("/full/path/to/demo.conf")
    publisher.setup_logs()
    dh = QuixoteHandler(publisher, 'Quixote/demo', server)
    server.install_handler(dh)
    asyncore.loop()

if __name__ == '__main__':
    main()

