Commit bd733599 authored by Martin Aspeli's avatar Martin Aspeli

Merge c110187 from 2.12 branch, adding IPubBeforeStreaming event

parent 4ad8ac12
......@@ -5,12 +5,92 @@ This file contains change information for the current Zope release.
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 @@ Features Added
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)
------------------------
......
......@@ -18,10 +18,12 @@ __version__ = '$Revision: 1.81 $'[11:-2]
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 @@ class HTTPResponse(BaseResponse):
"""
if not self._wrote:
notify(PubBeforeStreaming(self))
self.outputBody()
self._wrote = 1
self.stdout.flush()
......
......@@ -50,3 +50,11 @@ class IPubBeforeAbort(IPubEvent):
"""
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")
......@@ -10,7 +10,8 @@ for detailed time related analysis, inline request monitoring.
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 @@ class PubBeforeAbort(_Base):
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
from StringIO import StringIO
from sys import modules, exc_info
from unittest import TestCase, TestSuite, makeSuite, main
......@@ -7,11 +8,14 @@ from zope.event import subscribers
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 @@ class TestInterface(TestCase):
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 @@ class TestPubEvents(TestCase):
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():
''' '''
......
......@@ -20,8 +20,10 @@ and logging duties.
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 @@ class ZServerHTTPResponse(HTTPResponse):
stdout=self.stdout
if not self._wrote:
notify(PubBeforeStreaming(self))
l=self.headers.get('content-length', None)
if l is not None:
try:
......
......@@ -19,17 +19,21 @@ from ZServer.FTPResponse import FTPResponse
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 @@ class ZServerResponseTestCase(unittest.TestCase):
one = ZServerHTTPResponse(stdout=DummyChannel())
self.assertRaises(AssertionError,
one.setBody, test_streamiterator())
class DummyChannel:
def __init__(self):
self.out = StringIO()
......@@ -267,12 +271,39 @@ class ZServerHTTPResponseTestCase(unittest.TestCase):
'',
''))
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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment