Commit c4241373 authored by Hanno Schlichting's avatar Hanno Schlichting

Add support for raising HTTPOK and HTTPRedirection exceptions.

These need special casing in the publisher to be treated as successful
and result in transaction commits. Also prefer `raise Redirect` style
over `REQUEST.RESPONSE.redirect`.
parent 50447696
......@@ -16,6 +16,9 @@ Bugs Fixed
Features Added
++++++++++++++
- Add support for raising HTTPOK and HTTPRedirection exceptions and
have them result in successful transactions.
- Add better blob support to HTTPRequest.ZopeFieldStorage.
- Updated distributions:
......
......@@ -18,6 +18,8 @@ import urllib
from AccessControl.class_init import InitializeClass
from AccessControl.requestmethod import requestmethod
from Acquisition import Implicit
from zExceptions import Redirect
from App.config import getConfiguration
from App.Management import Tabs
from App.special_dtml import DTMLFile
......@@ -178,7 +180,6 @@ class AltDatabaseManager(Traversable, UndoSupport):
self._getDB().cacheMinimize()
if REQUEST is not None:
response = REQUEST['RESPONSE']
response.redirect(REQUEST['URL1'] + '/manage_main')
raise Redirect(REQUEST['URL1'] + '/manage_main')
InitializeClass(AltDatabaseManager)
......@@ -24,6 +24,8 @@ from Acquisition import Acquired
from Acquisition import aq_base
from Acquisition import Implicit
from ExtensionClass import Base
from zExceptions import Redirect
from OFS.metaconfigure import get_registered_packages
......@@ -159,6 +161,6 @@ class FactoryDispatcher(Implicit):
def manage_main(trueself, self, REQUEST, update_menu=0):
"""Implement a contents view by redirecting to the true view
"""
REQUEST['RESPONSE'].redirect(self.DestinationURL() + '/manage_main')
raise Redirect(self.DestinationURL() + '/manage_main')
InitializeClass(FactoryDispatcher)
......@@ -21,6 +21,7 @@ from AccessControl.class_init import InitializeClass
from AccessControl.Permissions import undo_changes
from DateTime.DateTime import DateTime
import transaction
from zExceptions import Redirect
from App.Management import Tabs
from App.special_dtml import DTMLFile
......@@ -114,10 +115,8 @@ class UndoSupport(Tabs, Implicit):
transaction.get().note("Undo %s" % ' '.join(descriptions))
self._p_jar.db().undoMultiple(tids)
if REQUEST is None:
return
REQUEST['RESPONSE'].redirect("%s/manage_UndoForm" % REQUEST['URL1'])
return ''
if REQUEST is not None:
raise Redirect('%s/manage_UndoForm' % REQUEST['URL1'])
InitializeClass(UndoSupport)
......
......@@ -16,17 +16,19 @@ from urllib import quote
from AccessControl import getSecurityManager
from AccessControl.class_init import InitializeClass
from App.special_dtml import DTMLFile
from App.special_dtml import HTML
from DocumentTemplate.permissions import change_dtml_methods
from DocumentTemplate.permissions import change_dtml_documents
from OFS.DTMLMethod import decapitate
from OFS.DTMLMethod import DTMLMethod
from OFS.PropertyManager import PropertyManager
from zExceptions import Redirect
from zExceptions import ResourceLockedError
from zExceptions.TracebackSupplement import PathTracebackSupplement
from zope.contenttype import guess_content_type
from App.special_dtml import DTMLFile
from App.special_dtml import HTML
from OFS.DTMLMethod import decapitate
from OFS.DTMLMethod import DTMLMethod
from OFS.PropertyManager import PropertyManager
done = 'done'
......@@ -148,5 +150,5 @@ def addDTMLDocument(self, id, title='', file='', REQUEST=None, submit=None):
u = REQUEST['URL1']
if submit == " Add and Edit ":
u = "%s/%s" % (u, quote(id))
REQUEST.RESPONSE.redirect(u + '/manage_main')
raise Redirect(u + '/manage_main')
return ''
......@@ -18,23 +18,25 @@ from urllib import quote
from AccessControl.class_init import InitializeClass
from AccessControl.SecurityInfo import ClassSecurityInfo
from Acquisition import Implicit
from App.special_dtml import DTMLFile
from App.special_dtml import HTML
from AccessControl import getSecurityManager
from AccessControl.Permissions import view_management_screens
from AccessControl.Permissions import view as View # NOQA
from AccessControl.Permissions import ftp_access
from AccessControl.tainted import TaintedString
from Acquisition import Implicit
from DocumentTemplate.permissions import change_dtml_methods
from DocumentTemplate.security import RestrictedDTML
from zExceptions import Redirect
from zExceptions import ResourceLockedError
from zExceptions.TracebackSupplement import PathTracebackSupplement
from zope.contenttype import guess_content_type
from App.special_dtml import DTMLFile
from App.special_dtml import HTML
from OFS import bbb
from OFS.Cache import Cacheable
from OFS.role import RoleManager
from OFS.SimpleItem import Item_w__name__
from zExceptions import ResourceLockedError
from zExceptions.TracebackSupplement import PathTracebackSupplement
from zope.contenttype import guess_content_type
if sys.version_info >= (3, ):
basestring = str
......@@ -308,5 +310,5 @@ def addDTMLMethod(self, id, title='', file='', REQUEST=None, submit=None):
u = REQUEST['URL1']
if submit == " Add and Edit ":
u = "%s/%s" % (u, quote(id))
REQUEST.RESPONSE.redirect(u + '/manage_main')
raise Redirect(u + '/manage_main')
return ''
......@@ -26,27 +26,26 @@ from AccessControl.Permissions import view as View # NOQA
from AccessControl.Permissions import ftp_access
from AccessControl.SecurityInfo import ClassSecurityInfo
from Acquisition import Implicit
from App.Common import rfc1123_date
from App.special_dtml import DTMLFile
from DateTime.DateTime import DateTime
from Persistence import Persistent
from ZPublisher import HTTPRangeSupport
from ZPublisher.HTTPRequest import FileUpload
from zExceptions import Redirect, ResourceLockedError
from zope.contenttype import guess_content_type
from zope.event import notify
from zope.interface import implementedBy
from zope.interface import implements
from zope.lifecycleevent import ObjectCreatedEvent
from zope.lifecycleevent import ObjectModifiedEvent
from App.Common import rfc1123_date
from App.special_dtml import DTMLFile
from OFS import bbb
from OFS.Cache import Cacheable
from OFS.interfaces import IWriteLock
from OFS.PropertyManager import PropertyManager
from OFS.role import RoleManager
from OFS.SimpleItem import Item_w__name__
from zope.event import notify
from zope.lifecycleevent import ObjectModifiedEvent
from zope.lifecycleevent import ObjectCreatedEvent
from ZPublisher import HTTPRangeSupport
from ZPublisher.HTTPRequest import FileUpload
if sys.version_info >= (3, ):
unicode = str
......@@ -85,7 +84,7 @@ def manage_addFile(self, id, file='', title='', precondition='',
notify(ObjectCreatedEvent(newFile))
if REQUEST is not None:
REQUEST['RESPONSE'].redirect(self.absolute_url() + '/manage_main')
raise Redirect(self.absolute_url() + '/manage_main')
class File(Persistent, Implicit, PropertyManager,
......@@ -671,7 +670,7 @@ def manage_addImage(self, id, file, title='', precondition='', content_type='',
url = self.DestinationURL()
except Exception:
url = REQUEST['URL1']
REQUEST.RESPONSE.redirect('%s/manage_main' % url)
raise Redirect('%s/manage_main' % url)
return id
......
......@@ -23,12 +23,14 @@ from AccessControl.SecurityInfo import ClassSecurityInfo
from Acquisition import aq_base
from Acquisition import aq_parent
from Acquisition import Implicit
from App.Management import Tabs
from ExtensionClass import Base
from OFS import bbb
from Persistence import Persistent
from Traversable import Traversable
from zExceptions import BadRequest
from zExceptions import Redirect
from App.Management import Tabs
from OFS import bbb
from OFS.Traversable import Traversable
from ZPublisher.Converters import type_converters
if bbb.HAS_ZSERVER:
......@@ -57,7 +59,7 @@ class View(Tabs, Base):
def manage_workspace(self, URL1, RESPONSE):
'''Implement a "management" interface
'''
RESPONSE.redirect(URL1 + '/manage')
raise Redirect(URL1 + '/manage')
def tpURL(self):
return self.getId()
......
......@@ -15,11 +15,6 @@
import urlparse
from Acquisition import aq_get
from Acquisition import aq_parent
from App.special_dtml import DTMLFile
from AccessControl.class_init import InitializeClass
from AccessControl.owner import Owned as BaseOwned
from AccessControl.owner import ownableFilter
......@@ -30,6 +25,11 @@ from AccessControl.requestmethod import requestmethod
from AccessControl.SecurityInfo import ClassSecurityInfo
from AccessControl.SecurityManagement import getSecurityManager
from AccessControl.unauthorized import Unauthorized
from Acquisition import aq_get
from Acquisition import aq_parent
from zExceptions import Redirect
from App.special_dtml import DTMLFile
class Owned(BaseOwned):
......@@ -63,7 +63,7 @@ class Owned(BaseOwned):
self.changeOwnership(security.getUser(), recursive)
RESPONSE.redirect(REQUEST['HTTP_REFERER'])
raise Redirect(REQUEST['HTTP_REFERER'])
security.declareProtected(take_ownership, 'manage_changeOwnershipType')
@requestmethod('POST')
......@@ -87,6 +87,6 @@ class Owned(BaseOwned):
del self._owner
if RESPONSE is not None:
RESPONSE.redirect(REQUEST['HTTP_REFERER'])
raise Redirect(REQUEST['HTTP_REFERER'])
InitializeClass(Owned)
......@@ -15,25 +15,25 @@
import os
from Acquisition import aq_base
from App.Management import Navigation
from App.Management import Tabs
from App.special_dtml import DTMLFile
from OFS.role import RoleManager
from OFS.SimpleItem import Item
from zExceptions import BadRequest
from AccessControl import ClassSecurityInfo
from AccessControl.class_init import InitializeClass
from AccessControl.Permissions import manage_users as ManageUsers # NOQA
from AccessControl.requestmethod import requestmethod
from AccessControl.rolemanager import DEFAULTMAXLISTUSERS
from AccessControl import userfolder as accesscontrol_userfolder
from AccessControl.users import readUserAccessFile
from AccessControl.users import _remote_user_mode
from AccessControl.users import emergency_user
from AccessControl.users import readUserAccessFile
from AccessControl.users import reqattr
from Acquisition import aq_base
from zExceptions import BadRequest
from zExceptions import Redirect
from App.Management import Navigation
from App.Management import Tabs
from App.special_dtml import DTMLFile
from OFS.role import RoleManager
from OFS.SimpleItem import Item
class BasicUserFolder(Navigation, Tabs, Item, RoleManager,
......@@ -306,4 +306,4 @@ def manage_addUserFolder(self, dtself=None, REQUEST=None, **ignored):
raise BadRequest('This object already contains a User Folder')
self.__allow_groups__ = f
if REQUEST is not None:
REQUEST['RESPONSE'].redirect(self.absolute_url() + '/manage_main')
raise Redirect(self.absolute_url() + '/manage_main')
......@@ -21,6 +21,8 @@ factory screen.
import operator
from zExceptions import BadRequest
from zExceptions import Redirect
from zope.browser.interfaces import IAdding
from zope.browsermenu.menu import getMenu
from zope.component import getMultiAdapter
......@@ -40,9 +42,7 @@ from zope.lifecycleevent import ObjectCreatedEvent
from zope.publisher.interfaces import IPublishTraverse
from zope.traversing.browser.absoluteurl import absoluteURL
from zExceptions import BadRequest
from OFS.SimpleItem import SimpleItem
from Products.Five import BrowserView
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
......@@ -136,8 +136,7 @@ class Adding(BrowserView):
name=view_name) is not None:
url = "%s/%s=%s" % (
absoluteURL(self, self.request), type_name, id)
self.request.response.redirect(url)
return
raise Redirect(url)
if not self.contentName:
self.contentName = id
......@@ -148,7 +147,7 @@ class Adding(BrowserView):
notify(ObjectCreatedEvent(content))
self.add(content)
self.request.response.redirect(self.nextURL())
raise Redirect(self.nextURL())
def nameAllowed(self):
"""Return whether names can be input by the user."""
......
......@@ -24,8 +24,11 @@ from AccessControl.Permissions import view_management_screens
from AccessControl.SecurityManagement import getSecurityManager
from AccessControl.SecurityInfo import ClassSecurityInfo
from Acquisition import Acquired
from Acquisition import Explicit
from Acquisition import aq_get
from Acquisition import Explicit
from zExceptions import Redirect
from zExceptions import ResourceLockedError
from App.Common import package_home
from OFS.Cache import Cacheable
from OFS.SimpleItem import SimpleItem
......@@ -33,14 +36,11 @@ from OFS.PropertyManager import PropertyManager
from OFS.Traversable import Traversable
from Shared.DC.Scripts.Script import Script
from Shared.DC.Scripts.Signature import FuncCode
from zExceptions import ResourceLockedError
from Products.PageTemplates import bbb
from Products.PageTemplates.Expressions import SecureModuleImporter
from Products.PageTemplates.PageTemplate import PageTemplate
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
from Products.PageTemplates.PageTemplateFile import guess_type
from Products.PageTemplates.Expressions import SecureModuleImporter
from Products.PageTemplates.utils import encodingFromXMLPreamble
from Products.PageTemplates.utils import charsetFromMetaEquiv
from Products.PageTemplates.utils import convertToUnicode
......@@ -405,9 +405,9 @@ def manage_addPageTemplate(self, id, title='', text='', encoding='utf-8',
if RESPONSE:
if submit == " Add and Edit ":
RESPONSE.redirect(zpt.absolute_url() + '/pt_editForm')
raise Redirect(zpt.absolute_url() + '/pt_editForm')
else:
RESPONSE.redirect(self.absolute_url() + '/manage_main')
raise Redirect(self.absolute_url() + '/manage_main')
else:
return zpt
......
......@@ -25,6 +25,7 @@ import zlib
from zope.event import notify
from zExceptions import (
HTTPRedirection,
Redirect,
status_reasons,
Unauthorized,
......@@ -554,10 +555,12 @@ class HTTPResponse(BaseResponse):
def redirect(self, location, status=302, lock=0):
"""Cause a redirection without raising an error"""
if isinstance(location, HTTPRedirection):
status = location.getStatus()
location = str(location)
self.setStatus(status, lock=lock)
self.setHeader('Location', location)
return str(location)
return location
# The following two methods are part of a private protocol with
# ZServer for handling fatal import errors.
......
......@@ -19,7 +19,11 @@ import transaction
from urlparse import urlparse
from six import reraise
from zExceptions import Redirect
from zExceptions import (
HTTPOk,
HTTPRedirection,
Redirect,
)
from zope.event import notify
from zope.publisher.interfaces import ISkinnable
from zope.publisher.interfaces.browser import IBrowserPage
......@@ -146,22 +150,29 @@ def publish(request, module_name, after_list, debug=0,
if transactions_manager:
transactions_manager.recordMetaData(object, request)
result = mapply(object, request.args, request,
call_object, 1,
missing_name,
dont_publish_class,
request, bind=1)
if result is not response:
response.setBody(result)
ok_exception = None
try:
result = mapply(object, request.args, request,
call_object, 1,
missing_name,
dont_publish_class,
request, bind=1)
except (HTTPOk, HTTPRedirection) as exc:
ok_exception = exc
else:
if result is not response:
response.setBody(result)
notify(pubevents.PubBeforeCommit(request))
if transactions_manager:
transactions_manager.commit()
endInteraction()
notify(pubevents.PubSuccess(request))
endInteraction()
if ok_exception:
raise ok_exception
return response
except:
......
......@@ -17,8 +17,11 @@ import sys
import time
import transaction
from zExceptions import Redirect
from zExceptions import Unauthorized
from zExceptions import (
HTTPOk,
HTTPRedirection,
Unauthorized,
)
from zope.event import notify
from zope.security.management import newInteraction, endInteraction
from zope.publisher.skinnable import setDefaultSkin
......@@ -182,19 +185,24 @@ def publish(request, module_info, repoze_tm_active=False):
if transactions_manager:
transactions_manager.recordMetaData(object, request)
result = mapply(object,
request.args,
request,
call_object,
1,
missing_name,
dont_publish_class,
request,
bind=1,
)
if result is not response:
response.setBody(result)
ok_exception = None
try:
result = mapply(object,
request.args,
request,
call_object,
1,
missing_name,
dont_publish_class,
request,
bind=1)
except (HTTPOk, HTTPRedirection) as exc:
# 2xx and 3xx responses raised as exceptions are considered
# successful.
ok_exception = exc
else:
if result is not response:
response.setBody(result)
notify(pubevents.PubBeforeCommit(request))
......@@ -202,6 +210,9 @@ def publish(request, module_info, repoze_tm_active=False):
transactions_manager.commit()
notify(pubevents.PubSuccess(request))
if ok_exception:
raise ok_exception
finally:
endInteraction()
......@@ -283,8 +294,8 @@ def publish_module(environ, start_response,
raise
except Unauthorized:
response._unauthorized()
except Redirect as v:
response.redirect(v)
except HTTPRedirection as exc:
response.redirect(exc)
# Start the WSGI server response
status, headers = response.finalize()
......
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