183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh"""BaseHTTPServer that implements the Python WSGI protocol (PEP 333, rev 1.21)
283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehThis is both an example of how WSGI can be implemented, and a basis for running
483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehsimple web applications on a local machine, such as might be done when testing
583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehor debugging an application.  It has not been reviewed for security issues,
683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehhowever, and we strongly recommend that you use a "real" web server for
783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehproduction use.
883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehFor example usage, see the 'if __name__=="__main__"' block at the end of the
1083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehmodule.  See also the BaseHTTPServer module docs for other API information.
1183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh"""
1283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
1383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehfrom BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
1483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport urllib, sys
1583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehfrom wsgiref.handlers import SimpleHandler
1683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
1783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh__version__ = "0.1"
1883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh__all__ = ['WSGIServer', 'WSGIRequestHandler', 'demo_app', 'make_server']
1983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
2083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
2183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehserver_version = "WSGIServer/" + __version__
2283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehsys_version = "Python/" + sys.version.split()[0]
2383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehsoftware_version = server_version + ' ' + sys_version
2483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
2583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
2683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass ServerHandler(SimpleHandler):
2783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
2883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    server_software = software_version
2983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
3083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def close(self):
3183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        try:
3283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.request_handler.log_request(
3383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                self.status.split(' ',1)[0], self.bytes_sent
3483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            )
3583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        finally:
3683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            SimpleHandler.close(self)
3783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
3883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
3983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
4083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass WSGIServer(HTTPServer):
4183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
4283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    """BaseHTTPServer that implements the Python WSGI protocol"""
4383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
4483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    application = None
4583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
4683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def server_bind(self):
4783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        """Override server_bind to store the server name."""
4883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        HTTPServer.server_bind(self)
4983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.setup_environ()
5083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
5183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def setup_environ(self):
5283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # Set up base environment
5383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        env = self.base_environ = {}
5483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        env['SERVER_NAME'] = self.server_name
5583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        env['GATEWAY_INTERFACE'] = 'CGI/1.1'
5683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        env['SERVER_PORT'] = str(self.server_port)
5783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        env['REMOTE_HOST']=''
5883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        env['CONTENT_LENGTH']=''
5983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        env['SCRIPT_NAME'] = ''
6083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
6183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def get_app(self):
6283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return self.application
6383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
6483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def set_app(self,application):
6583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.application = application
6683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
6783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
6883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
6983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass WSGIRequestHandler(BaseHTTPRequestHandler):
7083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
7183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    server_version = "WSGIServer/" + __version__
7283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
7383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def get_environ(self):
7483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        env = self.server.base_environ.copy()
7583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        env['SERVER_PROTOCOL'] = self.request_version
7683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        env['REQUEST_METHOD'] = self.command
7783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if '?' in self.path:
7883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            path,query = self.path.split('?',1)
7983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        else:
8083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            path,query = self.path,''
8183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
8283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        env['PATH_INFO'] = urllib.unquote(path)
8383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        env['QUERY_STRING'] = query
8483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
8583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        host = self.address_string()
8683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if host != self.client_address[0]:
8783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            env['REMOTE_HOST'] = host
8883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        env['REMOTE_ADDR'] = self.client_address[0]
8983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
9083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if self.headers.typeheader is None:
9183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            env['CONTENT_TYPE'] = self.headers.type
9283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        else:
9383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            env['CONTENT_TYPE'] = self.headers.typeheader
9483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
9583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        length = self.headers.getheader('content-length')
9683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if length:
9783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            env['CONTENT_LENGTH'] = length
9883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
9983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        for h in self.headers.headers:
10083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            k,v = h.split(':',1)
10183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            k=k.replace('-','_').upper(); v=v.strip()
10283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if k in env:
10383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                continue                    # skip content length, type,etc.
10483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if 'HTTP_'+k in env:
10583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                env['HTTP_'+k] += ','+v     # comma-separate multiple headers
10683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            else:
10783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                env['HTTP_'+k] = v
10883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return env
10983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
11083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def get_stderr(self):
11183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return sys.stderr
11283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
11383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def handle(self):
11483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        """Handle a single HTTP request"""
11583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
11683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.raw_requestline = self.rfile.readline()
11783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if not self.parse_request(): # An error code has been sent, just exit
11883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            return
11983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
12083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        handler = ServerHandler(
12183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.rfile, self.wfile, self.get_stderr(), self.get_environ()
12283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        )
12383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        handler.request_handler = self      # backpointer for logging
12483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        handler.run(self.server.get_app())
12583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
12683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
12783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
12883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef demo_app(environ,start_response):
12983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    from StringIO import StringIO
13083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    stdout = StringIO()
13183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    print >>stdout, "Hello world!"
13283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    print >>stdout
13383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    h = environ.items(); h.sort()
13483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    for k,v in h:
13583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        print >>stdout, k,'=', repr(v)
13683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    start_response("200 OK", [('Content-Type','text/plain')])
13783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    return [stdout.getvalue()]
13883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
13983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
14083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef make_server(
14183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler
14283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh):
14383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    """Create a new WSGI server listening on `host` and `port` for `app`"""
14483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    server = server_class((host, port), handler_class)
14583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    server.set_app(app)
14683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    return server
14783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
14883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
14983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehif __name__ == '__main__':
15083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    httpd = make_server('', 8000, demo_app)
15183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    sa = httpd.socket.getsockname()
15283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    print "Serving HTTP on", sa[0], "port", sa[1], "..."
15383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    import webbrowser
15483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    webbrowser.open('http://localhost:8000/xyz?abc')
15583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    httpd.handle_request()  # serve one request, then exit
156