[Zope] ZPublisher.Config and ZPublisher.Plumbing

Phillip J. Eby pje@telecommunity.com
Mon, 08 Feb 1999 15:22:54 -0500


--=====================_918523374==_
Content-Type: text/plain; charset="us-ascii"

At 10:55 AM 2/8/99 -0500, Phillip J. Eby wrote:
>
>My newer FastCGI code is more a matter of changing to use Robin Dunn's
>"fcgi" module in place of DC's "fcgiapp" so that it can be run
>multithreaded, and creating a class framework for standalone publishers
>that takes care of most of the messy plumbing overhead.  I'm factoring the
>code into (proposed) ZPublisher.Config and ZPublisher.Plumbing.  I hope to
>have some working code to present today.

Well, here they are:

ZPublisher.Config - configuration and publishing defaults for Zope
ZPublisher.Plumbing - Zope "plumbing" base class w/subclasses for CGI &
FastCGI
Zopestart - A script for starting Zope under CGI or FastCGI

I have been running Zope under an earlier FastCGI attempt for the last
couple of weeks; and have been running this version for a few hours today.
To use these files, you'll need to stick Plumbing.py and Config.py into the
lib/python/ZPublisher directory of your Zope installation, and Zopestart
someplace it can be executed by your CGI back-end.  You can edit it to
override "INSTANCE_HOME" or you can pass it INSTANCE_HOME in the
environment.  You will need a FastCGI-supporting server or a cgi-fcgi
script to use it.

It should be possible to create subclasses to handle PCGI and direct HTTP,
but may not be worthwhile in favor of using ZServer.

--=====================_918523374==_
Content-Type: text/plain; charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment; filename="Publish.py"

############################################################################=
##
# 
# Zope Public License (ZPL) Version 0.9.5
# ---------------------------------------
# 
# Copyright (c) Digital Creations.  All rights reserved.
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# 
# 1. Redistributions in source code must retain the above copyright
#    notice, this list of conditions, and the following disclaimer.
# 
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions, and the following disclaimer in
#    the documentation and/or other materials provided with the
#    distribution.
# 
# 3. Any use, including use of the Zope software to operate a website,
#    must either comply with the terms described below under
#    "Attribution" or alternatively secure a separate license from
#    Digital Creations.  Digital Creations will not unreasonably
#    deny such a separate license in the event that the request
#    explains in detail a valid reason for withholding attribution.
# 
# 4. All advertising materials and documentation mentioning
#    features derived from or use of this software must display
#    the following acknowledgement:
# 
#      "This product includes software developed by Digital Creations
#      for use in the Z Object Publishing Environment
#      (http://www.zope.org/)."
# 
#    In the event that the product being advertised includes an
#    intact Zope distribution (with copyright and license included)
#    then this clause is waived.
# 
# 5. Names associated with Zope or Digital Creations must not be used to
#    endorse or promote products derived from this software without
#    prior written permission from Digital Creations.
# 
# 6. Modified redistributions of any form whatsoever must retain
#    the following acknowledgment:
# 
#      "This product includes software developed by Digital Creations
#      for use in the Z Object Publishing Environment
#      (http://www.zope.org/)."
# 
#    Intact (re-)distributions of any official Zope release do not
#    require an external acknowledgement.
# 
# 7. Modifications are encouraged but must be packaged separately as
#    patches to official Zope releases.  Distributions that do not
#    clearly separate the patches from the original work must be clearly
#    labeled as unofficial distributions.  Modifications which do not
#    carry the name Zope may be packaged in any form, as long as they
#    conform to all of the clauses above.
# 
# 
# Disclaimer
# 
#   THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
#   EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
#   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
#   PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
#   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
#   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
#   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
#   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
#   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
#   SUCH DAMAGE.
# 
# Attribution
# 
#   Individuals or organizations using this software as a web site must
#   provide attribution by placing the accompanying "button" and a link
#   to the accompanying "credits page" on the website's main entry
#   point.  In cases where this placement of attribution is not
#   feasible, a separate arrangment must be concluded with Digital
#   Creations.  Those using the software for purposes other than web
#   sites must provide a corresponding attribution in locations that
#   include a copyright using a manner best suited to the application
#   environment.  Where attribution is not possible, or is considered
#   to be onerous for some other reason, a request should be made to
#   Digital Creations to waive this requirement in writing.  As stated
#   above, for valid requests, Digital Creations will not unreasonably
#   deny such requests.
# 
# This software consists of contributions made by Digital Creations and
# many individuals on behalf of Digital Creations.  Specific
# attributions are listed in the accompanying credits file.
#=
 
