1 # Copyright (c) Twisted Matrix Laboratories.
2 # See LICENSE for details.
6 U{Web Resource Gateway Interface<http://www.python.org/dev/peps/pep-0333/>}.
11 from sys import exc_info
13 from zope.interface import implements
15 from twisted.python.log import msg, err
16 from twisted.python.failure import Failure
17 from twisted.web.resource import IResource
18 from twisted.web.server import NOT_DONE_YET
19 from twisted.web.http import INTERNAL_SERVER_ERROR
24 File-like object instances of which are used as the value for the
25 C{'wsgi.errors'} key in the C{environ} dictionary passed to the application
28 This simply passes writes on to L{logging<twisted.python.log>} system as
29 error events from the C{'wsgi'} system. In the future, it may be desirable
30 to expose more information in the events it logs, such as the application
31 object which generated the message.
33 def write(self, bytes):
35 Generate an event for the logging system with the given bytes as the
38 This is called in a WSGI application thread, not the I/O thread.
40 msg(bytes, system='wsgi', isError=True)
43 def writelines(self, iovec):
45 Join the given lines and pass them to C{write} to be handled in the
48 This is called in a WSGI application thread, not the I/O thread.
50 @param iovec: A C{list} of C{'\\n'}-terminated C{str} which will be
53 self.write(''.join(iovec))
58 Nothing is buffered, so flushing does nothing. This method is required
59 to exist by PEP 333, though.
61 This is called in a WSGI application thread, not the I/O thread.
68 File-like object instances of which are used as the value for the
69 C{'wsgi.input'} key in the C{environ} dictionary passed to the application
72 This only exists to make the handling of C{readline(-1)} consistent across
73 different possible underlying file-like object implementations. The other
74 supported methods pass through directly to the wrapped object.
76 def __init__(self, input):
78 Initialize the instance.
80 This is called in the I/O thread, not a WSGI application thread.
85 def read(self, size=None):
87 Pass through to the underlying C{read}.
89 This is called in a WSGI application thread, not the I/O thread.
91 # Avoid passing None because cStringIO and file don't like it.
93 return self._wrapped.read()
94 return self._wrapped.read(size)
97 def readline(self, size=None):
99 Pass through to the underlying C{readline}, with a size of C{-1} replaced
100 with a size of C{None}.
102 This is called in a WSGI application thread, not the I/O thread.
104 # Check for -1 because StringIO doesn't handle it correctly. Check for
105 # None because files and tempfiles don't accept that.
106 if size == -1 or size is None:
107 return self._wrapped.readline()
108 return self._wrapped.readline(size)
111 def readlines(self, size=None):
113 Pass through to the underlying C{readlines}.
115 This is called in a WSGI application thread, not the I/O thread.
117 # Avoid passing None because cStringIO and file don't like it.
119 return self._wrapped.readlines()
120 return self._wrapped.readlines(size)
125 Pass through to the underlying C{__iter__}.
127 This is called in a WSGI application thread, not the I/O thread.
129 return iter(self._wrapped)
135 Helper for L{WSGIResource} which drives the WSGI application using a
136 threadpool and hooks it up to the L{Request}.
138 @ivar started: A C{bool} indicating whether or not the response status and
139 headers have been written to the request yet. This may only be read or
140 written in the WSGI application thread.
142 @ivar reactor: An L{IReactorThreads} provider which is used to call methods
143 on the request in the I/O thread.
145 @ivar threadpool: A L{ThreadPool} which is used to call the WSGI
146 application object in a non-I/O thread.
148 @ivar application: The WSGI application object.
150 @ivar request: The L{Request} upon which the WSGI environment is based and
151 to which the application's output will be sent.
153 @ivar environ: The WSGI environment C{dict}.
155 @ivar status: The HTTP response status C{str} supplied to the WSGI
156 I{start_response} callable by the application.
158 @ivar headers: A list of HTTP response headers supplied to the WSGI
159 I{start_response} callable by the application.
161 @ivar _requestFinished: A flag which indicates whether it is possible to
162 generate more response data or not. This is C{False} until
163 L{Request.notifyFinish} tells us the request is done, then C{True}.
166 _requestFinished = False
168 def __init__(self, reactor, threadpool, application, request):
170 self.reactor = reactor
171 self.threadpool = threadpool
172 self.application = application
173 self.request = request
174 self.request.notifyFinish().addBoth(self._finished)
177 scriptName = '/' + '/'.join(request.prepath)
182 pathInfo = '/' + '/'.join(request.postpath)
186 parts = request.uri.split('?', 1)
190 queryString = parts[1]
193 'REQUEST_METHOD': request.method,
194 'REMOTE_ADDR': request.getClientIP(),
195 'SCRIPT_NAME': scriptName,
196 'PATH_INFO': pathInfo,
197 'QUERY_STRING': queryString,
198 'CONTENT_TYPE': request.getHeader('content-type') or '',
199 'CONTENT_LENGTH': request.getHeader('content-length') or '',
200 'SERVER_NAME': request.getRequestHostname(),
201 'SERVER_PORT': str(request.getHost().port),
202 'SERVER_PROTOCOL': request.clientproto}
205 # The application object is entirely in control of response headers;
206 # disable the default Content-Type value normally provided by
207 # twisted.web.server.Request.
208 self.request.defaultContentType = None
210 for name, values in request.requestHeaders.getAllRawHeaders():
211 name = 'HTTP_' + name.upper().replace('-', '_')
212 # It might be preferable for http.HTTPChannel to clear out
214 self.environ[name] = ','.join([
215 v.replace('\n', ' ') for v in values])
217 self.environ.update({
218 'wsgi.version': (1, 0),
219 'wsgi.url_scheme': request.isSecure() and 'https' or 'http',
220 'wsgi.run_once': False,
221 'wsgi.multithread': True,
222 'wsgi.multiprocess': False,
223 'wsgi.errors': _ErrorStream(),
224 # Attend: request.content was owned by the I/O thread up until
225 # this point. By wrapping it and putting the result into the
226 # environment dictionary, it is effectively being given to
227 # another thread. This means that whatever it is, it has to be
228 # safe to access it from two different threads. The access
229 # *should* all be serialized (first the I/O thread writes to
230 # it, then the WSGI thread reads from it, then the I/O thread
231 # closes it). However, since the request is made available to
232 # arbitrary application code during resource traversal, it's
233 # possible that some other code might decide to use it in the
234 # I/O thread concurrently with its use in the WSGI thread.
235 # More likely than not, this will break. This seems like an
236 # unlikely possibility to me, but if it is to be allowed,
237 # something here needs to change. -exarkun
238 'wsgi.input': _InputStream(request.content)})
241 def _finished(self, ignored):
243 Record the end of the response generation for the request being
246 self._requestFinished = True
249 def startResponse(self, status, headers, excInfo=None):
251 The WSGI I{start_response} callable. The given values are saved until
252 they are needed to generate the response.
254 This will be called in a non-I/O thread.
256 if self.started and excInfo is not None:
257 raise excInfo[0], excInfo[1], excInfo[2]
259 self.headers = headers
263 def write(self, bytes):
265 The WSGI I{write} callable returned by the I{start_response} callable.
266 The given bytes will be written to the response body, possibly flushing
267 the status and headers first.
269 This will be called in a non-I/O thread.
271 def wsgiWrite(started):
273 self._sendResponseHeaders()
274 self.request.write(bytes)
275 self.reactor.callFromThread(wsgiWrite, self.started)
279 def _sendResponseHeaders(self):
281 Set the response code and response headers on the request object, but
282 do not flush them. The caller is responsible for doing a write in
283 order for anything to actually be written out in response to the
286 This must be called in the I/O thread.
288 code, message = self.status.split(None, 1)
290 self.request.setResponseCode(code, message)
292 for name, value in self.headers:
293 # Don't allow the application to control these required headers.
294 if name.lower() not in ('server', 'date'):
295 self.request.responseHeaders.addRawHeader(name, value)
300 Start the WSGI application in the threadpool.
302 This must be called in the I/O thread.
304 self.threadpool.callInThread(self.run)
309 Call the WSGI application object, iterate it, and handle its output.
311 This must be called in a non-I/O thread (ie, a WSGI application
315 appIterator = self.application(self.environ, self.startResponse)
316 for elem in appIterator:
319 if self._requestFinished:
321 close = getattr(appIterator, 'close', None)
322 if close is not None:
325 def wsgiError(started, type, value, traceback):
326 err(Failure(value, type, traceback), "WSGI application error")
328 self.request.transport.loseConnection()
330 self.request.setResponseCode(INTERNAL_SERVER_ERROR)
331 self.request.finish()
332 self.reactor.callFromThread(wsgiError, self.started, *exc_info())
334 def wsgiFinish(started):
335 if not self._requestFinished:
337 self._sendResponseHeaders()
338 self.request.finish()
339 self.reactor.callFromThread(wsgiFinish, self.started)
346 An L{IResource} implementation which delegates responsibility for all
347 resources hierarchically inferior to it to a WSGI application.
349 @ivar _reactor: An L{IReactorThreads} provider which will be passed on to
350 L{_WSGIResponse} to schedule calls in the I/O thread.
352 @ivar _threadpool: A L{ThreadPool} which will be passed on to
353 L{_WSGIResponse} to run the WSGI application object.
355 @ivar _application: The WSGI application object.
357 implements(IResource)
359 # Further resource segments are left up to the WSGI application object to
363 def __init__(self, reactor, threadpool, application):
364 self._reactor = reactor
365 self._threadpool = threadpool
366 self._application = application
369 def render(self, request):
371 Turn the request into the appropriate C{environ} C{dict} suitable to be
372 passed to the WSGI application object and then pass it on.
374 The WSGI application object is given almost complete control of the
375 rendering process. C{NOT_DONE_YET} will always be returned in order
376 and response completion will be dictated by the application object, as
377 will the status, headers, and the response body.
379 response = _WSGIResponse(
380 self._reactor, self._threadpool, self._application, request)
385 def getChildWithDefault(self, name, request):
387 Reject attempts to retrieve a child resource. All path segments beyond
388 the one which refers to this resource are handled by the WSGI
391 raise RuntimeError("Cannot get IResource children from WSGIResource")
394 def putChild(self, path, child):
396 Reject attempts to add a child resource to this resource. The WSGI
397 application object handles all path segments beneath this resource, so
398 L{IResource} children can never be found.
400 raise RuntimeError("Cannot put IResource children under WSGIResource")
403 __all__ = ['WSGIResource']