[Zope-Checkins] SVN: Zope/trunk/ Merge c110187 from 2.12 branch, adding IPubBeforeStreaming event

Martin Aspeli optilude at gmx.net
Fri Mar 26 09:31:11 EDT 2010


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
 



More information about the Zope-Checkins mailing list