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
...@@ -120,7 +126,7 @@ class SecurityManager: ...@@ -120,7 +126,7 @@ class SecurityManager:
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):
...@@ -144,7 +150,6 @@ class SecurityManager: ...@@ -144,7 +150,6 @@ class SecurityManager:
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,7 +158,7 @@ class SecurityManager: ...@@ -153,7 +158,7 @@ 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 *
...@@ -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)
...@@ -204,7 +207,6 @@ class SecurityManager: ...@@ -204,7 +207,6 @@ class SecurityManager:
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,10 +98,21 @@ _marker = [] # Create a new marker object. ...@@ -98,10 +98,21 @@ _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:
#raise ImportError
import os
if os.environ.get("ZOPE_SECURITY_POLICY", None) == "PYTHON":
raise ImportError # :)
from cAccessControl import aq_validate, guarded_getattr
except ImportError:
def aq_validate(inst, obj, name, v, validate):
return validate(inst, obj, name, v) return validate(inst, obj, name, v)
def guarded_getattr(inst, name, default=_marker):
def guarded_getattr(inst, name, default=_marker):
if name[:1] != '_': if name[:1] != '_':
# Try to get the attribute normally so that unusual # Try to get the attribute normally so that unusual
# exceptions are caught early. # exceptions are caught early.
...@@ -121,6 +132,7 @@ def guarded_getattr(inst, name, default=_marker): ...@@ -121,6 +132,7 @@ def guarded_getattr(inst, name, default=_marker):
if validate(inst, inst, name, v): if validate(inst, inst, name, v):
return v return v
raise Unauthorized, name 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,27 +742,48 @@ render_blocks_(PyObject *blocks, PyObject *rendered, ...@@ -735,27 +742,48 @@ 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)))
{
switch (PyString_AS_STRING(PyTuple_GET_ITEM(block, 0))[0])
{ {
int bs; 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);
if (t == NULL || (! PyString_Check(t)))
{ {
/* Simple var */ if (t) ASSIGN(t, PyObject_Str(t));
block=PyTuple_GET_ITEM(block,0); UNLESS(t) return -1;
if (PyString_Check(block)) block=PyObject_GetItem(md,block);
else block=PyObject_CallObject(block,mda);
if (block) ASSIGN(block, PyObject_Str(block));
UNLESS(block) return -1;
} }
else
if (PyString_Check(t)
&& PyTuple_GET_SIZE(block) == 3) /* html_quote */
{
if (strchr(PyString_AS_STRING(t), '&')
&& strchr(PyString_AS_STRING(t), '<')
&& strchr(PyString_AS_STRING(t), '>')
&& strchr(PyString_AS_STRING(t), '"')
)
ASSIGN(t, PyObject_CallFunction(html_quote, "O", t));
if (t == NULL) return -1;
}
block = t;
break;
case 'i': /* if */
{ {
/* if */ int icond, m, bs;
int icond, m;
PyObject *cond, *n, *cache; PyObject *cond, *n, *cache;
bs = PyTuple_GET_SIZE(block) - 1; /* subtract code */
UNLESS(cache=PyDict_New()) return -1; UNLESS(cache=PyDict_New()) return -1;
cond=PyObject_GetAttr(md,py__push); cond=PyObject_GetAttr(md,py__push);
if (cond) ASSIGN(cond, PyObject_CallFunction(cond,"O",cache)); if (cond) ASSIGN(cond, PyObject_CallFunction(cond,"O",cache));
...@@ -767,7 +795,7 @@ render_blocks_(PyObject *blocks, PyObject *rendered, ...@@ -767,7 +795,7 @@ render_blocks_(PyObject *blocks, PyObject *rendered,
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 */
...@@ -804,7 +832,7 @@ render_blocks_(PyObject *blocks, PyObject *rendered, ...@@ -804,7 +832,7 @@ render_blocks_(PyObject *blocks, PyObject *rendered,
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);
...@@ -815,7 +843,7 @@ render_blocks_(PyObject *blocks, PyObject *rendered, ...@@ -815,7 +843,7 @@ render_blocks_(PyObject *blocks, PyObject *rendered,
} }
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);
...@@ -823,6 +851,13 @@ render_blocks_(PyObject *blocks, PyObject *rendered, ...@@ -823,6 +851,13 @@ render_blocks_(PyObject *blocks, PyObject *rendered,
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))
{ {
...@@ -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