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