Skip to content

Commit

Permalink
No Content-Type text/html on empty exception views [4.x] (#1088)
Browse files Browse the repository at this point in the history
* Only set response header Content-Type as text/html on exception views when the response has content. This fixes a problem in Plone with caching.
* Fix test and add new test for Content-Type header of empty exception body.
* Apply code review changes co-authored-by: Jens Vagelpohl <jens@plyp.com>
* Fix tox lint. Use isort 5, which isort-apply was already using.
* tox -e isort-apply
* Please both flake8 and isort for an unused BBB import.
* Fix tox -e docs, Locally I got Python 3.10, which cannot install this version of Zope.
  • Loading branch information
mauritsvanrees committed Jan 9, 2023
1 parent 731ab99 commit 43f9a7a
Show file tree
Hide file tree
Showing 57 changed files with 193 additions and 119 deletions.
4 changes: 4 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ https://zope.readthedocs.io/en/2.13/CHANGES.html
4.8.7 (unreleased)
------------------

- Only set response header Content-Type as text/html on exception views when
the response has content.
(`#1089 <https://github.com/zopefoundation/Zope/issues/1089>`_)

- Update dependencies to the latest releases for each supported Python version.


Expand Down
2 changes: 2 additions & 0 deletions src/App/tests/test_ApplicationManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,7 @@ def _makeOne(self, id):
def _makeModuleClasses(self):
import sys
import types

from ExtensionClass import Base

class Foo(Base):
Expand Down Expand Up @@ -513,6 +514,7 @@ def test_refdict(self):

def test_rcsnapshot(self):
import sys

import App.ApplicationManager
from DateTime.DateTime import DateTime
dm = self._makeOne('test')
Expand Down
3 changes: 1 addition & 2 deletions src/App/tests/test_getZopeVersion.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@

import unittest

from pkg_resources import get_distribution

from App.version_txt import getZopeVersion
from pkg_resources import get_distribution


class Test(unittest.TestCase):
Expand Down
8 changes: 4 additions & 4 deletions src/OFS/Application.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,8 +295,8 @@ def install_inituser(self):
def install_virtual_hosting(self):
app = self.getApp()
if 'virtual_hosting' not in app:
from Products.SiteAccess.VirtualHostMonster \
import VirtualHostMonster
from Products.SiteAccess.VirtualHostMonster import \
VirtualHostMonster
any_vhm = [obj for obj in app.values()
if isinstance(obj, VirtualHostMonster)]
if not any_vhm:
Expand All @@ -308,8 +308,8 @@ def install_virtual_hosting(self):
def install_root_view(self):
app = self.getApp()
if 'index_html' not in app:
from Products.PageTemplates.ZopePageTemplate \
import ZopePageTemplate
from Products.PageTemplates.ZopePageTemplate import \
ZopePageTemplate
root_pt = ZopePageTemplate('index_html')
root_pt.pt_setTitle(u'Auto-generated default page')
app._setObject('index_html', root_pt)
Expand Down
1 change: 1 addition & 0 deletions src/OFS/ObjectManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,7 @@ def manage_FTPstat(self, REQUEST):
u'Zope 5.', DeprecationWarning, stacklevel=2)
mode = 0o0040000
from AccessControl.User import nobody

