|
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 |
|
41 |
|
42 class 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 |
|
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 class WSGIRequestHandler(BaseHTTPRequestHandler): |
|
84 |
|
85 server_version = "WSGIServer/" + __version__ |
|
86 |
|
87 def get_environ(self): |
|
88 env = self.server.base_environ.copy() |
|
89 env['SERVER_PROTOCOL'] = self.request_version |
|
90 env['REQUEST_METHOD'] = self.command |
|
91 if '?' in self.path: |
|
92 path,query = self.path.split('?',1) |
|
93 else: |
|
94 path,query = self.path,'' |
|
95 |
|
96 env['PATH_INFO'] = urllib.unquote(path) |
|
97 env['QUERY_STRING'] = query |
|
98 |
|
99 host = self.address_string() |
|
100 if host != self.client_address[0]: |
|
101 env['REMOTE_HOST'] = host |
|
102 env['REMOTE_ADDR'] = self.client_address[0] |
|
103 |
|
104 if self.headers.typeheader is None: |
|
105 env['CONTENT_TYPE'] = self.headers.type |
|
106 else: |
|
107 env['CONTENT_TYPE'] = self.headers.typeheader |
|
108 |
|
109 length = self.headers.getheader('content-length') |
|
110 if length: |
|
111 env['CONTENT_LENGTH'] = length |
|
112 |
|
113 for h in self.headers.headers: |
|
114 k,v = h.split(':',1) |
|
115 k=k.replace('-','_').upper(); v=v.strip() |
|
116 if k in env: |
|
117 continue # skip content length, type,etc. |
|
118 if 'HTTP_'+k in env: |
|
119 env['HTTP_'+k] += ','+v # comma-separate multiple headers |
|
120 else: |
|
121 env['HTTP_'+k] = v |
|
122 return env |
|
123 |
|
124 def get_stderr(self): |
|
125 return sys.stderr |
|
126 |
|
127 def handle(self): |
|
128 """Handle a single HTTP request""" |
|
129 |
|
130 self.raw_requestline = self.rfile.readline() |
|
131 if not self.parse_request(): # An error code has been sent, just exit |
|
132 return |
|
133 |
|
134 handler = ServerHandler( |
|
135 self.rfile, self.wfile, self.get_stderr(), self.get_environ() |
|
136 ) |
|
137 handler.request_handler = self # backpointer for logging |
|
138 handler.run(self.server.get_app()) |
|
139 |
|
140 |
|
141 |
|
142 |
|
143 |
|
144 |
|
145 |
|
146 |
|
147 |
|
148 |
|
149 |
|
150 |
|
151 |
|
152 |
|
153 |
|
154 |
|
155 |
|
156 |
|
157 |
|
158 |
|
159 |
|
160 |
|
161 |
|
162 |
|
163 |
|
164 |
|
165 def demo_app(environ,start_response): |
|
166 from StringIO import StringIO |
|
167 stdout = StringIO() |
|
168 print >>stdout, "Hello world!" |
|
169 print >>stdout |
|
170 h = environ.items(); h.sort() |
|
171 for k,v in h: |
|
172 print >>stdout, k,'=',`v` |
|
173 start_response("200 OK", [('Content-Type','text/plain')]) |
|
174 return [stdout.getvalue()] |
|
175 |
|
176 |
|
177 def make_server( |
|
178 host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler |
|
179 ): |
|
180 """Create a new WSGI server listening on `host` and `port` for `app`""" |
|
181 server = server_class((host, port), handler_class) |
|
182 server.set_app(app) |
|
183 return server |
|
184 |
|
185 |
|
186 if __name__ == '__main__': |
|
187 httpd = make_server('', 8000, demo_app) |
|
188 sa = httpd.socket.getsockname() |
|
189 print "Serving HTTP on", sa[0], "port", sa[1], "..." |
|
190 import webbrowser |
|
191 webbrowser.open('http://localhost:8000/xyz?abc') |
|
192 httpd.handle_request() # serve one request, then exit |
|
193 |
|
194 |
|
195 |
|
196 |
|
197 |
|
198 |
|
199 |
|
200 |
|
201 |
|
202 |
|
203 |
|
204 |
|
205 # |