[Zope-Perl] Perl External Methods

Chris McDonough chrism@digicool.com
Sun, 11 Jun 2000 16:16:21 -0400


Gisle Aas wrote:

> Another approach that I like better could be that all perl function
> and module names are always (automatically) prefixed by something like
> "ZopeExt::" in order to limit what can be done.  Perl External Method
> modules would then need to go into the ./Extensions/ZopeExt directory
> (or anywhere else perl looks for modules).

It would seem to me that narrowing the use path this way is a good
thing.
We want to make sure that only modules that reside in
$ZOPEHOME/Extensions are searched for and imported.
I suppose some fiddling with the @INC array would do this.  We'd need to
then unfiddle it when the method
was actually run.  I see you have something like that in there commented
out.
 
> -----lib/python/Products/PerlExternalMethod__init__.py-------------->8---
> # Copyright 2000 Digital Creations
> # Copyright 2000 ActiveState Tool Corp.
> #
> # This module can be redistributed and/or modified
> # under the terms of the Zope Public Licence v1.0.
> #
> # This product includes software developed by Digital Creations
> # for use in the Z Object Publishing Environment (http://www.zope.org/).
> 
> from Globals import Persistent, HTMLFile, MessageDialog
> import OFS.SimpleItem
> import AccessControl.Role
> import Acquisition
> 
> from string import split, strip, join, find
> 
> def get_perl_func(name, module):
>     import perl
>     if module:
>         # XXX unshift(@INC, qw(./Extensions/perl ./Extensions)
>         perl.require(module)  # XXX do we need some kind of untaint here??
>     f = perl.get_ref(name)
>     return f
> 
> # A class emulating internal func-code objects enough to fool
> # ZPublisher's mapply.  Need to emulate co_varnames and co_argcount.
> # For Python External methods you find a similar class in
> # App.Extentions.
> 
> class FuncCode:
>     def __init__(self, args = ""):
>         self.co_varnames = map(strip, split(args, ","))
>         self.co_argcount = len(self.co_varnames)
> 
>     def args(self):
>         return join(self.co_varnames, ", ")
> 
> # This is the actual class that we will store instances of, in the
> # ZODB as this product is instantiated through manage_addPerlExtMethod
> # below.  It stores enough information to obtain a reference to a single
> # perl function loaded from the file system on demand and the information
> # needed to fool mapply into thinking that this object is a function
> # by itself.
> 
> class PerlExtMethod(OFS.SimpleItem.Item, Persistent, Acquisition.Explicit,
>                     AccessControl.Role.RoleManager):
>     """Web-callable functions that encapsulate external perl functions."""
> 
>     # Emulated attributes of functions.  The func_code class attribute
>     # is not really used as instances override it with their own version.
>     func_defaults=()
>     func_code=FuncCode()
> 
>     # Set up various stuff that the Zope frameworks wants
>     meta_type='Perl External Method'
>     manage_options=(
>         (
>         {'label':'Properties', 'action':'manage_main',},
>         {'label':'Try It', 'action':''},
>         )
>         +OFS.SimpleItem.Item.manage_options
>         +AccessControl.Role.RoleManager.manage_options
>         )
> 
>     __ac_permissions__=(
>         ('View management screens', ('manage_main',)),
>         ('Change External Methods', ('manage_edit',)),
>         ('View', ('__call__','')),
>         )
> 
>     # I am not really sure why :-(
>     ZopeTime=Acquisition.Acquired
>     HelpSys=Acquisition.Acquired
> 
>     def __init__(self, id, title, module, function, args):
>         self.id=id
>         self.manage_edit(title, module, function, args)
> 
>     manage_main=HTMLFile('methodEdit', globals())
> 
>     def manage_edit(self, title, module, function, args, REQUEST=None):
>         """Change the perl external method"""
> 
>         self.title = str(title)
> 
>         module = strip(str(module))
>         if module[-3:]=='.pm': module=module[:-3]
>         self.module = module
> 
>         # XXX In order to improve security we might here require
>         # that the function name is prefixed with some specific
>         # package name (like "ZopeExt::").  This really allows
>         # access to any function to be set up.
>         function = strip(str(function))
>         if find(function, "::") < 0:
>             function = module + "::" + function
>         self.function = function
> 
>         self.func_code = FuncCode(str(args))
> 
>         #self.getFunction(1,1)
>         if REQUEST: return MessageDialog(
>             title  ='Changed %s' % self.id,
>             message='%s has been updated' % self.id,
>             action =REQUEST['URL2']+'/manage_main',
>             target ='manage_main')
> 
>     def __call__(self, *args, **kw):
>         """Invoke a PerlExternalMethod"""
> 
>         # The "_v_" prefix tells ZODB not try to store this thing
>         if not hasattr(self, "_v_f"):
>             self._v_f = get_perl_func(self.function, self.module)
>         return apply(self._v_f, args, kw)
> 
>     def args(self):
>         return self.func_code.args()
> 
> manage_addPerlExtMethodForm=HTMLFile('methodAdd', globals())
> 
> def manage_addPerlExtMethod(self, id, title, module, function, args,
>                             REQUEST=None):
>     """Add a perl external method to a folder"""
>     self._setObject(id, PerlExtMethod(id, title, module, function, args))
>     if REQUEST:
>         return self.manage_main(self, REQUEST)
> 
> def initialize(context):
>     context.registerClass(
>         PerlExtMethod,
>         constructors=(manage_addPerlExtMethodForm,
>                       manage_addPerlExtMethod),
>         icon='extmethod.gif',
>     )
> 
> _______________________________________________
> Zope-perl maillist  -  Zope-perl@zope.org
> http://lists.zope.org/mailman/listinfo/zope-perl