[Checkins] SVN: z3c.soap/ soap in zope2. initial import
Jean-Fran�ois Roche
jfroche at jfroche.be
Thu Nov 13 07:18:52 EST 2008
Log message for revision 92902:
soap in zope2. initial import
Changed:
A z3c.soap/
A z3c.soap/branches/
A z3c.soap/tags/
A z3c.soap/trunk/
A z3c.soap/trunk/bootstrap.py
A z3c.soap/trunk/buildout.cfg
A z3c.soap/trunk/docs/
A z3c.soap/trunk/docs/HISTORY.txt
A z3c.soap/trunk/setup.cfg
A z3c.soap/trunk/setup.py
A z3c.soap/trunk/z3c/
A z3c.soap/trunk/z3c/__init__.py
A z3c.soap/trunk/z3c/soap/
A z3c.soap/trunk/z3c/soap/HTTPRequest.py
A z3c.soap/trunk/z3c/soap/README.txt
A z3c.soap/trunk/z3c/soap/__init__.py
A z3c.soap/trunk/z3c/soap/ftesting.zcml
A z3c.soap/trunk/z3c/soap/ftests.py
A z3c.soap/trunk/z3c/soap/interfaces.py
A z3c.soap/trunk/z3c/soap/meta.zcml
A z3c.soap/trunk/z3c/soap/metaconfigure.py
A z3c.soap/trunk/z3c/soap/metadirectives.py
A z3c.soap/trunk/z3c/soap/patch.py
A z3c.soap/trunk/z3c/soap/publisher.py
A z3c.soap/trunk/z3c/soap/soap.py
A z3c.soap/trunk/z3c/soap/tests/
A z3c.soap/trunk/z3c/soap/tests/__init__.py
A z3c.soap/trunk/z3c/soap/tests/mailvalidation.py
A z3c.soap/trunk/z3c/soap/tests/soap.zcml
A z3c.soap/trunk/z3c/soap/tests/soap_error.zcml
A z3c.soap/trunk/z3c/soap/tests/test_directives.py
A z3c.soap/trunk/z3c/soap/tests/test_soappublication.py
A z3c.soap/trunk/z3c/soap/tests/test_soaprequest.py
-=-
Added: z3c.soap/trunk/bootstrap.py
===================================================================
--- z3c.soap/trunk/bootstrap.py (rev 0)
+++ z3c.soap/trunk/bootstrap.py 2008-11-13 12:18:51 UTC (rev 92902)
@@ -0,0 +1,52 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+
+$Id$
+"""
+
+import os, shutil, sys, tempfile, urllib2
+
+tmpeggs = tempfile.mkdtemp()
+
+ez = {}
+exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
+ ).read() in ez
+ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+import pkg_resources
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+if sys.platform == 'win32':
+ cmd = '"%s"' % cmd # work around spawn lamosity on windows
+
+ws = pkg_resources.working_set
+assert os.spawnle(
+ os.P_WAIT, sys.executable, sys.executable,
+ '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout',
+ dict(os.environ,
+ PYTHONPATH=
+ ws.find(pkg_resources.Requirement.parse('setuptools')).location
+ ),
+ ) == 0
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout')
+import zc.buildout.buildout
+zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
+shutil.rmtree(tmpeggs)
Property changes on: z3c.soap/trunk/bootstrap.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.soap/trunk/buildout.cfg
===================================================================
--- z3c.soap/trunk/buildout.cfg (rev 0)
+++ z3c.soap/trunk/buildout.cfg 2008-11-13 12:18:51 UTC (rev 92902)
@@ -0,0 +1,41 @@
+[buildout]
+parts =
+ instance
+ test
+
+find-links =
+
+develop =
+ .
+
+eggs =
+ ZSI
+
+unzip = true
+
+[zope2]
+recipe = plone.recipe.zope2install
+url = http://www.zope.org/Products/Zope/2.10.6/Zope-2.10.6-final.tgz
+fake-zope-eggs = true
+skip-fake-eggs = zope.testing
+
+[instance]
+recipe = plone.recipe.zope2instance
+zope2-location = ${zope2:location}
+user = admin:admin
+verbose-security = on
+debug-mode = on
+eggs =
+ ${buildout:eggs}
+ zope.testing
+ z3c.soap
+
+zcml =
+ z3c.soap-meta
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = z3c.soap
+defaults = ['--tests-pattern', '^f?tests$', '-c', '--module=z3c.soap']
+extra-paths = ${zope2:location}/lib/python
+
Added: z3c.soap/trunk/docs/HISTORY.txt
===================================================================
--- z3c.soap/trunk/docs/HISTORY.txt (rev 0)
+++ z3c.soap/trunk/docs/HISTORY.txt 2008-11-13 12:18:51 UTC (rev 92902)
@@ -0,0 +1,8 @@
+Changelog
+=========
+
+0.1 - Unreleased
+----------------
+
+* Initial release
+
Property changes on: z3c.soap/trunk/docs/HISTORY.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: z3c.soap/trunk/setup.cfg
===================================================================
--- z3c.soap/trunk/setup.cfg (rev 0)
+++ z3c.soap/trunk/setup.cfg 2008-11-13 12:18:51 UTC (rev 92902)
@@ -0,0 +1,3 @@
+[egg_info]
+#tag_build = dev
+#tag_svn_revision = true
Added: z3c.soap/trunk/setup.py
===================================================================
--- z3c.soap/trunk/setup.py (rev 0)
+++ z3c.soap/trunk/setup.py 2008-11-13 12:18:51 UTC (rev 92902)
@@ -0,0 +1,36 @@
+from setuptools import setup, find_packages
+import os
+
+version = '0.1'
+
+setup(name='z3c.soap',
+ version=version,
+ description="Soap using ZSI in Zope 2",
+ long_description=open(os.path.join("z3c", "soap",
+ "README.txt")).read() + "\n" +
+ open(os.path.join("docs", "HISTORY.txt")).read(),
+ classifiers=[
+ "Environment :: Web Environment",
+ "Framework :: Zope2",
+ "Framework :: Zope3",
+ "License :: OSI Approved :: Zope Public License",
+ "Operating System :: OS Independent",
+ "Programming Language :: Python",
+ "Topic :: Internet :: WWW/HTTP :: Site Management",
+ "Topic :: Software Development :: Libraries :: Python Modules"],
+ keywords='Zope2 SOAP ZSI',
+ author='Jean-Francois Roche',
+ author_email='jfroche at affinitic.be',
+ url='http://svn.zope.org/z3c.soap',
+ license='ZPL 2.1',
+ packages=find_packages(exclude=['ez_setup']),
+ namespace_packages=['z3c'],
+ include_package_data=True,
+ zip_safe=False,
+ install_requires=[
+ 'setuptools',
+ 'ZSI'],
+ entry_points="""
+ # -*- Entry points: -*-
+ """,
+ )
Property changes on: z3c.soap/trunk/setup.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.soap/trunk/z3c/__init__.py
===================================================================
--- z3c.soap/trunk/z3c/__init__.py (rev 0)
+++ z3c.soap/trunk/z3c/__init__.py 2008-11-13 12:18:51 UTC (rev 92902)
@@ -0,0 +1,6 @@
+# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages
+try:
+ __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+ from pkgutil import extend_path
+ __path__ = extend_path(__path__, __name__)
Property changes on: z3c.soap/trunk/z3c/__init__.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.soap/trunk/z3c/soap/HTTPRequest.py
===================================================================
--- z3c.soap/trunk/z3c/soap/HTTPRequest.py (rev 0)
+++ z3c.soap/trunk/z3c/soap/HTTPRequest.py 2008-11-13 12:18:51 UTC (rev 92902)
@@ -0,0 +1,726 @@
+##############################################################################
+#
+# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+#
+##############################################################################
+
+__version__='$Revision: 1.90.2.6 $'[11:-2]
+
+import re
+from cgi import FieldStorage, escape
+from ZPublisher.Converters import get_converter
+from ZPublisher.HTTPRequest import *
+from z3c.soap.interfaces import ISOAPRequest
+from ZPublisher.TaintedString import TaintedString
+from zope.interface import directlyProvides
+xmlrpc=None # Placeholder for module that we'll import if we have to.
+soap=None
+
+def processInputs(
+ self,
+ # "static" variables that we want to be local for speed
+ SEQUENCE=1,
+ DEFAULT=2,
+ RECORD=4,
+ RECORDS=8,
+ REC=12, # RECORD|RECORDS
+ EMPTY=16,
+ CONVERTED=32,
+ hasattr=hasattr,
+ getattr=getattr,
+ setattr=setattr,
+ search_type=re.compile('(:[a-zA-Z][-a-zA-Z0-9_]+|\\.[xy])$').search,
+ ):
+ """Process request inputs
+
+ We need to delay input parsing so that it is done under
+ publisher control for error handling purposes.
+ """
+ response=self.response
+ environ=self.environ
+ method=environ.get('REQUEST_METHOD','GET')
+
+ if method != 'GET': fp=self.stdin
+ else: fp=None
+
+ form=self.form
+ other=self.other
+ taintedform=self.taintedform
+
+ meth=None
+ fs=FieldStorage(fp=fp,environ=environ,keep_blank_values=1)
+ if not hasattr(fs,'list') or fs.list is None:
+ contentType = None
+ if fs.headers.has_key('content-type'):
+ contentType = fs.headers['content-type']
+ # cut off a possible charset definition
+ if contentType.find(';') >= 0:
+ contentType = contentType[0:contentType.find(';')]
+ # Hm, maybe it's an SOAP
+ # SOAP 1.1 has HTTP SOAPAction Field
+ # SOAP 1.2 has Content-Type application/soap+xml
+ #
+ # found a Content-Type of text/xml-SOAP on a Microsoft page
+ # this page points 3 HTTP-Fields for SOAP Requests:
+ # MethodName, InterfaceName (opt) and MessageCall
+ #
+ if (environ.has_key('HTTP_SOAPACTION') or
+ (contentType in ['application/soap+xml',
+ 'text/xml',
+ 'text/xml-SOAP']) and fs.value.find('SOAP-ENV:Body') > 0):
+ global soap
+ if soap is None:
+ import soap
+ fp.seek(0)
+ directlyProvides(self, ISOAPRequest)
+ sparser = soap.SOAPParser(fp.read())
+ meth = sparser.method
+ self.args = sparser.parse()
+ response = soap.SOAPResponse(response)
+ response._soap11 = environ.has_key('HTTP_SOAPACTION')
+ response._soap12 = (contentType == 'application/soap+xml')
+ response._contentType = contentType
+ response._method = meth
+ response._error_format = 'text/xml'
+ other['RESPONSE'] = self.response = response
+ other['REQUEST_METHOD'] = method
+ self.maybe_webdav_client = 0
+
+ # Hm, maybe it's an XML-RPC
+ # check for a real XML-RPC methodCall !
+ # This allows to post normal text/xml files to Zope !
+ elif (contentType == 'text/xml' and method == 'POST' and fs.value.find('<methodCall>') > 0):
+ # Ye haaa, XML-RPC!
+ global xmlrpc
+ if xmlrpc is None: from ZPublisher import xmlrpc
+ meth, self.args = xmlrpc.parse_input(fs.value)
+ response=xmlrpc.response(response)
+ other['RESPONSE']=self.response=response
+ self.maybe_webdav_client = 0
+ else:
+ self._file=fs.file
+ else:
+ fslist=fs.list
+ tuple_items={}
+ lt=type([])
+ CGI_name=isCGI_NAME
+ defaults={}
+ tainteddefaults={}
+ converter=None
+
+ for item in fslist:
+
+ isFileUpload = 0
+ key=item.name
+ if (hasattr(item,'file') and hasattr(item,'filename')
+ and hasattr(item,'headers')):
+ if (item.file and
+ (item.filename is not None
+ # RFC 1867 says that all fields get a content-type.
+ # or 'content-type' in map(lower, item.headers.keys())
+ )):
+ item=FileUpload(item)
+ isFileUpload = 1
+ else:
+ item=item.value
+
+ flags=0
+ character_encoding = ''
+ # Variables for potentially unsafe values.
+ tainted = None
+ converter_type = None
+
+ # Loop through the different types and set
+ # the appropriate flags
+
+ # We'll search from the back to the front.
+ # We'll do the search in two steps. First, we'll
+ # do a string search, and then we'll check it with
+ # a re search.
+
+
+ l=key.rfind(':')
+ if l >= 0:
+ mo = search_type(key,l)
+ if mo: l=mo.start(0)
+ else: l=-1
+
+ while l >= 0:
+ type_name=key[l+1:]
+ key=key[:l]
+ c=get_converter(type_name, None)
+
+ if c is not None:
+ converter=c
+ converter_type = type_name
+ flags=flags|CONVERTED
+ elif type_name == 'list':
+ flags=flags|SEQUENCE
+ elif type_name == 'tuple':
+ tuple_items[key]=1
+ flags=flags|SEQUENCE
+ elif (type_name == 'method' or type_name == 'action'):
+ if l: meth=key
+ else: meth=item
+ elif (type_name == 'default_method' or type_name == \
+ 'default_action'):
+ if not meth:
+ if l: meth=key
+ else: meth=item
+ elif type_name == 'default':
+ flags=flags|DEFAULT
+ elif type_name == 'record':
+ flags=flags|RECORD
+ elif type_name == 'records':
+ flags=flags|RECORDS
+ elif type_name == 'ignore_empty':
+ if not item: flags=flags|EMPTY
+ elif has_codec(type_name):
+ character_encoding = type_name
+
+ l=key.rfind(':')
+ if l < 0: break
+ mo=search_type(key,l)
+ if mo: l = mo.start(0)
+ else: l = -1
+
+
+
+ # Filter out special names from form:
+ if CGI_name(key) or key[:5]=='HTTP_': continue
+
+ # If the key is tainted, mark it so as well.
+ tainted_key = key
+ if '<' in key:
+ tainted_key = TaintedString(key)
+
+ if flags:
+
+ # skip over empty fields
+ if flags&EMPTY: continue
+
+ #Split the key and its attribute
+ if flags&REC:
+ key=key.split(".")
+ key, attr=".".join(key[:-1]), key[-1]
+
+ # Update the tainted_key if necessary
+ tainted_key = key
+ if '<' in key:
+ tainted_key = TaintedString(key)
+
+ # Attributes cannot hold a <.
+ if '<' in attr:
+ raise ValueError(
+ "%s is not a valid record attribute name" %
+ escape(attr))
+
+ # defer conversion
+ if flags&CONVERTED:
+ try:
+ if character_encoding:
+ # We have a string with a specified character encoding.
+ # This gets passed to the converter either as unicode, if it can
+ # handle it, or crunched back down to latin-1 if it can not.
+ item = unicode(item,character_encoding)
+ if hasattr(converter,'convert_unicode'):
+ item = converter.convert_unicode(item)
+ else:
+ item = converter(item.encode('iso-8859-15'))
+ else:
+ item=converter(item)
+
+ # Flag potentially unsafe values
+ if converter_type in ('string', 'required', 'text',
+ 'ustring', 'utext'):
+ if not isFileUpload and '<' in item:
+ tainted = TaintedString(item)
+ elif converter_type in ('tokens', 'lines',
+ 'utokens', 'ulines'):
+ is_tainted = 0
+ tainted = item[:]
+ for i in range(len(tainted)):
+ if '<' in tainted[i]:
+ is_tainted = 1
+ tainted[i] = TaintedString(tainted[i])
+ if not is_tainted:
+ tainted = None
+
+ except:
+ if (not item and not (flags&DEFAULT) and
+ defaults.has_key(key)):
+ item = defaults[key]
+ if flags&RECORD:
+ item=getattr(item,attr)
+ if flags&RECORDS:
+ item = getattr(item[-1], attr)
+ if tainteddefaults.has_key(tainted_key):
+ tainted = tainteddefaults[tainted_key]
+ if flags&RECORD:
+ tainted = getattr(tainted, attr)
+ if flags&RECORDS:
+ tainted = getattr(tainted[-1], attr)
+ else:
+ raise
+
+ elif not isFileUpload and '<' in item:
+ # Flag potentially unsafe values
+ tainted = TaintedString(item)
+
+ # If the key is tainted, we need to store stuff in the
+ # tainted dict as well, even if the value is safe.
+ if '<' in tainted_key and tainted is None:
+ tainted = item
+
+ #Determine which dictionary to use
+ if flags&DEFAULT:
+ mapping_object = defaults
+ tainted_mapping = tainteddefaults
+ else:
+ mapping_object = form
+ tainted_mapping = taintedform
+
+ #Insert in dictionary
+ if mapping_object.has_key(key):
+ if flags&RECORDS:
+ #Get the list and the last record
+ #in the list. reclist is mutable.
+ reclist = mapping_object[key]
+ x = reclist[-1]
+
+ if tainted:
+ # Store a tainted copy as well
+ if not tainted_mapping.has_key(tainted_key):
+ tainted_mapping[tainted_key] = deepcopy(
+ reclist)
+ treclist = tainted_mapping[tainted_key]
+ lastrecord = treclist[-1]
+
+ if not hasattr(lastrecord, attr):
+ if flags&SEQUENCE: tainted = [tainted]
+ setattr(lastrecord, attr, tainted)
+ else:
+ if flags&SEQUENCE:
+ getattr(lastrecord,
+ attr).append(tainted)
+ else:
+ newrec = record()
+ setattr(newrec, attr, tainted)
+ treclist.append(newrec)
+
+ elif tainted_mapping.has_key(tainted_key):
+ # If we already put a tainted value into this
+ # recordset, we need to make sure the whole
+ # recordset is built.
+ treclist = tainted_mapping[tainted_key]
+ lastrecord = treclist[-1]
+ copyitem = item
+
+ if not hasattr(lastrecord, attr):
+ if flags&SEQUENCE: copyitem = [copyitem]
+ setattr(lastrecord, attr, copyitem)
+ else:
+ if flags&SEQUENCE:
+ getattr(lastrecord,
+ attr).append(copyitem)
+ else:
+ newrec = record()
+ setattr(newrec, attr, copyitem)
+ treclist.append(newrec)
+
+ if not hasattr(x,attr):
+ #If the attribute does not
+ #exist, setit
+ if flags&SEQUENCE: item=[item]
+ setattr(x,attr,item)
+ else:
+ if flags&SEQUENCE:
+ # If the attribute is a
+ # sequence, append the item
+ # to the existing attribute
+ y = getattr(x, attr)
+ y.append(item)
+ setattr(x, attr, y)
+ else:
+ # Create a new record and add
+ # it to the list
+ n=record()
+ setattr(n,attr,item)
+ mapping_object[key].append(n)
+ elif flags&RECORD:
+ b=mapping_object[key]
+ if flags&SEQUENCE:
+ item=[item]
+ if not hasattr(b,attr):
+ # if it does not have the
+ # attribute, set it
+ setattr(b,attr,item)
+ else:
+ # it has the attribute so
+ # append the item to it
+ setattr(b,attr,getattr(b,attr)+item)
+ else:
+ # it is not a sequence so
+ # set the attribute
+ setattr(b,attr,item)
+
+ # Store a tainted copy as well if necessary
+ if tainted:
+ if not tainted_mapping.has_key(tainted_key):
+ tainted_mapping[tainted_key] = deepcopy(
+ mapping_object[key])
+ b = tainted_mapping[tainted_key]
+ if flags&SEQUENCE:
+ seq = getattr(b, attr, [])
+ seq.append(tainted)
+ setattr(b, attr, seq)
+ else:
+ setattr(b, attr, tainted)
+
+ elif tainted_mapping.has_key(tainted_key):
+ # If we already put a tainted value into this
+ # record, we need to make sure the whole record
+ # is built.
+ b = tainted_mapping[tainted_key]
+ if flags&SEQUENCE:
+ seq = getattr(b, attr, [])
+ seq.append(item)
+ setattr(b, attr, seq)
+ else:
+ setattr(b, attr, item)
+
+ else:
+ # it is not a record or list of records
+ found=mapping_object[key]
+
+ if tainted:
+ # Store a tainted version if necessary
+ if not tainted_mapping.has_key(tainted_key):
+ copied = deepcopy(found)
+ if isinstance(copied, lt):
+ tainted_mapping[tainted_key] = copied
+ else:
+ tainted_mapping[tainted_key] = [copied]
+ tainted_mapping[tainted_key].append(tainted)
+
+ elif tainted_mapping.has_key(tainted_key):
+ # We may already have encountered a tainted
+ # value for this key, and the tainted_mapping
+ # needs to hold all the values.
+ tfound = tainted_mapping[tainted_key]
+ if isinstance(tfound, lt):
+ tainted_mapping[tainted_key].append(item)
+ else:
+ tainted_mapping[tainted_key] = [tfound,
+ item]
+
+ if type(found) is lt:
+ found.append(item)
+ else:
+ found=[found,item]
+ mapping_object[key]=found
+ else:
+ # The dictionary does not have the key
+ if flags&RECORDS:
+ # Create a new record, set its attribute
+ # and put it in the dictionary as a list
+ a = record()
+ if flags&SEQUENCE: item=[item]
+ setattr(a,attr,item)
+ mapping_object[key]=[a]
+
+ if tainted:
+ # Store a tainted copy if necessary
+ a = record()
+ if flags&SEQUENCE: tainted = [tainted]
+ setattr(a, attr, tainted)
+ tainted_mapping[tainted_key] = [a]
+
+ elif flags&RECORD:
+ # Create a new record, set its attribute
+ # and put it in the dictionary
+ if flags&SEQUENCE: item=[item]
+ r = mapping_object[key]=record()
+ setattr(r,attr,item)
+
+ if tainted:
+ # Store a tainted copy if necessary
+ if flags&SEQUENCE: tainted = [tainted]
+ r = tainted_mapping[tainted_key] = record()
+ setattr(r, attr, tainted)
+ else:
+ # it is not a record or list of records
+ if flags&SEQUENCE: item=[item]
+ mapping_object[key]=item
+
+ if tainted:
+ # Store a tainted copy if necessary
+ if flags&SEQUENCE: tainted = [tainted]
+ tainted_mapping[tainted_key] = tainted
+
+ else:
+ # This branch is for case when no type was specified.
+ mapping_object = form
+
+ if not isFileUpload and '<' in item:
+ tainted = TaintedString(item)
+ elif '<' in key:
+ tainted = item
+
+ #Insert in dictionary
+ if mapping_object.has_key(key):
+ # it is not a record or list of records
+ found=mapping_object[key]
+
+ if tainted:
+ # Store a tainted version if necessary
+ if not taintedform.has_key(tainted_key):
+ copied = deepcopy(found)
+ if isinstance(copied, lt):
+ taintedform[tainted_key] = copied
+ else:
+ taintedform[tainted_key] = [copied]
+ elif not isinstance(taintedform[tainted_key], lt):
+ taintedform[tainted_key] = [
+ taintedform[tainted_key]]
+ taintedform[tainted_key].append(tainted)
+
+ elif taintedform.has_key(tainted_key):
+ # We may already have encountered a tainted value
+ # for this key, and the taintedform needs to hold
+ # all the values.
+ tfound = taintedform[tainted_key]
+ if isinstance(tfound, lt):
+ taintedform[tainted_key].append(item)
+ else:
+ taintedform[tainted_key] = [tfound, item]
+
+ if type(found) is lt:
+ found.append(item)
+ else:
+ found=[found,item]
+ mapping_object[key]=found
+ else:
+ mapping_object[key]=item
+ if tainted:
+ taintedform[tainted_key] = tainted
+
+ #insert defaults into form dictionary
+ if defaults:
+ for key, value in defaults.items():
+ tainted_key = key
+ if '<' in key: tainted_key = TaintedString(key)
+
+ if not form.has_key(key):
+ # if the form does not have the key,
+ # set the default
+ form[key]=value
+
+ if tainteddefaults.has_key(tainted_key):
+ taintedform[tainted_key] = \
+ tainteddefaults[tainted_key]
+ else:
+ #The form has the key
+ tdefault = tainteddefaults.get(tainted_key, value)
+ if isinstance(value, record):
+ # if the key is mapped to a record, get the
+ # record
+ r = form[key]
+
+ # First deal with tainted defaults.
+ if taintedform.has_key(tainted_key):
+ tainted = taintedform[tainted_key]
+ for k, v in tdefault.__dict__.items():
+ if not hasattr(tainted, k):
+ setattr(tainted, k, v)
+
+ elif tainteddefaults.has_key(tainted_key):
+ # Find out if any of the tainted default
+ # attributes needs to be copied over.
+ missesdefault = 0
+ for k, v in tdefault.__dict__.items():
+ if not hasattr(r, k):
+ missesdefault = 1
+ break
+ if missesdefault:
+ tainted = deepcopy(r)
+ for k, v in tdefault.__dict__.items():
+ if not hasattr(tainted, k):
+ setattr(tainted, k, v)
+ taintedform[tainted_key] = tainted
+
+ for k, v in value.__dict__.items():
+ # loop through the attributes and value
+ # in the default dictionary
+ if not hasattr(r, k):
+ # if the form dictionary doesn't have
+ # the attribute, set it to the default
+ setattr(r,k,v)
+ form[key] = r
+
+ elif isinstance(value, lt):
+ # the default value is a list
+ l = form[key]
+ if not isinstance(l, lt):
+ l = [l]
+
+ # First deal with tainted copies
+ if taintedform.has_key(tainted_key):
+ tainted = taintedform[tainted_key]
+ if not isinstance(tainted, lt):
+ tainted = [tainted]
+ for defitem in tdefault:
+ if isinstance(defitem, record):
+ for k, v in defitem.__dict__.items():
+ for origitem in tainted:
+ if not hasattr(origitem, k):
+ setattr(origitem, k, v)
+ else:
+ if not defitem in tainted:
+ tainted.append(defitem)
+ taintedform[tainted_key] = tainted
+
+ elif tainteddefaults.has_key(tainted_key):
+ missesdefault = 0
+ for defitem in tdefault:
+ if isinstance(defitem, record):
+ try:
+ for k, v in \
+ defitem.__dict__.items():
+ for origitem in l:
+ if not hasattr(origitem, k):
+ missesdefault = 1
+ raise NestedLoopExit
+ except NestedLoopExit:
+ break
+ else:
+ if not defitem in l:
+ missesdefault = 1
+ break
+ if missesdefault:
+ tainted = deepcopy(l)
+ for defitem in tdefault:
+ if isinstance(defitem, record):
+ for k, v in defitem.__dict__.items():
+ for origitem in tainted:
+ if not hasattr(origitem, k):
+ setattr(origitem, k, v)
+ else:
+ if not defitem in tainted:
+ tainted.append(defitem)
+ taintedform[tainted_key] = tainted
+
+ for x in value:
+ # for each x in the list
+ if isinstance(x, record):
+ # if the x is a record
+ for k, v in x.__dict__.items():
+
+ # loop through each
+ # attribute and value in
+ # the record
+
+ for y in l:
+
+ # loop through each
+ # record in the form
+ # list if it doesn't
+ # have the attributes
+ # in the default
+ # dictionary, set them
+
+ if not hasattr(y, k):
+ setattr(y, k, v)
+ else:
+ # x is not a record
+ if not x in l:
+ l.append(x)
+ form[key] = l
+ else:
+ # The form has the key, the key is not mapped
+ # to a record or sequence so do nothing
+ pass
+
+ # Convert to tuples
+ if tuple_items:
+ for key in tuple_items.keys():
+ # Split the key and get the attr
+ k=key.split( ".")
+ k,attr='.'.join(k[:-1]), k[-1]
+ a = attr
+ new = ''
+ # remove any type_names in the attr
+ while not a=='':
+ a=a.split( ":")
+ a,new=':'.join(a[:-1]), a[-1]
+ attr = new
+ if form.has_key(k):
+ # If the form has the split key get its value
+ tainted_split_key = k
+ if '<' in k: tainted_split_key = TaintedString(k)
+ item =form[k]
+ if isinstance(item, record):
+ # if the value is mapped to a record, check if it
+ # has the attribute, if it has it, convert it to
+ # a tuple and set it
+ if hasattr(item,attr):
+ value=tuple(getattr(item,attr))
+ setattr(item,attr,value)
+ else:
+ # It is mapped to a list of records
+ for x in item:
+ # loop through the records
+ if hasattr(x, attr):
+ # If the record has the attribute
+ # convert it to a tuple and set it
+ value=tuple(getattr(x,attr))
+ setattr(x,attr,value)
+
+ # Do the same for the tainted counterpart
+ if taintedform.has_key(tainted_split_key):
+ tainted = taintedform[tainted_split_key]
+ if isinstance(item, record):
+ seq = tuple(getattr(tainted, attr))
+ setattr(tainted, attr, seq)
+ else:
+ for trec in tainted:
+ if hasattr(trec, attr):
+ seq = getattr(trec, attr)
+ seq = tuple(seq)
+ setattr(trec, attr, seq)
+ else:
+ # the form does not have the split key
+ tainted_key = key
+ if '<' in key: tainted_key = TaintedString(key)
+ if form.has_key(key):
+ # if it has the original key, get the item
+ # convert it to a tuple
+ item=form[key]
+ item=tuple(form[key])
+ form[key]=item
+
+ if taintedform.has_key(tainted_key):
+ tainted = tuple(taintedform[tainted_key])
+ taintedform[tainted_key] = tainted
+
+ if meth:
+ if environ.has_key('PATH_INFO'):
+ path=environ['PATH_INFO']
+ while path[-1:]=='/': path=path[:-1]
+ else: path=''
+ other['PATH_INFO']=path="%s/%s" % (path,meth)
+ self._hacked_path=1
+
+HTTPRequest.processInputs = processInputs
+import logging
+logger = logging.getLogger('Zope')
+logger.info("""SOAPSupport: modified ZPublisher.HTTPRequest.processInputs, Dirk Datzert, 2007-02-06, version for Zope-2.8.x/Zope-2.9.x/Zope-2.10.x\n""")
+
+# vi:ts=4
Property changes on: z3c.soap/trunk/z3c/soap/HTTPRequest.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.soap/trunk/z3c/soap/README.txt
===================================================================
--- z3c.soap/trunk/z3c/soap/README.txt (rev 0)
+++ z3c.soap/trunk/z3c/soap/README.txt 2008-11-13 12:18:51 UTC (rev 92902)
@@ -0,0 +1,654 @@
+SOAP Support
+============
+
+This SOAP implementation allows you provide SOAP views for objects. The
+SOAP layer is based on `ZSI <http://pywebsvcs.sourceforge.net/>`__.
+
+The package requires ZSI 2.0 or better.
+
+SOAP support is implemented in a way very similar to the standard Zope
+XML-RPC support. To call methods via SOAP, you need to create and
+register SOAP views.
+
+This package is largely inspired from Zope 3 SOAP (http://svn.zope.org/soap).
+
+Let's write a simple SOAP view that echoes various types of input:
+
+ >>> from Products.Five import BrowserView
+ >>> class EchoView(BrowserView):
+ ...
+ ... def echoString(self, value):
+ ... return value
+ ...
+ ... def echoStringArray(self, value):
+ ... return value
+ ...
+ ... def echoInteger(self, value):
+ ... return value
+ ...
+ ... def echoIntegerArray(self, value):
+ ... return value
+ ...
+ ... def echoFloat(self, value):
+ ... return value
+ ...
+ ... def echoFloatArray(self, value):
+ ... return value
+ ...
+ ... def echoStruct(self, value):
+ ... return value
+ ...
+ ... def echoStructArray(self, value):
+ ... return value
+ ...
+ ... def echoVoid(self):
+ ... return
+ ...
+ ... def echoBase64(self, value):
+ ... import base64
+ ... return base64.encodestring(value)
+ ...
+ ... def echoDate(self, value):
+ ... import time
+ ... return time.gmtime(time.mktime(value))
+ ...
+ ... def echoDecimal(self, value):
+ ... return value
+ ...
+ ... def echoBoolean(self, value):
+ ... return value
+ ...
+ ... def ValidateEmailRequest(self, requestData, response):
+ ... mail = requestData._Email
+ ... response._Status = '%s is OK' % mail
+ ... return response
+
+
+Now we'll register it as a SOAP view. For now we'll just register the
+view for folder objects and call it on the root folder:
+
+ >>> from zope.configuration import xmlconfig
+ >>> ignored = xmlconfig.string("""
+ ... <configure
+ ... xmlns="http://namespaces.zope.org/zope"
+ ... xmlns:browser="http://namespaces.zope.org/browser"
+ ... xmlns:soap="http://namespaces.zope.org/soap"
+ ... >
+ ...
+ ... <!-- We only need to do this include in this example,
+ ... Normally the include has already been done for us. -->
+ ...
+ ... <include package="z3c.soap" file="meta.zcml" />
+ ... <include package="Products.Five" file="meta.zcml" />
+ ...
+ ... <soap:view
+ ... for="OFS.interfaces.IFolder"
+ ... methods="echoString echoStringArray echoInteger echoIntegerArray
+ ... echoFloat echoFloatArray echoStruct echoVoid echoBase64
+ ... echoDate echoDecimal echoBoolean ValidateEmailRequest"
+ ... class="z3c.soap.README.EchoView"
+ ... permission="cmf.ManageProperties"
+ ... />
+ ...
+ ... <utility
+ ... factory="z3c.soap.tests.mailvalidation.validateEmailIn"
+ ... name="ValidateEmailRequest"
+ ... provides="z3c.soap.interfaces.IZSIRequestType"/>
+ ...
+ ... <utility
+ ... factory="z3c.soap.tests.mailvalidation.validateEmailOut"
+ ... name="ValidateEmailRequest"
+ ... provides="z3c.soap.interfaces.IZSIResponseType"/>
+ ...
+ ...
+ ... </configure>
+ ... """)
+
+
+And call our SOAP method:
+
+ >>> from Testing.ZopeTestCase import user_name, user_password
+ >>> self.setRoles(['Manager'])
+
+ >>> print http(r"""
+ ... POST /test_folder_1_ HTTP/1.0
+ ... Authorization: Basic %s:%s
+ ... Content-Length: 102
+ ... Content-Type: text/xml
+ ... SOAPAction: /
+ ...
+ ... <?xml version="1.0"?>
+ ... <SOAP-ENV:Envelope
+ ... SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
+ ... xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ ... xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ ... <SOAP-ENV:Body>
+ ... <m:echoString xmlns:m="http://www.soapware.org/">
+ ... <arg1 xsi:type="xsd:string">hello</arg1>
+ ... </m:echoString>
+ ... </SOAP-ENV:Body>
+ ... </SOAP-ENV:Envelope>
+ ... """ % (user_name, user_password), handle_errors=True)
+ HTTP/1.0 200 OK
+ Content-Length: ...
+ Content-Type: text/xml
+ <BLANKLINE>
+ ...hello...
+
+
+Note that we get an unauthorized error if we don't supply authentication
+credentials, because we protected the view with the ManageContent permission
+when we registered it:
+
+ >>> self.logout()
+ >>> print http(r"""
+ ... POST /test_folder_1_ HTTP/1.0
+ ... Content-Length: 102
+ ... Content-Type: text/xml
+ ... SOAPAction: /
+ ...
+ ... <?xml version="1.0"?>
+ ... <SOAP-ENV:Envelope
+ ... SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
+ ... xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ ... xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ ... <SOAP-ENV:Body>
+ ... <m:echoString xmlns:m="http://www.soapware.org/">
+ ... <arg1 xsi:type="xsd:string">hello</arg1>
+ ... </m:echoString>
+ ... </SOAP-ENV:Body>
+ ... </SOAP-ENV:Envelope>
+ ... """)
+ HTTP/1.0 401 Unauthorized
+ ...
+
+
+Parameters
+----------
+
+SOAP views can take any parameters that ZSI can understand. The following
+demonstrate the use of primitive SOAP-defined types:
+
+ >>> print http(r"""
+ ... POST /test_folder_1_ HTTP/1.0
+ ... Authorization: Basic %s:%s
+ ... Content-Length: 102
+ ... Content-Type: text/xml
+ ... SOAPAction: /
+ ...
+ ... <?xml version="1.0"?>
+ ... <SOAP-ENV:Envelope
+ ... SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
+ ... xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ ... xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ ... <SOAP-ENV:Body>
+ ... <m:echoString xmlns:m="http://www.soapware.org/">
+ ... <arg1 xsi:type="xsd:string">hello</arg1>
+ ... </m:echoString>
+ ... </SOAP-ENV:Body>
+ ... </SOAP-ENV:Envelope>
+ ... """ % (user_name, user_password))
+ HTTP/1.0 200 OK
+ Content-Length: ...
+ Content-Type: text/xml...
+ <BLANKLINE>
+ ...hello...
+
+
+ >>> print http(r"""
+ ... POST /test_folder_1_ HTTP/1.0
+ ... Authorization: Basic %s:%s
+ ... Content-Length: 102
+ ... Content-Type: text/xml
+ ... SOAPAction: /
+ ...
+ ... <?xml version="1.0"?>
+ ... <SOAP-ENV:Envelope
+ ... SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
+ ... xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ ... xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ ... <SOAP-ENV:Body>
+ ... <m:echoStringArray xmlns:m="http://www.soapware.org/">
+ ... <param SOAP-ENC:arrayType="xsd:ur-type[4]" xsi:type="SOAP-ENC:Array">
+ ... <item xsi:type="xsd:string">one</item>
+ ... <item xsi:type="xsd:string">two</item>
+ ... <item xsi:type="xsd:string">three</item>
+ ... <item xsi:type="xsd:string">four</item>
+ ... </param>
+ ... </m:echoStringArray>
+ ... </SOAP-ENV:Body>
+ ... </SOAP-ENV:Envelope>
+ ... """ % (user_name, user_password))
+ HTTP/1.0 200 OK
+ Content-Length: ...
+ Content-Type: text/xml...
+ <BLANKLINE>
+ ...one...two...three...four...
+
+
+ >>> print http(r"""
+ ... POST /test_folder_1_ HTTP/1.0
+ ... Authorization: Basic %s:%s
+ ... Content-Length: 102
+ ... Content-Type: text/xml
+ ... SOAPAction: /
+ ...
+ ... <?xml version="1.0"?>
+ ... <SOAP-ENV:Envelope
+ ... SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
+ ... xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ ... xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ ... <SOAP-ENV:Body>
+ ... <m:echoInteger xmlns:m="http://www.soapware.org/">
+ ... <arg1 xsi:type="xsd:int">42</arg1>
+ ... </m:echoInteger>
+ ... </SOAP-ENV:Body>
+ ... </SOAP-ENV:Envelope>
+ ... """ % (user_name, user_password))
+ HTTP/1.0 200 OK
+ Content-Length: ...
+ Content-Type: text/xml...
+ <BLANKLINE>
+ ...42...
+
+
+ >>> print http(r"""
+ ... POST /test_folder_1_ HTTP/1.0
+ ... Authorization: Basic %s:%s
+ ... Content-Length: 102
+ ... Content-Type: text/xml
+ ... SOAPAction: /
+ ...
+ ... <?xml version="1.0"?>
+ ... <SOAP-ENV:Envelope
+ ... SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
+ ... xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ ... xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ ... <SOAP-ENV:Body>
+ ... <m:echoIntegerArray xmlns:m="http://www.soapware.org/">
+ ... <param SOAP-ENC:arrayType="xsd:ur-type[4]" xsi:type="SOAP-ENC:Array">
+ ... <item xsi:type="xsd:int">1</item>
+ ... <item xsi:type="xsd:int">2</item>
+ ... <item xsi:type="xsd:int">3</item>
+ ... <item xsi:type="xsd:int">4</item>
+ ... </param>
+ ... </m:echoIntegerArray>
+ ... </SOAP-ENV:Body>
+ ... </SOAP-ENV:Envelope>
+ ... """ % (user_name, user_password))
+ HTTP/1.0 200 OK
+ Content-Length: ...
+ Content-Type: text/xml...
+ <BLANKLINE>
+ ...1...2...3...4...
+
+
+Note that floats are returned as xsd:decimal values:
+
+ >>> print http(r"""
+ ... POST /test_folder_1_ HTTP/1.0
+ ... Authorization: Basic %s:%s
+ ... Content-Length: 102
+ ... Content-Type: text/xml
+ ... SOAPAction: /
+ ...
+ ... <?xml version="1.0"?>
+ ... <SOAP-ENV:Envelope
+ ... SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
+ ... xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ ... xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ ... <SOAP-ENV:Body>
+ ... <m:echoFloat xmlns:m="http://www.soapware.org/">
+ ... <arg1 xsi:type="xsd:float">42.2</arg1>
+ ... </m:echoFloat>
+ ... </SOAP-ENV:Body>
+ ... </SOAP-ENV:Envelope>
+ ... """ % (user_name, user_password))
+ HTTP/1.0 200 OK
+ Content-Length: ...
+ Content-Type: text/xml
+ <BLANKLINE>
+ ...xsi:type="xsd:float">42.200000</...
+
+
+Even if they're in float arrays:
+
+ >>> print http(r"""
+ ... POST /test_folder_1_ HTTP/1.0
+ ... Authorization: Basic %s:%s
+ ... Content-Length: 102
+ ... Content-Type: text/xml
+ ... SOAPAction: /
+ ...
+ ... <?xml version="1.0"?>
+ ... <SOAP-ENV:Envelope
+ ... SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
+ ... xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ ... xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ ... <SOAP-ENV:Body>
+ ... <m:echoFloatArray xmlns:m="http://www.soapware.org/">
+ ... <param SOAP-ENC:arrayType="xsd:ur-type[4]" xsi:type="SOAP-ENC:Array">
+ ... <item xsi:type="xsd:float">1.1</item>
+ ... <item xsi:type="xsd:float">2.2</item>
+ ... <item xsi:type="xsd:float">3.3</item>
+ ... <item xsi:type="xsd:float">4.4</item>
+ ... </param>
+ ... </m:echoFloatArray>
+ ... </SOAP-ENV:Body>
+ ... </SOAP-ENV:Envelope>
+ ... """ % (user_name, user_password))
+ HTTP/1.0 200 OK
+ Content-Length: ...
+ Content-Type: text/xml
+ <BLANKLINE>
+ ...xsi:type="xsd:float">1.100000</...
+ ...xsi:type="xsd:float">2.200000</...
+ ...xsi:type="xsd:float">3.300000</...
+ ...xsi:type="xsd:float">4.400000</...
+
+
+ >>> result = http(r"""
+ ... POST /test_folder_1_ HTTP/1.0
+ ... Authorization: Basic %s:%s
+ ... Content-Length: 102
+ ... Content-Type: text/xml
+ ... SOAPAction: /
+ ...
+ ... <?xml version="1.0"?>
+ ... <SOAP-ENV:Envelope
+ ... SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
+ ... xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ ... xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ ... <SOAP-ENV:Body>
+ ... <m:echoStruct xmlns:m="http://www.soapware.org/">
+ ... <param>
+ ... <first xsi:type="xsd:string">first 1</first>
+ ... <last xsi:type="xsd:string">last 1</last>
+ ... </param>
+ ... </m:echoStruct>
+ ... </SOAP-ENV:Body>
+ ... </SOAP-ENV:Envelope>
+ ... """ % (user_name, user_password))
+
+ >>> result = str(result)
+ >>> assert(result.find('first 1') > -1)
+ >>> assert(result.find('last 1') > -1)
+
+
+Note that arrays of structs (at least per the interop suite) do not
+seem to work:
+
+ >>> print http(r"""
+ ... POST /test_folder_1_ HTTP/1.0
+ ... Authorization: Basic %s:%s
+ ... Content-Length: 102
+ ... Content-Type: text/xml
+ ... SOAPAction: /
+ ...
+ ... <?xml version="1.0"?>
+ ... <SOAP-ENV:Envelope
+ ... SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
+ ... xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ ... xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ ... xmlns:so="http://soapinterop.org/">
+ ... <SOAP-ENV:Body>
+ ... <m:echoStructArray xmlns:m="http://www.soapware.org/xsd">
+ ... <inputArray SOAP-ENC:arrayType="so:SOAPStruct[2]"
+ ... xsi:type="SOAP-ENC:Array">
+ ... <item xsi:type="so:SOAPStruct">
+ ... <varString xsi:type="xsd:string">str 1</varString>
+ ... <varInt xsi:type="xsd:int">1</varInt>
+ ... </item>
+ ... <item xsi:type="so:SOAPStruct">
+ ... <varString xsi:type="xsd:string">str 2</varString>
+ ... <varInt xsi:type="xsd:int">2</varInt>
+ ... </item>
+ ... </inputArray>
+ ... </m:echoStructArray>
+ ... </SOAP-ENV:Body>
+ ... </SOAP-ENV:Envelope>
+ ... """ % (user_name, user_password), handle_errors=True)
+ HTTP/1.0 500 Internal Server Error
+ Content-Length: ...
+ Content-Type: text/xml
+ <BLANKLINE>
+ <SOAP-ENV:Envelope ...
+ ...
+ >>> print http(r"""
+ ... POST /test_folder_1_ HTTP/1.0
+ ... Authorization: Basic %s:%s
+ ... Content-Length: 102
+ ... Content-Type: text/xml
+ ... SOAPAction: /
+ ...
+ ... <?xml version="1.0"?>
+ ... <SOAP-ENV:Envelope
+ ... SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
+ ... xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ ... xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ ... <SOAP-ENV:Body>
+ ... <m:echoVoid xmlns:m="http://www.soapware.org/">
+ ... </m:echoVoid>
+ ... </SOAP-ENV:Body>
+ ... </SOAP-ENV:Envelope>
+ ... """ % (user_name, user_password))
+ HTTP/1.0 200 OK
+ Content-Length: ...
+ Content-Type: text/xml
+ <BLANKLINE>
+ ...echoVoidResponse...
+
+
+ >>> print http(r"""
+ ... POST /test_folder_1_ HTTP/1.0
+ ... Authorization: Basic %s:%s
+ ... Content-Length: 102
+ ... Content-Type: text/xml
+ ... SOAPAction: /
+ ...
+ ... <?xml version="1.0"?>
+ ... <SOAP-ENV:Envelope
+ ... SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
+ ... xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ ... xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ ... <SOAP-ENV:Body>
+ ... <m:echoBase64 xmlns:m="http://www.soapware.org/">
+ ... <arg1 xsi:type="SOAP-ENC:base64">AAECAwQF</arg1>
+ ... </m:echoBase64>
+ ... </SOAP-ENV:Body>
+ ... </SOAP-ENV:Envelope>
+ ... """ % (user_name, user_password))
+ HTTP/1.0 200 OK
+ Content-Length: ...
+ Content-Type: text/xml...
+ <BLANKLINE>
+ ...AAECAwQF...
+
+
+Datetimes appear to work:
+
+ >>> print http(r"""
+ ... POST /test_folder_1_ HTTP/1.0
+ ... Authorization: Basic %s:%s
+ ... Content-Length: 102
+ ... Content-Type: text/xml
+ ... SOAPAction: /
+ ...
+ ... <?xml version="1.0"?>
+ ... <SOAP-ENV:Envelope
+ ... SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
+ ... xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ ... xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ ... <SOAP-ENV:Body>
+ ... <m:echoDate xmlns:m="http://www.soapware.org/">
+ ... <arg1 xsi:type="xsd:dateTime">1970-11-27T11:34:56.000Z</arg1>
+ ... </m:echoDate>
+ ... </SOAP-ENV:Body>
+ ... </SOAP-ENV:Envelope>
+ ... """ % (user_name, user_password))
+ HTTP/1.0 200 OK
+ Content-Length: ...
+ Content-Type: text/xml...
+ <BLANKLINE>
+ ...1970-11-27T10:34:56...
+
+ >>> print http(r"""
+ ... POST /test_folder_1_ HTTP/1.0
+ ... Authorization: Basic %s:%s
+ ... Content-Length: 102
+ ... Content-Type: text/xml
+ ... SOAPAction: /
+ ...
+ ... <?xml version="1.0"?>
+ ... <SOAP-ENV:Envelope
+ ... SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
+ ... xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ ... xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ ... <SOAP-ENV:Body>
+ ... <m:echoDecimal xmlns:m="http://www.soapware.org/">
+ ... <arg1 xsi:type="xsd:float">123456789.0123</arg1>
+ ... </m:echoDecimal>
+ ... </SOAP-ENV:Body>
+ ... </SOAP-ENV:Envelope>
+ ... """ % (user_name, user_password))
+ HTTP/1.0 200 OK
+ Content-Length: ...
+ Content-Type: text/xml...
+ <BLANKLINE>
+ ...123456789.0123...
+
+
+ >>> print http(r"""
+ ... POST /test_folder_1_ HTTP/1.0
+ ... Authorization: Basic %s:%s
+ ... Content-Length: 102
+ ... Content-Type: text/xml
+ ... SOAPAction: /
+ ...
+ ... <?xml version="1.0"?>
+ ... <SOAP-ENV:Envelope
+ ... SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
+ ... xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ ... xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ ... <SOAP-ENV:Body>
+ ... <m:echoBoolean xmlns:m="http://www.soapware.org/">
+ ... <arg1 xsi:type="xsd:boolean">1</arg1>
+ ... </m:echoBoolean>
+ ... </SOAP-ENV:Body>
+ ... </SOAP-ENV:Envelope>
+ ... """ % (user_name, user_password))
+ HTTP/1.0 200 OK
+ Content-Length: ...
+ Content-Type: text/xml...
+ <BLANKLINE>
+ ...1...
+
+
+
+Complex Types
+-------------
+
+For ZSI to successfully marshal complex values (instances of classes),
+you must define a typecode that describes the object (see the ZSI docs
+for details on defining typecodes). Once the typecode is defined, it must
+be accessible through an instance via the attribute name 'typecode' to
+be automatically marshalled.
+
+
+Faults
+------
+
+If you need to raise an error, you can either raise an exception as usual
+or (if you need more control over fault info) return a `ZSI.Fault` object
+directly. Either case causes a fault response to be returned:
+
+ >>> print http(r"""
+ ... POST /test_folder_1_ HTTP/1.0
+ ... Authorization: Basic %s:%s
+ ... Content-Length: 104
+ ... Content-Type: text/xml
+ ... SOAPAction: /
+ ...
+ ... <?xml version="1.0"?>
+ ... <SOAP-ENV:Envelope
+ ... SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
+ ... xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ ... xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ ... <SOAP-ENV:Body>
+ ... <m:echoInteger xmlns:m="http://www.soapware.org/">
+ ... <arg1 xsi:type="xsd:int">hello</arg1>
+ ... </m:echoInteger>
+ ... </SOAP-ENV:Body>
+ ... </SOAP-ENV:Envelope>
+ ... """ % (user_name, user_password), handle_errors=True)
+ HTTP/1.0 500 Internal Server Error
+ Content-Length: ...
+ Content-Type: text/xml
+ <BLANKLINE>
+ <SOAP-ENV:Envelope ...
+ Processing Failure
+ <BLANKLINE>
+ Unparseable integer
+ ...
+
+
+Complex Types
+-------------
+
+ >>> print http(r"""
+ ... POST /test_folder_1_ HTTP/1.0
+ ... Authorization: Basic %s:%s
+ ... Content-Length: 104
+ ... Content-Type: text/xml
+ ... SOAPAction: /
+ ...
+ ... <SOAP-ENV:Envelope
+ ... xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
+ ... xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
+ ... xmlns:ZSI="http://www.zolera.com/schemas/ZSI/"
+ ... xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ ... xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ ... <SOAP-ENV:Header></SOAP-ENV:Header>
+ ... <SOAP-ENV:Body xmlns:ns1="urn:ws-xwebservices-com:XWebEmailValidation:EmailValidation:v2:Messages">
+ ... <ns1:ValidateEmailRequest>
+ ... <ns1:Email>jfroche at affinitic.be</ns1:Email>
+ ... </ns1:ValidateEmailRequest>
+ ... </SOAP-ENV:Body>
+ ... </SOAP-ENV:Envelope>""" % (user_name, user_password))
+ HTTP/1.0 200 OK
+ Content-Length: ...
+ Content-Type: text/xml
+ <BLANKLINE>
+ ...jfroche at affinitic.be is OK...
Property changes on: z3c.soap/trunk/z3c/soap/README.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Added: z3c.soap/trunk/z3c/soap/__init__.py
===================================================================
--- z3c.soap/trunk/z3c/soap/__init__.py (rev 0)
+++ z3c.soap/trunk/z3c/soap/__init__.py 2008-11-13 12:18:51 UTC (rev 92902)
@@ -0,0 +1,4 @@
+#NOCHECK
+# This is a Python package.
+import HTTPRequest
+from patch import *
Property changes on: z3c.soap/trunk/z3c/soap/__init__.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.soap/trunk/z3c/soap/ftesting.zcml
===================================================================
--- z3c.soap/trunk/z3c/soap/ftesting.zcml (rev 0)
+++ z3c.soap/trunk/z3c/soap/ftesting.zcml 2008-11-13 12:18:51 UTC (rev 92902)
@@ -0,0 +1,11 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ xmlns:meta="http://namespaces.zope.org/meta"
+ i18n_domain="z3c.soap">
+
+ <include package="Products.Five"/>
+
+ <include package="z3c.soap" file="meta.zcml" />
+
+</configure>
+
Added: z3c.soap/trunk/z3c/soap/ftests.py
===================================================================
--- z3c.soap/trunk/z3c/soap/ftests.py (rev 0)
+++ z3c.soap/trunk/z3c/soap/ftests.py 2008-11-13 12:18:51 UTC (rev 92902)
@@ -0,0 +1,108 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+Functional tests for SOAP.
+
+$Id$
+"""
+
+import sys
+import os
+import zope.interface
+from zope.testing import doctest
+from zope.app.folder.folder import IFolder
+from zope.app.testing.functional import ZCMLLayer
+from zope.app.testing import ztapi
+from z3c.soap.interfaces import ISOAPRequest
+
+
+# Evil hack to make pickling work with classes defined in doc tests
+
+
+class NoCopyDict(dict):
+
+ def copy(self):
+ return self
+
+
+class FakeModule:
+
+ def __init__(self, dict):
+ self.__dict = dict
+
+ def __getattr__(self, name):
+ try:
+ return self.__dict[name]
+ except KeyError:
+ raise AttributeError(name)
+
+
+globs = NoCopyDict()
+name = 'z3c.soap.README'
+
+
+def setUp(test):
+ globs['__name__'] = name
+ sys.modules[name] = FakeModule(globs)
+
+
+def tearDown(test):
+ # clean up the views we registered:
+
+ # we use the fact that registering None unregisters whatever is
+ # registered. We can't use an unregistration call because that
+ # requires the object that was registered and we don't have that handy.
+ # (OK, we could get it if we want. Maybe later.)
+
+ ztapi.provideView(IFolder,
+ ISOAPRequest,
+ zope.interface,
+ 'contents',
+ None,
+ )
+ ztapi.provideView(IFolder,
+ ISOAPRequest,
+ zope.interface,
+ 'contents',
+ None,
+ )
+
+ globs.clear()
+ del sys.modules[name]
+
+
+dir = os.path.abspath(os.path.dirname(__file__))
+filename = os.path.join(dir, 'ftesting.zcml')
+
+z3c_soap_functional_layer = ZCMLLayer(filename,
+ __name__,
+ 'z3c.soap_functional_layer')
+
+
+def test_suite():
+ #from zope.app.testing.functional import FunctionalDocFileSuite
+ from Testing.ZopeTestCase import FunctionalDocFileSuite
+ ftest = FunctionalDocFileSuite(
+ 'README.txt',
+ optionflags=doctest.ELLIPSIS|
+ doctest.REPORT_NDIFF|
+ doctest.REPORT_ONLY_FIRST_FAILURE|
+ doctest.NORMALIZE_WHITESPACE,
+ setUp=setUp, tearDown=tearDown, globs=globs)
+ ftest.layer = z3c_soap_functional_layer
+ return ftest
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main(defaultTest='test_suite')
Property changes on: z3c.soap/trunk/z3c/soap/ftests.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.soap/trunk/z3c/soap/interfaces.py
===================================================================
--- z3c.soap/trunk/z3c/soap/interfaces.py (rev 0)
+++ z3c.soap/trunk/z3c/soap/interfaces.py 2008-11-13 12:18:51 UTC (rev 92902)
@@ -0,0 +1,59 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+SOAP interfaces.
+
+$Id$
+"""
+
+from zope.publisher.interfaces.http import IHTTPRequest, IHTTPResponse
+from zope.component.interfaces import IView, IPresentation
+from zope.publisher.interfaces import IPublishTraverse
+from zope.publisher.interfaces import IPublication
+from zope.interface import Interface
+
+
+class ISOAPPublisher(IPublishTraverse):
+ """SOAP Publisher"""
+
+
+class ISOAPPublication(IPublication):
+ """Object publication framework."""
+
+ def getDefaultTraversal(request, ob):
+ """Get the default published object for the request."""
+
+
+class ISOAPRequest(IHTTPRequest):
+ """SOAP Request"""
+
+
+class ISOAPResponse(IHTTPResponse):
+ """SOAP Response"""
+
+
+class ISOAPPresentation(IPresentation):
+ """SOAP presentation"""
+
+
+class ISOAPView(ISOAPPresentation, IView):
+ """SOAP View"""
+
+
+class IZSIRequestType(Interface):
+ """Resolver for complex request"""
+
+
+class IZSIResponseType(Interface):
+ """Resolver for complex response"""
Property changes on: z3c.soap/trunk/z3c/soap/interfaces.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.soap/trunk/z3c/soap/meta.zcml
===================================================================
--- z3c.soap/trunk/z3c/soap/meta.zcml (rev 0)
+++ z3c.soap/trunk/z3c/soap/meta.zcml 2008-11-13 12:18:51 UTC (rev 92902)
@@ -0,0 +1,11 @@
+<configure
+ xmlns:meta="http://namespaces.zope.org/meta"
+ xmlns="http://namespaces.zope.org/zope">
+
+ <meta:directive
+ namespace="http://namespaces.zope.org/soap"
+ name="view"
+ schema=".metadirectives.IViewDirective"
+ handler=".metaconfigure.view" />
+
+</configure>
Added: z3c.soap/trunk/z3c/soap/metaconfigure.py
===================================================================
--- z3c.soap/trunk/z3c/soap/metaconfigure.py (rev 0)
+++ z3c.soap/trunk/z3c/soap/metaconfigure.py 2008-11-13 12:18:51 UTC (rev 92902)
@@ -0,0 +1,173 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+SOAP configuration code
+
+$Id$
+"""
+
+from zope.interface import Interface
+from zope.security.checker import CheckerPublic #, Checker
+#from zope.location import Location
+from zope.component.interface import provideInterface
+from Products.Five.security import protectClass, protectName
+from zope.app.publisher.browser.viewmeta import _handle_for
+
+# XXX handler is non-public. Should call directives instead
+from zope.app.component.metaconfigure import handler
+
+from inspect import ismethod
+from interfaces import ISOAPRequest
+from Globals import InitializeClass as initializeClass
+from Products.Five.security import getSecurityInfo
+from Products.Five.metaclass import makeClass
+
+from Products.Five.browser import BrowserView
+from Products.Five.browser.metaconfigure import ViewMixinForAttributes
+from Products.Five.security import CheckerPrivateId
+
+
+def view(_context, for_=None, interface=None, methods=None,
+ class_=None, permission=None, name=None):
+
+ interface = interface or []
+ methods = methods or []
+
+ # If there were special permission settings provided, then use them
+ if permission == 'zope.Public':
+ permission = CheckerPublic
+
+ require = {}
+ for attr_name in methods:
+ require[attr_name] = permission
+
+ if interface:
+ for iface in interface:
+ for field_name in iface:
+ require[field_name] = permission
+ _context.action(
+ discriminator = None,
+ callable = provideInterface,
+ args = ('', for_))
+
+ cdict = getSecurityInfo(class_)
+
+ if name:
+ # Register a single view
+# if permission:
+# checker = Checker(require)
+#
+# def proxyView(context, request, class_=class_, checker=checker):
+# view = class_(context, request)
+# # We need this in case the resource gets unwrapped and
+# # needs to be rewrapped
+# view.__Security_checker__ = checker
+# return view
+#
+# class_ = proxyView
+ cdict = getSecurityInfo(class_)
+ cdict['__name__'] = name
+ new_class = makeClass(class_.__name__,
+ (class_, BrowserView), cdict)
+
+ _handle_for(_context, for_)
+ # Register the new view.
+ _context.action(
+ discriminator = ('view', (for_, ), name, ISOAPRequest),
+ callable = handler,
+ args = ('registerAdapter',
+ new_class, (for_, ISOAPRequest),
+ Interface, name,
+ _context.info)
+ )
+ _context.action(
+ discriminator = ('five:protectClass', new_class),
+ callable = protectClass,
+ args = (new_class, permission))
+
+ for name in require:
+ _context.action(
+ discriminator = ('five:protectName', new_class, name),
+ callable = protectName,
+ args = (new_class, name, permission))
+
+ #else its private:
+ allowed = require
+ private_attrs = [name for name in dir(new_class)
+ if (not name.startswith('_')) and
+ (name not in allowed) and
+ ismethod(getattr(new_class, name))]
+ for attr in private_attrs:
+ _context.action(
+ discriminator = ('five:protectName', new_class, attr),
+ callable = protectName,
+ args = (new_class, attr, CheckerPrivateId))
+
+ else:
+# if permission:
+# checker = Checker({'__call__': permission})
+# else:
+ for name in require:
+ # create a new callable class with a security checker; mix
+ # in zope.app.location.Location so that the view inherits
+ # a security context
+ cdict.update({'__page_attribute__': name,
+ '__name__': name})
+ new_class = makeClass(class_.__name__,
+ (class_, ViewMixinForAttributes),
+ cdict)
+
+ # in case the attribute does not provide a docstring,
+ # ZPublisher refuses to publish it. So, as a workaround,
+ # we provide a stub docstring
+ func = getattr(new_class, name)
+ if not func.__doc__:
+ # cannot test for MethodType/UnboundMethod here
+ # because of ExtensionClass
+ if hasattr(func, 'im_func'):
+ # you can only set a docstring on functions, not
+ # on method objects
+ func = func.im_func
+ func.__doc__ = "Stub docstring to make ZPublisher work"
+
+ _context.action(
+ discriminator = ('view', (for_, ), name, ISOAPRequest),
+ callable = handler,
+ args = ('registerAdapter',
+ new_class,
+ (for_, ISOAPRequest), Interface, name,
+ _context.info))
+
+ _context.action(
+ discriminator = ('five:protectClass', new_class),
+ callable = protectClass,
+ args = (new_class, permission))
+
+ _context.action(
+ discriminator = ('five:protectName', new_class, name),
+ callable = protectName,
+ args = (new_class, name, permission))
+
+ _context.action(
+ discriminator = ('five:initialize:class', new_class),
+ callable = initializeClass,
+ args = (new_class, )
+ )
+
+ # Register the used interfaces with the interface service
+ if for_ is not None:
+ _context.action(
+ discriminator = None,
+ callable = provideInterface,
+ args = ('', for_))
Property changes on: z3c.soap/trunk/z3c/soap/metaconfigure.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.soap/trunk/z3c/soap/metadirectives.py
===================================================================
--- z3c.soap/trunk/z3c/soap/metadirectives.py (rev 0)
+++ z3c.soap/trunk/z3c/soap/metadirectives.py 2008-11-13 12:18:51 UTC (rev 92902)
@@ -0,0 +1,84 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+SOAP ZCML Namespace Schemas
+
+$Id$
+"""
+
+import zope.configuration.fields
+from zope.security.zcml import Permission
+from zope.interface import Interface
+from zope.schema import TextLine
+
+
+class IViewDirective(Interface):
+ """View Directive for SOAP methods."""
+
+ for_ = zope.configuration.fields.GlobalObject(
+ title=u"Published Object Type",
+ description=u"""The types of objects to be published via SOAP
+
+ This can be expressed with either a class or an interface
+ """,
+ required=True)
+
+ interface = zope.configuration.fields.Tokens(
+ title=u"Interface to be published.",
+ required=False,
+ value_type=zope.configuration.fields.GlobalInterface())
+
+ methods = zope.configuration.fields.Tokens(
+ title=u"Methods (or attributes) to be published",
+ required=False,
+ value_type=zope.configuration.fields.PythonIdentifier())
+
+ class_ = zope.configuration.fields.GlobalObject(
+ title=u"Class",
+ description=u"A class that provides attributes used by the view.",
+ required=False)
+
+ permission = Permission(
+ title=u"Permission",
+ description=u"""The permission needed to use the view.
+
+ If this option is used and a name is given for the view, then
+ the names defined by the given methods or interfaces will be
+ under the given permission.
+
+ If a name is not given for the view, then, this option is
+ required and the the given permission is required to call the
+ individual views defined by the given interface and methods.
+
+ (See the name attribute.)
+
+ If no permission is given, then permissions should be declared
+ for the view using other means, such as the class directive.
+ """,
+ required=False, )
+
+ name = TextLine(
+ title=u"The name of the view.",
+ description=u"""
+ If a name is given, then rpc methods are accessed by
+ traversing the name and then accessing the methods. In this
+ case, the class should implement
+ zope.pubisher.interfaces.IPublishTraverse.
+
+ If no name is provided, then the names given by the attributes
+ and interfaces are published directly as callable views.
+
+ """,
+ required=False,
+ )
Property changes on: z3c.soap/trunk/z3c/soap/metadirectives.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.soap/trunk/z3c/soap/patch.py
===================================================================
--- z3c.soap/trunk/z3c/soap/patch.py (rev 0)
+++ z3c.soap/trunk/z3c/soap/patch.py 2008-11-13 12:18:51 UTC (rev 92902)
@@ -0,0 +1,144 @@
+# -*- coding: utf-8 -*-
+"""
+z3c.soap
+
+Licensed under the GPL license, see LICENCE.txt for more details.
+Copyright by Affinitic sprl
+
+$Id$
+"""
+import sys
+from zExceptions import Redirect
+from ZPublisher.mapply import mapply
+from ZPublisher.Publish import (call_object, missing_name, dont_publish_class,
+ get_module_info, Retry)
+from zope.publisher.browser import setDefaultSkin
+from zope.security.management import newInteraction, endInteraction
+from z3c.soap.interfaces import ISOAPRequest
+from z3c.soap.soap import SOAPResponse
+
+
+def publish(request, module_name, after_list, debug=0,
+ call_object=call_object,
+ missing_name=missing_name,
+ dont_publish_class=dont_publish_class,
+ mapply=mapply,
+ ):
+
+ (bobo_before, bobo_after, object, realm, debug_mode, err_hook,
+ validated_hook, transactions_manager)= get_module_info(module_name)
+
+ parents=None
+ response=None
+
+ try:
+ # TODO pass request here once BaseRequest implements IParticipation
+ newInteraction()
+
+ request.processInputs()
+
+ request_get=request.get
+ response=request.response
+
+ # First check for "cancel" redirect:
+ if request_get('SUBMIT', '').strip().lower()=='cancel':
+ cancel=request_get('CANCEL_ACTION', '')
+ if cancel:
+ raise Redirect(cancel)
+
+ after_list[0]=bobo_after
+ if debug_mode:
+ response.debug_mode=debug_mode
+ if realm and not request.get('REMOTE_USER', None):
+ response.realm=realm
+
+ if bobo_before is not None:
+ bobo_before()
+
+ # Get the path list.
+ # According to RFC1738 a trailing space in the path is valid.
+ path=request_get('PATH_INFO')
+
+ request['PARENTS']=parents=[object]
+
+ if transactions_manager:
+ transactions_manager.begin()
+
+ object=request.traverse(path, validated_hook=validated_hook)
+
+ if transactions_manager:
+ transactions_manager.recordMetaData(object, request)
+
+ result=mapply(object, request.args, request,
+ call_object, 1,
+ missing_name,
+ dont_publish_class,
+ request, bind=1)
+
+ if result is not response:
+ response.setBody(result)
+
+ if transactions_manager:
+ transactions_manager.commit()
+ endInteraction()
+
+ return response
+ except:
+ # DM: provide nicer error message for FTP
+ sm = None
+ if response is not None:
+ sm = getattr(response, "setMessage", None)
+ if sm is not None:
+ from asyncore import compact_traceback
+ cl, val= sys.exc_info()[:2]
+ sm('%s: %s %s' % (
+ getattr(cl, '__name__', cl), val,
+ debug_mode and compact_traceback()[-1] or ''))
+ if ISOAPRequest.providedBy(request):
+ if transactions_manager:
+ transactions_manager.abort()
+ endInteraction()
+ if response is None:
+ response = SOAPResponse(request.response)
+ response.exception()
+ return response
+ if err_hook is not None:
+ if parents:
+ parents=parents[0]
+ try:
+ try:
+ return err_hook(parents, request,
+ sys.exc_info()[0],
+ sys.exc_info()[1],
+ sys.exc_info()[2],
+ )
+ except Retry:
+ if not request.supports_retry():
+ return err_hook(parents, request,
+ sys.exc_info()[0],
+ sys.exc_info()[1],
+ sys.exc_info()[2],
+ )
+ finally:
+ if transactions_manager:
+ transactions_manager.abort()
+ endInteraction()
+
+ # Only reachable if Retry is raised and request supports retry.
+ newrequest=request.retry()
+ request.close() # Free resources held by the request.
+ # Set the default layer/skin on the newly generated request
+ setDefaultSkin(newrequest)
+ try:
+ return publish(newrequest, module_name, after_list, debug)
+ finally:
+ newrequest.close()
+
+ else:
+ if transactions_manager:
+ transactions_manager.abort()
+ endInteraction()
+ raise
+
+import ZPublisher.Publish
+ZPublisher.Publish.publish = publish
Property changes on: z3c.soap/trunk/z3c/soap/patch.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.soap/trunk/z3c/soap/publisher.py
===================================================================
--- z3c.soap/trunk/z3c/soap/publisher.py (rev 0)
+++ z3c.soap/trunk/z3c/soap/publisher.py 2008-11-13 12:18:51 UTC (rev 92902)
@@ -0,0 +1,186 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+SOAP Publisher.
+
+$Id$
+"""
+
+import ZSI
+from zope.app.publication.interfaces import ISOAPRequestFactory
+from zope.publisher.http import HTTPRequest, HTTPResponse
+from z3c.soap.interfaces import ISOAPRequest, ISOAPResponse
+from ZSI import TC, ParsedSoap, ParseException
+from ZSI import SoapWriter, Fault
+from zope.security.proxy import isinstance
+from zope.security.interfaces import IUnauthorized
+from zope.publisher.xmlrpc import premarshal
+from zope.interface import implements
+from StringIO import StringIO
+import traceback
+
+
+class SOAPRequestFactory(object):
+ """
+ This class implements a SOAP request factory that is registered
+ for zope.app.publication.interfaces.ISOAPRequestFactory as a
+ utility. This lets the hook in the z3 publisher delegate to us
+ for SOAP requests.
+ """
+ implements(ISOAPRequestFactory)
+
+ def __call__(self, input, env):
+ return SOAPRequest(input, env)
+
+factory = SOAPRequestFactory()
+
+
+class SOAPRequest(HTTPRequest):
+
+ implements(ISOAPRequest)
+
+## __slots__ = (
+## '_target',
+## '_root',
+## )
+
+ _target = ''
+ _root = None
+ _args = ()
+
+ def _getPositionalArguments(self):
+ return self._args
+
+ def _createResponse(self):
+ """Create a specific SOAP response object."""
+ return SOAPResponse()
+
+ def _setError(self, error):
+ self._getResponse()._error = error
+
+ def processInputs(self):
+ try:
+ input = self._body_instream.read()
+ parsed = ParsedSoap(input)
+
+ # We do not currently handle actors or mustUnderstand elements.
+ actors = parsed.WhatActorsArePresent()
+ if len(actors):
+ self._setError(ZSI.FaultFromActor(actors[0]))
+ return
+
+ must = parsed.WhatMustIUnderstand()
+ if len(must):
+ uri, localname = must[0]
+ self._setError(ZSI.FaultFromNotUnderstood(uri, localname))
+ return
+
+ except ParseException, e:
+ self._setError(ZSI.FaultFromZSIException(e))
+ return
+
+ except Exception, e:
+ self._setError(ZSI.FaultFromException(e, 1))
+ return
+
+ # Parse the SOAP input.
+ try:
+ docstyle = 0 # cant really tell...
+ resolver = None # XXX
+ root = self._root = parsed.body_root
+ target = self._target = root.localName
+
+ self.setPathSuffix(target.split('.'))
+
+ if docstyle:
+ self._args = (root)
+ else:
+ data = ZSI._child_elements(root)
+ if len(data) == 0:
+ self._args = ()
+ else:
+ try:
+ try:
+ type = data[0].localName
+ tc = getattr(resolver, type).typecode
+ except Exception, e:
+ tc = TC.Any()
+ self._args = [tc.parse(e, parsed) for e in data]
+ self._args = tuple(self._args)
+ except ZSI.EvaluateException, e:
+ self._error = ZSI.FaultFromZSIException(e)
+ return
+
+ except Exception, e:
+ self._setError(ZSI.FaultFromException(e, 0))
+
+
+class SOAPResponse(HTTPResponse):
+
+ implements(ISOAPResponse)
+
+ _error = None
+
+ def setBody(self, body):
+ """Sets the body of the response"""
+ # A SOAP view can return a Fault directly to indicate an error.
+ if isinstance(body, Fault):
+ self._error = body
+
+ if not self._error:
+ try:
+ target = self._request._target
+ body = premarshal(body)
+ output = StringIO()
+ result = body
+
+ if hasattr(result, 'typecode'):
+ tc = result.typecode
+ else:
+ tc = TC.Any(aslist=1, pname=target + 'Response')
+ result = [result]
+
+ SoapWriter(output).serialize(result, tc)
+ output.seek(0)
+
+ if not self._status_set:
+ self.setStatus(200)
+ self.setHeader('content-type', 'text/xml')
+ self._body = output.read()
+ self._updateContentLength()
+ return
+
+ except Exception, e:
+ self._error = ZSI.FaultFromException(e, 0)
+
+ # Error occurred in input, during parsing or during processing.
+ self.setStatus(500)
+ self.setHeader('content-type', 'text/xml')
+ self.setResult(self._error.AsSOAP())
+ #self._updateContentLength()
+
+ def handleException(self, exc_info):
+ """Handle exceptions that occur during processing."""
+ type, value = exc_info[:2]
+ content = "".join(traceback.format_tb(exc_info[-1]))
+ if IUnauthorized.providedBy(value):
+ self.setStatus(401)
+ self.setBody("")
+ #XXXself._body = ""
+ #self._updateContentLength()
+ return
+ if not isinstance(value, Fault):
+ value = ZSI.FaultFromException(u"%s : %s" % (value, content), 0)
+ self.setStatus(500)
+ self.setBody(value)
Property changes on: z3c.soap/trunk/z3c/soap/publisher.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.soap/trunk/z3c/soap/soap.py
===================================================================
--- z3c.soap/trunk/z3c/soap/soap.py (rev 0)
+++ z3c.soap/trunk/z3c/soap/soap.py 2008-11-13 12:18:51 UTC (rev 92902)
@@ -0,0 +1,165 @@
+"""SOAP support module
+
+Based on the XML-RPC Zope support module written by Eric Kidd at UserLand
+software, with much help from Jim Fulton at DC.
+
+This code hooks Zope up to Fredrik Lundh's Python SOAP library.
+"""
+
+import sys
+import types
+from string import replace
+from zExceptions import Unauthorized
+from zope.publisher.xmlrpc import premarshal
+from ZSI import TC, ParsedSoap
+from ZSI import SoapWriter, Fault
+from zope.component import queryUtility
+from z3c.soap.interfaces import IZSIRequestType, IZSIResponseType
+import ZSI
+import logging
+import traceback
+from zope.interface import implements
+from z3c.soap.interfaces import ISOAPResponse
+
+
+class SOAPParser(object):
+
+ def __init__(self, data):
+ self.parsed = ParsedSoap(data)
+ self.root = self.parsed.body_root
+ self.target = self.root.localName
+ self.method = replace(self.target, '.', '/')
+
+ def parse(self):
+ data = ZSI._child_elements(self.root)
+ if len(data) == 0:
+ params = ()
+ else:
+ resolver = queryUtility(IZSIRequestType, name=self.target)
+ if resolver and hasattr(resolver, 'typecode'):
+ tc = resolver.typecode
+ params = [resolver.typecode.parse(self.root, self.parsed)]
+
+ resolver = queryUtility(IZSIResponseType, name=self.target)
+ params.append(resolver)
+ else:
+ tc = TC.Any()
+ params = [tc.parse(e, self.parsed) for e in data]
+ params = tuple(params)
+ return params
+
+
+def parse_input(data):
+ parser = SOAPParser(data)
+ return parser.parse()
+
+
+class SOAPResponse:
+ """Customized Response that handles SOAP-specific details.
+
+ We override setBody to marhsall Python objects into SOAP. We
+ also override exception to convert errors to SOAP faults.
+
+ If these methods stop getting called, make sure that ZPublisher is
+ using the soap.Response object created above and not the original
+ HTTPResponse object from which it was cloned.
+
+ It's probably possible to improve the 'exception' method quite a bit.
+ The current implementation, however, should suffice for now.
+ """
+ implements(ISOAPResponse)
+ _contentType = 'text/xml'
+
+ _soap11 = None
+ _soap12 = None
+ # Because we can't predict what kind of thing we're customizing,
+ # we have to use delegation, rather than inheritence to do the
+ # customization.
+
+ def __init__(self, real):
+ self.__dict__['_real']=real
+
+ def __getattr__(self, name):
+ return getattr(self._real, name)
+
+ def __setattr__(self, name, v):
+ return setattr(self._real, name, v)
+
+ def __delattr__(self, name):
+ return delattr(self._real, name)
+
+ def setBody(self, body, title='', is_error=0, bogus_str_search=None):
+ if isinstance(body, Fault):
+ # Convert Fault object to SOAP response.
+ #body = buildSOAP(args=body, config=Config)
+ body = ZSI.FaultFromException(body, 0)
+ body = body.AsSOAP()
+ else:
+ # Marshall our body as an SOAP response. Strings will be sent
+ # strings, integers as integers, etc. We do *not* convert
+ # everything to a string first.
+ try:
+ target = self._method
+ body = premarshal(body)
+ #output = StringIO()
+ result = body
+ if hasattr(result, 'typecode'):
+ tc = result.typecode
+ else:
+ tc = TC.Any(aslist=1, pname=target + 'Response')
+ result = [result]
+ sw = SoapWriter(nsdict={}, header=True, outputclass=None,
+ encodingStyle=None)
+ body = sw.serialize(result, tc).body
+ except:
+ self.exception()
+ return
+
+ # Set our body to the message, and fix our MIME type.
+ self._real.setBody(body)
+ self._setHeader()
+ return self
+
+ def exception(self, fatal=0, info=None,
+ absuri_match=None, tag_search=None):
+ # Fetch our exception info. t is type, v is value and tb is the
+ # traceback object.
+ if type(info) is type(()) and len(info)==3:
+ t, v, tb = info
+ else:
+ t, v, tb = sys.exc_info()
+
+ content = "".join(traceback.format_tb(tb))
+ logger = logging.getLogger('Zope')
+ logger.info('SOAPException: %s' % tb)
+ if t == 'Unauthorized' or t == Unauthorized or (
+ isinstance(t, types.ClassType) and issubclass(t, Unauthorized)):
+ realm=self._real.realm
+ if realm:
+ self._real.setHeader('WWW-Authenticate',
+ 'basic realm="%s"' % realm, 1)
+ self._real.setStatus(401)
+ return None
+
+ # Create an appropriate Fault object. Unfortunately, we throw away
+ # most of the debugging information. More useful error reporting is
+ # left as an exercise for the reader.
+ f=None
+ if not isinstance(v, Fault):
+ f = ZSI.FaultFromException(u"%s : %s" % (v, content), 0)
+ # Do the damage.
+ self.setBody(f)
+ self._real.setStatus(500)
+
+ return tb
+
+ def _setHeader(self):
+ self.setHeader('content-length', len(self._real.body))
+ self._real.setHeader('content-type', self._contentType)
+ if self._soap11:
+ self._real.setHeader('content-type', 'text/xml')
+ if self._soap12:
+ self._real.setHeader('content-type', 'application/soap+xml')
+
+
+response=SOAPResponse
Property changes on: z3c.soap/trunk/z3c/soap/soap.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.soap/trunk/z3c/soap/tests/__init__.py
===================================================================
--- z3c.soap/trunk/z3c/soap/tests/__init__.py (rev 0)
+++ z3c.soap/trunk/z3c/soap/tests/__init__.py 2008-11-13 12:18:51 UTC (rev 92902)
@@ -0,0 +1 @@
+# This directory is a Python package.
Property changes on: z3c.soap/trunk/z3c/soap/tests/__init__.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.soap/trunk/z3c/soap/tests/mailvalidation.py
===================================================================
--- z3c.soap/trunk/z3c/soap/tests/mailvalidation.py (rev 0)
+++ z3c.soap/trunk/z3c/soap/tests/mailvalidation.py 2008-11-13 12:18:51 UTC (rev 92902)
@@ -0,0 +1,78 @@
+from ZSI import TCcompound, TC
+from ZSI.schema import LocalElementDeclaration, ElementDeclaration
+from ZSI.schema import GED
+
+
+class ns0:
+ targetNamespace = "urn:ws-xwebservices-com:XWebEmailValidation:EmailValidation:v2"
+
+
+class ns1:
+ targetNamespace = "urn:ws-xwebservices-com:XWebEmailValidation:EmailValidation:v2:Messages"
+
+ class ValidateEmailRequest_Dec(TCcompound.ComplexType, ElementDeclaration):
+ literal = "ValidateEmailRequest"
+ schema = "urn:ws-xwebservices-com:XWebEmailValidation:EmailValidation:v2:Messages"
+
+ def __init__(self, **kw):
+ ns = ns1.ValidateEmailRequest_Dec.schema
+ TClist = [TC.String(pname=(ns, "Email"), aname="_Email",
+ minOccurs=1, maxOccurs=1, nillable=False,
+ typed=False, encoded=kw.get("encoded"))]
+ kw["pname"] = (u'urn:ws-xwebservices-com:XWebEmailValidation:EmailValidation:v2:Messages', u'ValidateEmailRequest')
+ kw["aname"] = "_ValidateEmailRequest"
+ self.attribute_typecode_dict = {}
+ TCcompound.ComplexType.__init__(self, None, TClist, inorder=0, **kw)
+
+ class Holder:
+ typecode = self
+
+ def __init__(self):
+ # pyclass
+ self._Email = None
+ return
+ Holder.__name__ = "ValidateEmailRequest_Holder"
+ self.pyclass = Holder
+
+
+ class ValidateEmailResponse_Dec(TCcompound.ComplexType, ElementDeclaration):
+ literal = "ValidateEmailResponse"
+ schema = "urn:ws-xwebservices-com:XWebEmailValidation:EmailValidation:v2:Messages"
+
+ def __init__(self, **kw):
+ ns = ns1.ValidateEmailResponse_Dec.schema
+ TClist = [self.__class__.Status_Dec(minOccurs=1, maxOccurs=1,
+ nillable=False,
+ encoded=kw.get("encoded"))]
+ kw["pname"] = (u'urn:ws-xwebservices-com:XWebEmailValidation:EmailValidation:v2:Messages', u'ValidateEmailResponse')
+ kw["aname"] = "_ValidateEmailResponse"
+ self.attribute_typecode_dict = {}
+ TCcompound.ComplexType.__init__(self, None, TClist, inorder=0, **kw)
+
+ class Holder:
+ typecode = self
+
+ def __init__(self):
+ # pyclass
+ self._Status = None
+ return
+
+ Holder.__name__ = "ValidateEmailResponse_Holder"
+ self.pyclass = Holder
+
+ class Status_Dec(TC.String, LocalElementDeclaration):
+ literal = "Status"
+ schema = "urn:ws-xwebservices-com:XWebEmailValidation:EmailValidation:v2:Messages"
+
+ def __init__(self, **kw):
+ kw["pname"] = "Status"
+ kw["aname"] = "_Status"
+ TC.String.__init__(self, **kw)
+
+ class IHolder(str):
+ typecode=self
+ self.pyclass = IHolder
+ IHolder.__name__ = "_Status_immutable_holder"
+
+validateEmailIn = GED("urn:ws-xwebservices-com:XWebEmailValidation:EmailValidation:v2:Messages", "ValidateEmailRequest").pyclass
+validateEmailOut = GED("urn:ws-xwebservices-com:XWebEmailValidation:EmailValidation:v2:Messages", "ValidateEmailResponse").pyclass
Property changes on: z3c.soap/trunk/z3c/soap/tests/mailvalidation.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.soap/trunk/z3c/soap/tests/soap.zcml
===================================================================
--- z3c.soap/trunk/z3c/soap/tests/soap.zcml (rev 0)
+++ z3c.soap/trunk/z3c/soap/tests/soap.zcml 2008-11-13 12:18:51 UTC (rev 92902)
@@ -0,0 +1,54 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+ xmlns:soap="http://namespaces.zope.org/soap"
+ i18n_domain="zope">
+
+ <include package="z3c.soap" file="meta.zcml"/>
+ <include package="zope.app.security" file="meta.zcml"/>
+
+ <soap:view
+ name="test"
+ class="zope.app.component.tests.views.V1"
+ for="zope.app.component.tests.views.IC"
+ permission="zope.Public"
+ />
+
+ <soap:view
+ name="test2"
+ class="zope.app.component.tests.views.V1"
+ for="zope.app.component.tests.views.IC"
+ permission="zope.Public"
+ interface="zope.app.component.tests.views.IV"
+ />
+
+ <soap:view
+ name="test3"
+ class="zope.app.component.tests.views.V1"
+ for="zope.app.component.tests.views.IC"
+ permission="zope.Public"
+ methods="action" />
+
+ <soap:view
+ name="test4"
+ class="zope.app.component.tests.views.V1"
+ for="zope.app.component.tests.views.IC"
+ permission="zope.Public"
+ methods="action"
+ interface="zope.app.component.tests.views.IV" />
+
+ <soap:view
+ name="test5"
+ class="zope.app.component.tests.views.V1"
+ for="zope.app.component.tests.views.IC"
+ permission="zope.Public"
+ methods="action index"
+ interface="zope.app.component.tests.views.IV" />
+
+ <soap:view
+ class="zope.app.component.tests.views.V1"
+ for="zope.app.component.tests.views.IC"
+ interface="zope.app.component.tests.views.IV"
+ methods="action"
+ permission="zope.Public"
+ />
+
+</configure>
Added: z3c.soap/trunk/z3c/soap/tests/soap_error.zcml
===================================================================
--- z3c.soap/trunk/z3c/soap/tests/soap_error.zcml (rev 0)
+++ z3c.soap/trunk/z3c/soap/tests/soap_error.zcml 2008-11-13 12:18:51 UTC (rev 92902)
@@ -0,0 +1,13 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+ xmlns:soap="http://namespaces.zope.org/soap"
+ i18n_domain="zope">
+
+ <include package="soap" file="meta.zcml"/>
+
+ <soap:view
+ name="test"
+ factory="zope.component.tests.views.V1"
+ for="zope.component.tests.views.IC"
+ methods="action index" />
+
+</configure>
Added: z3c.soap/trunk/z3c/soap/tests/test_directives.py
===================================================================
--- z3c.soap/trunk/z3c/soap/tests/test_directives.py (rev 0)
+++ z3c.soap/trunk/z3c/soap/tests/test_directives.py 2008-11-13 12:18:51 UTC (rev 92902)
@@ -0,0 +1,83 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+Test 'soap' ZCML Namespace directives.
+
+$Id$
+"""
+
+from zope.configuration import xmlconfig
+from zope.configuration.exceptions import ConfigurationError
+from zope.app.component.tests.views import IC
+from zope.component import getMultiAdapter, queryMultiAdapter
+from zope.app.testing.placelesssetup import PlacelessSetup
+from z3c.soap.interfaces import ISOAPRequest
+from zope.interface import alsoProvides
+from zope.interface import implements
+import unittest
+import z3c.soap.tests
+from zope.publisher.browser import TestRequest
+
+request = TestRequest(ISOAPRequest)
+alsoProvides(request, ISOAPRequest)
+
+
+class Ob(object):
+
+ implements(IC)
+
+ob = Ob()
+
+
+class DirectivesTest(PlacelessSetup, unittest.TestCase):
+
+ def testView(self):
+ self.assertEqual(
+ queryMultiAdapter((ob, request), name='test'), None)
+ xmlconfig.file("soap.zcml", z3c.soap.tests)
+ self.assertEqual(
+ str(queryMultiAdapter((ob, request), name='test').__class__),
+ "<class 'Products.Five.metaclass.V1'>")
+
+ def testInterfaceAndAttributeProtectedView(self):
+ xmlconfig.file("soap.zcml", z3c.soap.tests)
+ v = getMultiAdapter((ob, request), name='test4')
+ self.assertEqual(v.index(), 'V1 here')
+ self.assertEqual(v.action(), 'done')
+
+ def testDuplicatedInterfaceAndAttributeProtectedView(self):
+ xmlconfig.file("soap.zcml", z3c.soap.tests)
+ v = getMultiAdapter((ob, request), name='test5')
+ self.assertEqual(v.index(), 'V1 here')
+ self.assertEqual(v.action(), 'done')
+
+ def testIncompleteProtectedViewNoPermission(self):
+ self.assertRaises(ConfigurationError, xmlconfig.file,
+ "soap_error.zcml", z3c.soap.tests)
+
+ def test_no_name(self):
+ xmlconfig.file("soap.zcml", z3c.soap.tests)
+ v = getMultiAdapter((ob, request), name='index')
+ self.assertEqual(v(), 'V1 here')
+ v = getMultiAdapter((ob, request), name='action')
+ self.assertEqual(v(), 'done')
+
+
+def test_suite():
+ return unittest.TestSuite((
+ unittest.makeSuite(DirectivesTest),
+ ))
+
+if __name__ == '__main__':
+ unittest.main()
Property changes on: z3c.soap/trunk/z3c/soap/tests/test_directives.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.soap/trunk/z3c/soap/tests/test_soappublication.py
===================================================================
--- z3c.soap/trunk/z3c/soap/tests/test_soappublication.py (rev 0)
+++ z3c.soap/trunk/z3c/soap/tests/test_soappublication.py 2008-11-13 12:18:51 UTC (rev 92902)
@@ -0,0 +1,160 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+SOAP Publication Tests
+
+$Id$
+"""
+import unittest
+
+from zope.app.publication.tests.test_zopepublication import \
+ BasePublicationTests
+from zope.app.publication.traversers import TestTraverser
+from zope.app.publication.soap import SOAPPublication
+from zope.interface import Interface, implements
+from zope.proxy import removeAllProxies
+from zope.publisher.interfaces import NotFound
+from z3c.soap.interfaces import ISOAPPresentation, ISOAPRequest
+from z3c.soap.interfaces import ISOAPPublisher
+from z3c.soap.publisher import SOAPRequest
+from zope.app.testing import ztapi
+from StringIO import StringIO
+
+
+class TestRequest(SOAPRequest):
+
+ def __init__(self, body_instream=None, environ=None,
+ response=None, **kw):
+
+ _testEnv = {
+ 'SERVER_URL': 'http://127.0.0.1',
+ 'HTTP_HOST': '127.0.0.1',
+ 'CONTENT_LENGTH': '0',
+ 'GATEWAY_INTERFACE': 'TestFooInterface/1.0'}
+
+ if environ:
+ _testEnv.update(environ)
+ if kw:
+ _testEnv.update(kw)
+ if body_instream is None:
+ body_instream = StringIO('')
+
+ super(TestRequest, self).__init__(
+ body_instream, _testEnv, response)
+
+
+class SimpleObject(object):
+
+ def __init__(self, v):
+ self.v = v
+
+
+class SOAPPublicationTests(BasePublicationTests):
+
+ klass = SOAPPublication
+
+ def _createRequest(self, path, publication, **kw):
+ request = TestRequest(PATH_INFO=path, **kw)
+ request.setPublication(publication)
+ return request
+
+ def testTraverseName(self):
+ pub = self.klass(self.db)
+
+ class C(object):
+ x = SimpleObject(1)
+ ob = C()
+ r = self._createRequest('/x', pub)
+ ztapi.provideView(None, ISOAPRequest, ISOAPPublisher,
+ '', TestTraverser)
+ ob2 = pub.traverseName(r, ob, 'x')
+ self.assertEqual(removeAllProxies(ob2).v, 1)
+
+ def testDenyDirectMethodAccess(self):
+ pub = self.klass(self.db)
+
+ class I(Interface):
+ pass
+
+ class C(object):
+ implements(I)
+
+ def foo(self):
+ return 'bar'
+
+ class V(object):
+
+ def __init__(self, context, request):
+ pass
+ implements(ISOAPPresentation)
+
+ ob = C()
+ r = self._createRequest('/foo', pub)
+
+ ztapi.provideView(I, ISOAPPresentation, Interface, 'view', V)
+ ztapi.setDefaultViewName(I, 'view', type=ISOAPPresentation)
+ self.assertRaises(NotFound, pub.traverseName, r, ob, 'foo')
+
+ def testTraverseNameView(self):
+ pub = self.klass(self.db)
+
+ class I(Interface):
+ pass
+
+ class C(object):
+ implements(I)
+
+ ob = C()
+
+ class V(object):
+
+ def __init__(self, context, request):
+ pass
+ implements(ISOAPPresentation)
+
+
+ # Register the simple traverser so we can traverse without @@
+ from z3c.soap.interfaces import ISOAPPublisher, ISOAPRequest
+ from zope.app.publication.traversers import SimpleComponentTraverser
+ ztapi.provideView(Interface, ISOAPRequest, ISOAPPublisher, '',
+ SimpleComponentTraverser)
+
+ r = self._createRequest('/@@spam', pub)
+ ztapi.provideView(I, ISOAPRequest, Interface, 'spam', V)
+ ob2 = pub.traverseName(r, ob, '@@spam')
+ self.assertEqual(removeAllProxies(ob2).__class__, V)
+
+ ob2 = pub.traverseName(r, ob, 'spam')
+ self.assertEqual(removeAllProxies(ob2).__class__, V)
+
+ def testTraverseNameServices(self):
+ pub = self.klass(self.db)
+
+ class C(object):
+
+ def getSiteManager(self):
+ return SimpleObject(1)
+ ob = C()
+ r = self._createRequest('/++etc++site', pub)
+ ob2 = pub.traverseName(r, ob, '++etc++site')
+ self.assertEqual(removeAllProxies(ob2).v, 1)
+
+
+def test_suite():
+ return unittest.TestSuite((
+ unittest.makeSuite(SOAPPublicationTests),
+ ))
+
+if __name__ == '__main__':
+ unittest.main()
Property changes on: z3c.soap/trunk/z3c/soap/tests/test_soappublication.py
___________________________________________________________________
Added: svn:keywords
+ Id
Added: z3c.soap/trunk/z3c/soap/tests/test_soaprequest.py
===================================================================
--- z3c.soap/trunk/z3c/soap/tests/test_soaprequest.py (rev 0)
+++ z3c.soap/trunk/z3c/soap/tests/test_soaprequest.py 2008-11-13 12:18:51 UTC (rev 92902)
@@ -0,0 +1,140 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+Test SOAP requests.
+
+$Id$
+"""
+
+import unittest
+from StringIO import StringIO
+from zope.publisher.base import DefaultPublication
+from zope.publisher.http import HTTPCharsets
+from z3c.soap.publisher import SOAPRequest
+
+
+class Publication(DefaultPublication):
+
+ require_docstrings = 0
+
+ def getDefaultTraversal(self, request, ob):
+ if hasattr(ob, 'browserDefault'):
+ return ob.browserDefault(request)
+ return ob, ()
+
+
+class TestSOAPRequest(SOAPRequest, HTTPCharsets):
+ """Make sure that our request also implements IHTTPCharsets, so that we do
+ not need to register any adapters."""
+
+ def __init__(self, *args, **kw):
+ self.request = self
+ SOAPRequest.__init__(self, *args, **kw)
+
+
+rpc_call = u'''<?xml version="1.0"?>
+<SOAP-ENV:Envelope
+ SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+ xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
+ xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
+ xmlns:xsd="http://www.w3.org/1999/XMLSchema"
+ xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance">
+ <SOAP-ENV:Body>
+ <m:action xmlns:m="http://www.soapware.org/">
+ <arg1 xsi:type="xsd:int">42</arg1>
+ </m:action>
+ </SOAP-ENV:Body>
+</SOAP-ENV:Envelope>
+'''
+
+
+class SOAPTests(unittest.TestCase):
+ """ """
+
+ _testEnv = {
+ 'PATH_INFO': '/folder/item2/view/',
+ 'QUERY_STRING': '',
+ 'SERVER_URL': 'http://foobar.com',
+ 'HTTP_HOST': 'foobar.com',
+ 'CONTENT_LENGTH': '0',
+ 'REQUEST_METHOD': 'POST',
+ 'HTTP_AUTHORIZATION': 'Should be in accessible',
+ 'GATEWAY_INTERFACE': 'TestFooInterface/1.0',
+ 'HTTP_OFF_THE_WALL': "Spam 'n eggs",
+ 'HTTP_ACCEPT_CHARSET': 'ISO-8859-1, UTF-8;q=0.66, UTF-16;q=0.33'}
+
+ def setUp(self):
+ super(SOAPTests, self).setUp()
+
+ class AppRoot(object):
+ pass
+
+ class Folder(object):
+ pass
+
+ class Item(object):
+
+ def __call__(self, a, b):
+ return "%s, %s" % (`a`, `b`)
+
+ def doit(self, a, b):
+ return 'do something %s %s' % (a, b)
+
+ class View(object):
+
+ def action(self, a):
+ return "Parameter[type: %s; value: %s" %(
+ type(a).__name__, `a`)
+
+ class Item2(object):
+ view = View()
+
+
+ self.app = AppRoot()
+ self.app.folder = Folder()
+ self.app.folder.item = Item()
+ self.app.folder.item2 = Item2()
+
+ def _createRequest(self, extra_env={}, body=""):
+ env = self._testEnv.copy()
+ env.update(extra_env)
+ if len(body):
+ env['CONTENT_LENGTH'] = str(len(body))
+
+ publication = Publication(self.app)
+ instream = StringIO(body)
+ request = TestSOAPRequest(instream, env)
+ request.setPublication(publication)
+ return request
+
+ def testProcessInput(self):
+ req = self._createRequest({}, rpc_call)
+ req.processInputs()
+ self.failUnlessEqual(req._args, (42, ))
+ self.failUnlessEqual(tuple(req._path_suffix), ('action', ))
+
+ def testTraversal(self):
+ req = self._createRequest({}, rpc_call)
+ req.processInputs()
+ action = req.traverse(self.app)
+ self.failUnlessEqual(action(*req._args),
+ "Parameter[type: int; value: 42")
+
+
+def test_suite():
+ loader = unittest.TestLoader()
+ return loader.loadTestsFromTestCase(SOAPTests)
+
+if __name__=='__main__':
+ unittest.TextTestRunner().run(test_suite())
Property changes on: z3c.soap/trunk/z3c/soap/tests/test_soaprequest.py
___________________________________________________________________
Added: svn:keywords
+ Id
More information about the Checkins
mailing list