diff options
author | Ian Bicking <ian@ianbicking.org> | 2007-10-10 01:17:23 +0000 |
---|---|---|
committer | Ian Bicking <ian@ianbicking.org> | 2007-10-10 01:17:23 +0000 |
commit | 054e427ff60c5793494b8fee7931b00ab952d4b3 (patch) | |
tree | 4d4135cb96c062a16deedfff1297b211dd694850 | |
parent | 747299cd96382521f25223c171acca457fb1b081 (diff) | |
download | paste-git-054e427ff60c5793494b8fee7931b00ab952d4b3.tar.gz |
Fix #194, paste.cascade doesn't copy wsgi.input, and blocking can occur: now wsgi.input is copied and .seek(0) on each call
-rw-r--r-- | docs/news.txt | 4 | ||||
-rw-r--r-- | paste/cascade.py | 21 |
2 files changed, 25 insertions, 0 deletions
diff --git a/docs/news.txt b/docs/news.txt index 2c4da0c..f95eda9 100644 --- a/docs/news.txt +++ b/docs/news.txt @@ -23,6 +23,10 @@ svn trunk * ``paste.httpexceptions.HTTPExceptionHandler`` will no longer catch exceptions raised during the app_iter iteration. +* ``paste.cascade.Cascade`` copies ``wsgi.input`` when cascading, so + that one of the applications cannot read the input and leave a later + application blocked when it tries to read the input. + * Fix assigning to ``WSGIResponse.charset`` breaking the content-type. 1.4.2 diff --git a/paste/cascade.py b/paste/cascade.py index 9176320..962da31 100644 --- a/paste/cascade.py +++ b/paste/cascade.py @@ -7,6 +7,8 @@ return ``404 Not Found``. """ from paste import httpexceptions from paste.util import converters +import tempfile +from cStringIO import StringIO __all__ = ['Cascade'] @@ -74,8 +76,27 @@ class Cascade(object): return _consuming_writer return start_response(status, headers, exc_info) + length = int(environ.get('CONTENT_LENGTH', '0')) + if length > 0: + # We have to copy wsgi.input + copy_wsgi_input = True + if length > 4096 or length == -1: + f = tempfile.TemporaryFile() + copy_len = length + while copy_len: + chunk = environ['wsgi.input'].read(min(copy_len, 4096)) + f.write(chunk) + copy_len -= len(chunk) + f.seek(0) + else: + f = StringIO(environ['wsgi.input'].read(length)) + environ['wsgi.input'] = f + else: + copy_wsgi_input = False for app in self.apps[:-1]: environ_copy = environ.copy() + if copy_wsgi_input: + environ_copy['wsgi.input'].seek(0) failed = [] try: v = app(environ_copy, repl_start_response) |