[Repoze-checkins] r765 - in repoze.zope2/trunk: . repoze/zope2 repoze/zope2/tests
Chris McDonough
chrism at agendaless.com
Tue Mar 4 02:22:16 UTC 2008
Author: Chris McDonough <chrism at agendaless.com>
Date: Mon Mar 3 21:22:16 2008
New Revision: 765
Log:
- Fix bug reported by Martin Aspeli: repoze.zope2 would choke on
large images and files (symptom: broken images when images were
large). This was due to the fact that the Zope File- and
Image-rendering machinery used HTTPResponse.write, which
repoze.zope2's response handling didn't handle properly. We now
subclass HTTPResponse (as RepozeHTTPResponse) to solve the issue.
Added:
repoze.zope2/trunk/repoze/zope2/tests/test_request.py (contents, props changed)
Modified:
repoze.zope2/trunk/CHANGES.txt
repoze.zope2/trunk/repoze/zope2/request.py
repoze.zope2/trunk/repoze/zope2/tests/base.py
repoze.zope2/trunk/repoze/zope2/tests/test_z2bob.py
repoze.zope2/trunk/repoze/zope2/z2bob.py
repoze.zope2/trunk/setup.py
Modified: repoze.zope2/trunk/CHANGES.txt
==============================================================================
--- repoze.zope2/trunk/CHANGES.txt (original)
+++ repoze.zope2/trunk/CHANGES.txt Mon Mar 3 21:22:16 2008
@@ -1,3 +1,12 @@
+0.3.2 (2008-03-03)
+
+ - Fix bug reported by Martin Aspeli: repoze.zope2 would choke on
+ large images and files (symptom: broken images when images were
+ large). This was due to the fact that the Zope File- and
+ Image-rendering machinery used HTTPResponse.write, which
+ repoze.zope2's response handling didn't handle properly. We now
+ subclass HTTPResponse (as RepozeHTTPResponse) to solve the issue.
+
0.3.1 (2008-03-02)
- mkzope2instance now:
Modified: repoze.zope2/trunk/repoze/zope2/request.py
==============================================================================
--- repoze.zope2/trunk/repoze/zope2/request.py (original)
+++ repoze.zope2/trunk/repoze/zope2/request.py Mon Mar 3 21:22:16 2008
@@ -18,9 +18,18 @@
from ZPublisher.HTTPRequest import HTTPRequest
from tempfile import NamedTemporaryFile
+class RepozeHTTPResponse(HTTPResponse):
+ def write(self, data):
+ """
+ Override HTTPResponse.write in order to prevent it from writing
+ headers to output (we'll do that later).
+ """
+ self._wrote = True
+ self.stdout.write(data)
+
def makeRequest(environ):
temp = NamedTemporaryFile()
- response = HTTPResponse(stdout=temp)
+ response = RepozeHTTPResponse(stdout=temp)
stdin = environ['wsgi.input']
# The clean = True argument is important. If we don't pass it,
# our WSGI environment is copied and replaced, and thus we won't
Modified: repoze.zope2/trunk/repoze/zope2/tests/base.py
==============================================================================
--- repoze.zope2/trunk/repoze/zope2/tests/base.py (original)
+++ repoze.zope2/trunk/repoze/zope2/tests/base.py Mon Mar 3 21:22:16 2008
@@ -56,6 +56,9 @@
def setStatus(self, v):
self.setHeader('status', v)
self.status = v
+ def write(self, data):
+ self._wrote = True
+ self.stdout.write(data)
class DummyRequest:
def __init__(self, env):
Added: repoze.zope2/trunk/repoze/zope2/tests/test_request.py
==============================================================================
--- (empty file)
+++ repoze.zope2/trunk/repoze/zope2/tests/test_request.py Mon Mar 3 21:22:16 2008
@@ -0,0 +1,39 @@
+import unittest
+
+class TestMakeRequest(unittest.TestCase):
+ def _getFUT(self):
+ from repoze.zope2.z2bob import makeRequest
+ return makeRequest
+
+ def test_makeRequest(self):
+ from repoze.zope2.tests.base import _makeEnviron
+ makeRequest = self._getFUT()
+ environ = _makeEnviron()
+ request = makeRequest(environ)
+ self.failUnless(request.environ is environ, request.stdin)
+ self.failUnless(request.stdin is environ['wsgi.input'])
+ self.assertNotEqual(request.response, None)
+ from repoze.zope2.request import RepozeHTTPResponse
+ self.failUnless(isinstance(request.response, RepozeHTTPResponse))
+
+class TestRepozeHTTPResponse(unittest.TestCase):
+ def _getTargetClass(self):
+ from repoze.zope2.request import RepozeHTTPResponse
+ return RepozeHTTPResponse
+
+ def _makeOne(self, stdout):
+ return self._getTargetClass()(stdout=stdout)
+
+ def test_write(self):
+ from StringIO import StringIO
+ stdout = StringIO()
+ response = self._makeOne(stdout)
+ response.write('hello')
+ self.assertEqual(stdout.getvalue(), 'hello')
+ self.assertEqual(response._wrote, True)
+ response.write(' there')
+ self.assertEqual(stdout.getvalue(), 'hello there')
+ self.assertEqual(response._wrote, True)
+
+
+
Modified: repoze.zope2/trunk/repoze/zope2/tests/test_z2bob.py
==============================================================================
--- repoze.zope2/trunk/repoze/zope2/tests/test_z2bob.py (original)
+++ repoze.zope2/trunk/repoze/zope2/tests/test_z2bob.py Mon Mar 3 21:22:16 2008
@@ -64,14 +64,6 @@
finally:
z2bob.db = None
- def test_makeRequest(self):
- from repoze.zope2.z2bob import makeRequest
- environ = _makeEnviron()
- request = makeRequest(environ)
- self.failUnless(request.environ is environ, request.stdin)
- self.failUnless(request.stdin is environ['wsgi.input'])
- self.assertNotEqual(request.response, None)
-
def test_quote(self):
from repoze.zope2.z2bob import quote
quoted = quote('http://foo/bar/@@view')
@@ -657,17 +649,18 @@
self.assertEqual(headers[1], ('Content-Type',
'text/plain; charset=utf-8'))
- def test_map_result_response_stdout(self):
+ def test_map_result_response_written(self):
+ # if response.write is used, a tempfile is used to hold
+ # the result, and it becomes the body of the response
helper = self._makeOne()
- helper.request.response.headers['status'] = '200 OK'
- from StringIO import StringIO
- stdout = StringIO()
- stdout.write('Status: 401 Unauthorized\n\n\nbody')
- helper.request.response.stdout = stdout
+ response = helper.request.response
+ response.headers['status'] = '200 OK'
+ response.write('body')
status, headers, result = helper.map_result(None)
- self.assertEqual(status, '401')
- self.assertEqual(result, stdout)
- self.assertEqual(stdout.read(), 'body')
+ self.assertEqual(response._wrote, True)
+ self.assertEqual(status, '200 OK')
+ self.assertEqual(result, response.stdout)
+ self.assertEqual(result.read(), 'body')
def test_map_result_headers_normalized(self):
helper = self._makeOne()
Modified: repoze.zope2/trunk/repoze/zope2/z2bob.py
==============================================================================
--- repoze.zope2/trunk/repoze/zope2/z2bob.py (original)
+++ repoze.zope2/trunk/repoze/zope2/z2bob.py Mon Mar 3 21:22:16 2008
@@ -353,29 +353,9 @@
response = request.response
if response.stdout.tell():
- stdout = response.stdout
- stdout.seek(0)
- result = stdout
- last = None
- # the headers get written too, we need to unwind them
- while 1:
- line = stdout.readline()
- if not line:
- break
- if last == '\n' and line == '\n':
- break
- if line:
- if ':' in line:
- k, v = line.split(':', 1)
- k = k.strip()
- v = v.strip()
- if k.lower() == 'status':
- response.setStatus(v.split()[0])
- else:
- response.setHeader(k, v)
- last = line
-
- result = stdout
+ # someone used response.write
+ response.stdout.seek(0)
+ result = response.stdout
status = response.headers.get('status', None)
if status is None:
Modified: repoze.zope2/trunk/setup.py
==============================================================================
--- repoze.zope2/trunk/setup.py (original)
+++ repoze.zope2/trunk/setup.py Mon Mar 3 21:22:16 2008
@@ -12,7 +12,7 @@
#
##############################################################################
-__version__ = '0.3.1'
+__version__ = '0.3.2'
from ez_setup import use_setuptools
use_setuptools()
More information about the Repoze-checkins
mailing list