# check to see if we are acquiring our objectValues or not
parents = REQUEST.PARENTS
if not (len(parents) > 1
Expand Down
1 change: 0 additions & 1 deletion src/OFS/bbb.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
##############################################################################

import pkg_resources

from zope.deferredimport import deprecated


Expand Down
2 changes: 1 addition & 1 deletion src/OFS/tests/applicationproduct/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@


def initialize(context):
from OFS.Folder import Folder
import transaction
from OFS.Folder import Folder

app = context.getApplication()
folder = Folder('some_folder')
Expand Down
3 changes: 2 additions & 1 deletion src/OFS/tests/testApplication.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,9 @@ def test_bobo_traverse_attribute_key_miss_R_M_is_GET(self):
self.assertRaises(KeyError, app.__bobo_traverse__, request, 'NONESUCH')

def test_bobo_traverse_attribute_key_miss_R_M_not_GET_POST(self):
from Acquisition import aq_inner
from Acquisition import aq_parent
from webdav.NullResource import NullResource
from Acquisition import aq_inner, aq_parent

app = self._makeOne()
app._getOb = _noWay
Expand Down
3 changes: 2 additions & 1 deletion src/OFS/tests/testCopySupport.py
Original file line number Diff line number Diff line change
Expand Up @@ -362,8 +362,9 @@ def _scrubSecurity(self):
def _assertCopyErrorUnauth(self, callable, *args, **kw):

import re
from zExceptions import Unauthorized

from OFS.CopySupport import CopyError
from zExceptions import Unauthorized

ce_regex = kw.get('ce_regex')
if ce_regex is not None:
Expand Down
2 changes: 1 addition & 1 deletion src/OFS/tests/testEtagSupport.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
class TestEtagSupport(unittest.TestCase):

def test_interfaces(self):
from zope.interface.verify import verifyClass
from OFS.EtagSupport import EtagBaseInterface
from OFS.EtagSupport import EtagSupport
from zope.interface.verify import verifyClass

verifyClass(EtagBaseInterface, EtagSupport)
4 changes: 2 additions & 2 deletions src/OFS/tests/testFileAndImage.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,9 +314,9 @@ def test_manage_DAVget_text(self):
self.assertEqual(self.file.manage_DAVget(), text)

def test_interfaces(self):
from zope.interface.verify import verifyClass
from OFS.Image import File
from OFS.interfaces import IWriteLock
from zope.interface.verify import verifyClass
from ZPublisher.HTTPRangeSupport import HTTPRangeInterface

verifyClass(HTTPRangeInterface, File)
Expand Down Expand Up @@ -370,9 +370,9 @@ def testViewImageOrFile(self):
self.assertEqual(result, self.data)

def test_interfaces(self):
from zope.interface.verify import verifyClass
from OFS.Image import Image
from OFS.interfaces import IWriteLock
from zope.interface.verify import verifyClass

verifyClass(IWriteLock, Image)

Expand Down
4 changes: 2 additions & 2 deletions src/OFS/tests/testObjectManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -608,9 +608,9 @@ def test_export_import(self):

from OFS.Folder import Folder
from OFS.Image import File
from ZODB.DemoStorage import DemoStorage
from ZODB.DB import DB
from transaction import commit
from ZODB.DB import DB
from ZODB.DemoStorage import DemoStorage
try:
tf = None # temporary file required for export/import
# export/import needs the object manager in ZODB
Expand Down
3 changes: 2 additions & 1 deletion src/OFS/tests/testRanges.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class TestRequestRange(unittest.TestCase):
def setUp(self):
import io
import string

import transaction
from OFS.Application import Application
from OFS.Folder import manage_addFolder
Expand Down Expand Up @@ -168,9 +169,9 @@ def expectSingleRange(self, range, start, end, if_range=None):
self.assertEqual(body, self.data[start:end])

def expectMultipleRanges(self, range, sets, draft=0):
import email
import io
import re
import email
rangeParse = re.compile(r'bytes\s*(\d+)-(\d+)/(\d+)')
req = self.app.REQUEST
rsp = req.RESPONSE
Expand Down
6 changes: 4 additions & 2 deletions src/OFS/tests/testTraverse.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ class ProtectedMethodSecurityPolicy(object):
"""Check security strictly on bound methods.
"""
def validate(self, accessed, container, name, value, *args):
from Acquisition import aq_base
from AccessControl import Unauthorized
from Acquisition import aq_base
if getattr(aq_base(value), '__self__', None) is None:
return 1

Expand All @@ -65,6 +65,7 @@ class TestTraverse(unittest.TestCase):

def setUp(self):
import io

import transaction
from AccessControl import SecurityManager
from AccessControl.SecurityManagement import newSecurityManager
Expand Down Expand Up @@ -393,9 +394,10 @@ def testDefaultValueWhenUnathorized(self):
self.root.folder1.restrictedTraverse('stuff', 42), 42)

def testNotFoundIsRaised(self):
from operator import getitem

from OFS.SimpleItem import SimpleItem
from zExceptions import NotFound
from operator import getitem
self.folder1._setObject('foo', SimpleItem('foo'))
self.assertRaises(AttributeError, getitem, self.folder1.foo,
'doesntexist')
Expand Down
4 changes: 2 additions & 2 deletions src/OFS/tests/test_DTMLDocument.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ def _makeOne(self, *args, **kw):
return self._getTargetClass()(*args, **kw)

def test_class_conforms_to_IWriteLock(self):
from zope.interface.verify import verifyClass
from OFS.interfaces import IWriteLock
from zope.interface.verify import verifyClass
verifyClass(IWriteLock, self._getTargetClass())

def test_manage_upload__bytes(self):
Expand Down Expand Up @@ -70,8 +70,8 @@ class FactoryTests(unittest.TestCase):

def test_defaults_no_standard_html_header(self):
# see LP #496961
from OFS.DTMLDocument import addDTMLDocument
from OFS.DTMLDocument import DTMLDocument
from OFS.DTMLDocument import addDTMLDocument
dispatcher = DummyDispatcher()
addDTMLDocument(dispatcher, 'id')
method = dispatcher._set['id']
Expand Down
6 changes: 3 additions & 3 deletions src/OFS/tests/test_DTMLMethod.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@


def _lock_item(item):
from OFS.LockItem import LockItem
from AccessControl.users import nobody
from OFS.LockItem import LockItem
item.wl_setLock('token', LockItem(nobody, token='token'))


Expand All @@ -30,8 +30,8 @@ def _makeOne(self, *args, **kw):
return self._getTargetClass()(*args, **kw)

def test_class_conforms_to_IWriteLock(self):
from zope.interface.verify import verifyClass
from OFS.interfaces import IWriteLock
from zope.interface.verify import verifyClass
verifyClass(IWriteLock, self._getTargetClass())

def test_edit_taintedstring(self):
Expand Down Expand Up @@ -264,8 +264,8 @@ class FactoryTests(unittest.TestCase):

