[Zope3-checkins] CVS: Zope3/src/zope/app/publication - httpfactory.py:1.1.2.1 browser.py:1.4.2.1 http.py:1.2.4.1 xmlrpc.py:1.3.2.1 zopepublication.py:1.10.2.1 configure.zcml:NONE

Sidnei da Silva sidnei@x3ng.com.br
Tue, 11 Feb 2003 09:41:54 -0500


Update of /cvs-repository/Zope3/src/zope/app/publication
In directory cvs.zope.org:/tmp/cvs-serv18615/src/zope/app/publication

Modified Files:
      Tag: paris-copypasterename-branch
	browser.py http.py xmlrpc.py zopepublication.py 
Added Files:
      Tag: paris-copypasterename-branch
	httpfactory.py 
Removed Files:
      Tag: paris-copypasterename-branch
	configure.zcml 
Log Message:
Updating from HEAD to make sure everything still works before merging

=== Added File Zope3/src/zope/app/publication/httpfactory.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""

$Id: httpfactory.py,v 1.1.2.1 2003/02/11 14:41:22 sidnei Exp $
"""

from zope.publisher.http import HTTPRequest
from zope.publisher.browser import BrowserRequest
from zope.publisher.xmlrpc import XMLRPCRequest

from zope.app.interfaces.startup import IPublicationRequestFactoryFactory
from zope.app.interfaces.startup import IPublicationRequestFactory

from zope.app.publication.http import HTTPPublication
from zope.app.publication.browser import BrowserPublication
from zope.app.publication.xmlrpc import XMLRPCPublication


__implements__ = IPublicationRequestFactoryFactory

__metaclass__ = type

_browser_methods = 'GET', 'POST', 'HEAD'

class HTTPPublicationRequestFactory:

    __implements__ = IPublicationRequestFactory

    def __init__(self, db):
        'See IRequestFactory'

        self._http = HTTPPublication(db)
        self._brower = BrowserPublication(db)
        self._xmlrpc = XMLRPCPublication(db)

    def __call__(self, input_stream, output_steam, env):
        'See IRequestFactory'

        method = env.get('REQUEST_METHOD', 'GET').upper()

        if method in _browser_methods:
            if (method == 'POST' and
                env.get('CONTENT_TYPE', '').startswith('text/xml')
                ):
                request = XMLRPCRequest(input_stream, output_steam, env)
                request.setPublication(self._xmlrpc)
            else:
                request = BrowserRequest(input_stream, output_steam, env)
                request.setPublication(self._brower)
        else:
            request = HTTPRequest(input_stream, output_steam, env)
            request.setPublication(self._http)
        
        return request

realize = HTTPPublicationRequestFactory


=== Zope3/src/zope/app/publication/browser.py 1.4 => 1.4.2.1 ===
--- Zope3/src/zope/app/publication/browser.py:1.4	Tue Dec 31 13:26:57 2002
+++ Zope3/src/zope/app/publication/browser.py	Tue Feb 11 09:41:22 2003
@@ -19,7 +19,7 @@
 
 from zope.app.publication.publicationtraverse \
      import PublicationTraverser as PublicationTraverser_
-from zope.app.publication.http import ZopeHTTPPublication
+from zope.app.publication.zopepublication import ZopePublication
 from zope.component import queryAdapter, queryView
 from zope.proxy.context import ContextWrapper
 from zope.proxy.introspection import removeAllProxies
@@ -43,7 +43,7 @@
 
             ob = self.traversePath(request, ob, path)
 
-class BrowserPublication(ZopeHTTPPublication):
+class BrowserPublication(ZopePublication):
     """Web browser publication handling."""
 
     def getDefaultTraversal(self, request, ob):
@@ -64,6 +64,11 @@
 
         wrapped = ContextWrapper(ProxyFactory(r[0]), ob, name=None)
         return (wrapped, r[1])
+
+    def afterCall(self, request):
+        super(BrowserPublication, self).afterCall(request)
+        if request.method == 'HEAD':
+            request.response.setBody('')
 
 # For now, have a factory that returns a singleton
 class PublicationFactory:


=== Zope3/src/zope/app/publication/http.py 1.2 => 1.2.4.1 ===
--- Zope3/src/zope/app/publication/http.py:1.2	Wed Dec 25 09:13:08 2002
+++ Zope3/src/zope/app/publication/http.py	Tue Feb 11 09:41:22 2003
@@ -17,7 +17,13 @@
 """
 
 from zope.app.publication.zopepublication import ZopePublication
+from zope.component import getView
+from zope.publisher.publish import mapply
 
-class ZopeHTTPPublication(ZopePublication):
+class HTTPPublication(ZopePublication):
     "HTTP-specific support"
