• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(65537)
117        if len(self.raw_requestline) > 65536:
118            self.requestline = ''
119            self.request_version = ''
120            self.command = ''
121            self.send_error(414)
122            return
123
124        if not self.parse_request(): # An error code has been sent, just exit
125            return
126
127        handler = ServerHandler(
128            self.rfile, self.wfile, self.get_stderr(), self.get_environ()
129        )
130        handler.request_handler = self      # backpointer for logging
131        handler.run(self.server.get_app())
132
133
134
135def demo_app(environ,start_response):
136    from StringIO import StringIO
137    stdout = StringIO()
138    print >>stdout, "Hello world!"
139    print >>stdout
140    h = environ.items(); h.sort()
141    for k,v in h:
142        print >>stdout, k,'=', repr(v)
143    start_response("200 OK", [('Content-Type','text/plain')])
144    return [stdout.getvalue()]
145
146
147def make_server(
148    host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler
149):
150    """Create a new WSGI server listening on `host` and `port` for `app`"""
151    server = server_class((host, port), handler_class)
152    server.set_app(app)
153    return server
154
155
156if __name__ == '__main__':
157    httpd = make_server('', 8000, demo_app)
158    sa = httpd.socket.getsockname()
159    print "Serving HTTP on", sa[0], "port", sa[1], "..."
160    import webbrowser
161    webbrowser.open('http://localhost:8000/xyz?abc')
162    httpd.handle_request()  # serve one request, then exit
163    httpd.server_close()
164