simple_server.py 5.0 KB

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