Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 359 lines (305 sloc) 13.436 kB
2afa973 @finiteloop Move Tornado project to Github
finiteloop authored
1 #!/usr/bin/env python
2 #
3 # Copyright 2009 Facebook
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License"); you may
6 # not use this file except in compliance with the License. You may obtain
7 # a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 # License for the specific language governing permissions and limitations
15 # under the License.
16
17 """WSGI support for the Tornado web framework.
18
300d231 @bdarnell Finish this round of doc updates
bdarnell authored
19 WSGI is the Python standard for web servers, and allows for interoperability
20 between Tornado and other Python web frameworks and servers. This module
21 provides WSGI support in two ways:
22
6c7eac6 @bdarnell Unify WSGI support with the HTTPConnection abstraction.
bdarnell authored
23 * `WSGIAdapter` converts a `tornado.web.Application` to the WSGI application
24 interface. This is useful for running a Tornado app on another
25 HTTP server, such as Google App Engine. See the `WSGIAdapter` class
300d231 @bdarnell Finish this round of doc updates
bdarnell authored
26 documentation for limitations that apply.
27 * `WSGIContainer` lets you run other WSGI applications and frameworks on the
28 Tornado HTTP server. For example, with this class you can mix Django
29 and Tornado handlers in a single server.
2afa973 @finiteloop Move Tornado project to Github
finiteloop authored
30 """
31
65df55d @bdarnell Convert print to a function and add future imports.
bdarnell authored
32 from __future__ import absolute_import, division, print_function, with_statement
da6d821 @bdarnell Standardize future imports for all files in the package.
bdarnell authored
33
8ca6160 @finiteloop Add initial WSGI container support for running other frameworks on To…
finiteloop authored
34 import sys
dade9f1 @kmike remove dead code
kmike authored
35 from io import BytesIO
803f33c @bdarnell Add a tornado.version variable, and use it anywhere we use the current
bdarnell authored
36 import tornado
28adce3 Make all internal imports of tornado modules absolute
Ben Darnell authored
37
c93e961 @bdarnell Stream large response bodies from StaticFileHandler.
bdarnell authored
38 from tornado.concurrent import Future
28adce3 Make all internal imports of tornado modules absolute
Ben Darnell authored
39 from tornado import escape
40 from tornado import httputil
9b944aa @bdarnell Switch from root logger to separate loggers.
bdarnell authored
41 from tornado.log import access_log
28adce3 Make all internal imports of tornado modules absolute
Ben Darnell authored
42 from tornado import web
6c7eac6 @bdarnell Unify WSGI support with the HTTPConnection abstraction.
bdarnell authored
43 from tornado.escape import native_str
c6596d5 @methane Replace tornado.util.bytes_type to bytes
methane authored
44 from tornado.util import unicode_type
cab718a @bdarnell Make WSGIContainer work on python 3
bdarnell authored
45
2afa973 @finiteloop Move Tornado project to Github
finiteloop authored
46
051cd60 @bdarnell Checkpoint: tests can now be imported in python 3 without 2to3.
bdarnell authored
47 try:
900d5a2 @bdarnell Get all the tests passing under py3 without 2to3
bdarnell authored
48 import urllib.parse as urllib_parse # py3
49 except ImportError:
50 import urllib as urllib_parse
51
ca378b9 @bdarnell Run some (synchronous) web.py tests via wsgi too.
bdarnell authored
52 # PEP 3333 specifies that WSGI on python 3 generally deals with byte strings
53 # that are smuggled inside objects of type unicode (via the latin1 encoding).
54 # These functions are like those in the tornado.escape module, but defined
55 # here to minimize the temptation to use them in non-wsgi contexts.
051cd60 @bdarnell Checkpoint: tests can now be imported in python 3 without 2to3.
bdarnell authored
56 if str is unicode_type:
ca378b9 @bdarnell Run some (synchronous) web.py tests via wsgi too.
bdarnell authored
57 def to_wsgi_str(s):
c6596d5 @methane Replace tornado.util.bytes_type to bytes
methane authored
58 assert isinstance(s, bytes)
ca378b9 @bdarnell Run some (synchronous) web.py tests via wsgi too.
bdarnell authored
59 return s.decode('latin1')
60
61 def from_wsgi_str(s):
62 assert isinstance(s, str)
63 return s.encode('latin1')
64 else:
65 def to_wsgi_str(s):
c6596d5 @methane Replace tornado.util.bytes_type to bytes
methane authored
66 assert isinstance(s, bytes)
ca378b9 @bdarnell Run some (synchronous) web.py tests via wsgi too.
bdarnell authored
67 return s
68
69 def from_wsgi_str(s):
70 assert isinstance(s, str)
71 return s
72
73
2afa973 @finiteloop Move Tornado project to Github
finiteloop authored
74 class WSGIApplication(web.Application):
300d231 @bdarnell Finish this round of doc updates
bdarnell authored
75 """A WSGI equivalent of `tornado.web.Application`.
2afa973 @finiteloop Move Tornado project to Github
finiteloop authored
76
00229a2 @bdarnell The next version will be 4.0, not 3.3, so update all references to 3.3.
bdarnell authored
77 .. deprecated:: 4.0
6c7eac6 @bdarnell Unify WSGI support with the HTTPConnection abstraction.
bdarnell authored
78
79 Use a regular `.Application` and wrap it in `WSGIAdapter` instead.
80 """
81 def __call__(self, environ, start_response):
4f734dd @bdarnell Allow gzip to be used with WSGIApplication.
bdarnell authored
82 return WSGIAdapter(self)(environ, start_response)
6c7eac6 @bdarnell Unify WSGI support with the HTTPConnection abstraction.
bdarnell authored
83
84
c93e961 @bdarnell Stream large response bodies from StaticFileHandler.
bdarnell authored
85 # WSGI has no facilities for flow control, so just return an already-done
86 # Future when the interface requires it.
87 _dummy_future = Future()
88 _dummy_future.set_result(None)
89
90
42a00ef @bdarnell Make HTTP1Connection and WSGIConnection subclasses of HTTPConnection.
bdarnell authored
91 class _WSGIConnection(httputil.HTTPConnection):
894bab4 @bdarnell Move address manipulation from HTTP1Connection to HTTPServer.
bdarnell authored
92 def __init__(self, method, start_response, context):
b489ef6 @bdarnell Guard against framing errors when applications manually specify a Con…
bdarnell authored
93 self.method = method
6c7eac6 @bdarnell Unify WSGI support with the HTTPConnection abstraction.
bdarnell authored
94 self.start_response = start_response
894bab4 @bdarnell Move address manipulation from HTTP1Connection to HTTPServer.
bdarnell authored
95 self.context = context
6c7eac6 @bdarnell Unify WSGI support with the HTTPConnection abstraction.
bdarnell authored
96 self._write_buffer = []
97 self._finished = False
b489ef6 @bdarnell Guard against framing errors when applications manually specify a Con…
bdarnell authored
98 self._expected_content_remaining = None
99 self._error = None
6c7eac6 @bdarnell Unify WSGI support with the HTTPConnection abstraction.
bdarnell authored
100
101 def set_close_callback(self, callback):
102 # WSGI has no facility for detecting a closed connection mid-request,
103 # so we can simply ignore the callback.
104 pass
105
61c05ab @bdarnell Remove the has_body flag from write_headers.
bdarnell authored
106 def write_headers(self, start_line, headers, chunk=None, callback=None):
b489ef6 @bdarnell Guard against framing errors when applications manually specify a Con…
bdarnell authored
107 if self.method == 'HEAD':
108 self._expected_content_remaining = 0
109 elif 'Content-Length' in headers:
110 self._expected_content_remaining = int(headers['Content-Length'])
111 else:
112 self._expected_content_remaining = None
6c7eac6 @bdarnell Unify WSGI support with the HTTPConnection abstraction.
bdarnell authored
113 self.start_response(
114 '%s %s' % (start_line.code, start_line.reason),
115 [(native_str(k), native_str(v)) for (k, v) in headers.get_all()])
adc7e4f @bdarnell Add chunk and callback arguments to write_headers.
bdarnell authored
116 if chunk is not None:
117 self.write(chunk, callback)
118 elif callback is not None:
119 callback()
c93e961 @bdarnell Stream large response bodies from StaticFileHandler.
bdarnell authored
120 return _dummy_future
6c7eac6 @bdarnell Unify WSGI support with the HTTPConnection abstraction.
bdarnell authored
121
122 def write(self, chunk, callback=None):
b489ef6 @bdarnell Guard against framing errors when applications manually specify a Con…
bdarnell authored
123 if self._expected_content_remaining is not None:
124 self._expected_content_remaining -= len(chunk)
125 if self._expected_content_remaining < 0:
a0fe934 @bdarnell Rename HTTP{In,Out}putException to HTTP{In,Out}putError.
bdarnell authored
126 self._error = httputil.HTTPOutputError(
b489ef6 @bdarnell Guard against framing errors when applications manually specify a Con…
bdarnell authored
127 "Tried to write more data than Content-Length")
128 raise self._error
6c7eac6 @bdarnell Unify WSGI support with the HTTPConnection abstraction.
bdarnell authored
129 self._write_buffer.append(chunk)
130 if callback is not None:
131 callback()
c93e961 @bdarnell Stream large response bodies from StaticFileHandler.
bdarnell authored
132 return _dummy_future
6c7eac6 @bdarnell Unify WSGI support with the HTTPConnection abstraction.
bdarnell authored
133
134 def finish(self):
b489ef6 @bdarnell Guard against framing errors when applications manually specify a Con…
bdarnell authored
135 if (self._expected_content_remaining is not None and
1299bd6 @bdarnell Autopep8 formatting updates.
bdarnell authored
136 self._expected_content_remaining != 0):
a0fe934 @bdarnell Rename HTTP{In,Out}putException to HTTP{In,Out}putError.
bdarnell authored
137 self._error = httputil.HTTPOutputError(
b489ef6 @bdarnell Guard against framing errors when applications manually specify a Con…
bdarnell authored
138 "Tried to write %d bytes less than Content-Length" %
139 self._expected_content_remaining)
140 raise self._error
6c7eac6 @bdarnell Unify WSGI support with the HTTPConnection abstraction.
bdarnell authored
141 self._finished = True
142
143
894bab4 @bdarnell Move address manipulation from HTTP1Connection to HTTPServer.
bdarnell authored
144 class _WSGIRequestContext(object):
145 def __init__(self, remote_ip, protocol):
146 self.remote_ip = remote_ip
147 self.protocol = protocol
148
149 def __str__(self):
150 return self.remote_ip
151
152
6c7eac6 @bdarnell Unify WSGI support with the HTTPConnection abstraction.
bdarnell authored
153 class WSGIAdapter(object):
154 """Converts a `tornado.web.Application` instance into a WSGI application.
300d231 @bdarnell Finish this round of doc updates
bdarnell authored
155
156 Example usage::
157
158 import tornado.web
159 import tornado.wsgi
160 import wsgiref.simple_server
161
162 class MainHandler(tornado.web.RequestHandler):
163 def get(self):
164 self.write("Hello, world")
165
166 if __name__ == "__main__":
6c7eac6 @bdarnell Unify WSGI support with the HTTPConnection abstraction.
bdarnell authored
167 application = tornado.web.Application([
300d231 @bdarnell Finish this round of doc updates
bdarnell authored
168 (r"/", MainHandler),
169 ])
6c7eac6 @bdarnell Unify WSGI support with the HTTPConnection abstraction.
bdarnell authored
170 wsgi_app = tornado.wsgi.WSGIAdapter(application)
171 server = wsgiref.simple_server.make_server('', 8888, wsgi_app)
300d231 @bdarnell Finish this round of doc updates
bdarnell authored
172 server.serve_forever()
173
8525507 @bdarnell Doc updates: modules starting with W.
bdarnell authored
174 See the `appengine demo
5a542d8 @bdarnell Point all links to the 'demos' directory to the stable branch instead…
bdarnell authored
175 <https://github.com/tornadoweb/tornado/tree/stable/demos/appengine>`_
8525507 @bdarnell Doc updates: modules starting with W.
bdarnell authored
176 for an example of using this module to run a Tornado app on Google
177 App Engine.
300d231 @bdarnell Finish this round of doc updates
bdarnell authored
178
6c7eac6 @bdarnell Unify WSGI support with the HTTPConnection abstraction.
bdarnell authored
179 In WSGI mode asynchronous methods are not supported. This means
180 that it is not possible to use `.AsyncHTTPClient`, or the
181 `tornado.auth` or `tornado.websocket` modules.
182
00229a2 @bdarnell The next version will be 4.0, not 3.3, so update all references to 3.3.
bdarnell authored
183 .. versionadded:: 4.0
2afa973 @finiteloop Move Tornado project to Github
finiteloop authored
184 """
6c7eac6 @bdarnell Unify WSGI support with the HTTPConnection abstraction.
bdarnell authored
185 def __init__(self, application):
186 if isinstance(application, WSGIApplication):
187 self.application = lambda request: web.Application.__call__(
188 application, request)
189 else:
190 self.application = application
2afa973 @finiteloop Move Tornado project to Github
finiteloop authored
191
192 def __call__(self, environ, start_response):
6c7eac6 @bdarnell Unify WSGI support with the HTTPConnection abstraction.
bdarnell authored
193 method = environ["REQUEST_METHOD"]
194 uri = urllib_parse.quote(from_wsgi_str(environ.get("SCRIPT_NAME", "")))
195 uri += urllib_parse.quote(from_wsgi_str(environ.get("PATH_INFO", "")))
196 if environ.get("QUERY_STRING"):
197 uri += "?" + environ["QUERY_STRING"]
198 headers = httputil.HTTPHeaders()
2afa973 @finiteloop Move Tornado project to Github
finiteloop authored
199 if environ.get("CONTENT_TYPE"):
6c7eac6 @bdarnell Unify WSGI support with the HTTPConnection abstraction.
bdarnell authored
200 headers["Content-Type"] = environ["CONTENT_TYPE"]
2afa973 @finiteloop Move Tornado project to Github
finiteloop authored
201 if environ.get("CONTENT_LENGTH"):
6c7eac6 @bdarnell Unify WSGI support with the HTTPConnection abstraction.
bdarnell authored
202 headers["Content-Length"] = environ["CONTENT_LENGTH"]
2afa973 @finiteloop Move Tornado project to Github
finiteloop authored
203 for key in environ:
204 if key.startswith("HTTP_"):
6c7eac6 @bdarnell Unify WSGI support with the HTTPConnection abstraction.
bdarnell authored
205 headers[key[5:].replace("_", "-")] = environ[key]
206 if headers.get("Content-Length"):
207 body = environ["wsgi.input"].read(
208 int(headers["Content-Length"]))
2afa973 @finiteloop Move Tornado project to Github
finiteloop authored
209 else:
429aae4 @lwzm Ensure that HTTPServerRequest.body is a byte string
lwzm authored
210 body = b""
6c7eac6 @bdarnell Unify WSGI support with the HTTPConnection abstraction.
bdarnell authored
211 protocol = environ["wsgi.url_scheme"]
212 remote_ip = environ.get("REMOTE_ADDR", "")
2afa973 @finiteloop Move Tornado project to Github
finiteloop authored
213 if environ.get("HTTP_HOST"):
6c7eac6 @bdarnell Unify WSGI support with the HTTPConnection abstraction.
bdarnell authored
214 host = environ["HTTP_HOST"]
2afa973 @finiteloop Move Tornado project to Github
finiteloop authored
215 else:
6c7eac6 @bdarnell Unify WSGI support with the HTTPConnection abstraction.
bdarnell authored
216 host = environ["SERVER_NAME"]
894bab4 @bdarnell Move address manipulation from HTTP1Connection to HTTPServer.
bdarnell authored
217 connection = _WSGIConnection(method, start_response,
218 _WSGIRequestContext(remote_ip, protocol))
6c7eac6 @bdarnell Unify WSGI support with the HTTPConnection abstraction.
bdarnell authored
219 request = httputil.HTTPServerRequest(
894bab4 @bdarnell Move address manipulation from HTTP1Connection to HTTPServer.
bdarnell authored
220 method, uri, "HTTP/1.1", headers=headers, body=body,
6c7eac6 @bdarnell Unify WSGI support with the HTTPConnection abstraction.
bdarnell authored
221 host=host, connection=connection)
222 request._parse_body()
223 self.application(request)
b489ef6 @bdarnell Guard against framing errors when applications manually specify a Con…
bdarnell authored
224 if connection._error:
225 raise connection._error
6c7eac6 @bdarnell Unify WSGI support with the HTTPConnection abstraction.
bdarnell authored
226 if not connection._finished:
227 raise Exception("request did not finish synchronously")
228 return connection._write_buffer
2afa973 @finiteloop Move Tornado project to Github
finiteloop authored
229
230
8ca6160 @finiteloop Add initial WSGI container support for running other frameworks on To…
finiteloop authored
231 class WSGIContainer(object):
96c2f2f @bdarnell Finish automatic documentation
bdarnell authored
232 r"""Makes a WSGI-compatible function runnable on Tornado's HTTP server.
8ca6160 @finiteloop Add initial WSGI container support for running other frameworks on To…
finiteloop authored
233
f55f9d0 @bdarnell Add a warning label to WSGIContainer.
bdarnell authored
234 .. warning::
235
236 WSGI is a *synchronous* interface, while Tornado's concurrency model
237 is based on single-threaded asynchronous execution. This means that
238 running a WSGI app with Tornado's `WSGIContainer` is *less scalable*
239 than running the same app in a multi-threaded WSGI server like
240 ``gunicorn`` or ``uwsgi``. Use `WSGIContainer` only when there are
241 benefits to combining Tornado and WSGI in the same process that
242 outweigh the reduced scalability.
243
8525507 @bdarnell Doc updates: modules starting with W.
bdarnell authored
244 Wrap a WSGI function in a `WSGIContainer` and pass it to `.HTTPServer` to
96c2f2f @bdarnell Finish automatic documentation
bdarnell authored
245 run it. For example::
8ca6160 @finiteloop Add initial WSGI container support for running other frameworks on To…
finiteloop authored
246
247 def simple_app(environ, start_response):
248 status = "200 OK"
249 response_headers = [("Content-type", "text/plain")]
250 start_response(status, response_headers)
251 return ["Hello world!\n"]
252
253 container = tornado.wsgi.WSGIContainer(simple_app)
254 http_server = tornado.httpserver.HTTPServer(container)
255 http_server.listen(8888)
4f86890 @bdarnell Add make_current keyword argument to IOLoop constructor.
bdarnell authored
256 tornado.ioloop.IOLoop.current().start()
8ca6160 @finiteloop Add initial WSGI container support for running other frameworks on To…
finiteloop authored
257
258 This class is intended to let other frameworks (Django, web.py, etc)
300d231 @bdarnell Finish this round of doc updates
bdarnell authored
259 run on the Tornado HTTP server and I/O loop.
260
261 The `tornado.web.FallbackHandler` class is often useful for mixing
262 Tornado and WSGI apps in the same server. See
263 https://github.com/bdarnell/django-tornado-demo for a complete example.
8ca6160 @finiteloop Add initial WSGI container support for running other frameworks on To…
finiteloop authored
264 """
265 def __init__(self, wsgi_application):
266 self.wsgi_application = wsgi_application
267
268 def __call__(self, request):
269 data = {}
5f4413b Return a write method from start_response, as required by the wsgi spec.
Ben Darnell authored
270 response = []
c152b78 @bdarnell While I'm touching every file, run autopep8 too.
bdarnell authored
271
1ae186a @weaver Add exc_info parameter to start_response() in WSGIContainer.
weaver authored
272 def start_response(status, response_headers, exc_info=None):
8ca6160 @finiteloop Add initial WSGI container support for running other frameworks on To…
finiteloop authored
273 data["status"] = status
33a587b Don't put wsgi response headers in a dictionary to support repeated
Ben Darnell authored
274 data["headers"] = response_headers
5f4413b Return a write method from start_response, as required by the wsgi spec.
Ben Darnell authored
275 return response.append
df0d88e Close wsgi responses correctly - the close method, if present, will
Ben Darnell authored
276 app_response = self.wsgi_application(
277 WSGIContainer.environ(request), start_response)
72556cf @GrahamDumpleton WSGI specification requires that close() be called on iterable no mat…
GrahamDumpleton authored
278 try:
279 response.extend(app_response)
280 body = b"".join(response)
281 finally:
282 if hasattr(app_response, "close"):
283 app_response.close()
c152b78 @bdarnell While I'm touching every file, run autopep8 too.
bdarnell authored
284 if not data:
285 raise Exception("WSGI app did not call start_response")
8ca6160 @finiteloop Add initial WSGI container support for running other frameworks on To…
finiteloop authored
286
859df38 @bdarnell WSGIContainer now uses HTTPConnection to write its response.
bdarnell authored
287 status_code, reason = data["status"].split(' ', 1)
288 status_code = int(status_code)
8ca6160 @finiteloop Add initial WSGI container support for running other frameworks on To…
finiteloop authored
289 headers = data["headers"]
c152b78 @bdarnell While I'm touching every file, run autopep8 too.
bdarnell authored
290 header_set = set(k.lower() for (k, v) in headers)
8ca6160 @finiteloop Add initial WSGI container support for running other frameworks on To…
finiteloop authored
291 body = escape.utf8(body)
7610920 @bdarnell Run more of web_test in wsgi_test. Fix a bug with 304 in wsgi.
bdarnell authored
292 if status_code != 304:
293 if "content-length" not in header_set:
294 headers.append(("Content-Length", str(len(body))))
295 if "content-type" not in header_set:
296 headers.append(("Content-Type", "text/html; charset=UTF-8"))
33a587b Don't put wsgi response headers in a dictionary to support repeated
Ben Darnell authored
297 if "server" not in header_set:
803f33c @bdarnell Add a tornado.version variable, and use it anywhere we use the current
bdarnell authored
298 headers.append(("Server", "TornadoServer/%s" % tornado.version))
8ca6160 @finiteloop Add initial WSGI container support for running other frameworks on To…
finiteloop authored
299
859df38 @bdarnell WSGIContainer now uses HTTPConnection to write its response.
bdarnell authored
300 start_line = httputil.ResponseStartLine("HTTP/1.1", status_code, reason)
301 header_obj = httputil.HTTPHeaders()
33a587b Don't put wsgi response headers in a dictionary to support repeated
Ben Darnell authored
302 for key, value in headers:
859df38 @bdarnell WSGIContainer now uses HTTPConnection to write its response.
bdarnell authored
303 header_obj.add(key, value)
304 request.connection.write_headers(start_line, header_obj, chunk=body)
305 request.connection.finish()
8ca6160 @finiteloop Add initial WSGI container support for running other frameworks on To…
finiteloop authored
306 self._log(status_code, request)
307
400d2c9 Make WSGIContainer._environ public and static, so it can be used to a…
Ben Darnell authored
308 @staticmethod
309 def environ(request):
5d7e37c @bdarnell Fix doc references to HTTPRequest.
bdarnell authored
310 """Converts a `tornado.httputil.HTTPServerRequest` to a WSGI environment.
55d3be1 @bdarnell Run coverage check and fill in the blanks
bdarnell authored
311 """
8ca6160 @finiteloop Add initial WSGI container support for running other frameworks on To…
finiteloop authored
312 hostport = request.host.split(":")
313 if len(hostport) == 2:
314 host = hostport[0]
315 port = int(hostport[1])
316 else:
317 host = request.host
318 port = 443 if request.protocol == "https" else 80
319 environ = {
320 "REQUEST_METHOD": request.method,
321 "SCRIPT_NAME": "",
917fe80 @bdarnell Use plus=False when constructing and decoding url paths.
bdarnell authored
322 "PATH_INFO": to_wsgi_str(escape.url_unescape(
b2b8334 @bdarnell autopep8 whitespace fixes.
bdarnell authored
323 request.path, encoding=None, plus=False)),
8ca6160 @finiteloop Add initial WSGI container support for running other frameworks on To…
finiteloop authored
324 "QUERY_STRING": request.query,
41a9473 Add REMOTE_ADDR to WSGIContainer
Ben Darnell authored
325 "REMOTE_ADDR": request.remote_ip,
8ca6160 @finiteloop Add initial WSGI container support for running other frameworks on To…
finiteloop authored
326 "SERVER_NAME": host,
cab718a @bdarnell Make WSGIContainer work on python 3
bdarnell authored
327 "SERVER_PORT": str(port),
f6266ba Add SERVER_PROTOCOL variable to wsgi environment. This turns out to be
Ben Darnell authored
328 "SERVER_PROTOCOL": request.version,
8ca6160 @finiteloop Add initial WSGI container support for running other frameworks on To…
finiteloop authored
329 "wsgi.version": (1, 0),
330 "wsgi.url_scheme": request.protocol,
cab718a @bdarnell Make WSGIContainer work on python 3
bdarnell authored
331 "wsgi.input": BytesIO(escape.utf8(request.body)),
8ca6160 @finiteloop Add initial WSGI container support for running other frameworks on To…
finiteloop authored
332 "wsgi.errors": sys.stderr,
333 "wsgi.multithread": False,
334 "wsgi.multiprocess": True,
335 "wsgi.run_once": False,
336 }
337 if "Content-Type" in request.headers:
41b4af9 @bdarnell Test multipart/form-data parsing in wsgi and fix it for python3
bdarnell authored
338 environ["CONTENT_TYPE"] = request.headers.pop("Content-Type")
8ca6160 @finiteloop Add initial WSGI container support for running other frameworks on To…
finiteloop authored
339 if "Content-Length" in request.headers:
41b4af9 @bdarnell Test multipart/form-data parsing in wsgi and fix it for python3
bdarnell authored
340 environ["CONTENT_LENGTH"] = request.headers.pop("Content-Length")
900d5a2 @bdarnell Get all the tests passing under py3 without 2to3
bdarnell authored
341 for key, value in request.headers.items():
8ca6160 @finiteloop Add initial WSGI container support for running other frameworks on To…
finiteloop authored
342 environ["HTTP_" + key.replace("-", "_").upper()] = value
343 return environ
344
345 def _log(self, status_code, request):
346 if status_code < 400:
9b944aa @bdarnell Switch from root logger to separate loggers.
bdarnell authored
347 log_method = access_log.info
8ca6160 @finiteloop Add initial WSGI container support for running other frameworks on To…
finiteloop authored
348 elif status_code < 500:
9b944aa @bdarnell Switch from root logger to separate loggers.
bdarnell authored
349 log_method = access_log.warning
8ca6160 @finiteloop Add initial WSGI container support for running other frameworks on To…
finiteloop authored
350 else:
9b944aa @bdarnell Switch from root logger to separate loggers.
bdarnell authored
351 log_method = access_log.error
8ca6160 @finiteloop Add initial WSGI container support for running other frameworks on To…
finiteloop authored
352 request_time = 1000.0 * request.request_time()
353 summary = request.method + " " + request.uri + " (" + \
354 request.remote_ip + ")"
355 log_method("%d %s %.2fms", status_code, summary, request_time)
6c7eac6 @bdarnell Unify WSGI support with the HTTPConnection abstraction.
bdarnell authored
356
357
358 HTTPRequest = httputil.HTTPServerRequest
Something went wrong with that request. Please try again.