[Zope3-checkins] CVS: Zope3/src/zope/app/publication - __init__.py:1.1.2.1 browser.py:1.1.2.1 configure.zcml:1.1.2.1 http.py:1.1.2.1 publicationtraverse.py:1.1.2.1 traversers.py:1.1.2.1 vfs.py:1.1.2.1 xmlrpc.py:1.1.2.1 zopepublication.py:1.1.2.1
Jim Fulton
jim@zope.com
Mon, 23 Dec 2002 14:32:02 -0500
Update of /cvs-repository/Zope3/src/zope/app/publication
In directory cvs.zope.org:/tmp/cvs-serv19908/zope/app/publication
Added Files:
Tag: NameGeddon-branch
__init__.py browser.py configure.zcml http.py
publicationtraverse.py traversers.py vfs.py xmlrpc.py
zopepublication.py
Log Message:
Initial renaming before debugging
=== Added File Zope3/src/zope/app/publication/__init__.py ===
#
# This file is necessary to make this directory a package.
=== Added File Zope3/src/zope/app/publication/browser.py ===
##############################################################################
#
# Copyright (c) 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.
#
##############################################################################
"""XXX short summary goes here.
XXX longer description goes here.
$Id: browser.py,v 1.1.2.1 2002/12/23 19:31:59 jim Exp $
"""
__metaclass__ = type
from zope.app.publication.publicationtraverse \
import PublicationTraverser as PublicationTraverser_
from zope.publisher.interfaces.browser import IBrowserPublisher
from zope.component import queryAdapter
class PublicationTraverser(PublicationTraverser_):
def traverseRelativeURL(self, request, ob, path):
ob = self.traversePath(request, ob, path)
while 1:
adapter = queryAdapter(ob, IBrowserPublisher)
if adapter is None:
return ob
ob, path = adapter.browserDefault(request)
if not path:
return ob
ob = self.traversePath(request, ob, path)
"""
Revision information:
$Id: browser.py,v 1.1.2.1 2002/12/23 19:31:59 jim Exp $
"""
from zope.app.publication.http import ZopeHTTPPublication
from zope.publisher.interfaces.browser import IBrowserPublisher
from zope.component import queryView
from zope.proxy.context.context import ContextWrapper
from zope.proxy.introspection import removeAllProxies
class BrowserPublication(ZopeHTTPPublication):
"""Web browser publication handling."""
def getDefaultTraversal(self, request, ob):
r = ()
if IBrowserPublisher.isImplementedBy(removeAllProxies(ob)):
r = ob.browserDefault(request)
else:
adapter = queryView(ob, '_traverse', request , None)
if adapter is not None:
r = adapter.browserDefault(request)
else:
return (ob, None)
if r[0] is ob: return r
wrapped = ContextWrapper(r[0], ob, name=None)
return (wrapped, r[1])
# For now, have a factory that returns a singleton
class PublicationFactory:
def __init__(self, db):
self.__pub = BrowserPublication(db)
def __call__(self):
return self.__pub
=== Added File Zope3/src/zope/app/publication/configure.zcml ===
<zopeConfigure
xmlns='http://namespaces.zope.org/zope'
xmlns:browser='http://namespaces.zope.org/browser'
xmlns:xmlrpc='http://namespaces.zope.org/xmlrpc'
>
<browser:view name="_traverse"
for="zope.interface.Interface"
factory="zope.app.publication.traversers.SimpleComponentTraverser" />
<browser:view name="_traverse"
for="zope.app.interfaces.content.file.IFileContent"
factory="zope.app.publication.traversers.FileContentTraverser" />
<xmlrpc:view name="_traverse"
for="zope.interface.Interface"
factory="zope.app.publication.traversers.SimpleComponentTraverser" />
<include package=".TraversalViews" />
</zopeConfigure>
<zopeConfigure
xmlns='http://namespaces.zope.org/zope'
>
</zopeConfigure>
=== Added File Zope3/src/zope/app/publication/http.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: http.py,v 1.1.2.1 2002/12/23 19:31:59 jim Exp $
"""
from zope.app.publication.zopepublication import ZopePublication
class ZopeHTTPPublication(ZopePublication):
"HTTP-specific support"
# XXX do we need this?
=== Added File Zope3/src/zope/app/publication/publicationtraverse.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: publicationtraverse.py,v 1.1.2.1 2002/12/23 19:31:59 jim Exp $
"""
from zope.component import queryView, getService
from zope.interfaces.publisher import NotFound
from types import StringTypes
from zope.proxy.context.context import ContextWrapper
from zope.app.interfaces.container import IWriteContainer
from zope.proxy.introspection import removeAllProxies
from zope.app.traversing.namespaces import namespaceLookup
from zope.app.traversing.parameterparsing import parameterizedNameParse
from zope.interfaces.publisher import IPublishTraverse
class DuplicateNamespaces(Exception):
"""More than one namespace was specified in a request"""
class UnknownNamespace(Exception):
"""A parameter specified an unknown namespace"""
class PublicationTraverse:
def traverseName(self, request, ob, name):
nm = name # the name to look up the object with
if name and name[:1] in '@+':
# Process URI segment parameters.
ns, nm, parms = parameterizedNameParse(name)
unknown_parms = ()
for pname, pval in parms:
pset = getattr(self, "_parameterSet%s" % pname, self) # marker
if pset is self:
# We don't know about this one
unknown_parms += ((pname, pval),)
else:
pset(pname, pval, request)
if ns:
ob2 = namespaceLookup(name, ns, nm, unknown_parms, ob, request)
return ob2
if unknown_parms:
nm = "%s;%s" % (
nm,
';'.join(["%s=%s" % (parm[0], parm[1])
for parm in unknown_parms])
)
if not nm:
# Just set params, so skip
return ob
if nm == '.':
return ob
if IPublishTraverse.isImplementedBy(removeAllProxies(ob)):
ob2 = ob.publishTraverse(request, nm)
else:
adapter = queryView(ob, '_traverse', request, self) # marker
if adapter is not self:
ob2 = adapter.publishTraverse(request, nm)
else:
raise NotFound(ob, name, request)
return ContextWrapper(ob2, ob, name=name)
class PublicationTraverser(PublicationTraverse):
def traversePath(self, request, ob, path):
if isinstance(path, StringTypes):
path = path.split('/')
if len(path) > 1 and not path[-1]:
# Remove trailing slash
path.pop()
else:
path = list(path)
# Remove dingle dots
path = [x for x in path if x != '.']
path.reverse()
# Remove double dots
while '..' in path:
l = path.index('..')
if l < 0 or l+2 > len(path):
break
del path[l:l+2]
pop = path.pop
while path:
name = pop()
ob = self.traverseName(request, ob, name)
return ob
=== Added File Zope3/src/zope/app/publication/traversers.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"
__metaclass__ = type
from zope.interfaces.publisher import Unauthorized, NotFound, DebugError
from zope.publisher.interfaces.browser import IBrowserPublisher
from zope.publisher.interfaces.xmlrpc import IXMLRPCPublisher
from zope.component \
import queryView, getView, getDefaultViewName
from zope.component.exceptions import ComponentLookupError
class SimpleComponentTraverser:
"""Browser traverser for simple components that can only traverse to views
"""
__implements__ = IBrowserPublisher, IXMLRPCPublisher
def __init__(self, context, request):
self.context = context
self.request = request
def browserDefault(self, request):
ob = self.context
view_name = getDefaultViewName(ob, request)
return ob, (view_name,)
def publishTraverse(self, request, name):
ob = self.context
from zope.component.view import viewService
view = queryView(ob, name, request)
if view is None:
raise NotFound(ob, name)
return view
class FileContentTraverser(SimpleComponentTraverser):
"""Browser traverser for file content.
The default view for file content has effective URLs that don't end in
/. In particular, if the content inclused HTML, relative links in
the HTML are relative to the container the content is in.
"""
def browserDefault(self, request):
ob = self.context
view_name = getDefaultViewName(ob, request)
view = self.publishTraverse(request, view_name)
if hasattr(view, 'browserDefault'):
view, path = view.browserDefault(request)
if len(path) == 1:
view = view.publishTraverse(request, path[0])
path = ()
else:
path = ()
return view, path
class TestTraverser:
"Bobo-style traverser, mostly useful for testing"
__implements__ = IBrowserPublisher
def __init__(self, context, request):
self.context = context
def browserDefault(self, request):
ob = self.context
if hasattr(ob, '__implements__'):
view_name = getDefaultViewName(ob, request)
return ob, (("@@%s" % view_name),)
return ob, ()
def publishTraverse(self, request, name):
ob = self.context
if name.startswith('@@'):
return getView(ob, name[6:], request)
if name.startswith('_'):
raise Unauthorized("Name %s begins with an underscore" % `name`)
subob = getattr(ob, name, self) # self is marker here
if subob is self:
# no attribute
try:
subob = ob[name]
except (KeyError, IndexError,
TypeError, AttributeError):
raise NotFound(ob, name, request)
return subob
=== Added File Zope3/src/zope/app/publication/vfs.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: vfs.py,v 1.1.2.1 2002/12/23 19:31:59 jim Exp $
"""
from zope.app.publication.zopepublication import ZopePublication
from zope.component import queryView
from zope.interfaces.publisher import NotFound
from zope.publisher.publish import mapply
class VFSPublication(ZopePublication):
"""The Publication will do all the work for the VFS"""
def callObject(self, request, ob):
view = queryView(ob, 'vfs', request, self)
#view = ob
if view is not self:
method = getattr(view, request.method)
else:
raise NotFound(ob, 'vfs', request)
return mapply(method, request.getPositionalArguments(), request)
=== Added File Zope3/src/zope/app/publication/xmlrpc.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: xmlrpc.py,v 1.1.2.1 2002/12/23 19:31:59 jim Exp $
"""
from zope.proxy.introspection import removeAllProxies
from zope.app.publication.http import ZopeHTTPPublication
class XMLRPCPublication(ZopeHTTPPublication):
"""XML-RPC publication handling.
There is nothing special here right now.
"""
def traverseName(self, request, ob, name):
naked_ob = removeAllProxies(ob)
if hasattr(ob, name):
return getattr(ob, name)
else:
return super(XMLRPCPublication, self).traverseName(request,
ob, name)
# For now, have a factory that returns a singleton
class XMLRPCPublicationFactory:
def __init__(self, db):
self.__pub = XMLRPCPublication(db)
def __call__(self):
return self.__pub
=== Added File Zope3/src/zope/app/publication/zopepublication.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.
#
##############################################################################
import sys
import logging
from zope.component import getService
from zope.component.exceptions import ComponentLookupError
from zodb.interfaces import ConflictError
from zope.publisher.base import DefaultPublication
from zope.publisher.publish import mapply
from zope.interfaces.publisher import Retry
from zope.security.securitymanagement import getSecurityManager
from zope.security.securitymanagement import newSecurityManager
from zope.security.checker import ProxyFactory
from zope.proxy.introspection import removeAllProxies
from zope.app.interfaces.services.service \
import IServiceManagerContainer
from zope.exceptions import Unauthorized
from zope.app.applicationcontrol.applicationcontrol \
import applicationControllerRoot
from zope.app.security.registries.principalregistry \
import principalRegistry as prin_reg
from zope.app.interfaces.security \
import IUnauthenticatedPrincipal
from zope.app.publication.publicationtraverse import PublicationTraverse
from zope.proxy.context.context import ContextWrapper
# XXX Should this be imported here?
from transaction import get_transaction
class Cleanup:
def __init__(self, f):
self.__del__ = f
class ZopePublication(object, PublicationTraverse, DefaultPublication):
"""Base Zope publication specification."""
version_cookie = 'Zope-Version'
root_name = 'Application'
def __init__(self, db):
# db is a ZODB.DB.DB object.
self.db = db
def beforeTraversal(self, request):
# Try to authenticate against the default global registry.
p = prin_reg.authenticate(request)
if p is None:
p = prin_reg.unauthenticatedPrincipal()
if p is None:
raise Unauthorized # If there's no default principal
newSecurityManager(p.getId())
request.user = p
get_transaction().begin()
def _maybePlacefullyAuthenticate(self, request, ob):
if not IUnauthenticatedPrincipal.isImplementedBy(request.user):
# We've already got an authenticated user. There's nothing to do.
# Note that beforeTraversal guarentees that user is not None.
return
if not IServiceManagerContainer.isImplementedBy(ob):
# We won't find an authentication service here, so give up.
return
sm = removeAllProxies(ob).queryServiceManager()
if sm is None:
# No service manager here, and thus no auth service
return
sm = ContextWrapper(sm, ob, name="++etc++Services")
auth_service = sm.get('Authentication')
if auth_service is None:
# No auth service here
return
# Try to authenticate against the auth service
principal = auth_service.authenticate(request)
if principal is None:
principal = auth_service.unauthenticatedPrincipal()
if principal is None:
# nothing to do here
return
newSecurityManager(principal.getId())
request.user = principal
def callTraversalHooks(self, request, ob):
# Call __before_publishing_traverse__ hooks
# This is also a handy place to try and authenticate.
self._maybePlacefullyAuthenticate(request, ob)
def afterTraversal(self, request, ob):
#recordMetaData(object, request)
self._maybePlacefullyAuthenticate(request, ob)
def openedConnection(self, conn):
# Hook for auto-refresh
pass
def getApplication(self, request):
# If the first name is '++etc++ApplicationControl', then we should
# get it rather than look in the database!
stack = request.getTraversalStack()
if '++etc++ApplicationController' in stack:
return applicationControllerRoot
# Open the database.
version = request.get(self.version_cookie, '')
conn = self.db.open(version)
cleanup = Cleanup(conn.close)
request.hold(cleanup) # Close the connection on request.close()
self.openedConnection(conn)
## conn.setDebugInfo(getattr(request, 'environ', None), request.other)
root = conn.root()
app = root.get(self.root_name, None)
if app is None:
raise SystemError, "Zope Application Not Found"
return ProxyFactory(app)
def getDefaultTraversal(self, request, ob):
return ob, None
def callObject(self, request, ob):
return mapply(ob, request.getPositionalArguments(), request)
def afterCall(self, request):
get_transaction().commit()
def handleException(self, object, request, exc_info, retry_allowed=1):
try:
# Abort the transaction.
get_transaction().abort()
try:
errService = getService(object,'ErrorReportingService')
except ComponentLookupError:
pass
else:
try:
errService.raising(exc_info, request)
# It is important that an error in errService.raising
# does not propagate outside of here. Otherwise, nothing
# meaningful will be returned to the user.
#
# The error reporting service should not be doing database
# stuff, so we shouldn't get a conflict error.
# Even if we do, it is more important that we log this
# error, and proceed with the normal course of events.
# We should probably (somehow!) append to the standard
# 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):
logger.getLogger('ZopePublication').warn(
'Competing writes/reads at %s',
request.get('PATH_INFO', '???'),
exc_info=True)
raise Retry
# Let the response handle it as best it can.
# XXX Is this what we want in the long term?
response = request.response
response.handleException(exc_info)
return
finally:
# Avoid leaking
exc_info = 0
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 __call__(self, *args, **kw):
self.__ob(*args, **kw)
def callObject(self, request, ob):
return mapply(self.call_wrapper(ob),
request.getPositionalArguments(), request)