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 88 host = self.address_string() 89 if host != self.client_address[0]: 90 env['REMOTE_HOST'] = host 91 env['REMOTE_ADDR'] = self.client_address[0] 92 93 if self.headers.get('content-type') is None: 94 env['CONTENT_TYPE'] = self.headers.get_content_type() 95 else: 96 env['CONTENT_TYPE'] = self.headers['content-type'] 97 98 length = self.headers.get('content-length') 99 if length: 100 env['CONTENT_LENGTH'] = length 101 102 for k, v in self.headers.items(): 103 k=k.replace('-','_').upper(); v=v.strip() 104 if k in env: 105 continue # skip content length, type,etc. 106 if 'HTTP_'+k in env: 107 env['HTTP_'+k] += ','+v # comma-separate multiple headers 108 else: 109 env['HTTP_'+k] = v 110 return env 111 112 def get_stderr(self): 113 return sys.stderr 114 115 def handle(self): 116 """Handle a single HTTP request""" 117 118 self.raw_requestline = self.rfile.readline(65537) 119 if len(self.raw_requestline) > 65536: 120 self.requestline = '' 121 self.request_version = '' 122 self.command = '' 123 self.send_error(414) 124 return 125 126 if not self.parse_request(): # An error code has been sent, just exit 127 return 128 129 handler = ServerHandler( 130 self.rfile, self.wfile, self.get_stderr(), self.get_environ(), 131 multithread=False, 132 ) 133 handler.request_handler = self # backpointer for logging 134 handler.run(self.server.get_app()) 135 136 137 138def demo_app(environ,start_response): 139 from io import StringIO 140 stdout = StringIO() 141 print("Hello world!", file=stdout) 142 print(file=stdout) 143 h = sorted(environ.items()) 144 for k,v in h: 145 print(k,'=',repr(v), file=stdout) 146 start_response("200 OK", [('Content-Type','text/plain; charset=utf-8')]) 147 return [stdout.getvalue().encode("utf-8")] 148 149 150def make_server( 151 host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler 152): 153 """Create a new WSGI server listening on `host` and `port` for `app`""" 154 server = server_class((host, port), handler_class) 155 server.set_app(app) 156 return server 157 158 159if __name__ == '__main__': 160 with make_server('', 8000, demo_app) as httpd: 161 sa = httpd.socket.getsockname() 162 print("Serving HTTP on", sa[0], "port", sa[1], "...") 163 import webbrowser 164 webbrowser.open('http://localhost:8000/xyz?abc') 165 httpd.handle_request() # serve one request, then exit 166