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