blob: 231dc572f6219303f7467f019ea1c59a92be6fb8 [file] [log] [blame]
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001"""BaseHTTPServer that implements the Python WSGI protocol (PEP 333, rev 1.21)
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
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
17
18__version__ = "0.1"
19__all__ = ['WSGIServer', 'WSGIRequestHandler', 'demo_app', 'make_server']
20
21
22server_version = "WSGIServer/" + __version__
23sys_version = "Python/" + sys.version.split()[0]
24software_version = server_version + ' ' + sys_version
25
26
27class ServerHandler(SimpleHandler):
28
29 server_software = software_version
30
31 def close(self):
32 try:
33 self.request_handler.log_request(
34 self.status.split(' ',1)[0], self.bytes_sent
35 )
36 finally:
37 SimpleHandler.close(self)
38
39
40
Thomas Wouters0e3f5912006-08-11 14:57:12 +000041class WSGIServer(HTTPServer):
42
43 """BaseHTTPServer that implements the Python WSGI protocol"""
44
45 application = None
46
47 def server_bind(self):
48 """Override server_bind to store the server name."""
49 HTTPServer.server_bind(self)
50 self.setup_environ()
51
52 def setup_environ(self):
53 # Set up base environment
54 env = self.base_environ = {}
55 env['SERVER_NAME'] = self.server_name
56 env['GATEWAY_INTERFACE'] = 'CGI/1.1'
57 env['SERVER_PORT'] = str(self.server_port)
58 env['REMOTE_HOST']=''
59 env['CONTENT_LENGTH']=''
60 env['SCRIPT_NAME'] = ''
61
62 def get_app(self):
63 return self.application
64
65 def set_app(self,application):
66 self.application = application
67
68
69
Thomas Wouters0e3f5912006-08-11 14:57:12 +000070class WSGIRequestHandler(BaseHTTPRequestHandler):
71
72 server_version = "WSGIServer/" + __version__
73
74 def get_environ(self):
75 env = self.server.base_environ.copy()
76 env['SERVER_PROTOCOL'] = self.request_version
77 env['REQUEST_METHOD'] = self.command
78 if '?' in self.path:
79 path,query = self.path.split('?',1)
80 else:
81 path,query = self.path,''
82
Jeremy Hylton1afc1692008-06-18 20:49:58 +000083 env['PATH_INFO'] = urllib.parse.unquote(path)
Thomas Wouters0e3f5912006-08-11 14:57:12 +000084 env['QUERY_STRING'] = query
85
86 host = self.address_string()
87 if host != self.client_address[0]:
88 env['REMOTE_HOST'] = host
89 env['REMOTE_ADDR'] = self.client_address[0]
90
Barry Warsaw820c1202008-06-12 04:06:45 +000091 if self.headers.get('content-type') is None:
92 env['CONTENT_TYPE'] = self.headers.get_content_type()
Thomas Wouters0e3f5912006-08-11 14:57:12 +000093 else:
Barry Warsaw820c1202008-06-12 04:06:45 +000094 env['CONTENT_TYPE'] = self.headers['content-type']
Thomas Wouters0e3f5912006-08-11 14:57:12 +000095
Barry Warsaw820c1202008-06-12 04:06:45 +000096 length = self.headers.get('content-length')
Thomas Wouters0e3f5912006-08-11 14:57:12 +000097 if length:
98 env['CONTENT_LENGTH'] = length
99
Antoine Pitrou38a66ad2009-01-03 18:41:49 +0000100 for k, v in self.headers.items():
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000101 k=k.replace('-','_').upper(); v=v.strip()
102 if k in env:
103 continue # skip content length, type,etc.
104 if 'HTTP_'+k in env:
105 env['HTTP_'+k] += ','+v # comma-separate multiple headers
106 else:
107 env['HTTP_'+k] = v
108 return env
109
110 def get_stderr(self):
111 return sys.stderr
112
113 def handle(self):
114 """Handle a single HTTP request"""
115
116 self.raw_requestline = self.rfile.readline()
117 if not self.parse_request(): # An error code has been sent, just exit
118 return
119
120 handler = ServerHandler(
121 self.rfile, self.wfile, self.get_stderr(), self.get_environ()
122 )
123 handler.request_handler = self # backpointer for logging
124 handler.run(self.server.get_app())
125
126
127
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000128def demo_app(environ,start_response):
Guido van Rossum6a10e022007-08-08 17:01:45 +0000129 from io import StringIO
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000130 stdout = StringIO()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000131 print("Hello world!", file=stdout)
132 print(file=stdout)
Antoine Pitrou38a66ad2009-01-03 18:41:49 +0000133 h = sorted(environ.items())
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000134 for k,v in h:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000135 print(k,'=',repr(v), file=stdout)
Antoine Pitrou38a66ad2009-01-03 18:41:49 +0000136 start_response(b"200 OK", [(b'Content-Type',b'text/plain; charset=utf-8')])
137 return [stdout.getvalue().encode("utf-8")]
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000138
139
140def make_server(
141 host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler
142):
143 """Create a new WSGI server listening on `host` and `port` for `app`"""
144 server = server_class((host, port), handler_class)
145 server.set_app(app)
146 return server
147
148
149if __name__ == '__main__':
150 httpd = make_server('', 8000, demo_app)
151 sa = httpd.socket.getsockname()
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000152 print("Serving HTTP on", sa[0], "port", sa[1], "...")
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000153 import webbrowser
154 webbrowser.open('http://localhost:8000/xyz?abc')
155 httpd.handle_request() # serve one request, then exit