-    # XXX do we need this?
+
+    def callObject(self, request, ob):
+        ob = getView(ob, request.method, request)
+        ob = getattr(ob, request.method)
+        return mapply(ob, request.getPositionalArguments(), request)


=== Zope3/src/zope/app/publication/xmlrpc.py 1.3 => 1.3.2.1 ===
--- Zope3/src/zope/app/publication/xmlrpc.py:1.3	Tue Jan 14 15:26:05 2003
+++ Zope3/src/zope/app/publication/xmlrpc.py	Tue Feb 11 09:41:22 2003
@@ -15,11 +15,12 @@
 
 $Id$
 """
+
 from zope.proxy.introspection import removeAllProxies
-from zope.app.publication.http import ZopeHTTPPublication
+from zope.app.publication.zopepublication import ZopePublication
 from zope.component import queryView
 
-class XMLRPCPublication(ZopeHTTPPublication):
+class XMLRPCPublication(ZopePublication):
     """XML-RPC publication handling.
 
        There is nothing special here right now.


=== Zope3/src/zope/app/publication/zopepublication.py 1.10 => 1.10.2.1 ===
--- Zope3/src/zope/app/publication/zopepublication.py:1.10	Mon Feb  3 12:20:24 2003
+++ Zope3/src/zope/app/publication/zopepublication.py	Tue Feb 11 09:41:22 2003
@@ -14,12 +14,14 @@
 import sys
 import logging
 
-from zope.component import getService
+from zope.component import getService, getView, getDefaultViewName
+from zope.component import queryService, getAdapter
 from zope.component.exceptions import ComponentLookupError
+from zope.component.servicenames import ErrorReports, Authentication
 from zodb.interfaces import ConflictError
 
 from zope.publisher.publish import mapply
-from zope.publisher.interfaces import Retry
+from zope.publisher.interfaces import Retry, IExceptionSideEffects
 from zope.publisher.interfaces.http import IHTTPRequest
 
 from zope.security.management import getSecurityManager, newSecurityManager
@@ -70,7 +72,8 @@
                 raise Unauthorized # If there's no default principal
 
         newSecurityManager(p.getId())
-        request.user = p
+        # XXX add a test to check that request.user is context wrapped
+        request.user = ContextWrapper(p, prin_reg)
         get_transaction().begin()
 
     def _maybePlacefullyAuthenticate(self, request, ob):
@@ -90,7 +93,7 @@
 
         sm = ContextWrapper(sm, ob, name="++etc++Services")
 
-        auth_service = sm.get('Authentication')
+        auth_service = sm.get(Authentication)
         if auth_service is None:
             # No auth service here
             return
@@ -104,7 +107,8 @@
                 return
 
         newSecurityManager(principal.getId())
-        request.user = principal
+        # XXX add test that request.user is context-wrapped
+        request.user = ContextWrapper(principal, auth_service)
 
 
     def callTraversalHooks(self, request, ob):
@@ -160,16 +164,66 @@
         txn.setUser(request.user.getId())
         get_transaction().commit()
 
-    def handleException(self, object, request, exc_info, retry_allowed=1):
-        # Abort the transaction.
-        get_transaction().abort()
-
-        try:
-            errService = getService(object, 'ErrorReportingService')
-        except ComponentLookupError:
-            pass
+    def handleException(self, object, request, exc_info, retry_allowed=True):
+        # Convert ConflictErrors to Retry exceptions.
+        if retry_allowed and isinstance(exc_info[1], ConflictError):
+            get_transaction().abort()
+            tryToLogWarning('ZopePublication',
+                'Competing writes/reads at %s' % 
+                request.get('PATH_INFO', '???'),
+                exc_info=True)
+            raise Retry
+        # Are there any reasons why we'd want to let application-level error
+        # handling determine whether a retry is allowed or not?
+        # Assume not for now.
+
+        response = request.response
+        exception = None
+        legacy_exception = not isinstance(exc_info[1], Exception)
+        if legacy_exception:
+            response.handleException(exc_info)
+            get_transaction().abort()
+            if isinstance(exc_info[1], str):
+                tryToLogWarning(
+                    'Publisher received a legacy string exception: %s.'
+                    ' This will be handled by the request.' %
+                    exc_info[1])
+            else:
+                tryToLogWarning(
+                    'Publisher received a legacy classic class exception: %s.'
+                    ' This will be handled by the request.' %
+                    exc_info[1].__class__)
         else:
+            # We definitely have an Exception
             try:
