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