def test_defaults_no_standard_html_header(self):
# see LP #496961
from OFS.DTMLMethod import addDTMLMethod
from OFS.DTMLMethod import DTMLMethod
from OFS.DTMLMethod import addDTMLMethod
dispatcher = DummyDispatcher()
addDTMLMethod(dispatcher, 'id')
method = dispatcher._set['id']
Expand Down
4 changes: 2 additions & 2 deletions src/OFS/tests/test_Uninstalled.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,10 @@ def test_Broken_instance___getattr___allows_persistence_attrs(self):
class TestsIntegratedBroken(base.TestCase):

def test_Broken_instance___getstate___gives_access_to_its_state(self):
import transaction
from Acquisition import aq_base
from OFS.Uninstalled import BrokenClass
from OFS.tests import test_Uninstalled
import transaction
from OFS.Uninstalled import BrokenClass

# store an instance
tr = ToBreak()
Expand Down
3 changes: 2 additions & 1 deletion src/OFS/tests/test_metaconfigure.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ def setUp(self):
OFS.metaconfigure._meta_type_regs[:] = []

def tearDown(self):
from zope.component.testing import tearDown
import OFS.metaconfigure
from zope.component.testing import tearDown

# restore registrations
OFS.metaconfigure._meta_type_regs[:] = self._old_mt_regs
OFS.metaconfigure._register_monkies[:] = self._old_monkies
Expand Down
2 changes: 1 addition & 1 deletion src/OFS/userfolder.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from AccessControl import ClassSecurityInfo
from AccessControl import userfolder as accesscontrol_userfolder
from AccessControl.class_init import InitializeClass
from AccessControl.Permissions import manage_users as ManageUsers # NOQA
from AccessControl.Permissions import manage_users as ManageUsers
from AccessControl.requestmethod import requestmethod
from AccessControl.rolemanager import DEFAULTMAXLISTUSERS
from AccessControl.users import _remote_user_mode
Expand Down
2 changes: 1 addition & 1 deletion src/Products/Five/browser/adding.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
from zope.component.interfaces import IFactory
from zope.container.constraints import checkFactory
from zope.container.constraints import checkObject
from zope.container.i18n import ZopeMessageFactory as _ # NOQA
from zope.container.i18n import ZopeMessageFactory as _
from zope.container.interfaces import IContainerNamesContainer
from zope.container.interfaces import INameChooser
from zope.event import notify
Expand Down
3 changes: 2 additions & 1 deletion src/Products/Five/browser/tests/test_i18n.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ def test_zpt_i18n():


def test_suite():
from Testing.ZopeTestCase import FunctionalDocTestSuite
import doctest

from Testing.ZopeTestCase import FunctionalDocTestSuite
return FunctionalDocTestSuite(
optionflags=doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE)
12 changes: 6 additions & 6 deletions src/Products/Five/browser/tests/test_pagetemplatefile.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ def test_getId_with_path(self):
self.assertEqual(vptf.id, 'dirpage1.pt')

def test_pt_getEngine(self):
from Products.PageTemplates.Expressions import SecureModuleImporter
from Products.PageTemplates.Expressions import TrustedZopePathExpr
from Products.PageTemplates.Expressions import UnicodeAwareStringExpr
from zope.contentprovider.tales import TALESProviderExpression
from zope.tales.expressions import DeferExpr
from zope.tales.expressions import LazyExpr
from zope.tales.expressions import NotExpr
from zope.tales.pythonexpr import PythonExpr
from zope.contentprovider.tales import TALESProviderExpression
from Products.PageTemplates.Expressions import TrustedZopePathExpr
from Products.PageTemplates.Expressions import SecureModuleImporter
from Products.PageTemplates.Expressions import UnicodeAwareStringExpr

vptf = self._makeOne('seagull.pt')
engine = vptf.pt_getEngine()
Expand All @@ -59,9 +59,9 @@ def test_pt_getEngine(self):
self.assertEqual(engine.base_names['modules'], SecureModuleImporter)

def test_pt_getContext_no_kw_no_physicalRoot(self):
from AccessControl.SecurityManagement import newSecurityManager
from Products.Five.browser.pagetemplatefile import ViewMapper
from Products.PageTemplates.Expressions import SecureModuleImporter
from AccessControl.SecurityManagement import newSecurityManager
newSecurityManager(None, DummyUser('a_user'))
context = DummyContext()
request = DummyRequest()
Expand Down Expand Up @@ -191,8 +191,8 @@ def test___getitem___miss(self):
self.assertRaises(ComponentLookupError, mapper.__getitem__, 'nonesuch')

def test___getitem___hit(self):
from zope.interface import Interface
from zope.component import provideAdapter
from zope.interface import Interface

def _adapt(context, request):
return self
Expand Down
3 changes: 2 additions & 1 deletion src/Products/Five/browser/tests/test_zope3security.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ def test_allowed_interface():


def test_suite():
from Testing.ZopeTestCase import FunctionalDocTestSuite
from doctest import ELLIPSIS

from Testing.ZopeTestCase import FunctionalDocTestSuite
return FunctionalDocTestSuite(optionflags=ELLIPSIS)

0 comments on commit 43f9a7a

Please sign in to comment.