Log message for revision 110189: Merge c110187 from 2.12 branch, adding IPubBeforeStreaming event
Changed: U Zope/trunk/doc/CHANGES.rst U Zope/trunk/src/ZPublisher/HTTPResponse.py U Zope/trunk/src/ZPublisher/interfaces.py U Zope/trunk/src/ZPublisher/pubevents.py U Zope/trunk/src/ZPublisher/tests/testpubevents.py U Zope/trunk/src/ZServer/HTTPResponse.py U Zope/trunk/src/ZServer/tests/test_responses.py -=- Modified: Zope/trunk/doc/CHANGES.rst =================================================================== --- Zope/trunk/doc/CHANGES.rst 2010-03-26 13:25:09 UTC (rev 110188) +++ Zope/trunk/doc/CHANGES.rst 2010-03-26 13:31:10 UTC (rev 110189) @@ -5,12 +5,92 @@ Change information for previous versions of Zope can be found in the file HISTORY.txt. -Zope 2.12.2 (unreleased) +Zope 2.12.4 (Unreleased) ------------------------ Features Added ++++++++++++++ +- Updated packages: + + - Acquisition = 2.13.1 + - ExtensionClass = 2.13.0 + - Persistence = 2.13.0 + +- There is now an event ZPublisher.interfaces.IPubBeforeStreaming which will + be fired just before the first chunk of data is written to the response + stream when using the write() method on the response. This is the last + possible point at which response headers may be set in this case. + +Bugs Fixed +++++++++++ + +- Zope 3-style resource directories would throw an Unauthorized error when + trying to use restrictedTraverse() to reach a resource in a sub-directory + of the resource directory. + +- Restore ability to traverse to 'macros' on template-based browser views. + +- Protect ZCTextIndex's clear method against storing Acquisition wrappers. + +- LP #195761: fixed ZMI XML export / import and restored it to the UI. + +- MailHost should fall back to HELO when EHLO fails. + +Zope 2.12.3 (2010/01/12) +------------------------ + +Bugs Fixed +++++++++++ + +- LP #491224: proper escaping of rendered error message + +- LP #246983: Enabled unicode conflict resolution on variables inside "string:" + expressions in TALES. + +- Fixed possible TypeError while sending multipart emails. + +- Also look for ZEXP imports within the clienthome directory. This + provides a place to put imports that won't be clobbered by buildout + in a buildout-based Zope instance. + +- Fixed a SyntaxError in utilities/load_site.py script. + +Features Added +++++++++++++++ + +- Made OFS.Image.File and OFS.Image.Image send IObjectModifiedEvent when + created through their factories and modified through the ZMI forms + (manage_edit() and manage_upload()). + +- Moved zope.formlib / zope.app.form integration into a separate package + called five.formlib. + +Zope 2.12.2 (2009-12-22) +------------------------ + +Features Added +++++++++++++++ + +- Updated packages: + + - ZODB3 = 3.9.4 + - docutils = 0.6 + - pytz = 2009r + - zope.dottedname = 3.4.6 + - zope.i18n = 3.7.2 + - zope.interface = 3.5.3 + - zope.minmax = 1.1.1 + - zope.security = 3.7.2 + - zope.session = 3.9.2 + - zope.tal = 3.5.2 + +- Enhanced the internals of the DateRangeIndex based on an idea from + experimental.daterangeindexoptimisations, thanks to Matt Hamilton. + +- Updated the default value for ``management_page_charset`` from iso-8859-1 + to the nowadays more standard utf-8. + - Added IPubBeforeAbort event to mirror IPubBeforeCommit in failure scenarios. This event is fired just before IPubFailure, but, crucially, while the transaction is still open. @@ -24,9 +104,26 @@ Bugs Fixed ++++++++++ +- LP #143444: add labels to checkboxes / radio buttons on import / + export form. + +- LP #496941: Remove all mention of ``standard_html_header`` and + ``standard_html_footer`` from default DTML content. + +- Fixed a regression in Products.PageTemplates that meant filesystem templates + using Products.Five.browser.pagetemplatefile would treat TALES path + expressions (but not python expressions) as protected code and so attempt + to apply security. See original issue here: + http://codespeak.net/pipermail/z3-five/2007q2/002185.html + +- LP #491249: fix tabindex on ZRDB connection test form. + +- LP #490514: preserve tainting when calling into DTML from ZPT. + - Avoid possible errors on test tear-down in Products.Five.fiveconfigure's cleanUp() function if Products.meta_types has not been set + Zope 2.12.1 (2009/11/02) ------------------------ Modified: Zope/trunk/src/ZPublisher/HTTPResponse.py =================================================================== --- Zope/trunk/src/ZPublisher/HTTPResponse.py 2010-03-26 13:25:09 UTC (rev 110188) +++ Zope/trunk/src/ZPublisher/HTTPResponse.py 2010-03-26 13:31:10 UTC (rev 110189) @@ -18,10 +18,12 @@ import types, os, sys, re import zlib, struct from string import translate, maketrans +from zope.event import notify from BaseResponse import BaseResponse from zExceptions import Unauthorized, Redirect from zExceptions.ExceptionFormatter import format_exception from ZPublisher import BadRequest, InternalError, NotFound +from ZPublisher.pubevents import PubBeforeStreaming from cgi import escape from urllib import quote @@ -921,6 +923,9 @@ """ if not self._wrote: + + notify(PubBeforeStreaming(self)) + self.outputBody() self._wrote = 1 self.stdout.flush() Modified: Zope/trunk/src/ZPublisher/interfaces.py =================================================================== --- Zope/trunk/src/ZPublisher/interfaces.py 2010-03-26 13:25:09 UTC (rev 110188) +++ Zope/trunk/src/ZPublisher/interfaces.py 2010-03-26 13:31:10 UTC (rev 110189) @@ -50,3 +50,11 @@ """ exc_info = Attribute('''The exception info as returned by 'sys.exc_info()'.''') retry = Attribute('Whether the request will be retried') + +class IPubBeforeStreaming(Interface): + """Event fired just before a streaming response is initiated, i.e. when + something calls response.write() for the first time. Note that this is + carries a reference to the *response*, not the request. + """ + + response = Attribute(u"The current HTTP response") Modified: Zope/trunk/src/ZPublisher/pubevents.py =================================================================== --- Zope/trunk/src/ZPublisher/pubevents.py 2010-03-26 13:25:09 UTC (rev 110188) +++ Zope/trunk/src/ZPublisher/pubevents.py 2010-03-26 13:31:10 UTC (rev 110189) @@ -10,7 +10,8 @@ from zope.interface import implements from interfaces import IPubStart, IPubSuccess, IPubFailure, \ - IPubAfterTraversal, IPubBeforeCommit, IPubBeforeAbort + IPubAfterTraversal, IPubBeforeCommit, IPubBeforeAbort, \ + IPubBeforeStreaming class _Base(object): """PubEvent base class.""" @@ -49,3 +50,11 @@ def __init__(self, request, exc_info, retry): self.request, self.exc_info, self.retry = request, exc_info, retry + +class PubBeforeStreaming(object): + """Notified immediately before streaming via response.write() commences + """ + implements(IPubBeforeStreaming) + + def __init__(self, response): + self.response = response Modified: Zope/trunk/src/ZPublisher/tests/testpubevents.py =================================================================== --- Zope/trunk/src/ZPublisher/tests/testpubevents.py 2010-03-26 13:25:09 UTC (rev 110188) +++ Zope/trunk/src/ZPublisher/tests/testpubevents.py 2010-03-26 13:31:10 UTC (rev 110189) @@ -1,3 +1,4 @@ +from StringIO import StringIO from sys import modules, exc_info from unittest import TestCase, TestSuite, makeSuite, main @@ -7,11 +8,14 @@ from ZPublisher.Publish import publish, Retry from ZPublisher.BaseRequest import BaseRequest +from ZPublisher.HTTPResponse import HTTPResponse from ZPublisher.pubevents import PubStart, PubSuccess, PubFailure, \ - PubAfterTraversal, PubBeforeCommit, PubBeforeAbort + PubAfterTraversal, PubBeforeCommit, PubBeforeAbort, \ + PubBeforeStreaming from ZPublisher.interfaces import \ IPubStart, IPubEnd, IPubSuccess, IPubFailure, \ - IPubAfterTraversal, IPubBeforeCommit + IPubAfterTraversal, IPubBeforeCommit, \ + IPubBeforeStreaming PUBMODULE = 'TEST_testpubevents' @@ -41,7 +45,10 @@ def testBeforeCommit(self): e = PubBeforeCommit(_Request()) verifyObject(IPubBeforeCommit, e) - + + def testBeforeStreaming(self): + e = PubBeforeStreaming(_Response()) + verifyObject(IPubBeforeStreaming, e) class TestPubEvents(TestCase): def setUp(self): @@ -127,6 +134,21 @@ self.assert_(isinstance(events[5], PubBeforeCommit)) self.assert_(isinstance(events[6], PubSuccess)) + def testStreaming(self): + + out = StringIO() + response = HTTPResponse(stdout=out) + response.write('datachunk1') + response.write('datachunk2') + + events = self.reporter.events + self.assertEqual(len(events), 1) + self.assert_(isinstance(events[0], PubBeforeStreaming)) + self.assertEqual(events[0].response, response) + + self.failUnless('datachunk1datachunk2' in out.getvalue()) + + # Auxiliaries def _succeed(): ''' ''' Modified: Zope/trunk/src/ZServer/HTTPResponse.py =================================================================== --- Zope/trunk/src/ZServer/HTTPResponse.py 2010-03-26 13:25:09 UTC (rev 110188) +++ Zope/trunk/src/ZServer/HTTPResponse.py 2010-03-26 13:31:10 UTC (rev 110189) @@ -20,8 +20,10 @@ import time, re, sys, tempfile from cStringIO import StringIO import thread +from zope.event import notify from ZPublisher.HTTPResponse import HTTPResponse from ZPublisher.Iterators import IStreamIterator +from ZPublisher.pubevents import PubBeforeStreaming from medusa.http_date import build_http_date from PubCore.ZEvent import Wakeup from medusa.producers import hooked_producer @@ -165,6 +167,9 @@ stdout=self.stdout if not self._wrote: + + notify(PubBeforeStreaming(self)) + l=self.headers.get('content-length', None) if l is not None: try: Modified: Zope/trunk/src/ZServer/tests/test_responses.py =================================================================== --- Zope/trunk/src/ZServer/tests/test_responses.py 2010-03-26 13:25:09 UTC (rev 110188) +++ Zope/trunk/src/ZServer/tests/test_responses.py 2010-03-26 13:31:10 UTC (rev 110189) @@ -19,17 +19,21 @@ from ZServer.PCGIServer import PCGIResponse from ZServer.FCGIServer import FCGIResponse from ZPublisher.Iterators import IStreamIterator +from ZPublisher.pubevents import PubBeforeStreaming from zope.interface import implements import unittest from cStringIO import StringIO +from zope.event import subscribers + + class ZServerResponseTestCase(unittest.TestCase): """Test ZServer response objects.""" def test_http_response_write_unicode(self): response = ZServerHTTPResponse() self.assertRaises(TypeError, response.write, u'bad') - + def test_ftp_response_write_unicode(self): response = FTPResponse() self.assertRaises(TypeError, response.write, u'bad') @@ -57,7 +61,7 @@ one = ZServerHTTPResponse(stdout=DummyChannel()) self.assertRaises(AssertionError, one.setBody, test_streamiterator()) - + class DummyChannel: def __init__(self): self.out = StringIO() @@ -267,12 +271,39 @@ '', '')) +class _Reporter(object): + def __init__(self): self.events = [] + def __call__(self, event): self.events.append(event) +class ZServerHTTPResponseEventsTestCase(unittest.TestCase): + + def setUp(self): + self._saved_subscribers = subscribers[:] + self.reporter = r = _Reporter() + subscribers[:] = [r] + + def tearDown(self): + subscribers[:] = self._saved_subscribers + + def testStreaming(self): + out = StringIO() + response = ZServerHTTPResponse(stdout=out) + response.write('datachunk1') + response.write('datachunk2') + + events = self.reporter.events + self.assertEqual(len(events), 1) + self.assert_(isinstance(events[0], PubBeforeStreaming)) + self.assertEqual(events[0].response, response) + + self.failUnless('datachunk1datachunk2' in out.getvalue()) + def test_suite(): suite = unittest.TestSuite() suite.addTests(( unittest.makeSuite(ZServerResponseTestCase), - unittest.makeSuite(ZServerHTTPResponseTestCase) + unittest.makeSuite(ZServerHTTPResponseTestCase), + unittest.makeSuite(ZServerHTTPResponseEventsTestCase) )) return suite _______________________________________________ Zope-Checkins maillist - Zope-Checkins@zope.org https://mail.zope.org/mailman/listinfo/zope-checkins