blob: f71563a5ae0890e106de48a27661337660c13119 [file] [log] [blame]
Phillip J. Ebya01799f2010-11-03 00:46:45 +00001"""BaseHTTPServer that implements the Python WSGI protocol (PEP 3333)
Thomas Wouters0e3f5912006-08-11 14:57:12 +00002
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
Georg Brandl24420152008-05-26 16:32:26 +000013from http.server import BaseHTTPRequestHandler, HTTPServer
Jeremy Hylton1afc1692008-06-18 20:49:58 +000014import sys
15import urllib.parse
Thomas Wouters0e3f5912006-08-11 14:57:12 +000016from wsgiref.handlers import SimpleHandler
Senthil Kumarana5e0eaf2012-07-07 14:29:58 -070017from platform import python_implementation
Thomas Wouters0e3f5912006-08-11 14:57:12 +000018
Phillip J. Ebyb6d4a8e2010-11-03 22:39:01 +000019__version__ = "0.2"
Thomas Wouters0e3f5912006-08-11 14:57:12 +000020__all__ = ['WSGIServer', 'WSGIRequestHandler', 'demo_app', 'make_server']
21
22
23server_version = "WSGIServer/" + __version__
Senthil Kumarana5e0eaf2012-07-07 14:29:58 -070024sys_version = python_implementation() + "/" + sys.version.split()[0]
Thomas Wouters0e3f5912006-08-11 14:57:12 +000025software_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
Thomas Wouters0e3f5912006-08-11 14:57:12 +000042class 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
Thomas Wouters0e3f5912006-08-11 14:57:12 +000071class 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
Phillip J. Ebyb6d4a8e2010-11-03 22:39:01 +000078 env['SERVER_SOFTWARE'] = self.server_version
Thomas Wouters0e3f5912006-08-11 14:57:12 +000079 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
Martin Panter50dd1f72016-04-17 02:17:03 +000085 env['PATH_INFO'] = urllib.parse.unquote(path, 'iso-8859-1')
Thomas Wouters0e3f5912006-08-11 14:57:12 +000086 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
Barry Warsaw820c1202008-06-12 04:06:45 +000093 if self.headers.get('content-type') is None:
94 env['CONTENT_TYPE'] = self.headers.get_content_type()
Thomas Wouters0e3f5912006-08-11 14:57:12 +000095 else:
Barry Warsaw820c1202008-06-12 04:06:45 +000096 env['CONTENT_TYPE'] = self.headers['content-type']
Thomas Wouters0e3f5912006-08-11 14:57:12 +000097
Barry Warsaw820c1202008-06-12 04:06:45 +000098 length = self.headers.get('content-length')
Thomas Wouters0e3f5912006-08-11 14:57:12 +000099 if length:
100 env['CONTENT_LENGTH'] = length
101
Antoine Pitrou38a66ad2009-01-03 18:41:49 +0000102 for k, v in self.headers.items():
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000103 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
Senthil Kumarane025b522014-09-17 16:29:29 +0800118 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
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000126 if not self.parse_request(): # An error code has been sent, just exit
127 return
128
Martin Panter34eeed42016-06-29 10:12:22 +0000129 handler = ServerHandler(
130 self.rfile, self.wfile, self.get_stderr(), self.get_environ()
131 )
132 handler.request_handler = self # backpointer for logging
133 handler.run(self.server.get_app())
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000134
135
136
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000137def demo_app(environ,start_response):
Guido van Rossum6a10e022007-08-08 17:01:45 +0000138 from io import StringIO
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000139 stdout = StringIO()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000140 print("Hello world!", file=stdout)
141 print(file=stdout)
Antoine Pitrou38a66ad2009-01-03 18:41:49 +0000142 h = sorted(environ.items())
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000143 for k,v in h:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000144 print(k,'=',repr(v), file=stdout)
Phillip J. Ebya01799f2010-11-03 00:46:45 +0000145 start_response("200 OK", [('Content-Type','text/plain; charset=utf-8')])
Antoine Pitrou38a66ad2009-01-03 18:41:49 +0000146 return [stdout.getvalue().encode("utf-8")]
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000147
148
149def make_server(
150 host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler
151):
152 """Create a new WSGI server listening on `host` and `port` for `app`"""
153 server = server_class((host, port), handler_class)
154 server.set_app(app)
155 return server
156
157
158if __name__ == '__main__':
Martin Panter0cab9c12016-04-13 00:36:52 +0000159 with make_server('', 8000, demo_app) as httpd:
160 sa = httpd.socket.getsockname()
161 print("Serving HTTP on", sa[0], "port", sa[1], "...")
162 import webbrowser
163 webbrowser.open('http://localhost:8000/xyz?abc')
164 httpd.handle_request() # serve one request, then exit