1"""BaseHTTPServer that implements the Python WSGI protocol (PEP 333, rev 1.21)
2
3This is both an example of how WSGI can be implemented, and a basis for running
4simple web applications on a local machine, such as might be done when testing
5or debugging an application.  It has not been reviewed for security issues,
6however, and we strongly recommend that you use a "real" web server for
7production use.
8
9For example usage, see the 'if __name__=="__main__"' block at the end of the
10module.  See also the BaseHTTPServer module docs for other API information.
11"""
12
13from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
14import urllib, sys
15from wsgiref.handlers import SimpleHandler
16
17__version__ = "0.1"
18__all__ = ['WSGIServer', 'WSGIRequestHandler', 'demo_app', 'make_server']
19
20
21server_version = "WSGIServer/" + __version__
22sys_version = "Python/" + sys.version.split()[0]
23software_version = server_version + ' ' + sys_version
24
25
26class ServerHandler(SimpleHandler):
27
28    server_software = software_version
29
30    def close(self):
31        try:
32            self.request_handler.log_request(
33                self.status.split(' ',1)[0], self.bytes_sent
34            )
35        finally:
36            SimpleHandler.close(self)
37
38
39
40class WSGIServer(HTTPServer):
41
42    """BaseHTTPServer that implements the Python WSGI protocol"""
43
44    application = None
45
46    def server_bind(self):
47        """Override server_bind to store the server name."""
48        HTTPServer.server_bind(self)
49        self.setup_environ()
50
51    def setup_environ(self):
52        # Set up base environment
53        env = self.base_environ = {}
54        env['SERVER_NAME'] = self.server_name
55        env['GATEWAY_INTERFACE'] = 'CGI/1.1'
56        env['SERVER_PORT'] = str(self.server_port)
57        env['REMOTE_HOST']=''
58        env['CONTENT_LENGTH']=''
59        env['SCRIPT_NAME'] = ''
60
61    def get_app(self):
62        return self.application
63
64    def set_app(self,application):
65        self.application = application
66
67
68
69class WSGIRequestHandler(BaseHTTPRequestHandler):
70
71    server_version = "WSGIServer/" + __version__
72
73    def get_environ(self):
74        env = self.server.base_environ.copy()
75        env['SERVER_PROTOCOL'] = self.request_version
76        env['REQUEST_METHOD'] = self.command
77        if '?' in self.path:
78            path,query = self.path.split('?',1)
79        else:
80            path,query = self.path,''
81
82        env['PATH_INFO'] = urllib.unquote(path)
83        env['QUERY_STRING'] = query
84
85        host = self.address_string()
86        if host != self.client_address[0]:
87            env['REMOTE_HOST'] = host
88        env['REMOTE_ADDR'] = self.client_address[0]
89
90        if self.headers.typeheader is None:
91            env['CONTENT_TYPE'] = self.headers.type
92        else:
93            env['CONTENT_TYPE'] = self.headers.typeheader
94
95        length = self.headers.getheader('content-length')
96        if length:
97            env['CONTENT_LENGTH'] = length
98
99        for h in self.headers.headers:
100            k,v = h.split(':',1)
101            k=k.replace('-','_').upper(); v=v.strip()
102            if k in env:
103                continue                    # skip content length, type,etc.
104            if 'HTTP_'+k in env:
105                env['HTTP_'+k] += ','+v     # comma-separate multiple headers
106            else:
107                env['HTTP_'+k] = v
108        return env
109
110    def get_stderr(self):
111        return sys.stderr
112
113    def handle(self):
114        """Handle a single HTTP request"""
115
116        self.raw_requestline = self.rfile.readline()
117        if not self.parse_request(): # An error code has been sent, just exit
118            return
119
120        handler = ServerHandler(
121            self.rfile, self.wfile, self.get_stderr(), self.get_environ()
122        )
123        handler.request_handler = self      # backpointer for logging
124        handler.run(self.server.get_app())
125
126
127
128def demo_app(environ,start_response):
129    from StringIO import StringIO
130    stdout = StringIO()
131    print >>stdout, "Hello world!"
132    print >>stdout
133    h = environ.items(); h.sort()
134    for k,v in h:
135        print >>stdout, k,'=', repr(v)
136    start_response("200 OK", [('Content-Type','text/plain')])
137    return [stdout.getvalue()]
138
139
140def make_server(
141    host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler
142):
143    """Create a new WSGI server listening on `host` and `port` for `app`"""
144    server = server_class((host, port), handler_class)
145    server.set_app(app)
146    return server
147
148
149if __name__ == '__main__':
150    httpd = make_server('', 8000, demo_app)
151    sa = httpd.socket.getsockname()
152    print "Serving HTTP on", sa[0], "port", sa[1], "..."
153    import webbrowser
154    webbrowser.open('http://localhost:8000/xyz?abc')
155    httpd.handle_request()  # serve one request, then exit
156