############################################################################=
##
__doc__=3D"""Python Object Publisher -- Publish Python objects on web=
 servers

$Id: Publish.py,v 1.114 1998/12/11 20:53:46 jim Exp=
 $"""
__version__=3D'$Revision: 1.114 $'[11:-2]

import sys, os, string, cgi, regex
from string import lower, atoi, rfind, split, strip, join, upper, find
from Response import Response
from urllib import quote, unquote
from cgi import FieldStorage
from Request import Request, isCGI_NAME
from Converters import type_converters

# Waaaa, I wish I didn't have to work this hard.
try: from thread import allocate_lock
except:
    class allocate_lock:
        def acquire(*args): pass
        def release(*args):=
 pass


ListType=3Dtype([])
StringType=3Dtype('')

UNSPECIFIED_ROLES=3D''

try:
    from ExtensionClass import Base
    class RequestContainer(Base):
        def __init__(self,**kw):
            for k,v in kw.items(): self.__dict__[k]=3Dv

        def manage_property_types(self):
            return type_converters.keys()
            
except:
    class RequestContainer:
        def __init__(self,**kw):
            for k,v in kw.items(): self.__dict__[k]=3Dv

class ModulePublisher:

    HTTP_AUTHORIZATION=3DNone
    _hacked_path=3DNone
    
    def __init__(self,
                 stdin=3Dsys.stdin, stdout=3Dsys.stdout, stderr=3Dsys.stderr=
,
                 environ=3Dos.environ):
        self.environ=3Denviron
        fp=3DNone
        try:
            if environ['REQUEST_METHOD'] !=3D 'GET': fp=3Dstdin
        except: pass

        if environ.has_key('HTTP_AUTHORIZATION'):
            self.HTTP_AUTHORIZATION=3Denviron['HTTP_AUTHORIZATION']
            try: del environ['HTTP_AUTHORIZATION']
            except: pass
        elif environ.has_key('HTTP_CGI_AUTHORIZATION'):
            self.HTTP_AUTHORIZATION=3Denviron['HTTP_CGI_AUTHORIZATION']
            try: del environ['HTTP_CGI_AUTHORIZATION']
            except: pass

        form=3D{}
        form_has=3Dform.has_key
        other=3D{}
        fs=3DFieldStorage(fp=3Dfp,environ=3Denviron,keep_blank_values=3D1)
        if not hasattr(fs,'list') or fs.list is None:
            form['BODY']=3Dother['BODY']=3Dfs.value
        else:
            meth=3DNone
            fslist=3Dfs.list
            tuple_items=3D{}

            type_re=3Dregex.compile(':[a-zA-Z][a-zA-Z0-9_]+')
            type_search=3Dtype_re.search
            lt=3Dtype([])
            CGI_name=3DisCGI_NAME
            for item in fslist:
                key=3Dunquote(item.name)

                if (hasattr(item,'file') and hasattr(item,'filename')
                    and hasattr(item,'headers')):
                    if (item.file and
                        (item.filename is not None or
                         'content-type' in map(lower,
                                               item.headers.keys()))):
                        item=3DFileUpload(item)
                    else:
                        item=3Ditem.value

                seqf=3DNone

                l=3Dtype_search(key)
                while l >=3D 0:
                    type_name=3Dtype_re.group(0)[1:]
                    key=3Dkey[:l]+key[l+len(type_name)+1:]
                    if type_name =3D=3D 'list':
                        seqf=3Dlist
                    elif type_name =3D=3D 'tuple':
                        seqf=3Dtuple
                        tuple_items[key]=3D1
                    elif type_name =3D=3D 'method':
                        if l: meth=3Dkey
                        else: meth=3Ditem
                    elif type_name =3D=3D 'default_method':
                        if not meth:
                            if l: meth=3Dkey
                            else: meth=3Ditem
                    else:
                        item=3Dtype_converters[type_name](item)
                    l=3Dtype_search(key)
                    
                # Filter out special names from form:
                if CGI_name(key) or key[:5]=3D=3D'HTTP_': continue

                if form_has(key):
                    found=3Dform[key]
                    if type(found) is lt: found.append(item)
                    else:
                        found=3D[found,item]
                        form[key]=3Dfound
                        other[key]=3Dfound
                else:
                    if seqf: item=3D[item]
                    form[key]=3Ditem
                    other[key]=3Ditem

            for key in tuple_items.keys():
                item=3Dtuple(form[key])
                form[key]=3Ditem
                other[key]=3Ditem

            if meth:
                if environ.has_key('PATH_INFO'):
                    path=3Denviron['PATH_INFO']
                    while path[-1:]=3D=3D'/': path=3Dpath[:-1]
                else: path=3D''
                other['PATH_INFO']=3Dpath=3D"%s/%s" % (path,meth)
                self._hacked_path=3D1

        # Cookie values should *not* be appended to existing form
        # vars with the same name - they are more like default values
        # for names not otherwise specified in the form.
        cookies=3D{}
        if environ.has_key('HTTP_COOKIE'):
            parse_cookie(self.environ['HTTP_COOKIE'],cookies)
            for k,item in cookies.items():
                if not other.has_key(k):
                    other[k]=3Ditem

        request=3Dself.request=3DRequest(environ,other,stdin)
        request.form=3Dform
        if cookies is not None: request.cookies=3Dcookies
        self.response=3Dresponse=3DResponse(stdout=3Dstdout, stderr=3Dstderr=
)
        request['RESPONSE']=3Dresponse
        self.stdin=3Dstdin
        self.stdout=3Dstdout
        self.stderr=3Dstderr
        self.base=3Drequest.base
        self.script=3Drequest.script

    def html(self,title,body):
        return ("<html>\n"
                "<head>\n<title>%s</title>\n</head>\n"
                "<body>\n%s\n</body>\n"
                "</html>\n" % (title,body))

    def notFoundError(self,entry=3D'who knows!'):
        raise 'NotFound',self.html(
            "Resource not found",
            "Sorry, the requested document does not exist.<p>"
            "\n<!--\n%s\n-->" % entry)

    forbiddenError=3DnotFoundError  # If a resource is forbidden,
                                  # why reveal that it exists?

    def debugError(self,entry):
        raise 'NotFound',self.html(
            "Debugging Notice",
            "Bobo has encountered a problem publishing your object.<p>"
            "\n%s" % entry)

    def badRequestError(self,name):
        if regex.match('^[A-Z_0-9]+$',name) >=3D 0:
            raise 'InternalError', self.html(
                "Internal Error",
                "Sorry, an internal error occurred in this resource.")

        raise 'BadRequest',self.html(
            "Invalid request",
            "The parameter, <em>%s</em>, was omitted from the request."
            "<!--%s-->"
            % (name,self.request))

    def unauthorized(self, realm,debug_mode=3DNone):
        if not (self.request.has_key('REMOTE_USER') and
                self.request['REMOTE_USER']):
            self.response['WWW-authenticate']=3D'basic realm=3D"%s"' %=
 realm
        m=3D"<strong>You are not authorized to access this=
 resource.</strong>"
        if debug_mode:
            if self.HTTP_AUTHORIZATION:
                m=3Dm+'\nUsername and password are not correct.'
            else:
                m=3Dm+'\nNo Authorization header found.'
        raise 'Unauthorized', m

    def forbiddenError(self,object=3DNone):
        raise 'NotFound',self.html(
            "Resource not found",
            "Sorry, the requested document does not exist.<p>"
            "<!--%s-->" % object)

    def get_request_data(self,request_params):
        try: request_params=3Drequest_params()
        except: pass
        for key in request_params.keys():
                self.request[key]=3Drequest_params[key]


    def publish(self, module_name, after_list, published=3D'web_objects',
                imported_modules=3D{}, module_dicts=3D{},debug=3D0):

        request=3Dself.request
        request_get=3Drequest.get
        response=3Dself.response

        # First check for "cancel" redirect:
        cancel=3D''
        if request_get('SUBMIT','')=3D=3D'cancel':
            cancel=3Drequest_get('CANCEL_ACTION','')
            if cancel: raise 'Redirect', cancel

        (bobo_before, bobo_after, request_params,
         inherited_groups, groups, roles,
         object, doc, published, realm, module_name,
         debug_mode)=3D get_module_info(module_name)
 
        after_list[0]=3Dbobo_after

        if bobo_before is not None: bobo_before();

        if request_params: self.get_request_data(request_params)

        # Get a nice clean path list:
        path=3Dstrip(request_get('PATH_INFO'))

        __traceback_info__=3Dpath

        if path[:1] !=3D '/': path=3D'/'+path
        if path[-1:] !=3D '/': path=3Dpath+'/'
        if find(path,'/.') >=3D 0:
            path=3Djoin(split(path,'/./'),'/')
            l=3Dfind(path,'/../',1)
            while l > 0:
                p1=3Dpath[:l]
                path=3Dpath[:rfind(p1,'/')+1]+path[l+4:]
                l=3Dfind(path,'/../',1)
        path=3Dpath[1:-1]

        path=3Dsplit(path,'/')
        while path and not path[0]: path =3D path[1:]

        method=3Dupper(request_get('REQUEST_METHOD'))
        if method=3D=3D'GET' or method=3D=3D'POST': method=3D'index_html'

        URL=3Dself.script

        # if the top object has a __bobo_traverse__ method, then use it
        # to possibly traverse to an alternate top-level object.
        if hasattr(object,'__bobo_traverse__'):
            request['URL']=3DURL
            try: object=3Dobject.__bobo_traverse__(request)
            except: pass            

        # Get default object if no path was specified:
        if not path:
            entry_name=3Dmethod
            try:
                if hasattr(object,entry_name):
                    response.setBase(URL)
                    path=3D[entry_name]
                else:
                    try:
                        if object.has_key(entry_name):
                            path=3D[entry_name]
                    except: pass
            except: pass
            if not path: path =3D ['help']

        # Traverse the URL to find the object:
        request['PARENTS']=3Dparents=3D[]
    
        if hasattr(object, '__of__'): 
            # Try to bind the top-level object to the request
            object=3Dobject.__of__(RequestContainer(REQUEST=3Drequest))

        steps=3D[]
        while path:
            entry_name,path=3Dpath[0], path[1:]
            URL=3D"%s/%s" % (URL,quote(entry_name))
            got=3D0
            if entry_name:
                if entry_name[:1]=3D=3D'_':
                    if debug_mode:
                        self.debugError("Object name begins with an=
 underscore at: %s" % URL)
                    else: self.forbiddenError(entry_name)

                if hasattr(object,'__bobo_traverse__'):
                    request['URL']=3DURL
                    subobject=3Dobject.__bobo_traverse__(request,entry_name)
                    if type(subobject) is type(()) and len(subobject) > 1:
                        while len(subobject) > 2:
                            parents.append(subobject[0])
                            subobject=3Dsubobject[1:]
                        object, subobject =3D subobject
                else:
                    try:
                        subobject=3Dgetattr(object,entry_name)
                    except AttributeError:
                        got=3D1
                        try: subobject=3Dobject[entry_name]
                        except (KeyError, IndexError,
                                TypeError, AttributeError):
                            if entry_name=3D=3D'.': subobject=3Dobject
                            elif entry_name=3D=3D'..' and parents:
                                subobject=3Dparents[-1]
                            elif debug_mode:
                                self.debugError(
                                    "Cannot locate object at: %s" %URL) 
                            else: self.notFoundError(URL)

                if subobject is object and entry_name=3D=3D'.':
                    URL=3DURL[:rfind(URL,'/')]
                else:
                    try:
                        try: doc=3Dsubobject.__doc__
                        except: doc=3Dgetattr(object, entry_name+'__doc__')
                        if not doc: raise AttributeError, entry_name
                    except:
                        if debug_mode:
                            self.debugError("Missing doc string at: %s" %=
 URL)
                        else: self.notFoundError("%s" % (URL))

                    if hasattr(subobject,'__roles__'):
                        roles=3Dsubobject.__roles__
                    else:
                        if not got:
                            roleshack=3Dentry_name+'__roles__'
                            if hasattr(object, roleshack):
                                roles=3Dgetattr(object, roleshack)
    
                    # Promote subobject to object
                
                    parents.append(object)
                    object=3Dsubobject

                    steps.append(entry_name)
    
                # Check for method:
                if not path:
                    if hasattr(object,method) and entry_name !=3D method:
                        response.setBase(URL)
                        path=3D[method]
                    else:
                        if (hasattr(object, '__call__') and
                            hasattr(object.__call__,'__roles__')):
                            roles=3Dobject.__call__.__roles__
                        if self._hacked_path:
                            i=3Drfind(URL,'/')
                            if i > 0: response.setBase(URL[:i])
    
        if entry_name !=3D method and method !=3D 'index_html':
            if debug_mode:
                self.debugError("Method %s not found at: %s" %=
 (method,URL))
            else: self.notFoundError(method)

        request.steps=3Dsteps
        parents.reverse()

        # Do authorization checks
        user=3DNone
        i=3D0
        if roles is not None:

            last_parent_index=3Dlen(parents)
            if hasattr(object, '__allow_groups__'):
                groups=3Dobject.__allow_groups__
                inext=3D0
            else:
                inext=3DNone
                for i in range(last_parent_index):
                    if hasattr(parents[i],'__allow_groups__'):
                        groups=3Dparents[i].__allow_groups__
                        inext=3Di+1
                        break

            if inext is not None:
                i=3Dinext

                if hasattr(groups, 'validate'): v=3Dgroups.validate
                else: v=3Dold_validation

                auth=3Dself.HTTP_AUTHORIZATION

                if v is old_validation and roles is UNSPECIFIED_ROLES:
                    # No roles, so if we have a named group, get roles from
                    # group keys
                    if hasattr(groups,'keys'): roles=3Dgroups.keys()
                    else:
                        try: groups=3Dgroups()
                        except: pass
                        try: roles=3Dgroups.keys()
                        except: pass

                    if groups is None:
                        # Public group, hack structures to get it to=
 validate
                        roles=3DNone
                        auth=3D''

                if v is old_validation:
                    user=3Dold_validation(groups, request, auth, roles)
                elif roles is UNSPECIFIED_ROLES: user=3Dv(request, auth)
                else: user=3Dv(request, auth, roles)

        =20       while user is None and i < last_parent_index:
                    parent=3Dparents[i]
                    i=3Di+1
                    if hasattr(parent, '__allow_groups__'): 
                        groups=3Dparent.__allow_groups__
                    else: continue
                    if hasattr(groups,'validate'): v=3Dgroups.validate
                    else: v=3Dold_validation
                    if v is old_validation:
                        user=3Dold_validation(groups, request, auth, roles)
                    elif roles is UNSPECIFIED_ROLES: user=3Dv(request,=
 auth)
                    else: user=3Dv(request, auth, roles)
                    
            if user is None and roles !=3D UNSPECIFIED_ROLES:
                self.unauthorized(realm,debug_mode)

        steps=3Djoin(steps[:-i],'/')
        if user is not None:
            request['AUTHENTICATED_USER']=3Duser
            request['AUTHENTICATION_PATH']=3Dsteps
   
        # Attempt to start a transaction:
        try: transaction=3Dget_transaction()
        except: transaction=3DNone
        if transaction is not None:
            info=3D"\t" + request_get('PATH_INFO')
       
            auth_user=3Drequest_get('AUTHENTICATED_USER',None)
            if auth_user is not None:
                info=3D("%s %s" % (steps,auth_user))+info
            transaction.begin(info)

        # Now get object meta-data to decide if and how it should be
        # called:
        object_as_function=3Dobject
                
        # First, assume we have a method:
        if hasattr(object_as_function,'im_func'):
            f=3Dobject_as_function.im_func
            c=3Df.func_code
            defaults=3Df.func_defaults
            argument_names=3Dc.co_varnames[1:c.co_argcount]
        else:
            # Rather than sniff for FunctionType, assume its a
            # function and fall back to returning the object itself:       =
 
            if hasattr(object_as_function,'func_defaults'):
                defaults=3Dobject_as_function.func_defaults
                c=3Dobject_as_function.func_code
                argument_names=3Dc.co_varnames[:c.co_argcount]

                # Make sure we don't have a class that smells like a func
                if hasattr(object_as_function, '__bases__'):
                    self.forbiddenError(entry_name)
                
            else: return response.setBody(object)

        request['URL']=3DURL
        request['PARENT_URL']=3DURL[:rfind(URL,'/')]

        args=3D[]
        nrequired=3Dlen(argument_names) - (len(defaults or []))
        for name_index in range(len(argument_names)):
            argument_name=3Dargument_names[name_index]
            v=3Drequest_get(argument_name, args)
            if v is args:
                if argument_name=3D=3D'self': args.append(parents[0])
                elif name_index < nrequired:
                    self.badRequestError(argument_name)
                else: args.append(defaults[name_index-nrequired])
            else: args.append(v)

        args=3Dtuple(args)
        if debug: result=3Dself.call_object(object,args)
        else:     result=3Dapply(object,args)

        if result and result is not response: response.setBody(result)

        if transaction: transaction.commit()

        return response

    def call_object(self,object,args):
        result=3Dapply(object,args) # Type s<cr> to step into published=
 object.
        return result

_l=3Dallocate_lock()
def get_module_info(module_name, modules=3D{},
                    acquire=3D_l.acquire,
                    release=3D_l.release,
                    ):

    if modules.has_key(module_name): return modules[module_name]

    if module_name[-4:]=3D=3D'.cgi': module_name=3Dmodule_name[:-4]

    acquire()
    tb=3DNone
    try:
      try:
        module=3D__import__(module_name, globals(), globals(),=
 ('__doc__',))
    
        realm=3Dmodule_name
                
        # Let the app specify a realm
        if hasattr(module,'__bobo_realm__'):
            realm=3Dmodule.__bobo_realm__
        elif os.environ.has_key('Z_REALM'):
            realm=3Dos.environ['Z_REALM']
        elif os.environ.has_key('BOBO_REALM'):
            realm=3Dos.environ['BOBO_REALM']
        else: realm=3Dmodule_name

        # Check for debug mode
        if hasattr(module,'__bobo_debug_mode__'):
            debug_mode=3Dnot not module.__bobo_debug_mode__
        elif (os.environ.has_key('Z_DEBUG_MODE') or
              os.environ.has_key('BOBO_DEBUG_MODE')):
            if os.environ.has_key('Z_DEBUG_MODE'):
                debug_mode=3Dlower(os.environ['Z_DEBUG_MODE'])
            else:
                debug_mode=3Dlower(os.environ['BOBO_DEBUG_MODE'])
            if debug_mode=3D=3D'y' or debug_mode=3D=3D'yes':
                debug_mode=3D1
            else:
                try: debug_mode=3Datoi(debug_mode)
                except: debug_mode=3DNone
        else: debug_mode=3DNone

        # Check whether tracebacks should be hidden:
        if hasattr(module,'__bobo_hide_tracebacks__'):
            hide_tracebacks=3Dnot not module.__bobo_hide_tracebacks__
        elif os.environ.has_key('BOBO_HIDE_TRACEBACKS'):
            hide_tracebacks=3Dlower(os.environ['BOBO_HIDE_TRACEBACKS'])
            if hide_tracebacks=3D=3D'y' or hide_tracebacks=3D=3D'yes':
                hide_tracebacks=3D1
            else:
                try: hide_tracebacks=3Datoi(hide_tracebacks)
                except: hide_tracebacks=3DNone
        else: hide_tracebacks=3D1

        # Reset response handling of tracebacks, if necessary:
        if debug_mode or not hide_tracebacks:
            def hack_response():
                import Response
                Response._tbopen  =3D '<PRE>'
                Response._tbclose =3D '</PRE>'

            hack_response()
 
        if hasattr(module,'__bobo_before__'):
            bobo_before=3Dmodule.__bobo_before__
        else: bobo_before=3DNone
                
        if hasattr(module,'__bobo_after__'):=
 bobo_after=3Dmodule.__bobo_after__
        else: bobo_after=3DNone
    
        # Get request data from outermost environment:
        if hasattr(module,'__request_data__'):
            request_params=3Dmodule.__request_data__
        else: request_params=3DNone
    
        # Get initial group data:
        inherited_groups=3D[]
        if hasattr(module,'__allow_groups__'):
            groups=3Dmodule.__allow_groups__
            inherited_groups.append(groups)
        else: groups=3DNone
    
        web_objects=3DNone
        roles=3DUNSPECIFIED_ROLES
        if hasattr(module,'bobo_application'):
            object=3Dmodule.bobo_application
            if hasattr(object,'__allow_groups__'):
                groups=3Dobject.__allow_groups__
                inherited_groups.append(groups)
            else: groups=3DNone
            if hasattr(object,'__roles__'): roles=3Dobject.__roles__
        else:
            if hasattr(module,'web_objects'):
                web_objects=3Dmodule.web_objects
                object=3Dweb_objects
            else: object=3Dmodule
        published=3Dweb_objects
    
        try: doc=3Dmodule.__doc__
        except:
            if web_objects is not None: doc=3D' '
            else: doc=3DNone
    
        info=3D (bobo_before, bobo_after, request_params,
                inherited_groups, groups, roles,
                object, doc, published, realm, module_name,
                debug_mode)
    
        modules[module_name]=3Dmodules[module_name+'.cgi']=3Dinfo

        return info
      except:
          if hasattr(sys, 'exc_info'): t,v,tb=3Dsys.exc_info()
          else: t, v, tb =3D sys.exc_type, sys.exc_value, sys.exc_traceback
          v=3Dstr(v)
          raise ImportError, (t, v), tb
    finally:
        tb=3DNone
        release()

def str_field(v):
    if type(v) is ListType:
        return map(str_field,v)

    if hasattr(v,'__class__') and v.__class__ is FieldStorage:
        v=3Dv.value
    elif type(v) is not StringType:
        if hasattr(v,'file') and v.file: v=3Dv.file
        elif hasattr(v,'value'): v=3Dv.value
    return v


class FileUpload:
    '''\
    File upload objects

    File upload objects are used to represent file-uploaded data.

    File upload objects can be used just like files.

    In addition, they have a 'headers' attribute that is a dictionary
    containing the file-upload headers, and a 'filename' attribute
    containing the name of the uploaded file.
    '''

    def __init__(self, aFieldStorage):

        file=3DaFieldStorage.file
        if hasattr(file, '__methods__'): methods=3Dfile.__methods__
        else: methods=3D ['close', 'fileno', 'flush', 'isatty',
                        'read', 'readline', 'readlines', 'seek',
                        'tell', 'truncate', 'write', 'writelines']

        d=3Dself.__dict__
        for m in methods:
            if hasattr(file,m): d[m]=3Dgetattr(file,m)

        self.headers=3DaFieldStorage.headers
        self.filename=3DaFieldStorage.filename
    

parse_cookie_lock=3Dallocate_lock()
def parse_cookie(text,
                 result=3DNone,
                 qparmre=3Dregex.compile(
                     '\([\0- ]*'
                     '\([^\0- ;,=3D\"]+\)=3D"\([^"]*\)\"'
                     '\([\0- ]*[;,]\)?[\0- ]*\)'
                     ),
                 parmre=3Dregex.compile(
                     '\([\0- ]*'
                     '\([^\0- ;,=3D\"]+\)=3D\([^\0;-=3D\"]*\)'
                     '\([\0- ]*[;,]\)?[\0- ]*\)'
                     ),
                 acquire=3Dparse_cookie_lock.acquire,
                 release=3Dparse_cookie_lock.release,
                 ):

    if result is None: result=3D{}
    already_have=3Dresult.has_key

    acquire()
    try:
        if qparmre.match(text) >=3D 0:
            # Match quoted correct cookies
            name=3Dqparmre.group(2)
            value=3Dqparmre.group(3)
            l=3Dlen(qparmre.group(1))
        elif parmre.match(text) >=3D 0:
            # Match evil MSIE cookies ;)
            name=3Dparmre.group(2)
            value=3Dparmre.group(3)
            l=3Dlen(parmre.group(1))
        else:
            if not text or not strip(text): return result
            raise "InvalidParameter", text
    finally: release()

    if not already_have(name): result[name]=3Dvalue

    return apply(parse_cookie,(text[l:],result))

base64=3DNone
def old_validation(groups, request, HTTP_AUTHORIZATION,
                   roles=3DUNSPECIFIED_ROLES):
    global base64
    if base64 is None: import base64

    if HTTP_AUTHORIZATION:
        if lower(HTTP_AUTHORIZATION[:6]) !=3D 'basic ':
            if roles is None: return ''
            return None
        [name,password] =3D split(
            base64.decodestring(
                split(HTTP_AUTHORIZATION)[-1]), ':')
    elif request.environ.has_key('REMOTE_USER'):
        name=3Drequest.environ['REMOTE_USER']
        password=3DNone
    else:
        if roles is None: return ''
        return None

    if roles is None: return name

    keys=3DNone
    try:
        keys=3Dgroups.keys
    except:
        try:
            groups=3Dgroups() # Maybe it was a method defining a group
            keys=3Dgroups.keys
        except: pass

    if keys is not None:
        # OK, we have a named group, so apply the roles to the named
        # group.
        if roles is UNSPECIFIED_ROLES: roles=3Dkeys()
        g=3D[]
        for role in roles:
            if groups.has_key(role): g.append(groups[role])
        groups=3Dg

    for d in groups:
        if d.has_key(name) and (d[name]=3D=3Dpassword or password is None):
            return name

    if keys is None:
        # Not a named group, so don't go further
        raise 'Forbidden', (
            """<strong>You are not authorized to access this resource""")

    return None

def publish_module(module_name,
                   stdin=3Dsys.stdin, stdout=3Dsys.stdout,=
 stderr=3Dsys.stderr,
                   environ=3Dos.environ, debug=3D0):
    must_die=3D0
    status=3D200
    after_list=3D[None]
    request=3DNone
    try:
        try:
            try:
                response=3DResponse(stdout=3Dstdout, stderr=3Dstderr)
                publisher =3D ModulePublisher(
                    stdin=3Dstdin, stdout=3Dstdout, stderr=3Dstderr,
                    environ=3Denviron)
                response =3D publisher.response
                request=3Dpublisher.request
            finally:
                pass
            response =3D publisher.publish(module_name,after_list,
                                         debug=3Ddebug)
        except SystemExit, v:
            if hasattr(sys, 'exc_info'): must_die=3Dsys.exc_info()
            else: must_die =3D SystemExit, v, sys.exc_traceback
            response.exception(must_die)
        except ImportError, v:
            if type(v) is type(()) and len(v)=3D=3D3: must_die=3Dv
            elif hasattr(sys, 'exc_info'): must_die=3Dsys.exc_info()
            else: must_die =3D SystemExit, v, sys.exc_traceback
            response.exception(1, v)
        except:
            response.exception()
            status=3Dresponse.getStatus()
        if response:
            response=3Dstr(response)
        if response: stdout.write(response)

        # The module defined a post-access function, call it
        if after_list[0] is not None: after_list[0]()

    finally:
        if request is not None: request.other=3D{}

    if must_die: raise must_die[0], must_die[1], must_die[2]
    sys.exc_type, sys.exc_value, sys.exc_traceback =3D None, None, None
    return status


--=====================_918523374==_
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: attachment; filename="Config.py"

import __main__, os, sys

class ZConfig:
	"""ZPublisher Configuration Object"""

	def __init__(self):
		d=self.__dict__
		for k,v in os.environ.items(): d[k]=v
		d.update(__main__.__dict__)

	def __getattr__(self,attr):
		if hasattr(self.__dict__,attr): return getattr(self.__dict__,attr)
		else: return self[attr]

	def get(self,*args): return apply(self.__dict__.get,args)

	__getitem__ = get

	def default(self,item,val): setattr(self,item,self.get(item,val))



me = sys.argv[0]	# The original executable

ZConfig = ZConfig()
ZConfig.default('PUBLISHED_MODULE',os.path.splitext(os.path.basename(me))[0])
ZConfig.default('INCLUDE_PATHS',[])

using_symlinks = 0
while me and os.stat(me) != os.lstat(me): me = os.readlink(me); using_symlinks = 1
if using_symlinks: ZConfig.default('MODULE_HOME',os.path.dirname(me))

if ZConfig.INCLUDE_PATHS:
	sys.path[0:0]=filter(lambda p,pp=sys.path: p not in pp, ZConfig.INCLUDE_PATHS)

if ZConfig.MODULE_HOME:
	cdir=os.path.join(ZConfig.MODULE_HOME,'Components')
	sys.path[0:0]=[ZConfig.MODULE_HOME,cdir,os.path.join(cdir,sys.platform)]

try:	import thread
except: ZConfig.USE_THREADS = 0			# Don't have threads?  Can't use 'em
else:	ZConfig.default('USE_THREADS',1)	# Do have 'em, don't have to use 'em
ZConfig.default('SINGLE_THREAD_PUBLISHER',1)	# Either way, assume the safe thing.

ZConfig.default('MAX_REQUESTS',-1)		# Infinite number of requests
ZConfig.default('MAX_LIFETIME',0)		# Infinite lifetime
ZConfig.default('IDLE_TIMEOUT',0)		# Infinite idle timeout

ZConfig.default('IIS_HACK', string.find(ZConfig.get('SERVER_SOFTWARE',''),'Microsoft-IIS') != -1)

--=====================_918523374==_
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: attachment; filename="Zopestart"

#!/u/idsuser/Python151/bin/python

import os,sys

PUBLISHED_MODULE  = "Main"
SOFTWARE_HOME     = os.environ["SOFTWARE_HOME"] = "%s/lib/python" % os.path.dirname(sys.argv[0])
INCLUDE_PATHS     = [SOFTWARE_HOME]
PROCESS_LOCK_FILE = "%s/var/Zope.lock" % os.environ["INSTANCE_HOME"]
USE_THREADS	  = 0

sys.path[0:0]=INCLUDE_PATHS
import ZPublisher.Plumbing


--=====================_918523374==_--