Initial import to Tizen
[profile/ivi/python-twisted.git] / twisted / web / wsgi.py
1 # Copyright (c) Twisted Matrix Laboratories.
2 # See LICENSE for details.
3
4 """
5 An implementation of
6 U{Web Resource Gateway Interface<http://www.python.org/dev/peps/pep-0333/>}.
7 """
8
9 __metaclass__ = type
10
11 from sys import exc_info
12
13 from zope.interface import implements
14
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
20
21
22 class _ErrorStream:
23     """
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
26     object.
27
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.
32     """
33     def write(self, bytes):
34         """
35         Generate an event for the logging system with the given bytes as the
36         message.
37
38         This is called in a WSGI application thread, not the I/O thread.
39         """
40         msg(bytes, system='wsgi', isError=True)
41
42
43     def writelines(self, iovec):
44         """
45         Join the given lines and pass them to C{write} to be handled in the
46         usual way.
47
48         This is called in a WSGI application thread, not the I/O thread.
49
50         @param iovec: A C{list} of C{'\\n'}-terminated C{str} which will be
51             logged.
52         """
53         self.write(''.join(iovec))
54
55
56     def flush(self):
57         """
58         Nothing is buffered, so flushing does nothing.  This method is required
59         to exist by PEP 333, though.
60
61         This is called in a WSGI application thread, not the I/O thread.
62         """
63
64
65
66 class _InputStream:
67     """
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
70     object.
71
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.
75     """
76     def __init__(self, input):
77         """
78         Initialize the instance.
79
80         This is called in the I/O thread, not a WSGI application thread.
81         """
82         self._wrapped = input
83
84
85     def read(self, size=None):
86         """
87         Pass through to the underlying C{read}.
88
89         This is called in a WSGI application thread, not the I/O thread.
90         """
91         # Avoid passing None because cStringIO and file don't like it.
92         if size is None:
93             return self._wrapped.read()
94         return self._wrapped.read(size)
95
96
97     def readline(self, size=None):
98         """
99         Pass through to the underlying C{readline}, with a size of C{-1} replaced
100         with a size of C{None}.
101
102         This is called in a WSGI application thread, not the I/O thread.
103         """
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)
109
110
111     def readlines(self, size=None):
112         """
113         Pass through to the underlying C{readlines}.
114
115         This is called in a WSGI application thread, not the I/O thread.
116         """
117         # Avoid passing None because cStringIO and file don't like it.
118         if size is None:
119             return self._wrapped.readlines()
120         return self._wrapped.readlines(size)
121
122
123     def __iter__(self):
124         """
125         Pass through to the underlying C{__iter__}.
126
127         This is called in a WSGI application thread, not the I/O thread.
128         """
129         return iter(self._wrapped)
130
131
132
133 class _WSGIResponse:
134     """
135     Helper for L{WSGIResource} which drives the WSGI application using a
136     threadpool and hooks it up to the L{Request}.
137
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.
141
142     @ivar reactor: An L{IReactorThreads} provider which is used to call methods
143         on the request in the I/O thread.
144
145     @ivar threadpool: A L{ThreadPool} which is used to call the WSGI
146         application object in a non-I/O thread.
147
148     @ivar application: The WSGI application object.
149
150     @ivar request: The L{Request} upon which the WSGI environment is based and
151         to which the application's output will be sent.
152
153     @ivar environ: The WSGI environment C{dict}.
154
155     @ivar status: The HTTP response status C{str} supplied to the WSGI
156         I{start_response} callable by the application.
157
158     @ivar headers: A list of HTTP response headers supplied to the WSGI
159         I{start_response} callable by the application.
160
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}.
164     """
165
166     _requestFinished = False
167
168     def __init__(self, reactor, threadpool, application, request):
169         self.started = False
170         self.reactor = reactor
171         self.threadpool = threadpool
172         self.application = application
173         self.request = request
174         self.request.notifyFinish().addBoth(self._finished)
175
176         if request.prepath:
177             scriptName = '/' + '/'.join(request.prepath)
178         else:
179             scriptName = ''
180
181         if request.postpath:
182             pathInfo = '/' + '/'.join(request.postpath)
183         else:
184             pathInfo = ''
185
186         parts = request.uri.split('?', 1)
187         if len(parts) == 1:
188             queryString = ''
189         else:
190             queryString = parts[1]
191
192         self.environ = {
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}
203
204
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
209
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
213             # newlines.
214             self.environ[name] = ','.join([
215                     v.replace('\n', ' ') for v in values])
216
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)})
239
240
241     def _finished(self, ignored):
242         """
243         Record the end of the response generation for the request being
244         serviced.
245         """
246         self._requestFinished = True
247
248
249     def startResponse(self, status, headers, excInfo=None):
250         """
251         The WSGI I{start_response} callable.  The given values are saved until
252         they are needed to generate the response.
253
254         This will be called in a non-I/O thread.
255         """
256         if self.started and excInfo is not None:
257             raise excInfo[0], excInfo[1], excInfo[2]
258         self.status = status
259         self.headers = headers
260         return self.write
261
262
263     def write(self, bytes):
264         """
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.
268
269         This will be called in a non-I/O thread.
270         """
271         def wsgiWrite(started):
272             if not started:
273                 self._sendResponseHeaders()
274             self.request.write(bytes)
275         self.reactor.callFromThread(wsgiWrite, self.started)
276         self.started = True
277
278
279     def _sendResponseHeaders(self):
280         """
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
284         request.
285
286         This must be called in the I/O thread.
287         """
288         code, message = self.status.split(None, 1)
289         code = int(code)
290         self.request.setResponseCode(code, message)
291
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)
296
297
298     def start(self):
299         """
300         Start the WSGI application in the threadpool.
301
302         This must be called in the I/O thread.
303         """
304         self.threadpool.callInThread(self.run)
305
306
307     def run(self):
308         """
309         Call the WSGI application object, iterate it, and handle its output.
310
311         This must be called in a non-I/O thread (ie, a WSGI application
312         thread).
313         """
314         try:
315             appIterator = self.application(self.environ, self.startResponse)
316             for elem in appIterator:
317                 if elem:
318                     self.write(elem)
319                 if self._requestFinished:
320                     break
321             close = getattr(appIterator, 'close', None)
322             if close is not None:
323                 close()
324         except:
325             def wsgiError(started, type, value, traceback):
326                 err(Failure(value, type, traceback), "WSGI application error")
327                 if started:
328                     self.request.transport.loseConnection()
329                 else:
330                     self.request.setResponseCode(INTERNAL_SERVER_ERROR)
331                     self.request.finish()
332             self.reactor.callFromThread(wsgiError, self.started, *exc_info())
333         else:
334             def wsgiFinish(started):
335                 if not self._requestFinished:
336                     if not started:
337                         self._sendResponseHeaders()
338                     self.request.finish()
339             self.reactor.callFromThread(wsgiFinish, self.started)
340         self.started = True
341
342
343
344 class WSGIResource:
345     """
346     An L{IResource} implementation which delegates responsibility for all
347     resources hierarchically inferior to it to a WSGI application.
348
349     @ivar _reactor: An L{IReactorThreads} provider which will be passed on to
350         L{_WSGIResponse} to schedule calls in the I/O thread.
351
352     @ivar _threadpool: A L{ThreadPool} which will be passed on to
353         L{_WSGIResponse} to run the WSGI application object.
354
355     @ivar _application: The WSGI application object.
356     """
357     implements(IResource)
358
359     # Further resource segments are left up to the WSGI application object to
360     # handle.
361     isLeaf = True
362
363     def __init__(self, reactor, threadpool, application):
364         self._reactor = reactor
365         self._threadpool = threadpool
366         self._application = application
367
368
369     def render(self, request):
370         """
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.
373
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.
378         """
379         response = _WSGIResponse(
380             self._reactor, self._threadpool, self._application, request)
381         response.start()
382         return NOT_DONE_YET
383
384
385     def getChildWithDefault(self, name, request):
386         """
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
389         application object.
390         """
391         raise RuntimeError("Cannot get IResource children from WSGIResource")
392
393
394     def putChild(self, path, child):
395         """
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.
399         """
400         raise RuntimeError("Cannot put IResource children under WSGIResource")
401
402
403 __all__ = ['WSGIResource']