File: medusa_http.py

package info (click to toggle)
quixote1 1.2-5
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 1,020 kB
  • ctags: 1,115
  • sloc: python: 5,339; ansic: 1,297; makefile: 83; sh: 43
file content (146 lines) | stat: -rw-r--r-- 4,958 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#!/usr/bin/python

"""quixote.server.medusa_http

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

__revision__ = "$Id: medusa_http.py 25276 2004-10-06 15:46:53Z nascheme $"

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

import sys
import asyncore, rfc822, socket, urllib
from StringIO import StringIO
from medusa import http_server, xmlrpc_handler
from quixote.http_response import Stream
from quixote.publish import Publisher


class StreamProducer:
    def __init__(self, stream):
        self.iterator = iter(stream)

    def more(self):
        try:
            return self.iterator.next()
        except StopIteration:
            return ''


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
        if '#' in request.uri:
            # MSIE is buggy and sometimes includes fragments in URLs
            [request.uri, fragment] = request.uri.split('#', 1)
        if '?' in request.uri:
            [path, query_string] = request.uri.split('?', 1)
        else:
            path = request.uri
            query_string = ''

        path = urllib.unquote(path)
        server_port = str(self.server.port)
        http_host = msg.get("Host")
        if http_host:
            if ":" in http_host:
                server_name, server_port = http_host.split(":", 1)
            else:
                server_name = http_host
        else:
            server_name = (self.server.ip or
                           socket.gethostbyaddr(socket.gethostname())[0])

        environ = {'REQUEST_METHOD': request.command,
                   'ACCEPT_ENCODING': msg.get('Accept-encoding', ''),
                   'CONTENT_TYPE': msg.get('Content-type', ''),
                   'CONTENT_LENGTH': len(data),
                   "GATEWAY_INTERFACE": "CGI/1.1",
                   'PATH_INFO': path,
                   'QUERY_STRING': query_string,
                   'REMOTE_ADDR': remote_addr,
                   'REMOTE_PORT': str(remote_port),
                   'REQUEST_URI': request.uri,
                   'SCRIPT_NAME': '',
                   "SCRIPT_FILENAME": '',
                   'SERVER_NAME': server_name,
                   'SERVER_PORT': server_port,
                   'SERVER_PROTOCOL': 'HTTP/1.1',
                   'SERVER_SOFTWARE': self.server_name,
                   }
        for title, header in msg.items():
            envname = 'HTTP_' + title.replace('-', '_').upper()
            environ[envname] = header

        stdin = StringIO(data)
        qreq = self.publisher.create_request(stdin, environ)
        output = self.publisher.process_request(qreq, environ)

        qresponse = qreq.response
        if output:
            qresponse.set_body(output)

        # Copy headers from Quixote's HTTP response
        for name, value in qresponse.generate_headers():
            # XXX Medusa's HTTP request is buggy, and only allows unique
            # headers.
            request[name] = value

        request.response(qresponse.status_code)

        # XXX should we set a default Last-Modified time?
        if qresponse.body is not None:
            if isinstance(qresponse.body, Stream):
                request.push(StreamProducer(qresponse.body))
            else:
                request.push(qresponse.body)

        request.done()

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

    if len(sys.argv) == 2:
        port = int(sys.argv[1])
    else:
        port = 8080
    print 'Now serving the Quixote demo on port %d' % port
    server = http_server.http_server('', port)
    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()