+                # Set the request body, and abort the current transaction.
+                try:
+                    exception = ContextWrapper(exc_info[1], object)
+                    name = getDefaultViewName(exception, request)
+                    view = getView(exception, name, request)
+                    response.setBody(self.callObject(request, view))
+                except ComponentLookupError:
+                    # No view available for this exception, so let the
+                    # response handle it.
+                    response.handleException(exc_info)
+                except:
+                    # Problem getting a view for this exception. Log an error.
+                    tryToLogException(
+                        'Exception while getting view on exception')
+                    # So, let the response handle it.
+                    response.handleException(exc_info)
+            finally:
+                # Definitely abort the transaction that raised the exception.
+                get_transaction().abort()
+
+        # New transaction for side-effects
+        beginErrorHandlingTransaction(request)
+        transaction_ok = False
+
+        # Record the error with the ErrorReportingService
+        try:
+            errService = queryService(object, ErrorReports)
+            if errService is not None:
                 errService.raising(exc_info, request)
             # It is important that an error in errService.raising
             # does not propagate outside of here. Otherwise, nothing
@@ -183,64 +237,71 @@
             # error handling that this error occurred while using
             # the ErrorReportingService, and that it will be in
             # the zope log.
-            except:
-                logging.getLogger('SiteError').exception(
-                    'Error while reporting an error to the '
-                    'ErrorReportingService')
-
-        # Delegate Unauthorized errors to the authentication service
-        # XXX Is this the right way to handle Unauthorized?  We need
-        # to understand this better.
-        if isinstance(exc_info[1], Unauthorized):
-            sm = getSecurityManager()
-            id = sm.getPrincipal()
-            prin_reg.unauthorized(id, request) # May issue challenge
-            request.response.handleException(exc_info)
-            return
-
-        # XXX This is wrong. Should use getRequstView:
-        #
-        #
-        # # Look for a component to handle the exception.
-        # traversed = request.traversed
-        # if traversed:
-        #     context = traversed[-1]
-        #     #handler = getExceptionHandler(context, t, IBrowserPublisher)
-        #     handler = None  # no getExceptionHandler() exists yet.
-        #     if handler is not None:
-        #         handler(request, exc_info)
-        #         return
 
-        # Convert ConflictErrors to Retry exceptions.
-        if retry_allowed and isinstance(exc_info[1], ConflictError):
-            #XXX this code path needs a unit test
-            logging.getLogger('ZopePublication').warn(
-                'Competing writes/reads at %s',
-                request.get('PATH_INFO', '???'),
-                exc_info=True)
-            raise Retry
+        except:
+            tryToLogException(
+                'Error while reporting an error to the %s service' %
+                ErrorReports)
+            get_transaction().abort()
+            beginErrorHandlingTransaction(request)
+
+        if legacy_exception:
+            # There should be nothing of consequence done in this transaction,
+            # but this allows the error reporting service to save things
+            # persistently when we get a legacy exception.
+            get_transaction().commit()
+        else:
+            # See if there's an IExceptionSideEffects adapter for the
+            # exception
+            try:
+                adapter = getAdapter(exception, IExceptionSideEffects)
+                # view_presented is None if no view was presented, or the name
+                # of the view, if it was.
+                # Although request is passed in here, it should be considered
+                # read-only.
+                adapter(object, request, exc_info)
+                get_transaction().commit()
+            except:
+                get_transaction().abort()
 
-        # Let the response handle it as best it can.
-        # XXX Is this what we want in the long term?
-        request.response.handleException(exc_info)
         return
 
     def _parameterSetskin(self, pname, pval, request):
         request.setViewSkin(pval)
 
-class DebugPublication(object):
-
-    class call_wrapper:
-
-        def __init__(self, ob):
-            self.__ob = ob
-
-        def __getattr__(self, name):
-            return getattr(self.__ob, name)
+def tryToLogException(arg1, arg2=None):
+    if arg2 is None:
+        subsystem = 'SiteError'
+        message = arg1
+    else:
+        subsystem = arg1
+        message = arg2
+    try:
+        logging.getLogger(subsystem).exception(message)
+    # Bare except, because we want to swallow any exception raised while
+    # logging an exception.
+    except:
+        pass
 
-        def __call__(self, *args, **kw):
-            self.__ob(*args, **kw)
+def tryToLogWarning(arg1, arg2=None, exc_info=False):
+    if arg2 is None:
+        subsystem = 'SiteError'
+        message = arg1
+    else:
+        subsystem = arg1
+        message = arg2
+    try:
+        logging.getLogger(subsystem).warn(message, exc_info=exc_info)
+    # Bare except, because we want to swallow any exception raised while
+    # logging a warning.
+    except:
+        pass
 
-    def callObject(self, request, ob):
-        return mapply(self.call_wrapper(ob),
-                      request.getPositionalArguments(), request)
+def beginErrorHandlingTransaction(request):
+    get_transaction().begin()
+    if IHTTPRequest.isImplementedBy(request):
+        pathnote = '%s ' % request["PATH_INFO"]
+    else:
+        pathnote = ''
+    get_transaction().note(
+        '%s(application error handling)' % pathnote)

=== Removed File Zope3/src/zope/app/publication/configure.zcml ===