Commit 8997c967 authored by matt@zope.com's avatar matt@zope.com

Document Template accelerations and additonal C Security Manager accelerations

from cAccessControl-review-branch.
parent a7131d9f
...@@ -89,6 +89,11 @@ Zope Changes ...@@ -89,6 +89,11 @@ Zope Changes
- API help topics can now document functions as well as classes. - API help topics can now document functions as well as classes.
- Security accelerations in c
- Accelerated C Document Template handling; Document Templates
can now do additional rendering in C, improving performance.
Bugs fixed Bugs fixed
- WebDAV: Zope escaped nested object properties derived from - WebDAV: Zope escaped nested object properties derived from
......
...@@ -148,6 +148,16 @@ Security issues ...@@ -148,6 +148,16 @@ Security issues
2.5+) 2.5+)
ZSP_OWNEROUS_SKIP
If set, will cause the Zope Security Policy to skip checks relating
to ownership, for servers on which ownership is not important.
ZSP_AUTHENTICATED_SKIP
If set, will cause the Zope Security Policy to skip checks relating
to authentication, for servers which serve only anonymous content.
DISALLOW_LOCAL_PRODUCTS DISALLOW_LOCAL_PRODUCTS
unknown unknown
......
...@@ -84,26 +84,42 @@ ...@@ -84,26 +84,42 @@
############################################################################## ##############################################################################
'''Add security system support to Document Templates '''Add security system support to Document Templates
$Id: DTML.py,v 1.7 2001/06/21 17:16:31 shane Exp $''' $Id: DTML.py,v 1.8 2001/10/26 16:07:50 matt Exp $'''
__version__='$Revision: 1.7 $'[11:-2] __version__='$Revision: 1.8 $'[11:-2]
from DocumentTemplate import DT_Util from DocumentTemplate import DT_Util
import SecurityManagement, string, math, whrandom, random import SecurityManagement, string, math, whrandom, random
import DocumentTemplate.sequence import DocumentTemplate.sequence
from ZopeGuards import guarded_getattr, guarded_getitem, _marker from ZopeGuards import guarded_getattr, guarded_getitem
class RestrictedDTML: class RestrictedDTML:
''' '''
A mix-in for derivatives of DT_String.String that adds Zope security. A mix-in for derivatives of DT_String.String that adds Zope security.
''' '''
def guarded_getattr(self, ob, name, default=_marker): def guarded_getattr(self, *args): # ob, name [, default]
return guarded_getattr(ob, name, default) return guarded_getattr(*args)
def guarded_getitem(self, ob, index): def guarded_getitem(self, ob, index):
return guarded_getitem(ob, index) return guarded_getitem(ob, index)
try:
#raise ImportError
import os
if os.environ.get("ZOPE_SECURITY_POLICY", None) == "PYTHON":
raise ImportError # :)
from cAccessControl import RestrictedDTMLMixin
except ImportError:
pass
else:
class RestrictedDTML(RestrictedDTMLMixin, RestrictedDTML):
'''
A mix-in for derivatives of DT_String.String that adds Zope security.
'''
# Allow access to unprotected attributes # Allow access to unprotected attributes
DT_Util.TemplateDict.__allow_access_to_unprotected_subobjects__=1 DT_Util.TemplateDict.__allow_access_to_unprotected_subobjects__=1
string.__allow_access_to_unprotected_subobjects__=1 string.__allow_access_to_unprotected_subobjects__=1
......
...@@ -85,8 +85,8 @@ ...@@ -85,8 +85,8 @@
__doc__='''Objects that implement Permission-based roles. __doc__='''Objects that implement Permission-based roles.
$Id: PermissionRole.py,v 1.12 2001/10/19 15:12:25 shane Exp $''' $Id: PermissionRole.py,v 1.13 2001/10/26 16:07:50 matt Exp $'''
__version__='$Revision: 1.12 $'[11:-2] __version__='$Revision: 1.13 $'[11:-2]
_use_python_impl = 0 _use_python_impl = 0
import os import os
......
...@@ -85,8 +85,21 @@ ...@@ -85,8 +85,21 @@
__doc__='''short description __doc__='''short description
$Id: SecurityManagement.py,v 1.4 2001/07/02 16:29:55 evan Exp $''' $Id: SecurityManagement.py,v 1.5 2001/10/26 16:07:50 matt Exp $'''
__version__='$Revision: 1.4 $'[11:-2] __version__='$Revision: 1.5 $'[11:-2]
def getSecurityManager():
"""Get a security manager, for the current thread.
"""
thread_id=get_ident()
manager=_managers.get(thread_id, None)
if manager is None:
manager=SecurityManager(
thread_id,
SecurityContext(SpecialUsers.nobody))
_managers[thread_id]=manager
return manager
import SpecialUsers import SpecialUsers
from SecurityManager import SecurityManager from SecurityManager import SecurityManager
...@@ -110,19 +123,6 @@ def noSecurityManager(): ...@@ -110,19 +123,6 @@ def noSecurityManager():
except: pass except: pass
def getSecurityManager():
"""Get a security manager, for the current thread.
"""
thread_id=get_ident()
manager=_managers.get(thread_id, None)
if manager is None:
manager=SecurityManager(
thread_id,
SecurityContext(SpecialUsers.nobody))
_managers[thread_id]=manager
return manager
def setSecurityPolicy(aSecurityPolicy): def setSecurityPolicy(aSecurityPolicy):
"""Set the system default security policy. """Set the system default security policy.
......
...@@ -85,8 +85,8 @@ ...@@ -85,8 +85,8 @@
__doc__='''short description __doc__='''short description
$Id: SecurityManager.py,v 1.7 2001/10/19 15:12:25 shane Exp $''' $Id: SecurityManager.py,v 1.8 2001/10/26 16:07:50 matt Exp $'''
__version__='$Revision: 1.7 $'[11:-2] __version__='$Revision: 1.8 $'[11:-2]
import ZopeSecurityPolicy, os, string import ZopeSecurityPolicy, os, string
...@@ -95,7 +95,12 @@ _noroles = ZopeSecurityPolicy._noroles ...@@ -95,7 +95,12 @@ _noroles = ZopeSecurityPolicy._noroles
try: max_stack_size=string.atoi(os.environ.get('Z_MAX_STACK_SIZE','100')) try: max_stack_size=string.atoi(os.environ.get('Z_MAX_STACK_SIZE','100'))
except: max_stack_size=100 except: max_stack_size=100
_defaultPolicy=ZopeSecurityPolicy.ZopeSecurityPolicy() if os.environ.has_key("ZSP_OWNEROUS_SKIP"): ownerous=0
else: ownerous=1
if os.environ.has_key("ZSP_AUTHENTICATION_SKIP"): authenticated=0
else: authenticated=1
_defaultPolicy=ZopeSecurityPolicy.ZopeSecurityPolicy(ownerous=ownerous,
authenticated=authenticated)
def setSecurityPolicy(aSecurityPolicy): def setSecurityPolicy(aSecurityPolicy):
"""Set the system default security policy. """Set the system default security policy.
...@@ -107,6 +112,7 @@ def setSecurityPolicy(aSecurityPolicy): ...@@ -107,6 +112,7 @@ def setSecurityPolicy(aSecurityPolicy):
_defaultPolicy=aSecurityPolicy _defaultPolicy=aSecurityPolicy
return last return last
class SecurityManager: class SecurityManager:
"""A security manager provides methods for checking access and managing """A security manager provides methods for checking access and managing
executable context and policies executable context and policies
...@@ -116,35 +122,34 @@ class SecurityManager: ...@@ -116,35 +122,34 @@ class SecurityManager:
'validate': 1, 'validateValue': 1, 'checkPermission': 1, 'validate': 1, 'validateValue': 1, 'checkPermission': 1,
'getUser': 1, 'calledByExecutable': 1 'getUser': 1, 'calledByExecutable': 1
} }
def __init__(self, thread_id, context): def __init__(self, thread_id, context):
self._thread_id=thread_id self._thread_id=thread_id
self._context=context self._context=context
self._policy=None self._policy=_defaultPolicy
def validate(self, accessed=None, container=None, name=None, value=None, def validate(self, accessed=None, container=None, name=None, value=None,
roles=_noroles): roles=_noroles):
"""Validate access. """Validate access.
Arguments: Arguments:
accessed -- the object that was being accessed accessed -- the object that was being accessed
container -- the object the value was found in container -- the object the value was found in
name -- The name used to access the value name -- The name used to access the value
value -- The value retrieved though the access. value -- The value retrieved though the access.
roles -- The roles of the object if already known. roles -- The roles of the object if already known.
The arguments may be provided as keyword arguments. Some of these The arguments may be provided as keyword arguments. Some of these
arguments may be ommitted, however, the policy may reject access arguments may be ommitted, however, the policy may reject access
in some cases when arguments are ommitted. It is best to provide in some cases when arguments are ommitted. It is best to provide
all the values possible. all the values possible.
""" """
policy=self._policy policy=self._policy
if policy is None: policy=_defaultPolicy
if roles is _noroles: if roles is _noroles:
return policy.validate(accessed, container, name, value, return policy.validate(accessed, container, name, value,
self._context) self._context)
...@@ -153,19 +158,19 @@ class SecurityManager: ...@@ -153,19 +158,19 @@ class SecurityManager:
self._context, roles) self._context, roles)
def DTMLValidate(self, accessed=None, container=None, name=None, def DTMLValidate(self, accessed=None, container=None, name=None,
value=None,md=None): value=None, md=None):
"""Validate access. """Validate access.
* THIS EXISTS FOR DTML COMPATIBILITY * * THIS EXISTS FOR DTML COMPATIBILITY *
Arguments: Arguments:
accessed -- the object that was being accessed accessed -- the object that was being accessed
container -- the object the value was found in container -- the object the value was found in
name -- The name used to access the value name -- The name used to access the value
value -- The value retrieved though the access. value -- The value retrieved though the access.
md -- multidict for DTML (ignored) md -- multidict for DTML (ignored)
...@@ -177,7 +182,6 @@ class SecurityManager: ...@@ -177,7 +182,6 @@ class SecurityManager:
""" """
policy=self._policy policy=self._policy
if policy is None: policy=_defaultPolicy
return policy.validate(accessed, container, name, value, return policy.validate(accessed, container, name, value,
self._context) self._context)
...@@ -185,7 +189,6 @@ class SecurityManager: ...@@ -185,7 +189,6 @@ class SecurityManager:
"""Convenience for common case of simple value validation. """Convenience for common case of simple value validation.
""" """
policy=self._policy policy=self._policy
if policy is None: policy=_defaultPolicy
if roles is _noroles: if roles is _noroles:
return policy.validate(None, None, None, value, return policy.validate(None, None, None, value,
self._context) self._context)
...@@ -198,13 +201,12 @@ class SecurityManager: ...@@ -198,13 +201,12 @@ class SecurityManager:
the given object. the given object.
Arguments: Arguments:
permission -- A permission name permission -- A permission name
object -- The object being accessed according to the permission object -- The object being accessed according to the permission
""" """
policy=self._policy policy=self._policy
if policy is None: policy=_defaultPolicy
return policy.checkPermission(permission, object, return policy.checkPermission(permission, object,
self._context) self._context)
...@@ -218,7 +220,10 @@ class SecurityManager: ...@@ -218,7 +220,10 @@ class SecurityManager:
raise SystemError, 'Excessive recursion' raise SystemError, 'Excessive recursion'
stack.append(anExecutableObject) stack.append(anExecutableObject)
p=getattr(anExecutableObject, '_customSecurityPolicy', None) p=getattr(anExecutableObject, '_customSecurityPolicy', None)
if p is not None: p=p() if p is not None:
p=p()
else:
p=_defaultPolicy
self._policy=p self._policy=p
def removeContext(self, anExecutableObject, def removeContext(self, anExecutableObject,
...@@ -245,10 +250,13 @@ class SecurityManager: ...@@ -245,10 +250,13 @@ class SecurityManager:
if stack: if stack:
top=stack[-1] top=stack[-1]
p=getattr(top, '_customSecurityPolicy', None) p=getattr(top, '_customSecurityPolicy', None)
if p is not None: p=p() if p is not None:
p=p()
else:
p=_defaultPolicy
self._policy=p self._policy=p
else: else:
self._policy=None self._policy=_defaultPolicy
def getUser(self): def getUser(self):
"""Get the current authenticated user""" """Get the current authenticated user"""
...@@ -260,3 +268,17 @@ class SecurityManager: ...@@ -260,3 +268,17 @@ class SecurityManager:
return len(self._context.stack) return len(self._context.stack)
try:
#raise ImportError
import os
if os.environ.get("ZOPE_SECURITY_POLICY", None) == "PYTHON":
raise ImportError # :)
from cAccessControl import SecurityManager as cSecurityManager
except ImportError:
pass
else:
class SecurityManager(cSecurityManager, SecurityManager):
"""A security manager provides methods for checking access and managing
executable context and policies
"""
...@@ -83,7 +83,7 @@ ...@@ -83,7 +83,7 @@
# #
############################################################################## ##############################################################################
__version__='$Revision: 1.7 $'[11:-2] __version__='$Revision: 1.8 $'[11:-2]
from RestrictedPython.Guards import safe_builtins, _full_read_guard, \ from RestrictedPython.Guards import safe_builtins, _full_read_guard, \
full_write_guard full_write_guard
...@@ -98,29 +98,41 @@ _marker = [] # Create a new marker object. ...@@ -98,29 +98,41 @@ _marker = [] # Create a new marker object.
safe_builtins = safe_builtins.copy() safe_builtins = safe_builtins.copy()
safe_builtins.update(utility_builtins) safe_builtins.update(utility_builtins)
def aq_validate(inst, obj, name, v, validate): try:
return validate(inst, obj, name, v)
#raise ImportError
def guarded_getattr(inst, name, default=_marker): import os
if name[:1] != '_': if os.environ.get("ZOPE_SECURITY_POLICY", None) == "PYTHON":
# Try to get the attribute normally so that unusual raise ImportError # :)
# exceptions are caught early. from cAccessControl import aq_validate, guarded_getattr
try: v = getattr(inst, name)
except AttributeError: except ImportError:
if default is not _marker:
return default def aq_validate(inst, obj, name, v, validate):
raise return validate(inst, obj, name, v)
if Containers(type(inst)):
# Simple type. Short circuit.
return v def guarded_getattr(inst, name, default=_marker):
validate = getSecurityManager().validate if name[:1] != '_':
# Filter out the objects we can't access. # Try to get the attribute normally so that unusual
if hasattr(inst, 'aq_acquire'): # exceptions are caught early.
return inst.aq_acquire(name, aq_validate, validate) try: v = getattr(inst, name)
# Or just try to get the attribute directly. except AttributeError:
if validate(inst, inst, name, v): if default is not _marker:
return v return default
raise Unauthorized, name raise
if Containers(type(inst)):
# Simple type. Short circuit.
return v
validate = getSecurityManager().validate
# Filter out the objects we can't access.
if hasattr(inst, 'aq_acquire'):
return inst.aq_acquire(name, aq_validate, validate)
# Or just try to get the attribute directly.
if validate(inst, inst, name, v):
return v
raise Unauthorized, name
safe_builtins['getattr'] = guarded_getattr safe_builtins['getattr'] = guarded_getattr
def guarded_hasattr(object, name): def guarded_hasattr(object, name):
......
...@@ -85,8 +85,8 @@ ...@@ -85,8 +85,8 @@
__doc__='''Define Zope\'s default security policy __doc__='''Define Zope\'s default security policy
$Id: ZopeSecurityPolicy.py,v 1.14 2001/10/19 15:12:25 shane Exp $''' $Id: ZopeSecurityPolicy.py,v 1.15 2001/10/26 16:07:50 matt Exp $'''
__version__='$Revision: 1.14 $'[11:-2] __version__='$Revision: 1.15 $'[11:-2]
_use_python_impl = 0 _use_python_impl = 0
...@@ -119,8 +119,32 @@ if _use_python_impl: ...@@ -119,8 +119,32 @@ if _use_python_impl:
class ZopeSecurityPolicy: class ZopeSecurityPolicy:
def __init__(self, ownerous=1): def __init__(self, ownerous=1, authenticated=1):
"""Create a Zope security policy.
Two optional keyword arguments may be provided:
ownerous -- Untrusted users can create code
(e.g. Python scripts or templates),
so check that code owners can access resources.
The argument must have a truth value.
The default is true.
authenticated -- Allow access to resources based on the
privaledges of the authenticated user.
The argument must have a truth value.
The default is true.
This (somewhat experimental) option can be set
to false on sites that allow only public
(unauthenticated) access. An anticipated
scenario is a ZEO configuration in which some
clients allow only public access and other
clients allow full management.
"""
self._ownerous=ownerous self._ownerous=ownerous
self._authenticated=authenticated
def validate(self, accessed, container, name, value, context, def validate(self, accessed, container, name, value, context,
roles=_noroles, None=None, type=type, IntType=type(0), roles=_noroles, None=None, type=type, IntType=type(0),
...@@ -239,7 +263,8 @@ if _use_python_impl: ...@@ -239,7 +263,8 @@ if _use_python_impl:
try: try:
if context.user.allowed(value, roles): return 1 if self._authenticated and context.user.allowed(value, roles):
return 1
except AttributeError: pass except AttributeError: pass
# We don't want someone to acquire if they can't get an unacquired! # We don't want someone to acquire if they can't get an unacquired!
...@@ -254,4 +279,3 @@ if _use_python_impl: ...@@ -254,4 +279,3 @@ if _use_python_impl:
if type(roles) is StringType: if type(roles) is StringType:
roles=[roles] roles=[roles]
return context.user.allowed(object, roles) return context.user.allowed(object, roles)
This diff is collapsed.
...@@ -147,8 +147,8 @@ __doc__='''Conditional insertion ...@@ -147,8 +147,8 @@ __doc__='''Conditional insertion
variable is not reevaluated. variable is not reevaluated.
''' '''
__rcs_id__='$Id: DT_If.py,v 1.16 1999/03/10 00:15:07 klm Exp $' __rcs_id__='$Id: DT_If.py,v 1.17 2001/10/26 16:07:50 matt Exp $'
__version__='$Revision: 1.16 $'[11:-2] __version__='$Revision: 1.17 $'[11:-2]
from DT_Util import ParseError, parse_params, name_param, str from DT_Util import ParseError, parse_params, name_param, str
...@@ -192,7 +192,7 @@ class If: ...@@ -192,7 +192,7 @@ class If:
if elses is not None: sections.append(elses) if elses is not None: sections.append(elses)
self.simple_form=tuple(sections) self.simple_form=('i',)+tuple(sections)
class Unless: class Unless:
name='unless' name='unless'
...@@ -204,7 +204,7 @@ class Unless: ...@@ -204,7 +204,7 @@ class Unless:
name,expr=name_param(args,'unless',1) name,expr=name_param(args,'unless',1)
if expr is None: cond=name if expr is None: cond=name
else: cond=expr.eval else: cond=expr.eval
self.simple_form=(cond,None,section.blocks) self.simple_form=('i',cond,None,section.blocks)
class Else(Unless): class Else(Unless):
# The else tag is included for backward compatibility and is deprecated. # The else tag is included for backward compatibility and is deprecated.
......
...@@ -217,8 +217,8 @@ Evaluating expressions without rendering results ...@@ -217,8 +217,8 @@ Evaluating expressions without rendering results
''' # ' ''' # '
__rcs_id__='$Id: DT_Var.py,v 1.44 2001/10/02 14:23:32 shane Exp $' __rcs_id__='$Id: DT_Var.py,v 1.45 2001/10/26 16:07:50 matt Exp $'
__version__='$Revision: 1.44 $'[11:-2] __version__='$Revision: 1.45 $'[11:-2]
from DT_Util import parse_params, name_param, str from DT_Util import parse_params, name_param, str
import re, string, sys import re, string, sys
...@@ -254,7 +254,11 @@ class Var: ...@@ -254,7 +254,11 @@ class Var:
if len(args)==1 and fmt=='s': if len(args)==1 and fmt=='s':
if expr is None: expr=name if expr is None: expr=name
else: expr=expr.eval else: expr=expr.eval
self.simple_form=expr, self.simple_form=('v', expr)
elif len(args)==2 and fmt=='s' and args.has_key('html_quote'):
if expr is None: expr=name
else: expr=expr.eval
self.simple_form=('v', expr, 'h')
def render(self, md): def render(self, md):
args=self.args args=self.args
...@@ -353,7 +357,7 @@ class Call: ...@@ -353,7 +357,7 @@ class Call:
name, expr = name_param(args,'call',1) name, expr = name_param(args,'call',1)
if expr is None: expr=name if expr is None: expr=name
else: expr=expr.eval else: expr=expr.eval
self.simple_form=expr,None self.simple_form=('i', expr, None)
def url_quote(v, name='(Unknown name)', md={}): def url_quote(v, name='(Unknown name)', md={}):
......
...@@ -84,7 +84,7 @@ ...@@ -84,7 +84,7 @@
****************************************************************************/ ****************************************************************************/
static char cDocumentTemplate_module_documentation[] = static char cDocumentTemplate_module_documentation[] =
"" ""
"\n$Id: cDocumentTemplate.c,v 1.39 2001/06/21 19:08:59 shane Exp $" "\n$Id: cDocumentTemplate.c,v 1.40 2001/10/26 16:07:50 matt Exp $"
; ;
#include "ExtensionClass.h" #include "ExtensionClass.h"
...@@ -94,7 +94,7 @@ static PyObject *py___call__, *py___roles__, *py_AUTHENTICATED_USER; ...@@ -94,7 +94,7 @@ static PyObject *py___call__, *py___roles__, *py_AUTHENTICATED_USER;
static PyObject *py_hasRole, *py__proxy_roles, *py_Unauthorized; static PyObject *py_hasRole, *py__proxy_roles, *py_Unauthorized;
static PyObject *py_Unauthorized_fmt, *py_guarded_getattr; static PyObject *py_Unauthorized_fmt, *py_guarded_getattr;
static PyObject *py__push, *py__pop, *py_aq_base, *py_renderNS; static PyObject *py__push, *py__pop, *py_aq_base, *py_renderNS;
static PyObject *py___class__; static PyObject *py___class__, *html_quote;
/* ----------------------------------------------------- */ /* ----------------------------------------------------- */
...@@ -398,13 +398,29 @@ static PyObject * ...@@ -398,13 +398,29 @@ static PyObject *
MM_cget(MM *self, PyObject *key, int call) MM_cget(MM *self, PyObject *key, int call)
{ {
long i; long i;
PyObject *e, *rr, *tb; PyObject *e, *rr;
UNLESS(-1 != (i=PyList_Size(self->data))) return NULL; UNLESS(-1 != (i=PyList_Size(self->data))) return NULL;
while (--i >= 0) while (--i >= 0)
{ {
e=PyList_GetItem(self->data,i); e=PyList_GET_ITEM(self->data,i);
if ((e=PyObject_GetItem(e,key))) if (PyDict_Check(e))
{
e=PyDict_GetItem(e, key);
Py_XINCREF(e);
}
else
{
UNLESS (e=PyObject_GetItem(e,key))
{
if (PyErr_Occurred() == PyExc_KeyError)
PyErr_Clear();
else
return NULL;
}
}
if (e)
{ {
if (!call) return e; if (!call) return e;
...@@ -437,17 +453,8 @@ MM_cget(MM *self, PyObject *key, int call) ...@@ -437,17 +453,8 @@ MM_cget(MM *self, PyObject *key, int call)
} }
return e; return e;
} }
PyErr_Fetch(&e, &rr, &tb);
if (e != PyExc_KeyError)
{
PyErr_Restore(e,rr,tb);
return NULL;
}
Py_XDECREF(e);
Py_XDECREF(rr);
Py_XDECREF(tb);
} }
PyErr_SetObject(PyExc_KeyError,key); PyErr_SetObject(PyExc_KeyError, key);
return NULL; return NULL;
} }
...@@ -726,7 +733,7 @@ static int ...@@ -726,7 +733,7 @@ static int
render_blocks_(PyObject *blocks, PyObject *rendered, render_blocks_(PyObject *blocks, PyObject *rendered,
PyObject *md, PyObject *mda) PyObject *md, PyObject *mda)
{ {
PyObject *block; PyObject *block, *t;
int l, i, k=0, append; int l, i, k=0, append;
if ((l=PyList_Size(blocks)) < 0) return -1; if ((l=PyList_Size(blocks)) < 0) return -1;
...@@ -735,95 +742,123 @@ render_blocks_(PyObject *blocks, PyObject *rendered, ...@@ -735,95 +742,123 @@ render_blocks_(PyObject *blocks, PyObject *rendered,
block=PyList_GET_ITEM(((PyListObject*)blocks), i); block=PyList_GET_ITEM(((PyListObject*)blocks), i);
append=1; append=1;
if (PyTuple_Check(block)) if (PyTuple_Check(block)
&& PyTuple_GET_SIZE(block) > 1
&& PyTuple_GET_ITEM(block, 0)
&& PyString_Check(PyTuple_GET_ITEM(block, 0)))
{ {
int bs; switch (PyString_AS_STRING(PyTuple_GET_ITEM(block, 0))[0])
{
case 'v': /* var */
t=PyTuple_GET_ITEM(block,1);
bs=((PyTupleObject*)block)->ob_size; if (t == NULL) return -1;
if (bs==1) if (PyString_Check(t)) t=PyObject_GetItem(md, t);
{ else t=PyObject_CallObject(t, mda);
/* Simple var */
block=PyTuple_GET_ITEM(block,0); if (t == NULL || (! PyString_Check(t)))
if (PyString_Check(block)) block=PyObject_GetItem(md,block); {
else block=PyObject_CallObject(block,mda); if (t) ASSIGN(t, PyObject_Str(t));
if (block) ASSIGN(block, PyObject_Str(block)); UNLESS(t) return -1;
UNLESS(block) return -1; }
}
else if (PyString_Check(t)
{ && PyTuple_GET_SIZE(block) == 3) /* html_quote */
/* if */ {
int icond, m; if (strchr(PyString_AS_STRING(t), '&')
PyObject *cond, *n, *cache; && strchr(PyString_AS_STRING(t), '<')
&& strchr(PyString_AS_STRING(t), '>')
UNLESS(cache=PyDict_New()) return -1; && strchr(PyString_AS_STRING(t), '"')
cond=PyObject_GetAttr(md,py__push); )
if (cond) ASSIGN(cond, PyObject_CallFunction(cond,"O",cache)); ASSIGN(t, PyObject_CallFunction(html_quote, "O", t));
Py_DECREF(cache); if (t == NULL) return -1;
if (cond) Py_DECREF(cond); }
else return -1;
block = t;
break;
case 'i': /* if */
{
int icond, m, bs;
PyObject *cond, *n, *cache;
bs = PyTuple_GET_SIZE(block) - 1; /* subtract code */
UNLESS(cache=PyDict_New()) return -1;
cond=PyObject_GetAttr(md,py__push);
if (cond) ASSIGN(cond, PyObject_CallFunction(cond,"O",cache));
Py_DECREF(cache);
if (cond) Py_DECREF(cond);
else return -1;
append=0; append=0;
m=bs-1; m=bs-1;
for (icond=0; icond < m; icond += 2) for (icond=0; icond < m; icond += 2)
{ {
cond=PyTuple_GET_ITEM(block,icond); cond=PyTuple_GET_ITEM(block,icond+1);
if (PyString_Check(cond)) if (PyString_Check(cond))
{ {
/* We have to be careful to handle key errors here */ /* We have to be careful to handle key errors here */
n=cond; n=cond;
if ((cond=PyObject_GetItem(md,cond))) if ((cond=PyObject_GetItem(md,cond)))
{ {
if (PyDict_SetItem(cache, n, cond) < 0) if (PyDict_SetItem(cache, n, cond) < 0)
{ {
Py_DECREF(cond); Py_DECREF(cond);
return if_finally(md,1); return if_finally(md,1);
} }
} }
else else
{ {
PyObject *t, *v, *tb; PyObject *t, *v, *tb;
PyErr_Fetch(&t, &v, &tb); PyErr_Fetch(&t, &v, &tb);
if (t != PyExc_KeyError || PyObject_Compare(v,n)) if (t != PyExc_KeyError || PyObject_Compare(v,n))
{ {
PyErr_Restore(t,v,tb); PyErr_Restore(t,v,tb);
return if_finally(md,1); return if_finally(md,1);
} }
Py_XDECREF(t); Py_XDECREF(t);
Py_XDECREF(v); Py_XDECREF(v);
Py_XDECREF(tb); Py_XDECREF(tb);
cond=Py_None; cond=Py_None;
Py_INCREF(cond); Py_INCREF(cond);
} }
} }
else else
UNLESS(cond=PyObject_CallObject(cond,mda)) UNLESS(cond=PyObject_CallObject(cond,mda))
return if_finally(md,1); return if_finally(md,1);
if (PyObject_IsTrue(cond)) if (PyObject_IsTrue(cond))
{ {
Py_DECREF(cond); Py_DECREF(cond);
block=PyTuple_GET_ITEM(block,icond+1); block=PyTuple_GET_ITEM(block,icond+1+1);
if (block!=Py_None && if (block!=Py_None &&
render_blocks_(block, rendered, md, mda) < 0) render_blocks_(block, rendered, md, mda) < 0)
return if_finally(md,1); return if_finally(md,1);
m=-1; m=-1;
break; break;
} }
else Py_DECREF(cond); else Py_DECREF(cond);
} }
if (icond==m) if (icond==m)
{ {
block=PyTuple_GET_ITEM(block,icond); block=PyTuple_GET_ITEM(block,icond+1);
if (block!=Py_None && if (block!=Py_None &&
render_blocks_(block, rendered, md, mda) < 0) render_blocks_(block, rendered, md, mda) < 0)
return if_finally(md,1); return if_finally(md,1);
} }
if (if_finally(md,0) == -2) return -1; if (if_finally(md,0) == -2) return -1;
} }
} break;
default:
PyErr_Format(PyExc_ValueError,
"Invalid DTML command code, %s",
PyString_AS_STRING(PyTuple_GET_ITEM(block, 0)));
return -1;
}
}
else if (PyString_Check(block)) else if (PyString_Check(block))
{ {
Py_INCREF(block); Py_INCREF(block);
...@@ -904,10 +939,14 @@ void ...@@ -904,10 +939,14 @@ void
initcDocumentTemplate(void) initcDocumentTemplate(void)
{ {
PyObject *m, *d; PyObject *m, *d;
char *rev="$Revision: 1.39 $"; char *rev="$Revision: 1.40 $";
DictInstanceType.ob_type=&PyType_Type; DictInstanceType.ob_type=&PyType_Type;
UNLESS (html_quote = PyImport_ImportModule("html_quote")) return;
ASSIGN(html_quote, PyObject_GetAttrString(html_quote, "html_quote"));
UNLESS (html_quote) return;
UNLESS(py_isDocTemp=PyString_FromString("isDocTemp")) return; UNLESS(py_isDocTemp=PyString_FromString("isDocTemp")) return;
UNLESS(py_renderNS=PyString_FromString("__render_with_namespace__")) return; UNLESS(py_renderNS=PyString_FromString("__render_with_namespace__")) return;
UNLESS(py_blocks=PyString_FromString("blocks")) return; UNLESS(py_blocks=PyString_FromString("blocks")) return;
...@@ -946,6 +985,4 @@ initcDocumentTemplate(void) ...@@ -946,6 +985,4 @@ initcDocumentTemplate(void)
PyDict_SetItemString(d, "__version__", PyDict_SetItemString(d, "__version__",
PyString_FromStringAndSize(rev+11,strlen(rev+11)-2)); PyString_FromStringAndSize(rev+11,strlen(rev+11)-2));
if (PyErr_Occurred())
Py_FatalError("can't initialize module cDocumentTemplate");
} }
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