1 | """BaseHTTPServer that implements the Python WSGI protocol (PEP 333, rev 1.21)
|
---|
2 |
|
---|
3 | This is both an example of how WSGI can be implemented, and a basis for running
|
---|
4 | simple web applications on a local machine, such as might be done when testing
|
---|
5 | or debugging an application. It has not been reviewed for security issues,
|
---|
6 | however, and we strongly recommend that you use a "real" web server for
|
---|
7 | production use.
|
---|
8 |
|
---|
9 | For example usage, see the 'if __name__=="__main__"' block at the end of the
|
---|
10 | module. See also the BaseHTTPServer module docs for other API information.
|
---|
11 | """
|
---|
12 |
|
---|
13 | from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
|
---|
14 | import urllib, sys
|
---|
15 | from wsgiref.handlers import SimpleHandler
|
---|
16 |
|
---|
17 | __version__ = "0.1"
|
---|
18 | __all__ = ['WSGIServer', 'WSGIRequestHandler', 'demo_app', 'make_server']
|
---|
19 |
|
---|
20 |
|
---|
21 | server_version = "WSGIServer/" + __version__
|
---|
22 | sys_version = "Python/" + sys.version.split()[0]
|
---|
23 | software_version = server_version + ' ' + sys_version
|
---|
24 |
|
---|
25 |
|
---|
26 | class ServerHandler(SimpleHandler):
|
---|
27 |
|
---|
28 | server_software = software_version
|
---|
29 |
|
---|
30 | def close(self):
|
---|
31 | try:
|
---|
32 | self.request_handler.log_request(
|
---|
33 | self.status.split(' ',1)[0], self.bytes_sent
|
---|
34 | )
|
---|
35 | finally:
|
---|
36 | SimpleHandler.close(self)
|
---|
37 |
|
---|
38 |
|
---|
39 |
|
---|
40 | class WSGIServer(HTTPServer):
|
---|
41 |
|
---|
42 | """BaseHTTPServer that implements the Python WSGI protocol"""
|
---|
43 |
|
---|
44 | application = None
|
---|
45 |
|
---|
46 | def server_bind(self):
|
---|
47 | """Override server_bind to store the server name."""
|
---|
48 | HTTPServer.server_bind(self)
|
---|
49 | self.setup_environ()
|
---|
50 |
|
---|
51 | def setup_environ(self):
|
---|
52 | # Set up base environment
|
---|
53 | env = self.base_environ = {}
|
---|
54 | env['SERVER_NAME'] = self.server_name
|
---|
55 | env['GATEWAY_INTERFACE'] = 'CGI/1.1'
|
---|
56 | env['SERVER_PORT'] = str(self.server_port)
|
---|
57 | env['REMOTE_HOST']=''
|
---|
58 | env['CONTENT_LENGTH']=''
|
---|
59 | env['SCRIPT_NAME'] = ''
|
---|
60 |
|
---|
61 | def get_app(self):
|
---|
62 | return self.application
|
---|
63 |
|
---|
64 | def set_app(self,application):
|
---|
65 | self.application = application
|
---|
66 |
|
---|
67 |
|
---|
68 |
|
---|
69 | class WSGIRequestHandler(BaseHTTPRequestHandler):
|
---|
70 |
|
---|
71 | server_version = "WSGIServer/" + __version__
|
---|
72 |
|
---|
73 | def get_environ(self):
|
---|
74 | env = self.server.base_environ.copy()
|
---|
75 | env['SERVER_PROTOCOL'] = self.request_version
|
---|
76 | env['REQUEST_METHOD'] = self.command
|
---|
77 | if '?' in self.path:
|
---|
78 | path,query = self.path.split('?',1)
|
---|
79 | else:
|
---|
80 | path,query = self.path,''
|
---|
81 |
|
---|
82 | env['PATH_INFO'] = urllib.unquote(path)
|
---|
83 | env['QUERY_STRING'] = query
|
---|
84 |
|
---|
85 | host = self.address_string()
|
---|
86 | if host != self.client_address[0]:
|
---|
87 | env['REMOTE_HOST'] = host
|
---|
88 | env['REMOTE_ADDR'] = self.client_address[0]
|
---|
89 |
|
---|
90 | if self.headers.typeheader is None:
|
---|
91 | env['CONTENT_TYPE'] = self.headers.type
|
---|
92 | else:
|
---|
93 | env['CONTENT_TYPE'] = self.headers.typeheader
|
---|
94 |
|
---|
95 | length = self.headers.getheader('content-length')
|
---|
96 | if length:
|
---|
97 | env['CONTENT_LENGTH'] = length
|
---|
98 |
|
---|
99 | for h in self.headers.headers:
|
---|
100 | k,v = h.split(':',1)
|
---|
101 | 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 |
|
---|
128 | def demo_app(environ,start_response):
|
---|
129 | from StringIO import StringIO
|
---|
130 | stdout = StringIO()
|
---|
131 | print >>stdout, "Hello world!"
|
---|
132 | print >>stdout
|
---|
133 | h = environ.items(); h.sort()
|
---|
134 | for k,v in h:
|
---|
135 | print >>stdout, k,'=', repr(v)
|
---|
136 | start_response("200 OK", [('Content-Type','text/plain')])
|
---|
137 | return [stdout.getvalue()]
|
---|
138 |
|
---|
139 |
|
---|
140 | def 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 |
|
---|
149 | if __name__ == '__main__':
|
---|
150 | httpd = make_server('', 8000, demo_app)
|
---|
151 | sa = httpd.socket.getsockname()
|
---|
152 | print "Serving HTTP on", sa[0], "port", sa[1], "..."
|
---|
153 | import webbrowser
|
---|
154 | webbrowser.open('http://localhost:8000/xyz?abc')
|
---|
155 | httpd.handle_request() # serve one request, then exit
|
---|
156 | httpd.server_close()
|
---|