| @@ -0,0 +1,56 @@ | |||||
| ============================================== | |||||
| SOAPpy - Simple to use SOAP library for Python | |||||
| ============================================== | |||||
| Current Maintainers: | |||||
| Gregory R. Warnes <Gregory.R.Warnes@Pfizer.com> | |||||
| Christopher Blunck <blunck2@gst.com> | |||||
| Original Authors: | |||||
| Cayce Ullman <c_ullman@yahoo.com> | |||||
| Brian Matthews <blm@blmatthews.com> | |||||
| Contributions by: | |||||
| Brad Knotwell <b.knotwell@f5.com> | |||||
| Mark Bucciarelli <mark@hubcapconsulting.com> (ported WSDL | |||||
| client from ZSI) | |||||
| Ivan R. Judson <judson@mcs.anl.gov> (Globus support) | |||||
| Kirk Strauser <kirk@daycos.com> | |||||
| Antonio Beamud Montero <antonio.beamud@linkend.com> (patches | |||||
| for integrating SOAPpy into Zope) | |||||
| Copyright (c) 2002-2003, Pfizer, Inc. | |||||
| Copyright (c) 2001, Cayce Ullman. | |||||
| Copyright (c) 2001, Brian Matthews. | |||||
| All rights reserved. | |||||
| LICENSE: | |||||
| ---------------------------------------------------------------------------- | |||||
| Redistribution and use in source and binary forms, with or without | |||||
| modification, are permitted provided that the following conditions are met: | |||||
| Redistributions of source code must retain the above copyright notice, this | |||||
| list of conditions and the following disclaimer. | |||||
| Redistributions in binary form must reproduce the above copyright notice, | |||||
| this list of conditions and the following disclaimer in the documentation | |||||
| and/or other materials provided with the distribution. | |||||
| Neither the name of actzero, inc. nor the names of its contributors may | |||||
| be used to endorse or promote products derived from this software without | |||||
| specific prior written permission. | |||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||||
| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||||
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||||
| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | |||||
| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||||
| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |||||
| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |||||
| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||||
| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||||
| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | |||||
| DAMAGE. | |||||
| @@ -0,0 +1,10 @@ | |||||
| Metadata-Version: 1.0 | |||||
| Name: SOAPpy | |||||
| Version: 0.12.0 | |||||
| Summary: SOAP Services for Python | |||||
| Home-page: http://pywebsvcs.sf.net/ | |||||
| Author: Gregory Warnes | |||||
| Author-email: Gregory.R.Warnes@Pfizer.com | |||||
| License: UNKNOWN | |||||
| Description: SOAPpy provides tools for building SOAP clients and servers. For more information see http://pywebsvcs.sf.net/ | |||||
| Platform: UNKNOWN | |||||
| @@ -0,0 +1,237 @@ | |||||
| ============================================== | |||||
| SOAPpy - Simple to use SOAP library for Python | |||||
| ============================================== | |||||
| Current Maintainer: | |||||
| Gregory R. Warnes <Gregory.R.Warnes@Pfizer.com> | |||||
| Original Authors: | |||||
| Cayce Ullman <c_ullman@yahoo.com> | |||||
| Brian Matthews <blm@blmatthews.com> | |||||
| Contributions by: | |||||
| Christopher Blunck <blunck2@gst.com> | |||||
| Brad Knotwell <b.knotwell@f5.com> | |||||
| Mark Bucciarelli <mark@hubcapconsulting.com> (ported WSDL | |||||
| client from ZSI) | |||||
| Ivan R. Judson <judson@mcs.anl.gov> (Globus support) | |||||
| Kirk Strauser <kirk@daycos.com> | |||||
| Antonio Beamud Montero <antonio.beamud@linkend.com> (patches | |||||
| for integrating SOAPpy into Zope) | |||||
| And others. | |||||
| Copyright (c) 2002-2005, Pfizer, Inc. | |||||
| Copyright (c) 2001, Cayce Ullman. | |||||
| Copyright (c) 2001, Brian Matthews. | |||||
| All rights reserved, see the file LICENSE for conditions of use. | |||||
| INTRODUCTION | |||||
| ============ | |||||
| The goal of the SOAPpy team is to provide a full-featured SOAP library | |||||
| for Python that is very simple to use and that fully supports dynamic | |||||
| interaction between clients and servers. | |||||
| INCLUDED | |||||
| -------- | |||||
| - General SOAP Parser based on sax.xml | |||||
| - General SOAP Builder | |||||
| - SOAP Proxy for RPC client code | |||||
| - SOAP Server framework for RPC server code | |||||
| FEATURES | |||||
| -------- | |||||
| - Handles all SOAP 1.0 types | |||||
| - Handles faults | |||||
| - Allows namespace specification | |||||
| - Allows SOAPAction specification | |||||
| - Homogeneous typed arrays | |||||
| - Supports multiple schemas | |||||
| - Header support (mustUnderstand and actor) | |||||
| - XML attribute support | |||||
| - Multi-referencing support (Parser/Builder) | |||||
| - Understands SOAP-ENC:root attribute | |||||
| - Good interop, passes all client tests for Frontier, SOAP::LITE, SOAPRMI | |||||
| - Encodings | |||||
| - SSL clients (with Python compiled with OpenSSL support) | |||||
| - SSL servers (with Python compiled with OpenSSL support and M2Crypto | |||||
| installed) | |||||
| - Encodes XML tags per SOAP 1.2 name mangling specification (Gregory Warnes) | |||||
| - Automatic stateful SOAP server support (Apache v2.x) (blunck2) | |||||
| - WSDL client support | |||||
| - WSDL server support | |||||
| TODO (See RELEASE_INFO and CHANGELOG for recent changes) | |||||
| ---- | |||||
| - Timeout on method calls | |||||
| - Advanced arrays (sparse, multidimensional and partial) | |||||
| - Attachments | |||||
| - mod_python example | |||||
| - medusa example | |||||
| - Improved documentation | |||||
| MANIFEST | |||||
| -------- | |||||
| Files | |||||
| README This file | |||||
| RELEASE_NOTES General information about each release | |||||
| ChangeLog Detailed list of changes | |||||
| TODO List of tasks that need to be done | |||||
| setup.py Python installation control files | |||||
| MANIFEST | |||||
| MANIFEST.in | |||||
| SOAPpy.spec* RPM package control file | |||||
| Directories | |||||
| SOAPpy/* Source code for the package | |||||
| SOAPpy/wstools/* Source code for WSDL tools | |||||
| tests/* unit tests and examples | |||||
| validate/* interop client and servers | |||||
| bid/* N+I interop client and server | |||||
| doc/* Documentation | |||||
| contrib/ Contributed examples (also see test/) | |||||
| docs/ Documentation | |||||
| tools/ Misc tools useful for the SOAPpy developers | |||||
| zope/ Patches to Zope allowing it to provide SOAP services | |||||
| INSTALLATION | |||||
| ============ | |||||
| REQUIRED PACKAGES: | |||||
| ----------------- | |||||
| - fpconst 0.6.0 or later, | |||||
| <http://research.warnes.net/projects/rzope/fpconst/> | |||||
| - pyXML 0.8.3 or later, <http://pyxml.sourceforge.net> | |||||
| OPTIONAL PACKAGES | |||||
| ----------------- | |||||
| - pyGlobus, optional support for Globus, | |||||
| <http://www-itg.lbl.gov/gtg/projects/pyGlobus/> | |||||
| - M2Crypto.SSL, optional support for server-side SSL | |||||
| <http://sandbox.rulemaker.net/ngps/m2/> | |||||
| - If Python is compiled with SSL support (Python 2.3 does so by | |||||
| default), client-side use of SSL is supported | |||||
| INSTALLATION STEPS | |||||
| ------------------ | |||||
| As of version 0.9.8 SOAPpy can be installed using the standard python | |||||
| package installation tools. | |||||
| To install: | |||||
| 1) Unpack the distribution package: | |||||
| On Windows, use your favorite zip file uncompression tool. | |||||
| On Unix: | |||||
| $ tar -xvzf SOAPpy-$VERSION$.tar.gz | |||||
| if you have gnu tar, otherwise | |||||
| $ gzcat SOAPpy-$VERSION$.tar.gz | tar -xvf - | |||||
| 2) Change into the source directory | |||||
| $ cd SOAPpy-$VERSION$ | |||||
| 3) Compile the package | |||||
| $ python setup.py build | |||||
| 4) Install the package | |||||
| On Windows: | |||||
| $ python setup.py install | |||||
| On Unix install as the owner of the python directories | |||||
| (usally root): | |||||
| $ su root | |||||
| Password: XXXXXX | |||||
| $ python setup.py install | |||||
| DOCUMENTATION | |||||
| ============= | |||||
| QUICK START | |||||
| ----------- | |||||
| A simple "Hello World" http SOAP server: | |||||
| import SOAPpy | |||||
| def hello(): | |||||
| return "Hello World" | |||||
| server = SOAPpy.SOAPServer(("localhost", 8080)) | |||||
| server.registerFunction(hello) | |||||
| server.serve_forever() | |||||
| And the corresponding client: | |||||
| import SOAPpy | |||||
| server = SOAPpy.SOAPProxy("http://localhost:8080/") | |||||
| print server.hello() | |||||
| BASIC TUTORIAL | |||||
| -------------- | |||||
| Mark Pilgrims' _Dive Into Python_, published in printed form by | |||||
| Apress and online at at http://diveintopython.org provides a | |||||
| nice tutorial for SOAPpy in Chapter 12, "SOAP Web Services". | |||||
| See http://diveintopython.org/soap_web_services . | |||||
| OTHER DOCUMENTATION | |||||
| ------------------- | |||||
| For further information see the files in the docs/ directory. | |||||
| Note that documentation is one of SOAPpy's current weak points. | |||||
| Please help us out! | |||||
| GETTING HELP | |||||
| ============ | |||||
| REPORTING BUGS | |||||
| -------------- | |||||
| Please submit bug reports, feature requests, patches, etc at the | |||||
| Python Web Services web site: http://pywebsvcs.sourceforge.net. | |||||
| MAILING LIST | |||||
| ============ | |||||
| Please address questions and general discussion to the | |||||
| pywebsvcs-talk mailing list, pywebsvcs-talk@lists.sourceforge.net. | |||||
| For subscription information visit | |||||
| http://lists.sourceforge.net/lists/listinfo/pywebsvcs-talk. | |||||
| List archives are available at | |||||
| http://sourceforge.net/mailarchive/forum.php?forum=pywebsvcs-talk | |||||
| Please remember that the authors do have day jobs, so please try | |||||
| the mailing list before contacting them directy. | |||||
| $Id: README,v 1.18 2005/02/22 15:58:35 warnes Exp $ | |||||
| @@ -0,0 +1,590 @@ | |||||
| Release 0.12.0 of SOAPpy | |||||
| ------------------------ | |||||
| This release primarily foces on bug fixes. Primary changes: | |||||
| - Fixes for bug reports that have accumulated over the last year | |||||
| [ 916265] "Arrays of unicode do not serialize correctly (patch included)" | |||||
| [ 918216] "Parsing faults in SOAPpy 0.11.3" | |||||
| [ 925077] "SOAPpy prints out SOAP fault" (even when Config.debug is off). | |||||
| [1001646] "SOAPpy stomps headers when sending multirefs" | |||||
| [1001646] "SOAPpy stomps headers when sending multirefs. | |||||
| [1064233] "Bug fixes for complex types" | |||||
| [1064248] "Bugs in _asdict() and _asarray() in Types.py" | |||||
| [1078051] "Arrays of complex types (doc/lit)" | |||||
| [1096971] "Parse error: missing HTTP header 'Content-length'" | |||||
| [1106450] "Floats are truncated to 10 digits, causing precision loss" | |||||
| [1122991] "error from SOAPpy/Client.py for content_length evaluation?" | |||||
| - Fixes for 'rules' which allow control of the data types of *incoming* messages. | |||||
| As a consequence TCtest.py now passes all tests. | |||||
| - WSDL support has been improving, due to work on the 'wstools' | |||||
| module which is shared between ZSI and SOAPpy. | |||||
| - Some work has been done to improve documentation. | |||||
| Release 0.11.6 of SOAPpy | |||||
| ------------------------ | |||||
| Changes to URLs and email addresses in documentation. | |||||
| Release 0.11.5 of SOAPpy | |||||
| ------------------------ | |||||
| - Bug fixes | |||||
| - Fix string format error in fault handling | |||||
| Release 0.11.4 of SOAPpy | |||||
| ------------------------ | |||||
| - Bug fixes: | |||||
| - SOAPpy/Server.py: Check if header information contains SOAPAction | |||||
| key before checking its value. | |||||
| - Fixes for generating SOAP from complexType arrays, contributed by | |||||
| antonio.beamud@linkend.com | |||||
| - Fixed bug that caused typedArrayTypes to lose their type | |||||
| information when rendered to SOAP and added corresponding | |||||
| test case. | |||||
| - New Features | |||||
| - Enhancements to fault handling: The faultType Faultstring is now | |||||
| a non-variable string (i.e. no nsmethod in it) so that it can be | |||||
| programmatically checked. In addition fault handlers can now be | |||||
| registered to handle specific types of faults. | |||||
| - SOAPpy/Server.py: Modified unregsiterObject function to take | |||||
| optional namespace/path args to be consistent with registerObject. | |||||
| - SOAPpy/Server.py: Added an unregisterObject function | |||||
| - Changes to allow SOAPBuilder so it can handle a 'raw' Python object. | |||||
| Release 0.11.2 of SOAPpy | |||||
| ------------------------ | |||||
| - News: | |||||
| Ivan R. Judson has joined the SOAPpy team. He is focused on | |||||
| Globus support but is also responsible for a lot of other work for | |||||
| this release, | |||||
| - Bug fixes: | |||||
| - Code in Types.py assumes nested scopes, so I added the proper import so | |||||
| this will work under python 2.2.x | |||||
| - Fixing namespace collision | |||||
| - Fixed handing of named arguments bug introduced in 0.11.1. | |||||
| - Fix memory leak when exceptions are raised. | |||||
| - Fix bug when content-length is not present in parsed SOAP message. | |||||
| - Fix bug #888345: Python 2.3 boolean type serialized as int | |||||
| - Fix bug #875977: no escaping of bad tagnames for NoneTypes | |||||
| - New features: | |||||
| - Improved Globus support and documentation. Thanks Ivan! | |||||
| - Added context handling | |||||
| - Changed the use of SOAPAction, it used to default to setting it | |||||
| to "", now it defaults to setting it to the method (not the | |||||
| nsmethod). There is a clause in Server.py that catches 'old style' | |||||
| SOAPActions (aka "") and sets them to the method. When this is | |||||
| confirmed to be what everyone wants and we decide it's alright to | |||||
| (possibly) break client/server interop, we can take the clause out | |||||
| of Server.py and just handle SOAPActions of "" as a possible | |||||
| error/warning. | |||||
| - Additional test code. | |||||
| - Raise a SOAPException instead of returning a SOAPpy.faultType | |||||
| when a SOAP Fault is encountered and simplify_objects is enabled. | |||||
| Release 0.11.1 of SOAPpy | |||||
| ------------------------ | |||||
| - Bug fixes: | |||||
| - Fixed bug [ 792258 ] "SOAPBuilder.SOAPBuilder.dump can catch | |||||
| wrong exceptions" in SOAPBuilder.dump() submitted by Greg Chapman | |||||
| (glchapman). | |||||
| - Changes suggested by Richard Au (richardau) to fix ssl support. | |||||
| See bug report [ 752882 ] "SSL SOAP Server no longer working." | |||||
| - Remove call to gentag from 'dump' and add to 'dump_float', per | |||||
| bug report [ 792600 ] "SOAPBuilder.SOAPBuilder.dump possibly should | |||||
| not call gentag" by Greg Chapman (glchapman). | |||||
| - Add a tests for handling of nil="true" and nil="false". This | |||||
| fixes bug [ pywebsvcs-Bugs-858168 ] 'xsi:nil="true" causes | |||||
| exception' reported by Robert Zimmermann (robertzett): | |||||
| - testClient1.py now works properly. It had been failing to start the | |||||
| server thread on the second unit test. It turned out that the | |||||
| variable 'quit' needed to be reset to zero after the SOAP server | |||||
| thread for the first unit test exited. With the solution of this | |||||
| problem testClient1 can now be extended to run unit tests of both | |||||
| client and server components. | |||||
| - Added 'strict' option to the WSDL class. If strict is true, a | |||||
| RuntimeException will be raised if an unrecogned message is recieved. | |||||
| If strict is false, a warning will be printed to the console, the | |||||
| message type will be added to the WSDL schema, and processing will | |||||
| continue. This is in response to the second half of bug report [ | |||||
| 817331 ] "Some WSDL.py changes", submitted by Rudolf Ruland. | |||||
| Release 0.11.0 of SOAPpy | |||||
| ------------------------ | |||||
| - New/Changed configuration settings: | |||||
| - Config.simplify_objects=1 now converts all SOAPpy objects into basic | |||||
| Python types (list, dictionary, tuple, double, float, etc.). By default, | |||||
| Config.simplify_objects=0 for backward compatibility. | |||||
| - Config.dict_encoding='ascii' converts the keys of dictionaries | |||||
| (e.g. created when Config.simplify_objects=1) to ascii == plain python | |||||
| strings instead of unicode strings. This variable can be set to any | |||||
| encoding known to string.encode(). | |||||
| - Config.strict_range=1 forces the SOAP parsing routines to perform | |||||
| range checks on recieved SOAP float and double objects. When | |||||
| Config.strict_range=0, the default, parsing does not perform range | |||||
| checking (except for detecting overflows, which always occurs). In | |||||
| either case, range checking is performed when | |||||
| generating SOAP float and double objects. | |||||
| - Fixes for WSDLProxy. | |||||
| - Scripts in the test/ directory | |||||
| - Verbose debugging messages have been turned off.. | |||||
| - SOAPtest.py now functions when Config.simplify_objects=1 | |||||
| - SOAPtest.py now sets Config.strict_range=1 so that range | |||||
| checks are be properly tested. | |||||
| - New README file listing what test scripts fail and why. | |||||
| - Initial support for Globus via pyGlobus contributed by Ivan | |||||
| R. Judson <judson@mcs.anl.gov>. | |||||
| Release 0.10.4 of SOAPpy | |||||
| ------------------------ | |||||
| Dramatic performance improvements for large data transfers. | |||||
| Release 0.10.1 of SOAPpy | |||||
| ------------------------ | |||||
| only minor changes | |||||
| 1) Code now uses a single file to store version number | |||||
| 2) Client and server now report 'SOAPpy' as the server/user-agent. | |||||
| 3) All test scripts now use the local SOAPpy source instead of the | |||||
| globally installed version. | |||||
| Release 0.10.0 of SOAPpy | |||||
| ------------------------ | |||||
| Enhancements: | |||||
| 1) The new name handling mechanism has been enabled by default. | |||||
| The primary purpose of this release is to allow users to test this | |||||
| to see if it causes problems. Please take the time to do so. If | |||||
| there are no problems reported by April 15, 2003, 0.9.9 will be | |||||
| released with this feature enabled by default. | |||||
| Note that running a client under an old release of SOAPpy and a | |||||
| server under this release will be likely to generate errors due to | |||||
| the different name handling mechanisms. | |||||
| 2) MS-Windows systems should now be fully supported. | |||||
| This required implementing a new module, ieee754, which provides | |||||
| functions for detecting and generating IEEE 754 special floating | |||||
| point values (+Inf, -Inf, NaN) which are not properly handled by | |||||
| the Windows implementation of the float() function. | |||||
| 3) Code reorganization: The huge file SOAPpy/SOAP.py (4,122 lines, | |||||
| 131K) has been split into 10 separate files. In addition code | |||||
| shared with ZSI has been moved into a separate subdirectory and a | |||||
| separate CVS module. | |||||
| 4) Fixed bug 678239 which caused loss of namespace information in the | |||||
| client. | |||||
| 5) Mark Bucciarelli's <mark@hubcapconsulting.com> has ported client | |||||
| support for WSDL from ZSI, as well as providing a mechanism for | |||||
| SOAPpy servers to provide WSDL on properly structured .GET | |||||
| requests. | |||||
| 6) Added ThreadingSOAPServer which inherits from ThreadingTCPServer | |||||
| server so that multiple clients will be automatically multiplexed. | |||||
| VERSION 0.10.4 | |||||
| -------------- | |||||
| - Integrated a simple patch submitted by Erik Westra that dramatically | |||||
| improves parser performance. | |||||
| - WSDL tools now uses m2crypto for SSL if it's installed. | |||||
| - Various other WSDL changes. | |||||
| VERSION 0.10.3 | |||||
| -------------- | |||||
| - Removed import of obsoleted ieee753.py. Now use the fpconst module | |||||
| proposed by PEP 754, available from | |||||
| <http://research.warnes.net/Zope/projects/fpconst/> | |||||
| - SOAPpy should no longer depend on pyXML. | |||||
| VERSION 0.10.2 | |||||
| -------------- | |||||
| - Fixed client support for basic authentication | |||||
| - Fixed import error in Client.py | |||||
| - Improved Client parsing of namespaces to support stateful SOAP servers. | |||||
| VERSION 0.10.1 | |||||
| -------------- | |||||
| - Modified setup.py, Server.py, and Client.py to obtain SOAPpy version | |||||
| number from a new file, version.py. | |||||
| - SOAP server/user-agent is now to 'SOAPpy' instead of 'SOAP.py'. | |||||
| - Added ident string containing CVS version to all files that were | |||||
| lacking this. | |||||
| VERSION 0.10.0 | |||||
| -------------- | |||||
| CHANGES SINCE VERSION 0.9.9-pre5 | |||||
| - Major Change: The huge file SOAPpy/SOAP.py (4,122 lines, 131K) has | |||||
| been split into 10 separate files: | |||||
| Client.py NS.py SOAPBuilder.py Utilities.py | |||||
| Config.py Parser.py Server.py | |||||
| Errors.py SOAP.py Types.py | |||||
| This should ease navigation and maintenance. | |||||
| - A new CVS module 'wstools' was created to hold code which is used by | |||||
| both ZSI and SOAPpy. While this module is stored separately in CVS, | |||||
| it will be distributed as an integral part of both ZSI and SOAPpy, | |||||
| and will be included as an 'internal' module by both. In the SOAPpy | |||||
| source, it lives in the directory SOAPpy/wstools. | |||||
| - The files XMLname.py, ieee754.py, have been moved into SOAPpy/wstools. | |||||
| - Added TODO file | |||||
| - Fix bug in getNS that caused loss of namespace by using better | |||||
| pattern matching to find the namespace in the SOAP message. Fixes bug | |||||
| 678239 | |||||
| - Added Mark Bucciarelli's <mark@hubcapconsulting.com> patch to | |||||
| provide wsdl code on properly structured .GET requests to the server. | |||||
| - Added client support for WSDL, ported from ZSI by Mark Bucciarelli | |||||
| <mark@hubcapconsulting.com> | |||||
| - Added ThreadingSOAPServer which inherits from ThreadingTCPServer | |||||
| server so that muliple clients will be automatically multiplexed. | |||||
| - Removed some files from /test for services that no longer exist. | |||||
| CHANGES SINCE VERSION 0.9.9-pre4 | |||||
| -------------------------------- | |||||
| - Added client support for WSDL, ported from ZSI by Mark Bucciarelli | |||||
| <mark@hubcapconsulting.com>. | |||||
| CHANGES SINCE VERSION 0.9.9-pre3 | |||||
| -------------------------------- | |||||
| - Code shared between SOAPpy and ZSI now lives in | |||||
| SOAPpy/SOAPpy/wstools and is stored in a separate CVS package. This | |||||
| will allow ZSI and SOAPpy to keep these files synchronized. | |||||
| CHANGES SINCE VERSION 0.9.9-pre2 | |||||
| -------------------------------- | |||||
| - Fixed trivial compilation bug on Win32: Only define | |||||
| SOAPUnixSocketServer if the Unix domain sockets are supported | |||||
| CHANGES SINCE VERSION 0.9.9-pre1 | |||||
| -------------------------------- | |||||
| - Added request for nested scopes, should now work properly in python | |||||
| 2.1 with named argument calls. | |||||
| - Fixed bug caused by omission of the ieee754 module from __init__.py. | |||||
| - SOAPpy now provides a SOAPUnixSocketServer class, which uses a unix | |||||
| domain socket instead of a network TCP/IP socket for communication. A | |||||
| corresponding client will be provided in the future. [This class | |||||
| has not yet been tested.] | |||||
| CHANGES SINCE VERSION 0.9.8 | |||||
| --------------------------- | |||||
| - IEEE 754 floating point specials (Inf, -Inf, NaN) should now be | |||||
| properly and consistently handled on all platforms. | |||||
| Added code to explicitly check for and handle IEEE 754 floating | |||||
| point specials (Inf, -Inf, NaN). This replaces an ugly hack for | |||||
| systems whose python float() doesn't understand the strings "Inf", | |||||
| "NaN", etc. Floating point specials should now be properly handled | |||||
| on all operating systems. | |||||
| ***SOAPpy should now work properly on all versions of Microsoft Windows.*** | |||||
| A new module, ieee754 contains the functions required to detect and | |||||
| create NaN, Inf, and -Inf values. This module should be usable in | |||||
| other contexts. | |||||
| - *** The new argument handling method (via SOAPpy.SOAP.Config.specialArgs=1) | |||||
| is now enabled by default.*** | |||||
| - Changed all references to actzero.com in SOAP.py to pywebscvs.sf.net. | |||||
| - Fixed a bug where lists included as parameters to SOAP method calls | |||||
| were being incorrectly named 'Results' even when another name was | |||||
| given. | |||||
| CHANGES SINCE VERSION 0.9.7 | |||||
| --------------------------- | |||||
| - Modified structure to allow installation using Python distutils | |||||
| (i.e. setup.py). Access to the SOAPpy library now requires: | |||||
| from SOAPpy import SOAP | |||||
| - I (Gregory R. Warnes) have implemented an experimental and | |||||
| non-standard method of handling named and unnamed arguments. This | |||||
| mechanism is enabled in SOAPpy by setting | |||||
| SOAPpy.SOAP.Config.specialArgs=1. | |||||
| When enabled, parameters with names of the form _#### (i.e., | |||||
| matching the regexp "^_[0-9]+") are assumed to be unnamed parameters | |||||
| and are passed to the method in numeric order. All other parameters | |||||
| are assumed to be named and are passed using the xml tag id as the | |||||
| parameter name. Outgoing SOAP method calls now always generate | |||||
| names in this way--whether or not specialArgs is enabled--instead of | |||||
| using the pattern v#####. | |||||
| See the file README.MethodParameterNaming for more details. | |||||
| - Added noroot parameter to the SOAPBuilder and SOAPProxy objects | |||||
| in order to provide compatibility with an older version of | |||||
| EasySOAP (v0.2) that balked if the SOAP-ENC:root parameter was | |||||
| included.(Brad Knotwell) | |||||
| - Added support for namespace-rewriting (used by Apache v2.x SOAP server for | |||||
| error conditions as well as stateful communication) (Christopher Blunck) | |||||
| - Added string <-> str conversion for array types (Python 2.2+) | |||||
| (Christopher Blunck) | |||||
| - Added convenience method (invoke) to SOAPProxy that calls __call (not sure | |||||
| if it is necessary - feel free to remove if you want) (Christopher Blunck) | |||||
| - Python 'float' are equivalent to SOAP 'double'. Modified dump_float | |||||
| and dump_list to use SOAP type string 'double' | |||||
| appropriately. (Gregory R. Warnes) | |||||
| - Add basic authentication (Brad Knotwell) | |||||
| - Fixes to enable proper handling of SOAP faults by the client: | |||||
| - Fixed test of whether message content is text/xml when recieving a fault. | |||||
| - Added __call__ method to exception classes to match the current API. | |||||
| - The faultType.__repr__() method now print details if present | |||||
| (Gregory R. Warnes) | |||||
| - Added XMLnam.py which provides toXMLname() and fromXMLname() for | |||||
| properly encoding xml tag names per the SOAP 2.1 (draft) | |||||
| specification. (Gregory R. Warnes) | |||||
| - Added calls to toXMLname() and fromXMLname() so that tags names are | |||||
| properly encoded. This resolves bug [ 548785 ] 'Error passing dict | |||||
| keys containing space.' (Gregory R. Warnes) | |||||
| - Added code to cgi encode contents of tags when they are not a | |||||
| recognized type. Fixes bug [ 549551 ] 'Error when passing | |||||
| non-standard types'. (Gregory R. Warnes) | |||||
| - Added __init__.py, so that SOAPpy can be used like a standard python | |||||
| module. (Gregory R. Warnes) | |||||
| VERSION 0.9.7 (6/27/01) | |||||
| ----------------------- | |||||
| - Fixed the unamed ordered parameters bug | |||||
| - Added the ability to specify a http_proxy | |||||
| - Added a patch provided by Tim MiddelKoop to allow printing of proxy objects | |||||
| - Added the contrib directory and included a medusa implementation of a | |||||
| SOAP.py server by Ng Pheng Siong | |||||
| VERSION 0.9.6 (6/08/01) | |||||
| ----------------------- | |||||
| - The date and time types now check their initial values when the type | |||||
| is created, not when the data is marshalled. | |||||
| - The date and time types are now parsed and returned as tuples (for | |||||
| multi-element types) or scalars (for single element types) in UTC and thus | |||||
| can represent the entire range of SOAP dates. | |||||
| - If an element doesn't have a type but has a name with a namespace, the | |||||
| name is tried as the type. | |||||
| - Untyped compound types with more than one element and all the elements | |||||
| the same name are turned into an array when parsing. | |||||
| - When parsing a structType, elements with the same name are placed in a | |||||
| list instead of saving just the last one. _getItemsAsList can be used to | |||||
| get an element of a structure as a list, whether there was one or many | |||||
| occurances of the item. | |||||
| - Added schemaNamespace, schemaNamespaceURI, and namespaceStyle | |||||
| configuration options. namespaceStyle takes one of 1999, 2000, or 2001, | |||||
| and sets typesNamespace, typesNamespaceURI, schemaNamespace, and | |||||
| schemaNamespaceURI. | |||||
| - Normalized the type class names, replacing Compound with compoundType, | |||||
| Struct with structType, Header with headerType, Body with bodyType, Array | |||||
| with arrayType, TypedArray with typedArrayType, Fault with faultType, and | |||||
| urType with anyType. | |||||
| - Attributes now appear on an element itself instead of the element's | |||||
| parent. For elements parsed to builtin python types, the attributes are | |||||
| stored in a dictionary keyed by the element's python id. The dictionary | |||||
| is in the Context object, can be returned from parseSOAP*, and can be | |||||
| returned from method calls if the returnAllAttrs configuration option | |||||
| is set. | |||||
| - isinstance is used to check for a class, so classes can be subtyped. | |||||
| - An encoding of None can be specified to not include encoding information. | |||||
| - Problems with the SOAPProxy URL are now reported when the SOAPProxy | |||||
| instance is created instead of when the first method call is made. | |||||
| - The Binary, Boolean and DateTime types have been removed in favor of | |||||
| binaryType, booleanType, and dateTimeType. | |||||
| VERSION 0.9.5 (5/16/01) | |||||
| ----------------------- | |||||
| - Should parse and build all 1999, 2000, 2001, and SOAP-ENC datatypes. | |||||
| - Initial handling of multi-dimensional, partial, and sparse arrays. | |||||
| - Supports SSL clients (if Python built with OpenSSL). | |||||
| - Supports SSL servers (if M2Crypto installed). | |||||
| - Applies defaults to SOAPproxy URLs (nice for command-line tools). | |||||
| - Added the _SOAPContext object, gives registered server functions more info | |||||
| about the current call. | |||||
| - Now assumes that any type that isn't in a schema could be a struct. | |||||
| - Added the Config object, now config options can be set globally or on an | |||||
| individual call level. | |||||
| - Deprecated the DateTime, Binary and Boolean types, should now | |||||
| use dateTimeType, binaryType and booleanType. | |||||
| - Includes N+I interop suite. | |||||
| - Various bug fixes and improvements. | |||||
| VERSION 0.9 (5/01/01) | |||||
| ----------------------- | |||||
| - The Envelope now just contains definitions for namespaces actually used | |||||
| (Builder) | |||||
| - Namespace definitions are inherited by children but not siblings (Builder) | |||||
| - Further improved multi-reference parsing -- it handles circular references | |||||
| (Parser) | |||||
| - Added support for building recursive and circular types using references | |||||
| (Builder) | |||||
| - More types | |||||
| - Proper handling of overflow and underflow integral and floating point | |||||
| types (Parser) | |||||
| - More interop | |||||
| - Various bug fixes and improvements | |||||
| VERSION 0.8.5 (4/25/01) | |||||
| ----------------------- | |||||
| - buildSOAP, SOAPProxy, SOAPServer now taking encoding argument | |||||
| - Much improved multi-referencing (Parser) | |||||
| - Added base64 and dateTime to interop suite | |||||
| - Various bug fixes | |||||
| VERSION 0.8 (4/23/01) | |||||
| ----------------------- | |||||
| - Added more types | |||||
| - Early multi-referencing support (Parser) | |||||
| - Reorganized the parser, much cleaner now | |||||
| - Preserve whitepsace in strings (per the standard) | |||||
| - Full XML attribute support (Parser/Builder) | |||||
| - Object (de)serialization now maintains element order | |||||
| - Fixed the zero-length array problem | |||||
| - Made indentation uniform (spaces not tabs) | |||||
| - Made Header and Body work more like real structs | |||||
| - Changed the parseSOAP api, now returns the body structure, | |||||
| instead of a list of body elements | |||||
| - Changed the soapaction and namespaces for the interop server | |||||
| - New silabclient options | |||||
| - Initial encoding support | |||||
| VERSION 0.7 (4/19/01) | |||||
| ----------------------- | |||||
| - Fixed a bug that caused nothing to work with Python 2.1 | |||||
| - Float work arounds for WIN32 (others?) | |||||
| - DateTime parsing for WIN32 | |||||
| - Beginnings of XML attribute support | |||||
| - Better interop | |||||
| VERSION 0.6 (4/18/01) | |||||
| ----------------------- | |||||
| - Fixed numerous bugs (dateTime, float precision, Response Element, null | |||||
| strings) | |||||
| - Added more types | |||||
| - Homogeneous typed arrays | |||||
| - Added support for more schemas | |||||
| - Early Header support and mustUnderstand and actor | |||||
| - Added interop suite | |||||
| - Passes validator | |||||
| - Interop greatly improved, passes all client tests for Frontier, | |||||
| SOAP::LITE. | |||||
| VERSION 0.5 (4/17/01) | |||||
| ----------------------- | |||||
| - Initial public release | |||||
| @@ -0,0 +1,495 @@ | |||||
| """ | |||||
| ################################################################################ | |||||
| # | |||||
| # SOAPpy - Cayce Ullman (cayce@actzero.com) | |||||
| # Brian Matthews (blm@actzero.com) | |||||
| # Gregory Warnes (Gregory.R.Warnes@Pfizer.com) | |||||
| # Christopher Blunck (blunck@gst.com) | |||||
| # | |||||
| ################################################################################ | |||||
| # Copyright (c) 2003, Pfizer | |||||
| # Copyright (c) 2001, Cayce Ullman. | |||||
| # Copyright (c) 2001, Brian Matthews. | |||||
| # | |||||
| # All rights reserved. | |||||
| # | |||||
| # Redistribution and use in source and binary forms, with or without | |||||
| # modification, are permitted provided that the following conditions are met: | |||||
| # Redistributions of source code must retain the above copyright notice, this | |||||
| # list of conditions and the following disclaimer. | |||||
| # | |||||
| # Redistributions in binary form must reproduce the above copyright notice, | |||||
| # this list of conditions and the following disclaimer in the documentation | |||||
| # and/or other materials provided with the distribution. | |||||
| # | |||||
| # Neither the name of actzero, inc. nor the names of its contributors may | |||||
| # be used to endorse or promote products derived from this software without | |||||
| # specific prior written permission. | |||||
| # | |||||
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||||
| # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||||
| # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||||
| # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | |||||
| # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||||
| # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||||
| # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||||
| # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||||
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||||
| # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
| # | |||||
| ################################################################################ | |||||
| """ | |||||
| ident = '$Id: Client.py,v 1.27 2005/02/21 20:27:09 warnes Exp $' | |||||
| from version import __version__ | |||||
| from __future__ import nested_scopes | |||||
| #import xml.sax | |||||
| import urllib | |||||
| from types import * | |||||
| import re | |||||
| import base64 | |||||
| # SOAPpy modules | |||||
| from Errors import * | |||||
| from Config import Config | |||||
| from Parser import parseSOAPRPC | |||||
| from SOAPBuilder import buildSOAP | |||||
| from Utilities import * | |||||
| from Types import faultType, simplify | |||||
| ################################################################################ | |||||
| # Client | |||||
| ################################################################################ | |||||
| def SOAPUserAgent(): | |||||
| return "SOAPpy " + __version__ + " (pywebsvcs.sf.net)" | |||||
| class SOAPAddress: | |||||
| def __init__(self, url, config = Config): | |||||
| proto, uri = urllib.splittype(url) | |||||
| # apply some defaults | |||||
| if uri[0:2] != '//': | |||||
| if proto != None: | |||||
| uri = proto + ':' + uri | |||||
| uri = '//' + uri | |||||
| proto = 'http' | |||||
| host, path = urllib.splithost(uri) | |||||
| try: | |||||
| int(host) | |||||
| host = 'localhost:' + host | |||||
| except: | |||||
| pass | |||||
| if not path: | |||||
| path = '/' | |||||
| if proto not in ('http', 'https', 'httpg'): | |||||
| raise IOError, "unsupported SOAP protocol" | |||||
| if proto == 'httpg' and not config.GSIclient: | |||||
| raise AttributeError, \ | |||||
| "GSI client not supported by this Python installation" | |||||
| if proto == 'https' and not config.SSLclient: | |||||
| raise AttributeError, \ | |||||
| "SSL client not supported by this Python installation" | |||||
| self.user,host = urllib.splituser(host) | |||||
| self.proto = proto | |||||
| self.host = host | |||||
| self.path = path | |||||
| def __str__(self): | |||||
| return "%(proto)s://%(host)s%(path)s" % self.__dict__ | |||||
| __repr__ = __str__ | |||||
| class HTTPTransport: | |||||
| def getNS(self, original_namespace, data): | |||||
| """Extract the (possibly extended) namespace from the returned | |||||
| SOAP message.""" | |||||
| if type(original_namespace) == StringType: | |||||
| pattern="xmlns:\w+=['\"](" + original_namespace + "[^'\"]*)['\"]" | |||||
| match = re.search(pattern, data) | |||||
| if match: | |||||
| return match.group(1) | |||||
| else: | |||||
| return original_namespace | |||||
| else: | |||||
| return original_namespace | |||||
| # Need a Timeout someday? | |||||
| def call(self, addr, data, namespace, soapaction = None, encoding = None, | |||||
| http_proxy = None, config = Config): | |||||
| import httplib | |||||
| if not isinstance(addr, SOAPAddress): | |||||
| addr = SOAPAddress(addr, config) | |||||
| # Build a request | |||||
| if http_proxy: | |||||
| real_addr = http_proxy | |||||
| real_path = addr.proto + "://" + addr.host + addr.path | |||||
| else: | |||||
| real_addr = addr.host | |||||
| real_path = addr.path | |||||
| if addr.proto == 'httpg': | |||||
| from pyGlobus.io import GSIHTTP | |||||
| r = GSIHTTP(real_addr, tcpAttr = config.tcpAttr) | |||||
| elif addr.proto == 'https': | |||||
| r = httplib.HTTPS(real_addr) | |||||
| else: | |||||
| r = httplib.HTTP(real_addr) | |||||
| r.putrequest("POST", real_path) | |||||
| r.putheader("Host", addr.host) | |||||
| r.putheader("User-agent", SOAPUserAgent()) | |||||
| t = 'text/xml'; | |||||
| if encoding != None: | |||||
| t += '; charset="%s"' % encoding | |||||
| r.putheader("Content-type", t) | |||||
| r.putheader("Content-length", str(len(data))) | |||||
| # if user is not a user:passwd format | |||||
| # we'll receive a failure from the server. . .I guess (??) | |||||
| if addr.user != None: | |||||
| val = base64.encodestring(addr.user) | |||||
| r.putheader('Authorization','Basic ' + val.replace('\012','')) | |||||
| # This fixes sending either "" or "None" | |||||
| if soapaction == None or len(soapaction) == 0: | |||||
| r.putheader("SOAPAction", "") | |||||
| else: | |||||
| r.putheader("SOAPAction", '"%s"' % soapaction) | |||||
| if config.dumpHeadersOut: | |||||
| s = 'Outgoing HTTP headers' | |||||
| debugHeader(s) | |||||
| print "POST %s %s" % (real_path, r._http_vsn_str) | |||||
| print "Host:", addr.host | |||||
| print "User-agent: SOAPpy " + __version__ + " (http://pywebsvcs.sf.net)" | |||||
| print "Content-type:", t | |||||
| print "Content-length:", len(data) | |||||
| print 'SOAPAction: "%s"' % soapaction | |||||
| debugFooter(s) | |||||
| r.endheaders() | |||||
| if config.dumpSOAPOut: | |||||
| s = 'Outgoing SOAP' | |||||
| debugHeader(s) | |||||
| print data, | |||||
| if data[-1] != '\n': | |||||
| debugFooter(s) | |||||
| # send the payload | |||||
| r.send(data) | |||||
| # read response line | |||||
| code, msg, headers = r.getreply() | |||||
| if headers: | |||||
| content_type = headers.get("content-type","text/xml") | |||||
| content_length = headers.get("Content-length") | |||||
| else: | |||||
| content_type=None | |||||
| content_length=None | |||||
| # work around OC4J bug which does '<len>, <len>' for some reaason | |||||
| if content_length: | |||||
| comma=content_length.find(',') | |||||
| if comma>0: | |||||
| content_length = content_length[:comma] | |||||
| # attempt to extract integer message size | |||||
| try: | |||||
| message_len = int(content_length) | |||||
| except: | |||||
| message_len = -1 | |||||
| if message_len < 0: | |||||
| # Content-Length missing or invalid; just read the whole socket | |||||
| # This won't work with HTTP/1.1 chunked encoding | |||||
| data = r.getfile().read() | |||||
| message_len = len(data) | |||||
| else: | |||||
| data = r.getfile().read(message_len) | |||||
| if(config.debug): | |||||
| print "code=",code | |||||
| print "msg=", msg | |||||
| print "headers=", headers | |||||
| print "content-type=", content_type | |||||
| print "data=", data | |||||
| if config.dumpHeadersIn: | |||||
| s = 'Incoming HTTP headers' | |||||
| debugHeader(s) | |||||
| if headers.headers: | |||||
| print "HTTP/1.? %d %s" % (code, msg) | |||||
| print "\n".join(map (lambda x: x.strip(), headers.headers)) | |||||
| else: | |||||
| print "HTTP/0.9 %d %s" % (code, msg) | |||||
| debugFooter(s) | |||||
| def startswith(string, val): | |||||
| return string[0:len(val)] == val | |||||
| if code == 500 and not \ | |||||
| ( startswith(content_type, "text/xml") and message_len > 0 ): | |||||
| raise HTTPError(code, msg) | |||||
| if config.dumpSOAPIn: | |||||
| s = 'Incoming SOAP' | |||||
| debugHeader(s) | |||||
| print data, | |||||
| if (len(data)>0) and (data[-1] != '\n'): | |||||
| debugFooter(s) | |||||
| if code not in (200, 500): | |||||
| raise HTTPError(code, msg) | |||||
| # get the new namespace | |||||
| if namespace is None: | |||||
| new_ns = None | |||||
| else: | |||||
| new_ns = self.getNS(namespace, data) | |||||
| # return response payload | |||||
| return data, new_ns | |||||
| ################################################################################ | |||||
| # SOAP Proxy | |||||
| ################################################################################ | |||||
| class SOAPProxy: | |||||
| def __init__(self, proxy, namespace = None, soapaction = None, | |||||
| header = None, methodattrs = None, transport = HTTPTransport, | |||||
| encoding = 'UTF-8', throw_faults = 1, unwrap_results = None, | |||||
| http_proxy=None, config = Config, noroot = 0, | |||||
| simplify_objects=None): | |||||
| # Test the encoding, raising an exception if it's not known | |||||
| if encoding != None: | |||||
| ''.encode(encoding) | |||||
| # get default values for unwrap_results and simplify_objects | |||||
| # from config | |||||
| if unwrap_results is None: | |||||
| self.unwrap_results=config.unwrap_results | |||||
| else: | |||||
| self.unwrap_results=unwrap_results | |||||
| if simplify_objects is None: | |||||
| self.simplify_objects=config.simplify_objects | |||||
| else: | |||||
| self.simplify_objects=simplify_objects | |||||
| self.proxy = SOAPAddress(proxy, config) | |||||
| self.namespace = namespace | |||||
| self.soapaction = soapaction | |||||
| self.header = header | |||||
| self.methodattrs = methodattrs | |||||
| self.transport = transport() | |||||
| self.encoding = encoding | |||||
| self.throw_faults = throw_faults | |||||
| self.http_proxy = http_proxy | |||||
| self.config = config | |||||
| self.noroot = noroot | |||||
| # GSI Additions | |||||
| if hasattr(config, "channel_mode") and \ | |||||
| hasattr(config, "delegation_mode"): | |||||
| self.channel_mode = config.channel_mode | |||||
| self.delegation_mode = config.delegation_mode | |||||
| #end GSI Additions | |||||
| def invoke(self, method, args): | |||||
| return self.__call(method, args, {}) | |||||
| def __call(self, name, args, kw, ns = None, sa = None, hd = None, | |||||
| ma = None): | |||||
| ns = ns or self.namespace | |||||
| ma = ma or self.methodattrs | |||||
| if sa: # Get soapaction | |||||
| if type(sa) == TupleType: | |||||
| sa = sa[0] | |||||
| else: | |||||
| if self.soapaction: | |||||
| sa = self.soapaction | |||||
| else: | |||||
| sa = name | |||||
| if hd: # Get header | |||||
| if type(hd) == TupleType: | |||||
| hd = hd[0] | |||||
| else: | |||||
| hd = self.header | |||||
| hd = hd or self.header | |||||
| if ma: # Get methodattrs | |||||
| if type(ma) == TupleType: ma = ma[0] | |||||
| else: | |||||
| ma = self.methodattrs | |||||
| ma = ma or self.methodattrs | |||||
| m = buildSOAP(args = args, kw = kw, method = name, namespace = ns, | |||||
| header = hd, methodattrs = ma, encoding = self.encoding, | |||||
| config = self.config, noroot = self.noroot) | |||||
| call_retry = 0 | |||||
| try: | |||||
| r, self.namespace = self.transport.call(self.proxy, m, ns, sa, | |||||
| encoding = self.encoding, | |||||
| http_proxy = self.http_proxy, | |||||
| config = self.config) | |||||
| except Exception, ex: | |||||
| # | |||||
| # Call failed. | |||||
| # | |||||
| # See if we have a fault handling vector installed in our | |||||
| # config. If we do, invoke it. If it returns a true value, | |||||
| # retry the call. | |||||
| # | |||||
| # In any circumstance other than the fault handler returning | |||||
| # true, reraise the exception. This keeps the semantics of this | |||||
| # code the same as without the faultHandler code. | |||||
| # | |||||
| if hasattr(self.config, "faultHandler"): | |||||
| if callable(self.config.faultHandler): | |||||
| call_retry = self.config.faultHandler(self.proxy, ex) | |||||
| if not call_retry: | |||||
| raise | |||||
| else: | |||||
| raise | |||||
| else: | |||||
| raise | |||||
| if call_retry: | |||||
| r, self.namespace = self.transport.call(self.proxy, m, ns, sa, | |||||
| encoding = self.encoding, | |||||
| http_proxy = self.http_proxy, | |||||
| config = self.config) | |||||
| p, attrs = parseSOAPRPC(r, attrs = 1) | |||||
| try: | |||||
| throw_struct = self.throw_faults and \ | |||||
| isinstance (p, faultType) | |||||
| except: | |||||
| throw_struct = 0 | |||||
| if throw_struct: | |||||
| if Config.debug: | |||||
| print p | |||||
| raise p | |||||
| # If unwrap_results=1 and there is only element in the struct, | |||||
| # SOAPProxy will assume that this element is the result | |||||
| # and return it rather than the struct containing it. | |||||
| # Otherwise SOAPproxy will return the struct with all the | |||||
| # elements as attributes. | |||||
| if self.unwrap_results: | |||||
| try: | |||||
| count = 0 | |||||
| for i in p.__dict__.keys(): | |||||
| if i[0] != "_": # don't count the private stuff | |||||
| count += 1 | |||||
| t = getattr(p, i) | |||||
| if count == 1: # Only one piece of data, bubble it up | |||||
| p = t | |||||
| except: | |||||
| pass | |||||
| # Automatically simplfy SOAP complex types into the | |||||
| # corresponding python types. (structType --> dict, | |||||
| # arrayType --> array, etc.) | |||||
| if self.simplify_objects: | |||||
| p = simplify(p) | |||||
| if self.config.returnAllAttrs: | |||||
| return p, attrs | |||||
| return p | |||||
| def _callWithBody(self, body): | |||||
| return self.__call(None, body, {}) | |||||
| def __getattr__(self, name): # hook to catch method calls | |||||
| if name == '__del__': | |||||
| raise AttributeError, name | |||||
| return self.__Method(self.__call, name, config = self.config) | |||||
| # To handle attribute wierdness | |||||
| class __Method: | |||||
| # Some magic to bind a SOAP method to an RPC server. | |||||
| # Supports "nested" methods (e.g. examples.getStateName) -- concept | |||||
| # borrowed from xmlrpc/soaplib -- www.pythonware.com | |||||
| # Altered (improved?) to let you inline namespaces on a per call | |||||
| # basis ala SOAP::LITE -- www.soaplite.com | |||||
| def __init__(self, call, name, ns = None, sa = None, hd = None, | |||||
| ma = None, config = Config): | |||||
| self.__call = call | |||||
| self.__name = name | |||||
| self.__ns = ns | |||||
| self.__sa = sa | |||||
| self.__hd = hd | |||||
| self.__ma = ma | |||||
| self.__config = config | |||||
| return | |||||
| def __call__(self, *args, **kw): | |||||
| if self.__name[0] == "_": | |||||
| if self.__name in ["__repr__","__str__"]: | |||||
| return self.__repr__() | |||||
| else: | |||||
| return self.__f_call(*args, **kw) | |||||
| else: | |||||
| return self.__r_call(*args, **kw) | |||||
| def __getattr__(self, name): | |||||
| if name == '__del__': | |||||
| raise AttributeError, name | |||||
| if self.__name[0] == "_": | |||||
| # Don't nest method if it is a directive | |||||
| return self.__class__(self.__call, name, self.__ns, | |||||
| self.__sa, self.__hd, self.__ma) | |||||
| return self.__class__(self.__call, "%s.%s" % (self.__name, name), | |||||
| self.__ns, self.__sa, self.__hd, self.__ma) | |||||
| def __f_call(self, *args, **kw): | |||||
| if self.__name == "_ns": self.__ns = args | |||||
| elif self.__name == "_sa": self.__sa = args | |||||
| elif self.__name == "_hd": self.__hd = args | |||||
| elif self.__name == "_ma": self.__ma = args | |||||
| return self | |||||
| def __r_call(self, *args, **kw): | |||||
| return self.__call(self.__name, args, kw, self.__ns, self.__sa, | |||||
| self.__hd, self.__ma) | |||||
| def __repr__(self): | |||||
| return "<%s at %d>" % (self.__class__, id(self)) | |||||
| @@ -0,0 +1,202 @@ | |||||
| """ | |||||
| ################################################################################ | |||||
| # Copyright (c) 2003, Pfizer | |||||
| # Copyright (c) 2001, Cayce Ullman. | |||||
| # Copyright (c) 2001, Brian Matthews. | |||||
| # | |||||
| # All rights reserved. | |||||
| # | |||||
| # Redistribution and use in source and binary forms, with or without | |||||
| # modification, are permitted provided that the following conditions are met: | |||||
| # Redistributions of source code must retain the above copyright notice, this | |||||
| # list of conditions and the following disclaimer. | |||||
| # | |||||
| # Redistributions in binary form must reproduce the above copyright notice, | |||||
| # this list of conditions and the following disclaimer in the documentation | |||||
| # and/or other materials provided with the distribution. | |||||
| # | |||||
| # Neither the name of actzero, inc. nor the names of its contributors may | |||||
| # be used to endorse or promote products derived from this software without | |||||
| # specific prior written permission. | |||||
| # | |||||
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||||
| # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||||
| # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||||
| # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | |||||
| # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||||
| # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||||
| # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||||
| # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||||
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||||
| # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
| # | |||||
| ################################################################################ | |||||
| """ | |||||
| ident = '$Id: Config.py,v 1.9 2004/01/31 04:20:05 warnes Exp $' | |||||
| from version import __version__ | |||||
| import copy, socket | |||||
| from types import * | |||||
| from NS import NS | |||||
| ################################################################################ | |||||
| # Configuration class | |||||
| ################################################################################ | |||||
| class SOAPConfig: | |||||
| __readonly = ('SSLserver', 'SSLclient', 'GSIserver', 'GSIclient') | |||||
| def __init__(self, config = None, **kw): | |||||
| d = self.__dict__ | |||||
| if config: | |||||
| if not isinstance(config, SOAPConfig): | |||||
| raise AttributeError, \ | |||||
| "initializer must be SOAPConfig instance" | |||||
| s = config.__dict__ | |||||
| for k, v in s.items(): | |||||
| if k[0] != '_': | |||||
| d[k] = v | |||||
| else: | |||||
| # Setting debug also sets returnFaultInfo, | |||||
| # dumpHeadersIn, dumpHeadersOut, dumpSOAPIn, and dumpSOAPOut | |||||
| self.debug = 0 | |||||
| self.dumpFaultInfo = 1 | |||||
| # Setting namespaceStyle sets typesNamespace, typesNamespaceURI, | |||||
| # schemaNamespace, and schemaNamespaceURI | |||||
| self.namespaceStyle = '1999' | |||||
| self.strictNamespaces = 0 | |||||
| self.typed = 1 | |||||
| self.buildWithNamespacePrefix = 1 | |||||
| self.returnAllAttrs = 0 | |||||
| # Strict checking of range for floats and doubles | |||||
| self.strict_range = 0 | |||||
| # Default encoding for dictionary keys | |||||
| self.dict_encoding = 'ascii' | |||||
| # New argument name handling mechanism. See | |||||
| # README.MethodParameterNaming for details | |||||
| self.specialArgs = 1 | |||||
| # If unwrap_results=1 and there is only element in the struct, | |||||
| # SOAPProxy will assume that this element is the result | |||||
| # and return it rather than the struct containing it. | |||||
| # Otherwise SOAPproxy will return the struct with all the | |||||
| # elements as attributes. | |||||
| self.unwrap_results = 1 | |||||
| # Automatically convert SOAP complex types, and | |||||
| # (recursively) public contents into the corresponding | |||||
| # python types. (Private subobjects have names that start | |||||
| # with '_'.) | |||||
| # | |||||
| # Conversions: | |||||
| # - faultType --> raise python exception | |||||
| # - arrayType --> array | |||||
| # - compoundType --> dictionary | |||||
| # | |||||
| self.simplify_objects = 0 | |||||
| # Per-class authorization method. If this is set, before | |||||
| # calling a any class method, the specified authorization | |||||
| # method will be called. If it returns 1, the method call | |||||
| # will proceed, otherwise the call will throw with an | |||||
| # authorization error. | |||||
| self.authMethod = None | |||||
| # Globus Support if pyGlobus.io available | |||||
| try: | |||||
| from pyGlobus import io; | |||||
| d['GSIserver'] = 1 | |||||
| d['GSIclient'] = 1 | |||||
| except: | |||||
| d['GSIserver'] = 0 | |||||
| d['GSIclient'] = 0 | |||||
| # Server SSL support if M2Crypto.SSL available | |||||
| try: | |||||
| from M2Crypto import SSL | |||||
| d['SSLserver'] = 1 | |||||
| except: | |||||
| d['SSLserver'] = 0 | |||||
| # Client SSL support if socket.ssl available | |||||
| try: | |||||
| from socket import ssl | |||||
| d['SSLclient'] = 1 | |||||
| except: | |||||
| d['SSLclient'] = 0 | |||||
| for k, v in kw.items(): | |||||
| if k[0] != '_': | |||||
| setattr(self, k, v) | |||||
| def __setattr__(self, name, value): | |||||
| if name in self.__readonly: | |||||
| raise AttributeError, "readonly configuration setting" | |||||
| d = self.__dict__ | |||||
| if name in ('typesNamespace', 'typesNamespaceURI', | |||||
| 'schemaNamespace', 'schemaNamespaceURI'): | |||||
| if name[-3:] == 'URI': | |||||
| base, uri = name[:-3], 1 | |||||
| else: | |||||
| base, uri = name, 0 | |||||
| if type(value) == StringType: | |||||
| if NS.NSMAP.has_key(value): | |||||
| n = (value, NS.NSMAP[value]) | |||||
| elif NS.NSMAP_R.has_key(value): | |||||
| n = (NS.NSMAP_R[value], value) | |||||
| else: | |||||
| raise AttributeError, "unknown namespace" | |||||
| elif type(value) in (ListType, TupleType): | |||||
| if uri: | |||||
| n = (value[1], value[0]) | |||||
| else: | |||||
| n = (value[0], value[1]) | |||||
| else: | |||||
| raise AttributeError, "unknown namespace type" | |||||
| d[base], d[base + 'URI'] = n | |||||
| try: | |||||
| d['namespaceStyle'] = \ | |||||
| NS.STMAP_R[(d['typesNamespace'], d['schemaNamespace'])] | |||||
| except: | |||||
| d['namespaceStyle'] = '' | |||||
| elif name == 'namespaceStyle': | |||||
| value = str(value) | |||||
| if not NS.STMAP.has_key(value): | |||||
| raise AttributeError, "unknown namespace style" | |||||
| d[name] = value | |||||
| n = d['typesNamespace'] = NS.STMAP[value][0] | |||||
| d['typesNamespaceURI'] = NS.NSMAP[n] | |||||
| n = d['schemaNamespace'] = NS.STMAP[value][1] | |||||
| d['schemaNamespaceURI'] = NS.NSMAP[n] | |||||
| elif name == 'debug': | |||||
| d[name] = \ | |||||
| d['returnFaultInfo'] = \ | |||||
| d['dumpHeadersIn'] = \ | |||||
| d['dumpHeadersOut'] = \ | |||||
| d['dumpSOAPIn'] = \ | |||||
| d['dumpSOAPOut'] = value | |||||
| else: | |||||
| d[name] = value | |||||
| Config = SOAPConfig() | |||||
| @@ -0,0 +1,79 @@ | |||||
| """ | |||||
| ################################################################################ | |||||
| # | |||||
| # SOAPpy - Cayce Ullman (cayce@actzero.com) | |||||
| # Brian Matthews (blm@actzero.com) | |||||
| # Gregory Warnes (Gregory.R.Warnes@Pfizer.com) | |||||
| # Christopher Blunck (blunck@gst.com) | |||||
| # | |||||
| ################################################################################ | |||||
| # Copyright (c) 2003, Pfizer | |||||
| # Copyright (c) 2001, Cayce Ullman. | |||||
| # Copyright (c) 2001, Brian Matthews. | |||||
| # | |||||
| # All rights reserved. | |||||
| # | |||||
| # Redistribution and use in source and binary forms, with or without | |||||
| # modification, are permitted provided that the following conditions are met: | |||||
| # Redistributions of source code must retain the above copyright notice, this | |||||
| # list of conditions and the following disclaimer. | |||||
| # | |||||
| # Redistributions in binary form must reproduce the above copyright notice, | |||||
| # this list of conditions and the following disclaimer in the documentation | |||||
| # and/or other materials provided with the distribution. | |||||
| # | |||||
| # Neither the name of actzero, inc. nor the names of its contributors may | |||||
| # be used to endorse or promote products derived from this software without | |||||
| # specific prior written permission. | |||||
| # | |||||
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||||
| # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||||
| # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||||
| # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | |||||
| # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||||
| # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||||
| # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||||
| # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||||
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||||
| # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
| # | |||||
| ################################################################################ | |||||
| """ | |||||
| ident = '$Id: Errors.py,v 1.5 2005/02/15 16:32:22 warnes Exp $' | |||||
| from version import __version__ | |||||
| import exceptions | |||||
| ################################################################################ | |||||
| # Exceptions | |||||
| ################################################################################ | |||||
| class Error(exceptions.Exception): | |||||
| def __init__(self, msg): | |||||
| self.msg = msg | |||||
| def __str__(self): | |||||
| return "<Error : %s>" % self.msg | |||||
| __repr__ = __str__ | |||||
| def __call__(self): | |||||
| return (msg,) | |||||
| class RecursionError(Error): | |||||
| pass | |||||
| class UnknownTypeError(Error): | |||||
| pass | |||||
| class HTTPError(Error): | |||||
| # indicates an HTTP protocol error | |||||
| def __init__(self, code, msg): | |||||
| self.code = code | |||||
| self.msg = msg | |||||
| def __str__(self): | |||||
| return "<HTTPError %s %s>" % (self.code, self.msg) | |||||
| __repr__ = __str__ | |||||
| def __call___(self): | |||||
| return (self.code, self.msg, ) | |||||
| class UnderflowError(exceptions.ArithmeticError): | |||||
| pass | |||||
| @@ -0,0 +1,143 @@ | |||||
| """ | |||||
| GSIServer - Contributed by Ivan R. Judson <judson@mcs.anl.gov> | |||||
| ################################################################################ | |||||
| # | |||||
| # SOAPpy - Cayce Ullman (cayce@actzero.com) | |||||
| # Brian Matthews (blm@actzero.com) | |||||
| # Gregory Warnes (Gregory.R.Warnes@Pfizer.com) | |||||
| # Christopher Blunck (blunck@gst.com) | |||||
| # | |||||
| ################################################################################ | |||||
| # Copyright (c) 2003, Pfizer | |||||
| # Copyright (c) 2001, Cayce Ullman. | |||||
| # Copyright (c) 2001, Brian Matthews. | |||||
| # | |||||
| # All rights reserved. | |||||
| # | |||||
| # Redistribution and use in source and binary forms, with or without | |||||
| # modification, are permitted provided that the following conditions are met: | |||||
| # Redistributions of source code must retain the above copyright notice, this | |||||
| # list of conditions and the following disclaimer. | |||||
| # | |||||
| # Redistributions in binary form must reproduce the above copyright notice, | |||||
| # this list of conditions and the following disclaimer in the documentation | |||||
| # and/or other materials provided with the distribution. | |||||
| # | |||||
| # Neither the name of actzero, inc. nor the names of its contributors may | |||||
| # be used to endorse or promote products derived from this software without | |||||
| # specific prior written permission. | |||||
| # | |||||
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||||
| # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||||
| # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||||
| # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | |||||
| # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||||
| # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||||
| # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||||
| # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||||
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||||
| # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
| # | |||||
| ################################################################################ | |||||
| """ | |||||
| ident = '$Id: GSIServer.py,v 1.5 2005/02/15 16:32:22 warnes Exp $' | |||||
| from version import __version__ | |||||
| from __future__ import nested_scopes | |||||
| #import xml.sax | |||||
| import re | |||||
| import socket | |||||
| import sys | |||||
| import SocketServer | |||||
| from types import * | |||||
| import BaseHTTPServer | |||||
| # SOAPpy modules | |||||
| from Parser import parseSOAPRPC | |||||
| from Config import SOAPConfig | |||||
| from Types import faultType, voidType, simplify | |||||
| from NS import NS | |||||
| from SOAPBuilder import buildSOAP | |||||
| from Utilities import debugHeader, debugFooter | |||||
| try: from M2Crypto import SSL | |||||
| except: pass | |||||
| ##### | |||||
| from Server import * | |||||
| from pyGlobus.io import GSITCPSocketServer, ThreadingGSITCPSocketServer | |||||
| from pyGlobus import ioc | |||||
| def GSIConfig(): | |||||
| config = SOAPConfig() | |||||
| config.channel_mode = ioc.GLOBUS_IO_SECURE_CHANNEL_MODE_GSI_WRAP | |||||
| config.delegation_mode = ioc.GLOBUS_IO_SECURE_DELEGATION_MODE_FULL_PROXY | |||||
| config.tcpAttr = None | |||||
| config.authMethod = "_authorize" | |||||
| return config | |||||
| Config = GSIConfig() | |||||
| class GSISOAPServer(GSITCPSocketServer, SOAPServerBase): | |||||
| def __init__(self, addr = ('localhost', 8000), | |||||
| RequestHandler = SOAPRequestHandler, log = 0, | |||||
| encoding = 'UTF-8', config = Config, namespace = None): | |||||
| # Test the encoding, raising an exception if it's not known | |||||
| if encoding != None: | |||||
| ''.encode(encoding) | |||||
| self.namespace = namespace | |||||
| self.objmap = {} | |||||
| self.funcmap = {} | |||||
| self.encoding = encoding | |||||
| self.config = config | |||||
| self.log = log | |||||
| self.allow_reuse_address= 1 | |||||
| GSITCPSocketServer.__init__(self, addr, RequestHandler, | |||||
| self.config.channel_mode, | |||||
| self.config.delegation_mode, | |||||
| tcpAttr = self.config.tcpAttr) | |||||
| def get_request(self): | |||||
| sock, addr = GSITCPSocketServer.get_request(self) | |||||
| return sock, addr | |||||
| class ThreadingGSISOAPServer(ThreadingGSITCPSocketServer, SOAPServerBase): | |||||
| def __init__(self, addr = ('localhost', 8000), | |||||
| RequestHandler = SOAPRequestHandler, log = 0, | |||||
| encoding = 'UTF-8', config = Config, namespace = None): | |||||
| # Test the encoding, raising an exception if it's not known | |||||
| if encoding != None: | |||||
| ''.encode(encoding) | |||||
| self.namespace = namespace | |||||
| self.objmap = {} | |||||
| self.funcmap = {} | |||||
| self.encoding = encoding | |||||
| self.config = config | |||||
| self.log = log | |||||
| self.allow_reuse_address= 1 | |||||
| ThreadingGSITCPSocketServer.__init__(self, addr, RequestHandler, | |||||
| self.config.channel_mode, | |||||
| self.config.delegation_mode, | |||||
| tcpAttr = self.config.tcpAttr) | |||||
| def get_request(self): | |||||
| sock, addr = ThreadingGSITCPSocketServer.get_request(self) | |||||
| return sock, addr | |||||
| @@ -0,0 +1,104 @@ | |||||
| """ | |||||
| ################################################################################ | |||||
| # | |||||
| # SOAPpy - Cayce Ullman (cayce@actzero.com) | |||||
| # Brian Matthews (blm@actzero.com) | |||||
| # Gregory Warnes (Gregory.R.Warnes@Pfizer.com) | |||||
| # Christopher Blunck (blunck@gst.com) | |||||
| # | |||||
| ################################################################################ | |||||
| # Copyright (c) 2003, Pfizer | |||||
| # Copyright (c) 2001, Cayce Ullman. | |||||
| # Copyright (c) 2001, Brian Matthews. | |||||
| # | |||||
| # All rights reserved. | |||||
| # | |||||
| # Redistribution and use in source and binary forms, with or without | |||||
| # modification, are permitted provided that the following conditions are met: | |||||
| # Redistributions of source code must retain the above copyright notice, this | |||||
| # list of conditions and the following disclaimer. | |||||
| # | |||||
| # Redistributions in binary form must reproduce the above copyright notice, | |||||
| # this list of conditions and the following disclaimer in the documentation | |||||
| # and/or other materials provided with the distribution. | |||||
| # | |||||
| # Neither the name of actzero, inc. nor the names of its contributors may | |||||
| # be used to endorse or promote products derived from this software without | |||||
| # specific prior written permission. | |||||
| # | |||||
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||||
| # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||||
| # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||||
| # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | |||||
| # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||||
| # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||||
| # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||||
| # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||||
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||||
| # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
| # | |||||
| ################################################################################ | |||||
| """ | |||||
| from __future__ import nested_scopes | |||||
| ident = '$Id: NS.py,v 1.4 2005/02/15 16:32:22 warnes Exp $' | |||||
| from version import __version__ | |||||
| ############################################################################## | |||||
| # Namespace Class | |||||
| ################################################################################ | |||||
| def invertDict(dict): | |||||
| d = {} | |||||
| for k, v in dict.items(): | |||||
| d[v] = k | |||||
| return d | |||||
| class NS: | |||||
| XML = "http://www.w3.org/XML/1998/namespace" | |||||
| ENV = "http://schemas.xmlsoap.org/soap/envelope/" | |||||
| ENC = "http://schemas.xmlsoap.org/soap/encoding/" | |||||
| XSD = "http://www.w3.org/1999/XMLSchema" | |||||
| XSD2 = "http://www.w3.org/2000/10/XMLSchema" | |||||
| XSD3 = "http://www.w3.org/2001/XMLSchema" | |||||
| XSD_L = [XSD, XSD2, XSD3] | |||||
| EXSD_L= [ENC, XSD, XSD2, XSD3] | |||||
| XSI = "http://www.w3.org/1999/XMLSchema-instance" | |||||
| XSI2 = "http://www.w3.org/2000/10/XMLSchema-instance" | |||||
| XSI3 = "http://www.w3.org/2001/XMLSchema-instance" | |||||
| XSI_L = [XSI, XSI2, XSI3] | |||||
| URN = "http://soapinterop.org/xsd" | |||||
| # For generated messages | |||||
| XML_T = "xml" | |||||
| ENV_T = "SOAP-ENV" | |||||
| ENC_T = "SOAP-ENC" | |||||
| XSD_T = "xsd" | |||||
| XSD2_T= "xsd2" | |||||
| XSD3_T= "xsd3" | |||||
| XSI_T = "xsi" | |||||
| XSI2_T= "xsi2" | |||||
| XSI3_T= "xsi3" | |||||
| URN_T = "urn" | |||||
| NSMAP = {ENV_T: ENV, ENC_T: ENC, XSD_T: XSD, XSD2_T: XSD2, | |||||
| XSD3_T: XSD3, XSI_T: XSI, XSI2_T: XSI2, XSI3_T: XSI3, | |||||
| URN_T: URN} | |||||
| NSMAP_R = invertDict(NSMAP) | |||||
| STMAP = {'1999': (XSD_T, XSI_T), '2000': (XSD2_T, XSI2_T), | |||||
| '2001': (XSD3_T, XSI3_T)} | |||||
| STMAP_R = invertDict(STMAP) | |||||
| def __init__(self): | |||||
| raise Error, "Don't instantiate this" | |||||
| @@ -0,0 +1,40 @@ | |||||
| """This file is here for backward compatibility with versions <= 0.9.9 | |||||
| Delete when 1.0.0 is released! | |||||
| """ | |||||
| ident = '$Id: SOAP.py,v 1.38 2004/01/31 04:20:06 warnes Exp $' | |||||
| from version import __version__ | |||||
| from Client import * | |||||
| from Config import * | |||||
| from Errors import * | |||||
| from NS import * | |||||
| from Parser import * | |||||
| from SOAPBuilder import * | |||||
| from Server import * | |||||
| from Types import * | |||||
| from Utilities import * | |||||
| import wstools | |||||
| import WSDL | |||||
| from warnings import warn | |||||
| warn(""" | |||||
| The sub-module SOAPpy.SOAP is deprecated and is only | |||||
| provided for short-term backward compatibility. Objects are now | |||||
| available directly within the SOAPpy module. Thus, instead of | |||||
| from SOAPpy import SOAP | |||||
| ... | |||||
| SOAP.SOAPProxy(...) | |||||
| use | |||||
| from SOAPpy import SOAPProxy | |||||
| ... | |||||
| SOAPProxy(...) | |||||
| instead. | |||||
| """, DeprecationWarning) | |||||
| @@ -0,0 +1,634 @@ | |||||
| """ | |||||
| ################################################################################ | |||||
| # Copyright (c) 2003, Pfizer | |||||
| # Copyright (c) 2001, Cayce Ullman. | |||||
| # Copyright (c) 2001, Brian Matthews. | |||||
| # | |||||
| # All rights reserved. | |||||
| # | |||||
| # Redistribution and use in source and binary forms, with or without | |||||
| # modification, are permitted provided that the following conditions are met: | |||||
| # Redistributions of source code must retain the above copyright notice, this | |||||
| # list of conditions and the following disclaimer. | |||||
| # | |||||
| # Redistributions in binary form must reproduce the above copyright notice, | |||||
| # this list of conditions and the following disclaimer in the documentation | |||||
| # and/or other materials provided with the distribution. | |||||
| # | |||||
| # Neither the name of actzero, inc. nor the names of its contributors may | |||||
| # be used to endorse or promote products derived from this software without | |||||
| # specific prior written permission. | |||||
| # | |||||
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||||
| # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||||
| # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||||
| # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | |||||
| # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||||
| # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||||
| # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||||
| # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||||
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||||
| # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
| # | |||||
| ################################################################################ | |||||
| """ | |||||
| ident = '$Id: SOAPBuilder.py,v 1.27 2005/02/21 20:24:13 warnes Exp $' | |||||
| from version import __version__ | |||||
| import cgi | |||||
| import copy | |||||
| from wstools.XMLname import toXMLname, fromXMLname | |||||
| import fpconst | |||||
| # SOAPpy modules | |||||
| from Config import Config | |||||
| from NS import NS | |||||
| from Types import * | |||||
| # Test whether this Python version has Types.BooleanType | |||||
| # If it doesn't have it, then False and True are serialized as integers | |||||
| try: | |||||
| BooleanType | |||||
| pythonHasBooleanType = 1 | |||||
| except NameError: | |||||
| pythonHasBooleanType = 0 | |||||
| ################################################################################ | |||||
| # SOAP Builder | |||||
| ################################################################################ | |||||
| class SOAPBuilder: | |||||
| _xml_top = '<?xml version="1.0"?>\n' | |||||
| _xml_enc_top = '<?xml version="1.0" encoding="%s"?>\n' | |||||
| _env_top = ( '%(ENV_T)s:Envelope\n' + \ | |||||
| ' %(ENV_T)s:encodingStyle="%(ENC)s"\n' ) % \ | |||||
| NS.__dict__ | |||||
| _env_bot = '</%(ENV_T)s:Envelope>\n' % NS.__dict__ | |||||
| # Namespaces potentially defined in the Envelope tag. | |||||
| _env_ns = {NS.ENC: NS.ENC_T, NS.ENV: NS.ENV_T, | |||||
| NS.XSD: NS.XSD_T, NS.XSD2: NS.XSD2_T, NS.XSD3: NS.XSD3_T, | |||||
| NS.XSI: NS.XSI_T, NS.XSI2: NS.XSI2_T, NS.XSI3: NS.XSI3_T} | |||||
| def __init__(self, args = (), kw = {}, method = None, namespace = None, | |||||
| header = None, methodattrs = None, envelope = 1, encoding = 'UTF-8', | |||||
| use_refs = 0, config = Config, noroot = 0): | |||||
| # Test the encoding, raising an exception if it's not known | |||||
| if encoding != None: | |||||
| ''.encode(encoding) | |||||
| self.args = args | |||||
| self.kw = kw | |||||
| self.envelope = envelope | |||||
| self.encoding = encoding | |||||
| self.method = method | |||||
| self.namespace = namespace | |||||
| self.header = header | |||||
| self.methodattrs= methodattrs | |||||
| self.use_refs = use_refs | |||||
| self.config = config | |||||
| self.out = [] | |||||
| self.tcounter = 0 | |||||
| self.ncounter = 1 | |||||
| self.icounter = 1 | |||||
| self.envns = {} | |||||
| self.ids = {} | |||||
| self.depth = 0 | |||||
| self.multirefs = [] | |||||
| self.multis = 0 | |||||
| self.body = not isinstance(args, bodyType) | |||||
| self.noroot = noroot | |||||
| def build(self): | |||||
| if Config.debug: print "In build." | |||||
| ns_map = {} | |||||
| # Cache whether typing is on or not | |||||
| typed = self.config.typed | |||||
| if self.header: | |||||
| # Create a header. | |||||
| self.dump(self.header, "Header", typed = typed) | |||||
| #self.header = None # Wipe it out so no one is using it. | |||||
| if self.body: | |||||
| # Call genns to record that we've used SOAP-ENV. | |||||
| self.depth += 1 | |||||
| body_ns = self.genns(ns_map, NS.ENV)[0] | |||||
| self.out.append("<%sBody>\n" % body_ns) | |||||
| if self.method: | |||||
| # Save the NS map so that it can be restored when we | |||||
| # fall out of the scope of the method definition | |||||
| save_ns_map = ns_map.copy() | |||||
| self.depth += 1 | |||||
| a = '' | |||||
| if self.methodattrs: | |||||
| for (k, v) in self.methodattrs.items(): | |||||
| a += ' %s="%s"' % (k, v) | |||||
| if self.namespace: # Use the namespace info handed to us | |||||
| methodns, n = self.genns(ns_map, self.namespace) | |||||
| else: | |||||
| methodns, n = '', '' | |||||
| self.out.append('<%s%s%s%s%s>\n' % ( | |||||
| methodns, self.method, n, a, self.genroot(ns_map))) | |||||
| try: | |||||
| if type(self.args) != TupleType: | |||||
| args = (self.args,) | |||||
| else: | |||||
| args = self.args | |||||
| for i in args: | |||||
| self.dump(i, typed = typed, ns_map = ns_map) | |||||
| if hasattr(self.config, "argsOrdering") and self.config.argsOrdering.has_key(self.method): | |||||
| for k in self.config.argsOrdering.get(self.method): | |||||
| self.dump(self.kw.get(k), k, typed = typed, ns_map = ns_map) | |||||
| else: | |||||
| for (k, v) in self.kw.items(): | |||||
| self.dump(v, k, typed = typed, ns_map = ns_map) | |||||
| except RecursionError: | |||||
| if self.use_refs == 0: | |||||
| # restart | |||||
| b = SOAPBuilder(args = self.args, kw = self.kw, | |||||
| method = self.method, namespace = self.namespace, | |||||
| header = self.header, methodattrs = self.methodattrs, | |||||
| envelope = self.envelope, encoding = self.encoding, | |||||
| use_refs = 1, config = self.config) | |||||
| return b.build() | |||||
| raise | |||||
| if self.method: | |||||
| self.out.append("</%s%s>\n" % (methodns, self.method)) | |||||
| # End of the method definition; drop any local namespaces | |||||
| ns_map = save_ns_map | |||||
| self.depth -= 1 | |||||
| if self.body: | |||||
| # dump may add to self.multirefs, but the for loop will keep | |||||
| # going until it has used all of self.multirefs, even those | |||||
| # entries added while in the loop. | |||||
| self.multis = 1 | |||||
| for obj, tag in self.multirefs: | |||||
| self.dump(obj, tag, typed = typed, ns_map = ns_map) | |||||
| self.out.append("</%sBody>\n" % body_ns) | |||||
| self.depth -= 1 | |||||
| if self.envelope: | |||||
| e = map (lambda ns: ' xmlns:%s="%s"\n' % (ns[1], ns[0]), | |||||
| self.envns.items()) | |||||
| self.out = ['<', self._env_top] + e + ['>\n'] + \ | |||||
| self.out + \ | |||||
| [self._env_bot] | |||||
| if self.encoding != None: | |||||
| self.out.insert(0, self._xml_enc_top % self.encoding) | |||||
| return ''.join(self.out).encode(self.encoding) | |||||
| self.out.insert(0, self._xml_top) | |||||
| return ''.join(self.out) | |||||
| def gentag(self): | |||||
| if Config.debug: print "In gentag." | |||||
| self.tcounter += 1 | |||||
| return "v%d" % self.tcounter | |||||
| def genns(self, ns_map, nsURI): | |||||
| if nsURI == None: | |||||
| return ('', '') | |||||
| if type(nsURI) == TupleType: # already a tuple | |||||
| if len(nsURI) == 2: | |||||
| ns, nsURI = nsURI | |||||
| else: | |||||
| ns, nsURI = None, nsURI[0] | |||||
| else: | |||||
| ns = None | |||||
| if ns_map.has_key(nsURI): | |||||
| return (ns_map[nsURI] + ':', '') | |||||
| if self._env_ns.has_key(nsURI): | |||||
| ns = self.envns[nsURI] = ns_map[nsURI] = self._env_ns[nsURI] | |||||
| return (ns + ':', '') | |||||
| if not ns: | |||||
| ns = "ns%d" % self.ncounter | |||||
| self.ncounter += 1 | |||||
| ns_map[nsURI] = ns | |||||
| if self.config.buildWithNamespacePrefix: | |||||
| return (ns + ':', ' xmlns:%s="%s"' % (ns, nsURI)) | |||||
| else: | |||||
| return ('', ' xmlns="%s"' % (nsURI)) | |||||
| def genroot(self, ns_map): | |||||
| if self.noroot: | |||||
| return '' | |||||
| if self.depth != 2: | |||||
| return '' | |||||
| ns, n = self.genns(ns_map, NS.ENC) | |||||
| return ' %sroot="%d"%s' % (ns, not self.multis, n) | |||||
| # checkref checks an element to see if it needs to be encoded as a | |||||
| # multi-reference element or not. If it returns None, the element has | |||||
| # been handled and the caller can continue with subsequent elements. | |||||
| # If it returns a string, the string should be included in the opening | |||||
| # tag of the marshaled element. | |||||
| def checkref(self, obj, tag, ns_map): | |||||
| if self.depth < 2: | |||||
| return '' | |||||
| if not self.ids.has_key(id(obj)): | |||||
| n = self.ids[id(obj)] = self.icounter | |||||
| self.icounter = n + 1 | |||||
| if self.use_refs == 0: | |||||
| return '' | |||||
| if self.depth == 2: | |||||
| return ' id="i%d"' % n | |||||
| self.multirefs.append((obj, tag)) | |||||
| else: | |||||
| if self.use_refs == 0: | |||||
| raise RecursionError, "Cannot serialize recursive object" | |||||
| n = self.ids[id(obj)] | |||||
| if self.multis and self.depth == 2: | |||||
| return ' id="i%d"' % n | |||||
| self.out.append('<%s href="#i%d"%s/>\n' % | |||||
| (tag, n, self.genroot(ns_map))) | |||||
| return None | |||||
| # dumpers | |||||
| def dump(self, obj, tag = None, typed = 1, ns_map = {}): | |||||
| if Config.debug: print "In dump.", "obj=", obj | |||||
| ns_map = ns_map.copy() | |||||
| self.depth += 1 | |||||
| if type(tag) not in (NoneType, StringType, UnicodeType): | |||||
| raise KeyError, "tag must be a string or None" | |||||
| try: | |||||
| meth = getattr(self, "dump_" + type(obj).__name__) | |||||
| except AttributeError: | |||||
| if type(obj) == LongType: | |||||
| obj_type = "integer" | |||||
| elif pythonHasBooleanType and type(obj) == BooleanType: | |||||
| obj_type = "boolean" | |||||
| else: | |||||
| obj_type = type(obj).__name__ | |||||
| self.out.append(self.dumper(None, obj_type, obj, tag, typed, | |||||
| ns_map, self.genroot(ns_map))) | |||||
| else: | |||||
| meth(obj, tag, typed, ns_map) | |||||
| self.depth -= 1 | |||||
| # generic dumper | |||||
| def dumper(self, nsURI, obj_type, obj, tag, typed = 1, ns_map = {}, | |||||
| rootattr = '', id = '', | |||||
| xml = '<%(tag)s%(type)s%(id)s%(attrs)s%(root)s>%(data)s</%(tag)s>\n'): | |||||
| if Config.debug: print "In dumper." | |||||
| if nsURI == None: | |||||
| nsURI = self.config.typesNamespaceURI | |||||
| tag = tag or self.gentag() | |||||
| tag = toXMLname(tag) # convert from SOAP 1.2 XML name encoding | |||||
| a = n = t = '' | |||||
| if typed and obj_type: | |||||
| ns, n = self.genns(ns_map, nsURI) | |||||
| ins = self.genns(ns_map, self.config.schemaNamespaceURI)[0] | |||||
| t = ' %stype="%s%s"%s' % (ins, ns, obj_type, n) | |||||
| try: a = obj._marshalAttrs(ns_map, self) | |||||
| except: pass | |||||
| try: data = obj._marshalData() | |||||
| except: | |||||
| if (obj_type != "string"): # strings are already encoded | |||||
| data = cgi.escape(str(obj)) | |||||
| else: | |||||
| data = obj | |||||
| return xml % {"tag": tag, "type": t, "data": data, "root": rootattr, | |||||
| "id": id, "attrs": a} | |||||
| def dump_float(self, obj, tag, typed = 1, ns_map = {}): | |||||
| if Config.debug: print "In dump_float." | |||||
| tag = tag or self.gentag() | |||||
| tag = toXMLname(tag) # convert from SOAP 1.2 XML name encoding | |||||
| if Config.strict_range: | |||||
| doubleType(obj) | |||||
| if fpconst.isPosInf(obj): | |||||
| obj = "INF" | |||||
| elif fpconst.isNegInf(obj): | |||||
| obj = "-INF" | |||||
| elif fpconst.isNaN(obj): | |||||
| obj = "NaN" | |||||
| else: | |||||
| obj = repr(obj) | |||||
| # Note: python 'float' is actually a SOAP 'double'. | |||||
| self.out.append(self.dumper(None, "double", obj, tag, typed, ns_map, | |||||
| self.genroot(ns_map))) | |||||
| def dump_string(self, obj, tag, typed = 0, ns_map = {}): | |||||
| if Config.debug: print "In dump_string." | |||||
| tag = tag or self.gentag() | |||||
| tag = toXMLname(tag) # convert from SOAP 1.2 XML name encoding | |||||
| id = self.checkref(obj, tag, ns_map) | |||||
| if id == None: | |||||
| return | |||||
| try: data = obj._marshalData() | |||||
| except: data = obj | |||||
| self.out.append(self.dumper(None, "string", cgi.escape(data), tag, | |||||
| typed, ns_map, self.genroot(ns_map), id)) | |||||
| dump_str = dump_string # For Python 2.2+ | |||||
| dump_unicode = dump_string | |||||
| def dump_None(self, obj, tag, typed = 0, ns_map = {}): | |||||
| if Config.debug: print "In dump_None." | |||||
| tag = tag or self.gentag() | |||||
| tag = toXMLname(tag) # convert from SOAP 1.2 XML name encoding | |||||
| ns = self.genns(ns_map, self.config.schemaNamespaceURI)[0] | |||||
| self.out.append('<%s %snull="1"%s/>\n' % | |||||
| (tag, ns, self.genroot(ns_map))) | |||||
| dump_NoneType = dump_None # For Python 2.2+ | |||||
| def dump_list(self, obj, tag, typed = 1, ns_map = {}): | |||||
| if Config.debug: print "In dump_list.", "obj=", obj | |||||
| tag = tag or self.gentag() | |||||
| tag = toXMLname(tag) # convert from SOAP 1.2 XML name encoding | |||||
| if type(obj) == InstanceType: | |||||
| data = obj.data | |||||
| else: | |||||
| data = obj | |||||
| if typed: | |||||
| id = self.checkref(obj, tag, ns_map) | |||||
| if id == None: | |||||
| return | |||||
| try: | |||||
| sample = data[0] | |||||
| empty = 0 | |||||
| except: | |||||
| # preserve type if present | |||||
| if getattr(obj,"_typed",None) and getattr(obj,"_type",None): | |||||
| if getattr(obj, "_complexType", None): | |||||
| sample = typedArrayType(typed=obj._type, | |||||
| complexType = obj._complexType) | |||||
| sample._typename = obj._type | |||||
| if not getattr(obj,"_ns",None): obj._ns = NS.URN | |||||
| else: | |||||
| sample = typedArrayType(typed=obj._type) | |||||
| else: | |||||
| sample = structType() | |||||
| empty = 1 | |||||
| # First scan list to see if all are the same type | |||||
| same_type = 1 | |||||
| if not empty: | |||||
| for i in data[1:]: | |||||
| if type(sample) != type(i) or \ | |||||
| (type(sample) == InstanceType and \ | |||||
| sample.__class__ != i.__class__): | |||||
| same_type = 0 | |||||
| break | |||||
| ndecl = '' | |||||
| if same_type: | |||||
| if (isinstance(sample, structType)) or \ | |||||
| type(sample) == DictType or \ | |||||
| (isinstance(sample, anyType) and \ | |||||
| (getattr(sample, "_complexType", None) and \ | |||||
| sample._complexType)): # force to urn struct | |||||
| try: | |||||
| tns = obj._ns or NS.URN | |||||
| except: | |||||
| tns = NS.URN | |||||
| ns, ndecl = self.genns(ns_map, tns) | |||||
| try: | |||||
| typename = sample._typename | |||||
| except: | |||||
| typename = "SOAPStruct" | |||||
| t = ns + typename | |||||
| elif isinstance(sample, anyType): | |||||
| ns = sample._validNamespaceURI(self.config.typesNamespaceURI, | |||||
| self.config.strictNamespaces) | |||||
| if ns: | |||||
| ns, ndecl = self.genns(ns_map, ns) | |||||
| t = ns + str(sample._type) | |||||
| else: | |||||
| t = 'ur-type' | |||||
| else: | |||||
| typename = type(sample).__name__ | |||||
| # For Python 2.2+ | |||||
| if type(sample) == StringType: typename = 'string' | |||||
| # HACK: unicode is a SOAP string | |||||
| if type(sample) == UnicodeType: typename = 'string' | |||||
| # HACK: python 'float' is actually a SOAP 'double'. | |||||
| if typename=="float": typename="double" | |||||
| t = self.genns(ns_map, self.config.typesNamespaceURI)[0] + \ | |||||
| typename | |||||
| else: | |||||
| t = self.genns(ns_map, self.config.typesNamespaceURI)[0] + \ | |||||
| "ur-type" | |||||
| try: a = obj._marshalAttrs(ns_map, self) | |||||
| except: a = '' | |||||
| ens, edecl = self.genns(ns_map, NS.ENC) | |||||
| ins, idecl = self.genns(ns_map, self.config.schemaNamespaceURI) | |||||
| if typed: | |||||
| self.out.append( | |||||
| '<%s %sarrayType="%s[%d]" %stype="%sArray"%s%s%s%s%s%s>\n' % | |||||
| (tag, ens, t, len(data), ins, ens, ndecl, edecl, idecl, | |||||
| self.genroot(ns_map), id, a)) | |||||
| if typed: | |||||
| try: elemsname = obj._elemsname | |||||
| except: elemsname = "item" | |||||
| else: | |||||
| elemsname = tag | |||||
| for i in data: | |||||
| self.dump(i, elemsname, not same_type, ns_map) | |||||
| if typed: self.out.append('</%s>\n' % tag) | |||||
| dump_tuple = dump_list | |||||
| def dump_dictionary(self, obj, tag, typed = 1, ns_map = {}): | |||||
| if Config.debug: print "In dump_dictionary." | |||||
| tag = tag or self.gentag() | |||||
| tag = toXMLname(tag) # convert from SOAP 1.2 XML name encoding | |||||
| id = self.checkref(obj, tag, ns_map) | |||||
| if id == None: | |||||
| return | |||||
| try: a = obj._marshalAttrs(ns_map, self) | |||||
| except: a = '' | |||||
| self.out.append('<%s%s%s%s>\n' % | |||||
| (tag, id, a, self.genroot(ns_map))) | |||||
| for (k, v) in obj.items(): | |||||
| if k[0] != "_": | |||||
| self.dump(v, k, 1, ns_map) | |||||
| self.out.append('</%s>\n' % tag) | |||||
| dump_dict = dump_dictionary # For Python 2.2+ | |||||
| def dump_instance(self, obj, tag, typed = 1, ns_map = {}): | |||||
| if Config.debug: print "In dump_instance.", "obj=", obj, "tag=", tag | |||||
| if not tag: | |||||
| # If it has a name use it. | |||||
| if isinstance(obj, anyType) and obj._name: | |||||
| tag = obj._name | |||||
| else: | |||||
| tag = self.gentag() | |||||
| tag = toXMLname(tag) # convert from SOAP 1.2 XML name encoding | |||||
| if isinstance(obj, arrayType): # Array | |||||
| self.dump_list(obj, tag, typed, ns_map) | |||||
| return | |||||
| if isinstance(obj, faultType): # Fault | |||||
| cns, cdecl = self.genns(ns_map, NS.ENC) | |||||
| vns, vdecl = self.genns(ns_map, NS.ENV) | |||||
| self.out.append('''<%sFault %sroot="1"%s%s> | |||||
| <faultcode>%s</faultcode> | |||||
| <faultstring>%s</faultstring> | |||||
| ''' % (vns, cns, vdecl, cdecl, obj.faultcode, obj.faultstring)) | |||||
| if hasattr(obj, "detail"): | |||||
| self.dump(obj.detail, "detail", typed, ns_map) | |||||
| self.out.append("</%sFault>\n" % vns) | |||||
| return | |||||
| r = self.genroot(ns_map) | |||||
| try: a = obj._marshalAttrs(ns_map, self) | |||||
| except: a = '' | |||||
| if isinstance(obj, voidType): # void | |||||
| self.out.append("<%s%s%s></%s>\n" % (tag, a, r, tag)) | |||||
| return | |||||
| id = self.checkref(obj, tag, ns_map) | |||||
| if id == None: | |||||
| return | |||||
| if isinstance(obj, structType): | |||||
| # Check for namespace | |||||
| ndecl = '' | |||||
| ns = obj._validNamespaceURI(self.config.typesNamespaceURI, | |||||
| self.config.strictNamespaces) | |||||
| if ns: | |||||
| ns, ndecl = self.genns(ns_map, ns) | |||||
| tag = ns + tag | |||||
| self.out.append("<%s%s%s%s%s>\n" % (tag, ndecl, id, a, r)) | |||||
| keylist = obj.__dict__.keys() | |||||
| # first write out items with order information | |||||
| if hasattr(obj, '_keyord'): | |||||
| for i in range(len(obj._keyord)): | |||||
| self.dump(obj._aslist(i), obj._keyord[i], 1, ns_map) | |||||
| keylist.remove(obj._keyord[i]) | |||||
| # now write out the rest | |||||
| for k in keylist: | |||||
| if (k[0] != "_"): | |||||
| self.dump(getattr(obj,k), k, 1, ns_map) | |||||
| if isinstance(obj, bodyType): | |||||
| self.multis = 1 | |||||
| for v, k in self.multirefs: | |||||
| self.dump(v, k, typed = typed, ns_map = ns_map) | |||||
| self.out.append('</%s>\n' % tag) | |||||
| elif isinstance(obj, anyType): | |||||
| t = '' | |||||
| if typed: | |||||
| ns = obj._validNamespaceURI(self.config.typesNamespaceURI, | |||||
| self.config.strictNamespaces) | |||||
| if ns: | |||||
| ons, ondecl = self.genns(ns_map, ns) | |||||
| ins, indecl = self.genns(ns_map, | |||||
| self.config.schemaNamespaceURI) | |||||
| t = ' %stype="%s%s"%s%s' % \ | |||||
| (ins, ons, obj._type, ondecl, indecl) | |||||
| self.out.append('<%s%s%s%s%s>%s</%s>\n' % | |||||
| (tag, t, id, a, r, obj._marshalData(), tag)) | |||||
| else: # Some Class | |||||
| self.out.append('<%s%s%s>\n' % (tag, id, r)) | |||||
| for (k, v) in obj.__dict__.items(): | |||||
| if k[0] != "_": | |||||
| self.dump(v, k, 1, ns_map) | |||||
| self.out.append('</%s>\n' % tag) | |||||
| ################################################################################ | |||||
| # SOAPBuilder's more public interface | |||||
| ################################################################################ | |||||
| def buildSOAP(args=(), kw={}, method=None, namespace=None, | |||||
| header=None, methodattrs=None, envelope=1, encoding='UTF-8', | |||||
| config=Config, noroot = 0): | |||||
| t = SOAPBuilder(args=args, kw=kw, method=method, namespace=namespace, | |||||
| header=header, methodattrs=methodattrs,envelope=envelope, | |||||
| encoding=encoding, config=config,noroot=noroot) | |||||
| return t.build() | |||||
| @@ -0,0 +1,706 @@ | |||||
| """ | |||||
| ################################################################################ | |||||
| # | |||||
| # SOAPpy - Cayce Ullman (cayce@actzero.com) | |||||
| # Brian Matthews (blm@actzero.com) | |||||
| # Gregory Warnes (Gregory.R.Warnes@Pfizer.com) | |||||
| # Christopher Blunck (blunck@gst.com) | |||||
| # | |||||
| ################################################################################ | |||||
| # Copyright (c) 2003, Pfizer | |||||
| # Copyright (c) 2001, Cayce Ullman. | |||||
| # Copyright (c) 2001, Brian Matthews. | |||||
| # | |||||
| # All rights reserved. | |||||
| # | |||||
| # Redistribution and use in source and binary forms, with or without | |||||
| # modification, are permitted provided that the following conditions are met: | |||||
| # Redistributions of source code must retain the above copyright notice, this | |||||
| # list of conditions and the following disclaimer. | |||||
| # | |||||
| # Redistributions in binary form must reproduce the above copyright notice, | |||||
| # this list of conditions and the following disclaimer in the documentation | |||||
| # and/or other materials provided with the distribution. | |||||
| # | |||||
| # Neither the name of actzero, inc. nor the names of its contributors may | |||||
| # be used to endorse or promote products derived from this software without | |||||
| # specific prior written permission. | |||||
| # | |||||
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||||
| # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||||
| # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||||
| # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | |||||
| # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||||
| # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||||
| # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||||
| # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||||
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||||
| # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
| # | |||||
| ################################################################################ | |||||
| """ | |||||
| ident = '$Id: Server.py,v 1.21 2005/02/15 16:32:22 warnes Exp $' | |||||
| from version import __version__ | |||||
| from __future__ import nested_scopes | |||||
| #import xml.sax | |||||
| import re | |||||
| import socket | |||||
| import sys | |||||
| import SocketServer | |||||
| from types import * | |||||
| import BaseHTTPServer | |||||
| import thread | |||||
| # SOAPpy modules | |||||
| from Parser import parseSOAPRPC | |||||
| from Config import Config | |||||
| from Types import faultType, voidType, simplify | |||||
| from NS import NS | |||||
| from SOAPBuilder import buildSOAP | |||||
| from Utilities import debugHeader, debugFooter | |||||
| try: from M2Crypto import SSL | |||||
| except: pass | |||||
| ident = '$Id: Server.py,v 1.21 2005/02/15 16:32:22 warnes Exp $' | |||||
| from version import __version__ | |||||
| ################################################################################ | |||||
| # Call context dictionary | |||||
| ################################################################################ | |||||
| _contexts = dict() | |||||
| def GetSOAPContext(): | |||||
| global _contexts | |||||
| return _contexts[thread.get_ident()] | |||||
| ################################################################################ | |||||
| # Server | |||||
| ################################################################################ | |||||
| # Method Signature class for adding extra info to registered funcs, right now | |||||
| # used just to indicate it should be called with keywords, instead of ordered | |||||
| # params. | |||||
| class MethodSig: | |||||
| def __init__(self, func, keywords=0, context=0): | |||||
| self.func = func | |||||
| self.keywords = keywords | |||||
| self.context = context | |||||
| self.__name__ = func.__name__ | |||||
| def __call__(self, *args, **kw): | |||||
| return apply(self.func,args,kw) | |||||
| class SOAPContext: | |||||
| def __init__(self, header, body, attrs, xmldata, connection, httpheaders, | |||||
| soapaction): | |||||
| self.header = header | |||||
| self.body = body | |||||
| self.attrs = attrs | |||||
| self.xmldata = xmldata | |||||
| self.connection = connection | |||||
| self.httpheaders= httpheaders | |||||
| self.soapaction = soapaction | |||||
| # A class to describe how header messages are handled | |||||
| class HeaderHandler: | |||||
| # Initially fail out if there are any problems. | |||||
| def __init__(self, header, attrs): | |||||
| for i in header.__dict__.keys(): | |||||
| if i[0] == "_": | |||||
| continue | |||||
| d = getattr(header, i) | |||||
| try: | |||||
| fault = int(attrs[id(d)][(NS.ENV, 'mustUnderstand')]) | |||||
| except: | |||||
| fault = 0 | |||||
| if fault: | |||||
| raise faultType, ("%s:MustUnderstand" % NS.ENV_T, | |||||
| "Required Header Misunderstood", | |||||
| "%s" % i) | |||||
| ################################################################################ | |||||
| # SOAP Server | |||||
| ################################################################################ | |||||
| class SOAPServerBase: | |||||
| def get_request(self): | |||||
| sock, addr = SocketServer.TCPServer.get_request(self) | |||||
| if self.ssl_context: | |||||
| sock = SSL.Connection(self.ssl_context, sock) | |||||
| sock._setup_ssl(addr) | |||||
| if sock.accept_ssl() != 1: | |||||
| raise socket.error, "Couldn't accept SSL connection" | |||||
| return sock, addr | |||||
| def registerObject(self, object, namespace = '', path = ''): | |||||
| if namespace == '' and path == '': namespace = self.namespace | |||||
| if namespace == '' and path != '': | |||||
| namespace = path.replace("/", ":") | |||||
| if namespace[0] == ":": namespace = namespace[1:] | |||||
| self.objmap[namespace] = object | |||||
| def registerFunction(self, function, namespace = '', funcName = None, | |||||
| path = ''): | |||||
| if not funcName : funcName = function.__name__ | |||||
| if namespace == '' and path == '': namespace = self.namespace | |||||
| if namespace == '' and path != '': | |||||
| namespace = path.replace("/", ":") | |||||
| if namespace[0] == ":": namespace = namespace[1:] | |||||
| if self.funcmap.has_key(namespace): | |||||
| self.funcmap[namespace][funcName] = function | |||||
| else: | |||||
| self.funcmap[namespace] = {funcName : function} | |||||
| def registerKWObject(self, object, namespace = '', path = ''): | |||||
| if namespace == '' and path == '': namespace = self.namespace | |||||
| if namespace == '' and path != '': | |||||
| namespace = path.replace("/", ":") | |||||
| if namespace[0] == ":": namespace = namespace[1:] | |||||
| for i in dir(object.__class__): | |||||
| if i[0] != "_" and callable(getattr(object, i)): | |||||
| self.registerKWFunction(getattr(object,i), namespace) | |||||
| # convenience - wraps your func for you. | |||||
| def registerKWFunction(self, function, namespace = '', funcName = None, | |||||
| path = ''): | |||||
| if namespace == '' and path == '': namespace = self.namespace | |||||
| if namespace == '' and path != '': | |||||
| namespace = path.replace("/", ":") | |||||
| if namespace[0] == ":": namespace = namespace[1:] | |||||
| self.registerFunction(MethodSig(function,keywords=1), namespace, | |||||
| funcName) | |||||
| def unregisterObject(self, object, namespace = '', path = ''): | |||||
| if namespace == '' and path == '': namespace = self.namespace | |||||
| if namespace == '' and path != '': | |||||
| namespace = path.replace("/", ":") | |||||
| if namespace[0] == ":": namespace = namespace[1:] | |||||
| del self.objmap[namespace] | |||||
| class SOAPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): | |||||
| def version_string(self): | |||||
| return '<a href="http://pywebsvcs.sf.net">' + \ | |||||
| 'SOAPpy ' + __version__ + '</a> (Python ' + \ | |||||
| sys.version.split()[0] + ')' | |||||
| def date_time_string(self): | |||||
| self.__last_date_time_string = \ | |||||
| BaseHTTPServer.BaseHTTPRequestHandler.\ | |||||
| date_time_string(self) | |||||
| return self.__last_date_time_string | |||||
| def do_POST(self): | |||||
| global _contexts | |||||
| status = 500 | |||||
| try: | |||||
| if self.server.config.dumpHeadersIn: | |||||
| s = 'Incoming HTTP headers' | |||||
| debugHeader(s) | |||||
| print self.raw_requestline.strip() | |||||
| print "\n".join(map (lambda x: x.strip(), | |||||
| self.headers.headers)) | |||||
| debugFooter(s) | |||||
| data = self.rfile.read(int(self.headers["Content-length"])) | |||||
| if self.server.config.dumpSOAPIn: | |||||
| s = 'Incoming SOAP' | |||||
| debugHeader(s) | |||||
| print data, | |||||
| if data[-1] != '\n': | |||||
| debugFooter(s) | |||||
| (r, header, body, attrs) = \ | |||||
| parseSOAPRPC(data, header = 1, body = 1, attrs = 1) | |||||
| method = r._name | |||||
| args = r._aslist() | |||||
| kw = r._asdict() | |||||
| if Config.simplify_objects: | |||||
| args = simplify(args) | |||||
| kw = simplify(kw) | |||||
| # Handle mixed named and unnamed arguments by assuming | |||||
| # that all arguments with names of the form "v[0-9]+" | |||||
| # are unnamed and should be passed in numeric order, | |||||
| # other arguments are named and should be passed using | |||||
| # this name. | |||||
| # This is a non-standard exension to the SOAP protocol, | |||||
| # but is supported by Apache AXIS. | |||||
| # It is enabled by default. To disable, set | |||||
| # Config.specialArgs to False. | |||||
| if Config.specialArgs: | |||||
| ordered_args = {} | |||||
| named_args = {} | |||||
| for (k,v) in kw.items(): | |||||
| if k[0]=="v": | |||||
| try: | |||||
| i = int(k[1:]) | |||||
| ordered_args[i] = v | |||||
| except ValueError: | |||||
| named_args[str(k)] = v | |||||
| else: | |||||
| named_args[str(k)] = v | |||||
| # We have to decide namespace precedence | |||||
| # I'm happy with the following scenario | |||||
| # if r._ns is specified use it, if not check for | |||||
| # a path, if it's specified convert it and use it as the | |||||
| # namespace. If both are specified, use r._ns. | |||||
| ns = r._ns | |||||
| if len(self.path) > 1 and not ns: | |||||
| ns = self.path.replace("/", ":") | |||||
| if ns[0] == ":": ns = ns[1:] | |||||
| # authorization method | |||||
| a = None | |||||
| keylist = ordered_args.keys() | |||||
| keylist.sort() | |||||
| # create list in proper order w/o names | |||||
| tmp = map( lambda x: ordered_args[x], keylist) | |||||
| ordered_args = tmp | |||||
| #print '<-> Argument Matching Yielded:' | |||||
| #print '<-> Ordered Arguments:' + str(ordered_args) | |||||
| #print '<-> Named Arguments :' + str(named_args) | |||||
| resp = "" | |||||
| # For fault messages | |||||
| if ns: | |||||
| nsmethod = "%s:%s" % (ns, method) | |||||
| else: | |||||
| nsmethod = method | |||||
| try: | |||||
| # First look for registered functions | |||||
| if self.server.funcmap.has_key(ns) and \ | |||||
| self.server.funcmap[ns].has_key(method): | |||||
| f = self.server.funcmap[ns][method] | |||||
| # look for the authorization method | |||||
| if self.server.config.authMethod != None: | |||||
| authmethod = self.server.config.authMethod | |||||
| if self.server.funcmap.has_key(ns) and \ | |||||
| self.server.funcmap[ns].has_key(authmethod): | |||||
| a = self.server.funcmap[ns][authmethod] | |||||
| else: | |||||
| # Now look at registered objects | |||||
| # Check for nested attributes. This works even if | |||||
| # there are none, because the split will return | |||||
| # [method] | |||||
| f = self.server.objmap[ns] | |||||
| # Look for the authorization method | |||||
| if self.server.config.authMethod != None: | |||||
| authmethod = self.server.config.authMethod | |||||
| if hasattr(f, authmethod): | |||||
| a = getattr(f, authmethod) | |||||
| # then continue looking for the method | |||||
| l = method.split(".") | |||||
| for i in l: | |||||
| f = getattr(f, i) | |||||
| except: | |||||
| info = sys.exc_info() | |||||
| try: | |||||
| resp = buildSOAP(faultType("%s:Client" % NS.ENV_T, | |||||
| "Method Not Found", | |||||
| "%s : %s %s %s" % (nsmethod, | |||||
| info[0], | |||||
| info[1], | |||||
| info[2])), | |||||
| encoding = self.server.encoding, | |||||
| config = self.server.config) | |||||
| finally: | |||||
| del info | |||||
| status = 500 | |||||
| else: | |||||
| try: | |||||
| if header: | |||||
| x = HeaderHandler(header, attrs) | |||||
| fr = 1 | |||||
| # call context book keeping | |||||
| # We're stuffing the method into the soapaction if there | |||||
| # isn't one, someday, we'll set that on the client | |||||
| # and it won't be necessary here | |||||
| # for now we're doing both | |||||
| if "SOAPAction".lower() not in self.headers.keys() or \ | |||||
| self.headers["SOAPAction"] == "\"\"": | |||||
| self.headers["SOAPAction"] = method | |||||
| thread_id = thread.get_ident() | |||||
| _contexts[thread_id] = SOAPContext(header, body, | |||||
| attrs, data, | |||||
| self.connection, | |||||
| self.headers, | |||||
| self.headers["SOAPAction"]) | |||||
| # Do an authorization check | |||||
| if a != None: | |||||
| if not apply(a, (), {"_SOAPContext" : | |||||
| _contexts[thread_id] }): | |||||
| raise faultType("%s:Server" % NS.ENV_T, | |||||
| "Authorization failed.", | |||||
| "%s" % nsmethod) | |||||
| # If it's wrapped, some special action may be needed | |||||
| if isinstance(f, MethodSig): | |||||
| c = None | |||||
| if f.context: # retrieve context object | |||||
| c = _contexts[thread_id] | |||||
| if Config.specialArgs: | |||||
| if c: | |||||
| named_args["_SOAPContext"] = c | |||||
| fr = apply(f, ordered_args, named_args) | |||||
| elif f.keywords: | |||||
| # This is lame, but have to de-unicode | |||||
| # keywords | |||||
| strkw = {} | |||||
| for (k, v) in kw.items(): | |||||
| strkw[str(k)] = v | |||||
| if c: | |||||
| strkw["_SOAPContext"] = c | |||||
| fr = apply(f, (), strkw) | |||||
| elif c: | |||||
| fr = apply(f, args, {'_SOAPContext':c}) | |||||
| else: | |||||
| fr = apply(f, args, {}) | |||||
| else: | |||||
| if Config.specialArgs: | |||||
| fr = apply(f, ordered_args, named_args) | |||||
| else: | |||||
| fr = apply(f, args, {}) | |||||
| if type(fr) == type(self) and \ | |||||
| isinstance(fr, voidType): | |||||
| resp = buildSOAP(kw = {'%sResponse' % method: fr}, | |||||
| encoding = self.server.encoding, | |||||
| config = self.server.config) | |||||
| else: | |||||
| resp = buildSOAP(kw = | |||||
| {'%sResponse' % method: {'Result': fr}}, | |||||
| encoding = self.server.encoding, | |||||
| config = self.server.config) | |||||
| # Clean up _contexts | |||||
| if _contexts.has_key(thread_id): | |||||
| del _contexts[thread_id] | |||||
| except Exception, e: | |||||
| import traceback | |||||
| info = sys.exc_info() | |||||
| try: | |||||
| if self.server.config.dumpFaultInfo: | |||||
| s = 'Method %s exception' % nsmethod | |||||
| debugHeader(s) | |||||
| traceback.print_exception(info[0], info[1], | |||||
| info[2]) | |||||
| debugFooter(s) | |||||
| if isinstance(e, faultType): | |||||
| f = e | |||||
| else: | |||||
| f = faultType("%s:Server" % NS.ENV_T, | |||||
| "Method Failed", | |||||
| "%s" % nsmethod) | |||||
| if self.server.config.returnFaultInfo: | |||||
| f._setDetail("".join(traceback.format_exception( | |||||
| info[0], info[1], info[2]))) | |||||
| elif not hasattr(f, 'detail'): | |||||
| f._setDetail("%s %s" % (info[0], info[1])) | |||||
| finally: | |||||
| del info | |||||
| resp = buildSOAP(f, encoding = self.server.encoding, | |||||
| config = self.server.config) | |||||
| status = 500 | |||||
| else: | |||||
| status = 200 | |||||
| except faultType, e: | |||||
| import traceback | |||||
| info = sys.exc_info() | |||||
| try: | |||||
| if self.server.config.dumpFaultInfo: | |||||
| s = 'Received fault exception' | |||||
| debugHeader(s) | |||||
| traceback.print_exception(info[0], info[1], | |||||
| info[2]) | |||||
| debugFooter(s) | |||||
| if self.server.config.returnFaultInfo: | |||||
| e._setDetail("".join(traceback.format_exception( | |||||
| info[0], info[1], info[2]))) | |||||
| elif not hasattr(e, 'detail'): | |||||
| e._setDetail("%s %s" % (info[0], info[1])) | |||||
| finally: | |||||
| del info | |||||
| resp = buildSOAP(e, encoding = self.server.encoding, | |||||
| config = self.server.config) | |||||
| status = 500 | |||||
| except Exception, e: | |||||
| # internal error, report as HTTP server error | |||||
| if self.server.config.dumpFaultInfo: | |||||
| s = 'Internal exception %s' % e | |||||
| import traceback | |||||
| debugHeader(s) | |||||
| info = sys.exc_info() | |||||
| try: | |||||
| traceback.print_exception(info[0], info[1], info[2]) | |||||
| finally: | |||||
| del info | |||||
| debugFooter(s) | |||||
| self.send_response(500) | |||||
| self.end_headers() | |||||
| if self.server.config.dumpHeadersOut and \ | |||||
| self.request_version != 'HTTP/0.9': | |||||
| s = 'Outgoing HTTP headers' | |||||
| debugHeader(s) | |||||
| if self.responses.has_key(status): | |||||
| s = ' ' + self.responses[status][0] | |||||
| else: | |||||
| s = '' | |||||
| print "%s %d%s" % (self.protocol_version, 500, s) | |||||
| print "Server:", self.version_string() | |||||
| print "Date:", self.__last_date_time_string | |||||
| debugFooter(s) | |||||
| else: | |||||
| # got a valid SOAP response | |||||
| self.send_response(status) | |||||
| t = 'text/xml'; | |||||
| if self.server.encoding != None: | |||||
| t += '; charset="%s"' % self.server.encoding | |||||
| self.send_header("Content-type", t) | |||||
| self.send_header("Content-length", str(len(resp))) | |||||
| self.end_headers() | |||||
| if self.server.config.dumpHeadersOut and \ | |||||
| self.request_version != 'HTTP/0.9': | |||||
| s = 'Outgoing HTTP headers' | |||||
| debugHeader(s) | |||||
| if self.responses.has_key(status): | |||||
| s = ' ' + self.responses[status][0] | |||||
| else: | |||||
| s = '' | |||||
| print "%s %d%s" % (self.protocol_version, status, s) | |||||
| print "Server:", self.version_string() | |||||
| print "Date:", self.__last_date_time_string | |||||
| print "Content-type:", t | |||||
| print "Content-length:", len(resp) | |||||
| debugFooter(s) | |||||
| if self.server.config.dumpSOAPOut: | |||||
| s = 'Outgoing SOAP' | |||||
| debugHeader(s) | |||||
| print resp, | |||||
| if resp[-1] != '\n': | |||||
| debugFooter(s) | |||||
| self.wfile.write(resp) | |||||
| self.wfile.flush() | |||||
| # We should be able to shut down both a regular and an SSL | |||||
| # connection, but under Python 2.1, calling shutdown on an | |||||
| # SSL connections drops the output, so this work-around. | |||||
| # This should be investigated more someday. | |||||
| if self.server.config.SSLserver and \ | |||||
| isinstance(self.connection, SSL.Connection): | |||||
| self.connection.set_shutdown(SSL.SSL_SENT_SHUTDOWN | | |||||
| SSL.SSL_RECEIVED_SHUTDOWN) | |||||
| else: | |||||
| self.connection.shutdown(1) | |||||
| def do_GET(self): | |||||
| #print 'command ', self.command | |||||
| #print 'path ', self.path | |||||
| #print 'request_version', self.request_version | |||||
| #print 'headers' | |||||
| #print ' type ', self.headers.type | |||||
| #print ' maintype', self.headers.maintype | |||||
| #print ' subtype ', self.headers.subtype | |||||
| #print ' params ', self.headers.plist | |||||
| path = self.path.lower() | |||||
| if path.endswith('wsdl'): | |||||
| method = 'wsdl' | |||||
| function = namespace = None | |||||
| if self.server.funcmap.has_key(namespace) \ | |||||
| and self.server.funcmap[namespace].has_key(method): | |||||
| function = self.server.funcmap[namespace][method] | |||||
| else: | |||||
| if namespace in self.server.objmap.keys(): | |||||
| function = self.server.objmap[namespace] | |||||
| l = method.split(".") | |||||
| for i in l: | |||||
| function = getattr(function, i) | |||||
| if function: | |||||
| self.send_response(200) | |||||
| self.send_header("Content-type", 'text/plain') | |||||
| self.end_headers() | |||||
| response = apply(function, ()) | |||||
| self.wfile.write(str(response)) | |||||
| return | |||||
| # return error | |||||
| self.send_response(200) | |||||
| self.send_header("Content-type", 'text/html') | |||||
| self.end_headers() | |||||
| self.wfile.write('''\ | |||||
| <title> | |||||
| <head>Error!</head> | |||||
| </title> | |||||
| <body> | |||||
| <h1>Oops!</h1> | |||||
| <p> | |||||
| This server supports HTTP GET requests only for the the purpose of | |||||
| obtaining Web Services Description Language (WSDL) for a specific | |||||
| service. | |||||
| Either you requested an URL that does not end in "wsdl" or this | |||||
| server does not implement a wsdl method. | |||||
| </p> | |||||
| </body>''') | |||||
| def log_message(self, format, *args): | |||||
| if self.server.log: | |||||
| BaseHTTPServer.BaseHTTPRequestHandler.\ | |||||
| log_message (self, format, *args) | |||||
| class SOAPServer(SOAPServerBase, SocketServer.TCPServer): | |||||
| def __init__(self, addr = ('localhost', 8000), | |||||
| RequestHandler = SOAPRequestHandler, log = 0, encoding = 'UTF-8', | |||||
| config = Config, namespace = None, ssl_context = None): | |||||
| # Test the encoding, raising an exception if it's not known | |||||
| if encoding != None: | |||||
| ''.encode(encoding) | |||||
| if ssl_context != None and not config.SSLserver: | |||||
| raise AttributeError, \ | |||||
| "SSL server not supported by this Python installation" | |||||
| self.namespace = namespace | |||||
| self.objmap = {} | |||||
| self.funcmap = {} | |||||
| self.ssl_context = ssl_context | |||||
| self.encoding = encoding | |||||
| self.config = config | |||||
| self.log = log | |||||
| self.allow_reuse_address= 1 | |||||
| SocketServer.TCPServer.__init__(self, addr, RequestHandler) | |||||
| class ThreadingSOAPServer(SOAPServerBase, SocketServer.ThreadingTCPServer): | |||||
| def __init__(self, addr = ('localhost', 8000), | |||||
| RequestHandler = SOAPRequestHandler, log = 0, encoding = 'UTF-8', | |||||
| config = Config, namespace = None, ssl_context = None): | |||||
| # Test the encoding, raising an exception if it's not known | |||||
| if encoding != None: | |||||
| ''.encode(encoding) | |||||
| if ssl_context != None and not config.SSLserver: | |||||
| raise AttributeError, \ | |||||
| "SSL server not supported by this Python installation" | |||||
| self.namespace = namespace | |||||
| self.objmap = {} | |||||
| self.funcmap = {} | |||||
| self.ssl_context = ssl_context | |||||
| self.encoding = encoding | |||||
| self.config = config | |||||
| self.log = log | |||||
| self.allow_reuse_address= 1 | |||||
| SocketServer.ThreadingTCPServer.__init__(self, addr, RequestHandler) | |||||
| # only define class if Unix domain sockets are available | |||||
| if hasattr(socket, "AF_UNIX"): | |||||
| class SOAPUnixSocketServer(SOAPServerBase, SocketServer.UnixStreamServer): | |||||
| def __init__(self, addr = 8000, | |||||
| RequestHandler = SOAPRequestHandler, log = 0, encoding = 'UTF-8', | |||||
| config = Config, namespace = None, ssl_context = None): | |||||
| # Test the encoding, raising an exception if it's not known | |||||
| if encoding != None: | |||||
| ''.encode(encoding) | |||||
| if ssl_context != None and not config.SSLserver: | |||||
| raise AttributeError, \ | |||||
| "SSL server not supported by this Python installation" | |||||
| self.namespace = namespace | |||||
| self.objmap = {} | |||||
| self.funcmap = {} | |||||
| self.ssl_context = ssl_context | |||||
| self.encoding = encoding | |||||
| self.config = config | |||||
| self.log = log | |||||
| self.allow_reuse_address= 1 | |||||
| SocketServer.UnixStreamServer.__init__(self, str(addr), RequestHandler) | |||||
| @@ -0,0 +1,23 @@ | |||||
| """Provide a class for loading data from URL's that handles basic | |||||
| authentication""" | |||||
| ident = '$Id: URLopener.py,v 1.2 2004/01/31 04:20:06 warnes Exp $' | |||||
| from version import __version__ | |||||
| from Config import Config | |||||
| from urllib import FancyURLopener | |||||
| class URLopener(FancyURLopener): | |||||
| username = None | |||||
| passwd = None | |||||
| def __init__(self, username=None, passwd=None, *args, **kw): | |||||
| FancyURLopener.__init__( self, *args, **kw) | |||||
| self.username = username | |||||
| self.passwd = passwd | |||||
| def prompt_user_passwd(self, host, realm): | |||||
| return self.username, self.passwd | |||||
| @@ -0,0 +1,178 @@ | |||||
| """ | |||||
| ################################################################################ | |||||
| # Copyright (c) 2003, Pfizer | |||||
| # Copyright (c) 2001, Cayce Ullman. | |||||
| # Copyright (c) 2001, Brian Matthews. | |||||
| # | |||||
| # All rights reserved. | |||||
| # | |||||
| # Redistribution and use in source and binary forms, with or without | |||||
| # modification, are permitted provided that the following conditions are met: | |||||
| # Redistributions of source code must retain the above copyright notice, this | |||||
| # list of conditions and the following disclaimer. | |||||
| # | |||||
| # Redistributions in binary form must reproduce the above copyright notice, | |||||
| # this list of conditions and the following disclaimer in the documentation | |||||
| # and/or other materials provided with the distribution. | |||||
| # | |||||
| # Neither the name of actzero, inc. nor the names of its contributors may | |||||
| # be used to endorse or promote products derived from this software without | |||||
| # specific prior written permission. | |||||
| # | |||||
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||||
| # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||||
| # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||||
| # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | |||||
| # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||||
| # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||||
| # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||||
| # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||||
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||||
| # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
| # | |||||
| ################################################################################ | |||||
| """ | |||||
| ident = '$Id: Utilities.py,v 1.4 2004/01/31 04:20:06 warnes Exp $' | |||||
| from version import __version__ | |||||
| import exceptions | |||||
| import copy | |||||
| import re | |||||
| import string | |||||
| import sys | |||||
| from types import * | |||||
| # SOAPpy modules | |||||
| from Errors import * | |||||
| ################################################################################ | |||||
| # Utility infielders | |||||
| ################################################################################ | |||||
| def collapseWhiteSpace(s): | |||||
| return re.sub('\s+', ' ', s).strip() | |||||
| def decodeHexString(data): | |||||
| conv = { | |||||
| '0': 0x0, '1': 0x1, '2': 0x2, '3': 0x3, '4': 0x4, | |||||
| '5': 0x5, '6': 0x6, '7': 0x7, '8': 0x8, '9': 0x9, | |||||
| 'a': 0xa, 'b': 0xb, 'c': 0xc, 'd': 0xd, 'e': 0xe, | |||||
| 'f': 0xf, | |||||
| 'A': 0xa, 'B': 0xb, 'C': 0xc, 'D': 0xd, 'E': 0xe, | |||||
| 'F': 0xf, | |||||
| } | |||||
| ws = string.whitespace | |||||
| bin = '' | |||||
| i = 0 | |||||
| while i < len(data): | |||||
| if data[i] not in ws: | |||||
| break | |||||
| i += 1 | |||||
| low = 0 | |||||
| while i < len(data): | |||||
| c = data[i] | |||||
| if c in string.whitespace: | |||||
| break | |||||
| try: | |||||
| c = conv[c] | |||||
| except KeyError: | |||||
| raise ValueError, \ | |||||
| "invalid hex string character `%s'" % c | |||||
| if low: | |||||
| bin += chr(high * 16 + c) | |||||
| low = 0 | |||||
| else: | |||||
| high = c | |||||
| low = 1 | |||||
| i += 1 | |||||
| if low: | |||||
| raise ValueError, "invalid hex string length" | |||||
| while i < len(data): | |||||
| if data[i] not in string.whitespace: | |||||
| raise ValueError, \ | |||||
| "invalid hex string character `%s'" % c | |||||
| i += 1 | |||||
| return bin | |||||
| def encodeHexString(data): | |||||
| h = '' | |||||
| for i in data: | |||||
| h += "%02X" % ord(i) | |||||
| return h | |||||
| def leapMonth(year, month): | |||||
| return month == 2 and \ | |||||
| year % 4 == 0 and \ | |||||
| (year % 100 != 0 or year % 400 == 0) | |||||
| def cleanDate(d, first = 0): | |||||
| ranges = (None, (1, 12), (1, 31), (0, 23), (0, 59), (0, 61)) | |||||
| months = (0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) | |||||
| names = ('year', 'month', 'day', 'hours', 'minutes', 'seconds') | |||||
| if len(d) != 6: | |||||
| raise ValueError, "date must have 6 elements" | |||||
| for i in range(first, 6): | |||||
| s = d[i] | |||||
| if type(s) == FloatType: | |||||
| if i < 5: | |||||
| try: | |||||
| s = int(s) | |||||
| except OverflowError: | |||||
| if i > 0: | |||||
| raise | |||||
| s = long(s) | |||||
| if s != d[i]: | |||||
| raise ValueError, "%s must be integral" % names[i] | |||||
| d[i] = s | |||||
| elif type(s) == LongType: | |||||
| try: s = int(s) | |||||
| except: pass | |||||
| elif type(s) != IntType: | |||||
| raise TypeError, "%s isn't a valid type" % names[i] | |||||
| if i == first and s < 0: | |||||
| continue | |||||
| if ranges[i] != None and \ | |||||
| (s < ranges[i][0] or ranges[i][1] < s): | |||||
| raise ValueError, "%s out of range" % names[i] | |||||
| if first < 6 and d[5] >= 61: | |||||
| raise ValueError, "seconds out of range" | |||||
| if first < 2: | |||||
| leap = first < 1 and leapMonth(d[0], d[1]) | |||||
| if d[2] > months[d[1]] + leap: | |||||
| raise ValueError, "day out of range" | |||||
| def debugHeader(title): | |||||
| s = '*** ' + title + ' ' | |||||
| print s + ('*' * (72 - len(s))) | |||||
| def debugFooter(title): | |||||
| print '*' * 72 | |||||
| sys.stdout.flush() | |||||
| @@ -0,0 +1,119 @@ | |||||
| """Parse web services description language to get SOAP methods. | |||||
| Rudimentary support.""" | |||||
| ident = '$Id: WSDL.py,v 1.11 2005/02/21 20:16:15 warnes Exp $' | |||||
| from version import __version__ | |||||
| import wstools | |||||
| from Client import SOAPProxy, SOAPAddress | |||||
| from Config import Config | |||||
| import urllib | |||||
| class Proxy: | |||||
| """WSDL Proxy. | |||||
| SOAPProxy wrapper that parses method names, namespaces, soap actions from | |||||
| the web service description language (WSDL) file passed into the | |||||
| constructor. The WSDL reference can be passed in as a stream, an url, a | |||||
| file name, or a string. | |||||
| Loads info into self.methods, a dictionary with methodname keys and values | |||||
| of WSDLTools.SOAPCallinfo. | |||||
| For example, | |||||
| url = 'http://www.xmethods.org/sd/2001/TemperatureService.wsdl' | |||||
| wsdl = WSDL.Proxy(url) | |||||
| print len(wsdl.methods) # 1 | |||||
| print wsdl.methods.keys() # getTemp | |||||
| See WSDLTools.SOAPCallinfo for more info on each method's attributes. | |||||
| """ | |||||
| def __init__(self, wsdlsource, config=Config, **kw ): | |||||
| reader = wstools.WSDLTools.WSDLReader() | |||||
| self.wsdl = None | |||||
| # From Mark Pilgrim's "Dive Into Python" toolkit.py--open anything. | |||||
| if self.wsdl is None and hasattr(wsdlsource, "read"): | |||||
| #print 'stream' | |||||
| self.wsdl = reader.loadFromStream(wsdlsource) | |||||
| # NOT TESTED (as of April 17, 2003) | |||||
| #if self.wsdl is None and wsdlsource == '-': | |||||
| # import sys | |||||
| # self.wsdl = reader.loadFromStream(sys.stdin) | |||||
| # print 'stdin' | |||||
| if self.wsdl is None: | |||||
| try: | |||||
| file(wsdlsource) | |||||
| self.wsdl = reader.loadFromFile(wsdlsource) | |||||
| #print 'file' | |||||
| except (IOError, OSError): | |||||
| pass | |||||
| if self.wsdl is None: | |||||
| try: | |||||
| stream = urllib.urlopen(wsdlsource) | |||||
| self.wsdl = reader.loadFromStream(stream, wsdlsource) | |||||
| except (IOError, OSError): pass | |||||
| if self.wsdl is None: | |||||
| import StringIO | |||||
| self.wsdl = reader.loadFromString(str(wsdlsource)) | |||||
| #print 'string' | |||||
| # Package wsdl info as a dictionary of remote methods, with method name | |||||
| # as key (based on ServiceProxy.__init__ in ZSI library). | |||||
| self.methods = {} | |||||
| service = self.wsdl.services[0] | |||||
| port = service.ports[0] | |||||
| name = service.name | |||||
| binding = port.getBinding() | |||||
| portType = binding.getPortType() | |||||
| for operation in portType.operations: | |||||
| callinfo = wstools.WSDLTools.callInfoFromWSDL(port, operation.name) | |||||
| self.methods[callinfo.methodName] = callinfo | |||||
| self.soapproxy = SOAPProxy('http://localhost/dummy.webservice', | |||||
| config=config, **kw) | |||||
| def __str__(self): | |||||
| s = '' | |||||
| for method in self.methods.values(): | |||||
| s += str(method) | |||||
| return s | |||||
| def __getattr__(self, name): | |||||
| """Set up environment then let parent class handle call. | |||||
| Raises AttributeError is method name is not found.""" | |||||
| if not self.methods.has_key(name): raise AttributeError, name | |||||
| callinfo = self.methods[name] | |||||
| self.soapproxy.proxy = SOAPAddress(callinfo.location) | |||||
| self.soapproxy.namespace = callinfo.namespace | |||||
| self.soapproxy.soapaction = callinfo.soapAction | |||||
| return self.soapproxy.__getattr__(name) | |||||
| def show_methods(self): | |||||
| for key in self.methods.keys(): | |||||
| method = self.methods[key] | |||||
| print "Method Name:", key.ljust(15) | |||||
| inps = method.inparams | |||||
| for parm in range(len(inps)): | |||||
| details = inps[parm] | |||||
| print " In #%d: %s (%s)" % (parm, details.name, details.type) | |||||
| outps = method.outparams | |||||
| for parm in range(len(outps)): | |||||
| details = outps[parm] | |||||
| print " Out #%d: %s (%s)" % (parm, details.name, details.type) | |||||
| @@ -0,0 +1,15 @@ | |||||
| ident = '$Id: __init__.py,v 1.9 2004/01/31 04:20:06 warnes Exp $' | |||||
| from version import __version__ | |||||
| from Client import * | |||||
| from Config import * | |||||
| from Errors import * | |||||
| from NS import * | |||||
| from Parser import * | |||||
| from SOAPBuilder import * | |||||
| from Server import * | |||||
| from Types import * | |||||
| from Utilities import * | |||||
| import wstools | |||||
| import WSDL | |||||
| @@ -0,0 +1,2 @@ | |||||
| __version__="0.12.0" | |||||
| @@ -0,0 +1,125 @@ | |||||
| #! /usr/bin/env python | |||||
| """Namespace module, so you don't need PyXML | |||||
| """ | |||||
| try: | |||||
| from xml.ns import SOAP, SCHEMA, WSDL, XMLNS, DSIG, ENCRYPTION | |||||
| DSIG.C14N = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315" | |||||
| except: | |||||
| class SOAP: | |||||
| ENV = "http://schemas.xmlsoap.org/soap/envelope/" | |||||
| ENC = "http://schemas.xmlsoap.org/soap/encoding/" | |||||
| ACTOR_NEXT = "http://schemas.xmlsoap.org/soap/actor/next" | |||||
| class SCHEMA: | |||||
| XSD1 = "http://www.w3.org/1999/XMLSchema" | |||||
| XSD2 = "http://www.w3.org/2000/10/XMLSchema" | |||||
| XSD3 = "http://www.w3.org/2001/XMLSchema" | |||||
| XSD_LIST = [ XSD1, XSD2, XSD3 ] | |||||
| XSI1 = "http://www.w3.org/1999/XMLSchema-instance" | |||||
| XSI2 = "http://www.w3.org/2000/10/XMLSchema-instance" | |||||
| XSI3 = "http://www.w3.org/2001/XMLSchema-instance" | |||||
| XSI_LIST = [ XSI1, XSI2, XSI3 ] | |||||
| BASE = XSD3 | |||||
| class WSDL: | |||||
| BASE = "http://schemas.xmlsoap.org/wsdl/" | |||||
| BIND_HTTP = "http://schemas.xmlsoap.org/wsdl/http/" | |||||
| BIND_MIME = "http://schemas.xmlsoap.org/wsdl/mime/" | |||||
| BIND_SOAP = "http://schemas.xmlsoap.org/wsdl/soap/" | |||||
| BIND_SOAP12 = "http://schemas.xmlsoap.org/wsdl/soap12/" | |||||
| class XMLNS: | |||||
| BASE = "http://www.w3.org/2000/xmlns/" | |||||
| XML = "http://www.w3.org/XML/1998/namespace" | |||||
| HTML = "http://www.w3.org/TR/REC-html40" | |||||
| class DSIG: | |||||
| BASE = "http://www.w3.org/2000/09/xmldsig#" | |||||
| C14N = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315" | |||||
| C14N_COMM = "http://www.w3.org/TR/2000/CR-xml-c14n-20010315#WithComments" | |||||
| C14N_EXCL = "http://www.w3.org/2001/10/xml-exc-c14n#" | |||||
| DIGEST_MD2 = "http://www.w3.org/2000/09/xmldsig#md2" | |||||
| DIGEST_MD5 = "http://www.w3.org/2000/09/xmldsig#md5" | |||||
| DIGEST_SHA1 = "http://www.w3.org/2000/09/xmldsig#sha1" | |||||
| ENC_BASE64 = "http://www.w3.org/2000/09/xmldsig#base64" | |||||
| ENVELOPED = "http://www.w3.org/2000/09/xmldsig#enveloped-signature" | |||||
| HMAC_SHA1 = "http://www.w3.org/2000/09/xmldsig#hmac-sha1" | |||||
| SIG_DSA_SHA1 = "http://www.w3.org/2000/09/xmldsig#dsa-sha1" | |||||
| SIG_RSA_SHA1 = "http://www.w3.org/2000/09/xmldsig#rsa-sha1" | |||||
| XPATH = "http://www.w3.org/TR/1999/REC-xpath-19991116" | |||||
| XSLT = "http://www.w3.org/TR/1999/REC-xslt-19991116" | |||||
| class ENCRYPTION: | |||||
| BASE = "http://www.w3.org/2001/04/xmlenc#" | |||||
| BLOCK_3DES = "http://www.w3.org/2001/04/xmlenc#des-cbc" | |||||
| BLOCK_AES128 = "http://www.w3.org/2001/04/xmlenc#aes128-cbc" | |||||
| BLOCK_AES192 = "http://www.w3.org/2001/04/xmlenc#aes192-cbc" | |||||
| BLOCK_AES256 = "http://www.w3.org/2001/04/xmlenc#aes256-cbc" | |||||
| DIGEST_RIPEMD160 = "http://www.w3.org/2001/04/xmlenc#ripemd160" | |||||
| DIGEST_SHA256 = "http://www.w3.org/2001/04/xmlenc#sha256" | |||||
| DIGEST_SHA512 = "http://www.w3.org/2001/04/xmlenc#sha512" | |||||
| KA_DH = "http://www.w3.org/2001/04/xmlenc#dh" | |||||
| KT_RSA_1_5 = "http://www.w3.org/2001/04/xmlenc#rsa-1_5" | |||||
| KT_RSA_OAEP = "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" | |||||
| STREAM_ARCFOUR = "http://www.w3.org/2001/04/xmlenc#arcfour" | |||||
| WRAP_3DES = "http://www.w3.org/2001/04/xmlenc#kw-3des" | |||||
| WRAP_AES128 = "http://www.w3.org/2001/04/xmlenc#kw-aes128" | |||||
| WRAP_AES192 = "http://www.w3.org/2001/04/xmlenc#kw-aes192" | |||||
| WRAP_AES256 = "http://www.w3.org/2001/04/xmlenc#kw-aes256" | |||||
| class OASIS: | |||||
| '''URLs for Oasis specifications | |||||
| ''' | |||||
| WSSE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" | |||||
| UTILITY = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" | |||||
| LIFETIME = "http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ResourceLifetime-1.2-draft-01.xsd" | |||||
| PROPERTIES = "http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ResourceProperties-1.2-draft-01.xsd" | |||||
| BASENOTIFICATION = "http://docs.oasis-open.org/wsn/2004/06/wsn-WS-BaseNotification-1.2-draft-01.xsd" | |||||
| BASEFAULTS = "http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-BaseFaults-1.2-draft-01.xsd" | |||||
| class WSSE: | |||||
| BASE = "http://schemas.xmlsoap.org/ws/2002/04/secext" | |||||
| TRUST = "http://schemas.xmlsoap.org/ws/2004/04/trust" | |||||
| class WSU: | |||||
| BASE = "http://schemas.xmlsoap.org/ws/2002/04/utility" | |||||
| UTILITY = "http://schemas.xmlsoap.org/ws/2002/07/utility" | |||||
| class WSR: | |||||
| PROPERTIES = "http://www.ibm.com/xmlns/stdwip/web-services/WS-ResourceProperties" | |||||
| LIFETIME = "http://www.ibm.com/xmlns/stdwip/web-services/WS-ResourceLifetime" | |||||
| class WSA200408: | |||||
| ADDRESS = "http://schemas.xmlsoap.org/ws/2004/08/addressing" | |||||
| ANONYMOUS = "%s/role/anonymous" %ADDRESS | |||||
| FAULT = "%s/fault" %ADDRESS | |||||
| WSA = WSA200408 | |||||
| class WSA200403: | |||||
| ADDRESS = "http://schemas.xmlsoap.org/ws/2004/03/addressing" | |||||
| ANONYMOUS = "%s/role/anonymous" %ADDRESS | |||||
| FAULT = "%s/fault" %ADDRESS | |||||
| class WSA200303: | |||||
| ADDRESS = "http://schemas.xmlsoap.org/ws/2003/03/addressing" | |||||
| ANONYMOUS = "%s/role/anonymous" %ADDRESS | |||||
| FAULT = None | |||||
| class WSP: | |||||
| POLICY = "http://schemas.xmlsoap.org/ws/2002/12/policy" | |||||
| class BEA: | |||||
| SECCONV = "http://schemas.xmlsoap.org/ws/2004/04/sc" | |||||
| class GLOBUS: | |||||
| SECCONV = "http://wsrf.globus.org/core/2004/07/security/secconv" | |||||
| CORE = "http://www.globus.org/namespaces/2004/06/core" | |||||
| SIG = "http://www.globus.org/2002/04/xmlenc#gssapi-sign" | |||||
| ZSI_SCHEMA_URI = 'http://www.zolera.com/schemas/ZSI/' | |||||
| @@ -0,0 +1,179 @@ | |||||
| """Based on code from timeout_socket.py, with some tweaks for compatibility. | |||||
| These tweaks should really be rolled back into timeout_socket, but it's | |||||
| not totally clear who is maintaining it at this point. In the meantime, | |||||
| we'll use a different module name for our tweaked version to avoid any | |||||
| confusion. | |||||
| The original timeout_socket is by: | |||||
| Scott Cotton <scott@chronis.pobox.com> | |||||
| Lloyd Zusman <ljz@asfast.com> | |||||
| Phil Mayes <pmayes@olivebr.com> | |||||
| Piers Lauder <piers@cs.su.oz.au> | |||||
| Radovan Garabik <garabik@melkor.dnp.fmph.uniba.sk> | |||||
| """ | |||||
| ident = "$Id: TimeoutSocket.py,v 1.2 2003/05/20 21:10:12 warnes Exp $" | |||||
| import string, socket, select, errno | |||||
| WSAEINVAL = getattr(errno, 'WSAEINVAL', 10022) | |||||
| class TimeoutSocket: | |||||
| """A socket imposter that supports timeout limits.""" | |||||
| def __init__(self, timeout=20, sock=None): | |||||
| self.timeout = float(timeout) | |||||
| self.inbuf = '' | |||||
| if sock is None: | |||||
| sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |||||
| self.sock = sock | |||||
| self.sock.setblocking(0) | |||||
| self._rbuf = '' | |||||
| self._wbuf = '' | |||||
| def __getattr__(self, name): | |||||
| # Delegate to real socket attributes. | |||||
| return getattr(self.sock, name) | |||||
| def connect(self, *addr): | |||||
| timeout = self.timeout | |||||
| sock = self.sock | |||||
| try: | |||||
| # Non-blocking mode | |||||
| sock.setblocking(0) | |||||
| apply(sock.connect, addr) | |||||
| sock.setblocking(timeout != 0) | |||||
| return 1 | |||||
| except socket.error,why: | |||||
| if not timeout: | |||||
| raise | |||||
| sock.setblocking(1) | |||||
| if len(why.args) == 1: | |||||
| code = 0 | |||||
| else: | |||||
| code, why = why | |||||
| if code not in ( | |||||
| errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK | |||||
| ): | |||||
| raise | |||||
| r,w,e = select.select([],[sock],[],timeout) | |||||
| if w: | |||||
| try: | |||||
| apply(sock.connect, addr) | |||||
| return 1 | |||||
| except socket.error,why: | |||||
| if len(why.args) == 1: | |||||
| code = 0 | |||||
| else: | |||||
| code, why = why | |||||
| if code in (errno.EISCONN, WSAEINVAL): | |||||
| return 1 | |||||
| raise | |||||
| raise TimeoutError('socket connect() timeout.') | |||||
| def send(self, data, flags=0): | |||||
| total = len(data) | |||||
| next = 0 | |||||
| while 1: | |||||
| r, w, e = select.select([],[self.sock], [], self.timeout) | |||||
| if w: | |||||
| buff = data[next:next + 8192] | |||||
| sent = self.sock.send(buff, flags) | |||||
| next = next + sent | |||||
| if next == total: | |||||
| return total | |||||
| continue | |||||
| raise TimeoutError('socket send() timeout.') | |||||
| def recv(self, amt, flags=0): | |||||
| if select.select([self.sock], [], [], self.timeout)[0]: | |||||
| return self.sock.recv(amt, flags) | |||||
| raise TimeoutError('socket recv() timeout.') | |||||
| buffsize = 4096 | |||||
| handles = 1 | |||||
| def makefile(self, mode="r", buffsize=-1): | |||||
| self.handles = self.handles + 1 | |||||
| self.mode = mode | |||||
| return self | |||||
| def close(self): | |||||
| self.handles = self.handles - 1 | |||||
| if self.handles == 0 and self.sock.fileno() >= 0: | |||||
| self.sock.close() | |||||
| def read(self, n=-1): | |||||
| if not isinstance(n, type(1)): | |||||
| n = -1 | |||||
| if n >= 0: | |||||
| k = len(self._rbuf) | |||||
| if n <= k: | |||||
| data = self._rbuf[:n] | |||||
| self._rbuf = self._rbuf[n:] | |||||
| return data | |||||
| n = n - k | |||||
| L = [self._rbuf] | |||||
| self._rbuf = "" | |||||
| while n > 0: | |||||
| new = self.recv(max(n, self.buffsize)) | |||||
| if not new: break | |||||
| k = len(new) | |||||
| if k > n: | |||||
| L.append(new[:n]) | |||||
| self._rbuf = new[n:] | |||||
| break | |||||
| L.append(new) | |||||
| n = n - k | |||||
| return "".join(L) | |||||
| k = max(4096, self.buffsize) | |||||
| L = [self._rbuf] | |||||
| self._rbuf = "" | |||||
| while 1: | |||||
| new = self.recv(k) | |||||
| if not new: break | |||||
| L.append(new) | |||||
| k = min(k*2, 1024**2) | |||||
| return "".join(L) | |||||
| def readline(self, limit=-1): | |||||
| data = "" | |||||
| i = self._rbuf.find('\n') | |||||
| while i < 0 and not (0 < limit <= len(self._rbuf)): | |||||
| new = self.recv(self.buffsize) | |||||
| if not new: break | |||||
| i = new.find('\n') | |||||
| if i >= 0: i = i + len(self._rbuf) | |||||
| self._rbuf = self._rbuf + new | |||||
| if i < 0: i = len(self._rbuf) | |||||
| else: i = i+1 | |||||
| if 0 <= limit < len(self._rbuf): i = limit | |||||
| data, self._rbuf = self._rbuf[:i], self._rbuf[i:] | |||||
| return data | |||||
| def readlines(self, sizehint = 0): | |||||
| total = 0 | |||||
| list = [] | |||||
| while 1: | |||||
| line = self.readline() | |||||
| if not line: break | |||||
| list.append(line) | |||||
| total += len(line) | |||||
| if sizehint and total >= sizehint: | |||||
| break | |||||
| return list | |||||
| def writelines(self, list): | |||||
| self.send(''.join(list)) | |||||
| def write(self, data): | |||||
| self.send(data) | |||||
| def flush(self): | |||||
| pass | |||||
| class TimeoutError(Exception): | |||||
| pass | |||||
| @@ -0,0 +1,99 @@ | |||||
| """ | |||||
| A more or less complete user-defined wrapper around tuple objects. | |||||
| Adapted version of the standard library's UserList. | |||||
| Taken from Stefan Schwarzer's ftputil library, available at | |||||
| <http://www.ndh.net/home/sschwarzer/python/python_software.html>, and used under this license: | |||||
| Copyright (C) 1999, Stefan Schwarzer | |||||
| All rights reserved. | |||||
| Redistribution and use in source and binary forms, with or without | |||||
| modification, are permitted provided that the following conditions are | |||||
| met: | |||||
| - Redistributions of source code must retain the above copyright | |||||
| notice, this list of conditions and the following disclaimer. | |||||
| - Redistributions in binary form must reproduce the above copyright | |||||
| notice, this list of conditions and the following disclaimer in the | |||||
| documentation and/or other materials provided with the distribution. | |||||
| - Neither the name of the above author nor the names of the | |||||
| contributors to the software may be used to endorse or promote | |||||
| products derived from this software without specific prior written | |||||
| permission. | |||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |||||
| ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |||||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |||||
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR | |||||
| CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |||||
| EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |||||
| PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |||||
| PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |||||
| LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |||||
| NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||||
| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
| """ | |||||
| # $Id: UserTuple.py,v 1.1 2003/07/21 14:18:54 warnes Exp $ | |||||
| #XXX tuple instances (in Python 2.2) contain also: | |||||
| # __class__, __delattr__, __getattribute__, __hash__, __new__, | |||||
| # __reduce__, __setattr__, __str__ | |||||
| # What about these? | |||||
| class UserTuple: | |||||
| def __init__(self, inittuple=None): | |||||
| self.data = () | |||||
| if inittuple is not None: | |||||
| # XXX should this accept an arbitrary sequence? | |||||
| if type(inittuple) == type(self.data): | |||||
| self.data = inittuple | |||||
| elif isinstance(inittuple, UserTuple): | |||||
| # this results in | |||||
| # self.data is inittuple.data | |||||
| # but that's ok for tuples because they are | |||||
| # immutable. (Builtin tuples behave the same.) | |||||
| self.data = inittuple.data[:] | |||||
| else: | |||||
| # the same applies here; (t is tuple(t)) == 1 | |||||
| self.data = tuple(inittuple) | |||||
| def __repr__(self): return repr(self.data) | |||||
| def __lt__(self, other): return self.data < self.__cast(other) | |||||
| def __le__(self, other): return self.data <= self.__cast(other) | |||||
| def __eq__(self, other): return self.data == self.__cast(other) | |||||
| def __ne__(self, other): return self.data != self.__cast(other) | |||||
| def __gt__(self, other): return self.data > self.__cast(other) | |||||
| def __ge__(self, other): return self.data >= self.__cast(other) | |||||
| def __cast(self, other): | |||||
| if isinstance(other, UserTuple): return other.data | |||||
| else: return other | |||||
| def __cmp__(self, other): | |||||
| return cmp(self.data, self.__cast(other)) | |||||
| def __contains__(self, item): return item in self.data | |||||
| def __len__(self): return len(self.data) | |||||
| def __getitem__(self, i): return self.data[i] | |||||
| def __getslice__(self, i, j): | |||||
| i = max(i, 0); j = max(j, 0) | |||||
| return self.__class__(self.data[i:j]) | |||||
| def __add__(self, other): | |||||
| if isinstance(other, UserTuple): | |||||
| return self.__class__(self.data + other.data) | |||||
| elif isinstance(other, type(self.data)): | |||||
| return self.__class__(self.data + other) | |||||
| else: | |||||
| return self.__class__(self.data + tuple(other)) | |||||
| # dir( () ) contains no __radd__ (at least in Python 2.2) | |||||
| def __mul__(self, n): | |||||
| return self.__class__(self.data*n) | |||||
| __rmul__ = __mul__ | |||||
| @@ -0,0 +1,90 @@ | |||||
| """Translate strings to and from SOAP 1.2 XML name encoding | |||||
| Implements rules for mapping application defined name to XML names | |||||
| specified by the w3 SOAP working group for SOAP version 1.2 in | |||||
| Appendix A of "SOAP Version 1.2 Part 2: Adjuncts", W3C Working Draft | |||||
| 17, December 2001, <http://www.w3.org/TR/soap12-part2/#namemap> | |||||
| Also see <http://www.w3.org/2000/xp/Group/xmlp-issues>. | |||||
| Author: Gregory R. Warnes <Gregory.R.Warnes@Pfizer.com> | |||||
| Date:: 2002-04-25 | |||||
| Version 0.9.0 | |||||
| """ | |||||
| ident = "$Id: XMLname.py,v 1.4 2005/02/16 14:45:37 warnes Exp $" | |||||
| from re import * | |||||
| def _NCNameChar(x): | |||||
| return x.isalpha() or x.isdigit() or x=="." or x=='-' or x=="_" | |||||
| def _NCNameStartChar(x): | |||||
| return x.isalpha() or x=="_" | |||||
| def _toUnicodeHex(x): | |||||
| hexval = hex(ord(x[0]))[2:] | |||||
| hexlen = len(hexval) | |||||
| # Make hexval have either 4 or 8 digits by prepending 0's | |||||
| if (hexlen==1): hexval = "000" + hexval | |||||
| elif (hexlen==2): hexval = "00" + hexval | |||||
| elif (hexlen==3): hexval = "0" + hexval | |||||
| elif (hexlen==4): hexval = "" + hexval | |||||
| elif (hexlen==5): hexval = "000" + hexval | |||||
| elif (hexlen==6): hexval = "00" + hexval | |||||
| elif (hexlen==7): hexval = "0" + hexval | |||||
| elif (hexlen==8): hexval = "" + hexval | |||||
| else: raise Exception, "Illegal Value returned from hex(ord(x))" | |||||
| return "_x"+ hexval + "_" | |||||
| def _fromUnicodeHex(x): | |||||
| return eval( r'u"\u'+x[2:-1]+'"' ) | |||||
| def toXMLname(string): | |||||
| """Convert string to a XML name.""" | |||||
| if string.find(':') != -1 : | |||||
| (prefix, localname) = string.split(':',1) | |||||
| else: | |||||
| prefix = None | |||||
| localname = string | |||||
| T = unicode(localname) | |||||
| N = len(localname) | |||||
| X = []; | |||||
| for i in range(N) : | |||||
| if i< N-1 and T[i]==u'_' and T[i+1]==u'x': | |||||
| X.append(u'_x005F_') | |||||
| elif i==0 and N >= 3 and \ | |||||
| ( T[0]==u'x' or T[0]==u'X' ) and \ | |||||
| ( T[1]==u'm' or T[1]==u'M' ) and \ | |||||
| ( T[2]==u'l' or T[2]==u'L' ): | |||||
| X.append(u'_xFFFF_' + T[0]) | |||||
| elif (not _NCNameChar(T[i])) or (i==0 and not _NCNameStartChar(T[i])): | |||||
| X.append(_toUnicodeHex(T[i])) | |||||
| else: | |||||
| X.append(T[i]) | |||||
| if prefix: | |||||
| return "%s:%s" % (prefix, u''.join(X)) | |||||
| return u''.join(X) | |||||
| def fromXMLname(string): | |||||
| """Convert XML name to unicode string.""" | |||||
| retval = sub(r'_xFFFF_','', string ) | |||||
| def fun( matchobj ): | |||||
| return _fromUnicodeHex( matchobj.group(0) ) | |||||
| retval = sub(r'_x[0-9A-Za-z]+_', fun, retval ) | |||||
| return retval | |||||
| @@ -0,0 +1,9 @@ | |||||
| #! /usr/bin/env python | |||||
| """WSDL parsing services package for Web Services for Python.""" | |||||
| ident = "$Id: __init__.py,v 1.11 2004/12/07 15:54:53 blunck2 Exp $" | |||||
| import WSDLTools | |||||
| import XMLname | |||||
| import logging | |||||
| @@ -0,0 +1,536 @@ | |||||
| #! /usr/bin/env python | |||||
| """Compatibility module, imported by ZSI if you don't have PyXML 0.7. | |||||
| No copyright violations -- we're only using parts of PyXML that we | |||||
| wrote. | |||||
| """ | |||||
| _copyright = '''ZSI: Zolera Soap Infrastructure. | |||||
| Copyright 2001, Zolera Systems, Inc. All Rights Reserved. | |||||
| Copyright 2002-2003, Rich Salz. All Rights Reserved. | |||||
| Permission is hereby granted, free of charge, to any person obtaining a | |||||
| copy of this software and associated documentation files (the "Software"), | |||||
| to deal in the Software without restriction, including without limitation | |||||
| the rights to use, copy, modify, merge, publish, distribute, and/or | |||||
| sell copies of the Software, and to permit persons to whom the Software | |||||
| is furnished to do so, provided that the above copyright notice(s) and | |||||
| this permission notice appear in all copies of the Software and that | |||||
| both the above copyright notice(s) and this permission notice appear in | |||||
| supporting documentation. | |||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |||||
| EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |||||
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT | |||||
| OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS | |||||
| INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT | |||||
| OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS | |||||
| OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE | |||||
| OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE | |||||
| OR PERFORMANCE OF THIS SOFTWARE. | |||||
| Except as contained in this notice, the name of a copyright holder | |||||
| shall not be used in advertising or otherwise to promote the sale, use | |||||
| or other dealings in this Software without prior written authorization | |||||
| of the copyright holder. | |||||
| ''' | |||||
| _copyright += "\n\nPortions are also: " | |||||
| _copyright += '''Copyright 2001, Zolera Systems Inc. All Rights Reserved. | |||||
| Copyright 2001, MIT. All Rights Reserved. | |||||
| Distributed under the terms of: | |||||
| Python 2.0 License or later. | |||||
| http://www.python.org/2.0.1/license.html | |||||
| or | |||||
| W3C Software License | |||||
| http://www.w3.org/Consortium/Legal/copyright-software-19980720 | |||||
| ''' | |||||
| from xml.dom import Node | |||||
| from Namespaces import XMLNS | |||||
| import cStringIO as StringIO | |||||
| try: | |||||
| from xml.dom.ext import c14n | |||||
| except ImportError, ex: | |||||
| _implementation2 = None | |||||
| _attrs = lambda E: (E.attributes and E.attributes.values()) or [] | |||||
| _children = lambda E: E.childNodes or [] | |||||
| else: | |||||
| class _implementation2(c14n._implementation): | |||||
| """Patch for exclusive c14n | |||||
| """ | |||||
| def __init__(self, node, write, **kw): | |||||
| self.unsuppressedPrefixes = kw.get('unsuppressedPrefixes') | |||||
| self._exclusive = None | |||||
| if node.nodeType == Node.ELEMENT_NODE: | |||||
| if not c14n._inclusive(self): | |||||
| self._exclusive = self._inherit_context(node) | |||||
| c14n._implementation.__init__(self, node, write, **kw) | |||||
| def _do_element(self, node, initial_other_attrs = []): | |||||
| """Patch for the xml.dom.ext.c14n implemenation _do_element method. | |||||
| This fixes a problem with sorting of namespaces. | |||||
| """ | |||||
| # Get state (from the stack) make local copies. | |||||
| # ns_parent -- NS declarations in parent | |||||
| # ns_rendered -- NS nodes rendered by ancestors | |||||
| # ns_local -- NS declarations relevant to this element | |||||
| # xml_attrs -- Attributes in XML namespace from parent | |||||
| # xml_attrs_local -- Local attributes in XML namespace. | |||||
| ns_parent, ns_rendered, xml_attrs = \ | |||||
| self.state[0], self.state[1].copy(), self.state[2].copy() #0422 | |||||
| ns_local = ns_parent.copy() | |||||
| xml_attrs_local = {} | |||||
| # Divide attributes into NS, XML, and others. | |||||
| #other_attrs = initial_other_attrs[:] | |||||
| other_attrs = [] | |||||
| sort_these_attrs = initial_other_attrs[:] | |||||
| in_subset = c14n._in_subset(self.subset, node) | |||||
| #for a in _attrs(node): | |||||
| sort_these_attrs +=c14n._attrs(node) | |||||
| for a in sort_these_attrs: | |||||
| if a.namespaceURI == c14n.XMLNS.BASE: | |||||
| n = a.nodeName | |||||
| if n == "xmlns:": n = "xmlns" # DOM bug workaround | |||||
| ns_local[n] = a.nodeValue | |||||
| elif a.namespaceURI == c14n.XMLNS.XML: | |||||
| if c14n._inclusive(self) or (in_subset and c14n._in_subset(self.subset, a)): #020925 Test to see if attribute node in subset | |||||
| xml_attrs_local[a.nodeName] = a #0426 | |||||
| else: | |||||
| if c14n._in_subset(self.subset, a): #020925 Test to see if attribute node in subset | |||||
| other_attrs.append(a) | |||||
| #add local xml:foo attributes to ancestor's xml:foo attributes | |||||
| xml_attrs.update(xml_attrs_local) | |||||
| # Render the node | |||||
| W, name = self.write, None | |||||
| if in_subset: | |||||
| name = node.nodeName | |||||
| W('<') | |||||
| W(name) | |||||
| # Create list of NS attributes to render. | |||||
| ns_to_render = [] | |||||
| for n,v in ns_local.items(): | |||||
| # If default namespace is XMLNS.BASE or empty, | |||||
| # and if an ancestor was the same | |||||
| if n == "xmlns" and v in [ c14n.XMLNS.BASE, '' ] \ | |||||
| and ns_rendered.get('xmlns') in [ c14n.XMLNS.BASE, '', None ]: | |||||
| continue | |||||
| # "omit namespace node with local name xml, which defines | |||||
| # the xml prefix, if its string value is | |||||
| # http://www.w3.org/XML/1998/namespace." | |||||
| if n in ["xmlns:xml", "xml"] \ | |||||
| and v in [ 'http://www.w3.org/XML/1998/namespace' ]: | |||||
| continue | |||||
| # If not previously rendered | |||||
| # and it's inclusive or utilized | |||||
| if (n,v) not in ns_rendered.items() \ | |||||
| and (c14n._inclusive(self) or \ | |||||
| c14n._utilized(n, node, other_attrs, self.unsuppressedPrefixes)): | |||||
| ns_to_render.append((n, v)) | |||||
| ##################################### | |||||
| # JRB | |||||
| ##################################### | |||||
| if not c14n._inclusive(self): | |||||
| if node.prefix is None: | |||||
| look_for = [('xmlns', node.namespaceURI),] | |||||
| else: | |||||
| look_for = [('xmlns:%s' %node.prefix, node.namespaceURI),] | |||||
| for a in c14n._attrs(node): | |||||
| if a.namespaceURI != XMLNS.BASE: | |||||
| #print "ATTRIBUTE: ", (a.namespaceURI, a.prefix) | |||||
| if a.prefix: | |||||
| #print "APREFIX: ", a.prefix | |||||
| look_for.append(('xmlns:%s' %a.prefix, a.namespaceURI)) | |||||
| for key,namespaceURI in look_for: | |||||
| if ns_rendered.has_key(key): | |||||
| if ns_rendered[key] == namespaceURI: | |||||
| # Dont write out | |||||
| pass | |||||
| else: | |||||
| #ns_to_render += [(key, namespaceURI)] | |||||
| pass | |||||
| elif (key,namespaceURI) in ns_to_render: | |||||
| # Dont write out | |||||
| pass | |||||
| else: | |||||
| # Unique write out, rewrite to render | |||||
| ns_local[key] = namespaceURI | |||||
| for a in self._exclusive: | |||||
| if a.nodeName == key: | |||||
| #self._do_attr(a.nodeName, a.value) | |||||
| #ns_rendered[key] = namespaceURI | |||||
| #break | |||||
| ns_to_render += [(a.nodeName, a.value)] | |||||
| break | |||||
| elif key is None and a.nodeName == 'xmlns': | |||||
| #print "DEFAULT: ", (a.nodeName, a.value) | |||||
| ns_to_render += [(a.nodeName, a.value)] | |||||
| break | |||||
| #print "KEY: ", key | |||||
| else: | |||||
| #print "Look for: ", look_for | |||||
| #print "NS_TO_RENDER: ", ns_to_render | |||||
| #print "EXCLUSIVE NS: ", map(lambda f: (f.nodeName,f.value),self._exclusive) | |||||
| raise RuntimeError, \ | |||||
| 'can not find namespace (%s="%s") for exclusive canonicalization'\ | |||||
| %(key, namespaceURI) | |||||
| ##################################### | |||||
| # Sort and render the ns, marking what was rendered. | |||||
| ns_to_render.sort(c14n._sorter_ns) | |||||
| for n,v in ns_to_render: | |||||
| #XXX JRB, getting 'xmlns,None' here when xmlns='' | |||||
| if v: self._do_attr(n, v) | |||||
| else: | |||||
| v = '' | |||||
| self._do_attr(n, v) | |||||
| ns_rendered[n]=v #0417 | |||||
| # If exclusive or the parent is in the subset, add the local xml attributes | |||||
| # Else, add all local and ancestor xml attributes | |||||
| # Sort and render the attributes. | |||||
| if not c14n._inclusive(self) or c14n._in_subset(self.subset,node.parentNode): #0426 | |||||
| other_attrs.extend(xml_attrs_local.values()) | |||||
| else: | |||||
| other_attrs.extend(xml_attrs.values()) | |||||
| #print "OTHER: ", other_attrs | |||||
| other_attrs.sort(c14n._sorter) | |||||
| for a in other_attrs: | |||||
| self._do_attr(a.nodeName, a.value) | |||||
| W('>') | |||||
| # Push state, recurse, pop state. | |||||
| state, self.state = self.state, (ns_local, ns_rendered, xml_attrs) | |||||
| for c in c14n._children(node): | |||||
| c14n._implementation.handlers[c.nodeType](self, c) | |||||
| self.state = state | |||||
| if name: W('</%s>' % name) | |||||
| c14n._implementation.handlers[c14n.Node.ELEMENT_NODE] = _do_element | |||||
| _IN_XML_NS = lambda n: n.namespaceURI == XMLNS.XML | |||||
| # Does a document/PI has lesser/greater document order than the | |||||
| # first element? | |||||
| _LesserElement, _Element, _GreaterElement = range(3) | |||||
| def _sorter(n1,n2): | |||||
| '''_sorter(n1,n2) -> int | |||||
| Sorting predicate for non-NS attributes.''' | |||||
| i = cmp(n1.namespaceURI, n2.namespaceURI) | |||||
| if i: return i | |||||
| return cmp(n1.localName, n2.localName) | |||||
| def _sorter_ns(n1,n2): | |||||
| '''_sorter_ns((n,v),(n,v)) -> int | |||||
| "(an empty namespace URI is lexicographically least)."''' | |||||
| if n1[0] == 'xmlns': return -1 | |||||
| if n2[0] == 'xmlns': return 1 | |||||
| return cmp(n1[0], n2[0]) | |||||
| def _utilized(n, node, other_attrs, unsuppressedPrefixes): | |||||
| '''_utilized(n, node, other_attrs, unsuppressedPrefixes) -> boolean | |||||
| Return true if that nodespace is utilized within the node''' | |||||
| if n.startswith('xmlns:'): | |||||
| n = n[6:] | |||||
| elif n.startswith('xmlns'): | |||||
| n = n[5:] | |||||
| if n == node.prefix or n in unsuppressedPrefixes: return 1 | |||||
| for attr in other_attrs: | |||||
| if n == attr.prefix: return 1 | |||||
| return 0 | |||||
| _in_subset = lambda subset, node: not subset or node in subset | |||||
| # | |||||
| # JRB. Currently there is a bug in do_element, but since the underlying | |||||
| # Data Structures in c14n have changed I can't just apply the | |||||
| # _implementation2 patch above. But this will work OK for most uses, | |||||
| # just not XML Signatures. | |||||
| # | |||||
| class _implementation: | |||||
| '''Implementation class for C14N. This accompanies a node during it's | |||||
| processing and includes the parameters and processing state.''' | |||||
| # Handler for each node type; populated during module instantiation. | |||||
| handlers = {} | |||||
| def __init__(self, node, write, **kw): | |||||
| '''Create and run the implementation.''' | |||||
| self.write = write | |||||
| self.subset = kw.get('subset') | |||||
| if self.subset: | |||||
| self.comments = kw.get('comments', 1) | |||||
| else: | |||||
| self.comments = kw.get('comments', 0) | |||||
| self.unsuppressedPrefixes = kw.get('unsuppressedPrefixes') | |||||
| nsdict = kw.get('nsdict', { 'xml': XMLNS.XML, 'xmlns': XMLNS.BASE }) | |||||
| # Processing state. | |||||
| self.state = (nsdict, ['xml'], []) | |||||
| if node.nodeType == Node.DOCUMENT_NODE: | |||||
| self._do_document(node) | |||||
| elif node.nodeType == Node.ELEMENT_NODE: | |||||
| self.documentOrder = _Element # At document element | |||||
| if self.unsuppressedPrefixes is not None: | |||||
| self._do_element(node) | |||||
| else: | |||||
| inherited = self._inherit_context(node) | |||||
| self._do_element(node, inherited) | |||||
| elif node.nodeType == Node.DOCUMENT_TYPE_NODE: | |||||
| pass | |||||
| else: | |||||
| raise TypeError, str(node) | |||||
| def _inherit_context(self, node): | |||||
| '''_inherit_context(self, node) -> list | |||||
| Scan ancestors of attribute and namespace context. Used only | |||||
| for single element node canonicalization, not for subset | |||||
| canonicalization.''' | |||||
| # Collect the initial list of xml:foo attributes. | |||||
| xmlattrs = filter(_IN_XML_NS, _attrs(node)) | |||||
| # Walk up and get all xml:XXX attributes we inherit. | |||||
| inherited, parent = [], node.parentNode | |||||
| while parent and parent.nodeType == Node.ELEMENT_NODE: | |||||
| for a in filter(_IN_XML_NS, _attrs(parent)): | |||||
| n = a.localName | |||||
| if n not in xmlattrs: | |||||
| xmlattrs.append(n) | |||||
| inherited.append(a) | |||||
| parent = parent.parentNode | |||||
| return inherited | |||||
| def _do_document(self, node): | |||||
| '''_do_document(self, node) -> None | |||||
| Process a document node. documentOrder holds whether the document | |||||
| element has been encountered such that PIs/comments can be written | |||||
| as specified.''' | |||||
| self.documentOrder = _LesserElement | |||||
| for child in node.childNodes: | |||||
| if child.nodeType == Node.ELEMENT_NODE: | |||||
| self.documentOrder = _Element # At document element | |||||
| self._do_element(child) | |||||
| self.documentOrder = _GreaterElement # After document element | |||||
| elif child.nodeType == Node.PROCESSING_INSTRUCTION_NODE: | |||||
| self._do_pi(child) | |||||
| elif child.nodeType == Node.COMMENT_NODE: | |||||
| self._do_comment(child) | |||||
| elif child.nodeType == Node.DOCUMENT_TYPE_NODE: | |||||
| pass | |||||
| else: | |||||
| raise TypeError, str(child) | |||||
| handlers[Node.DOCUMENT_NODE] = _do_document | |||||
| def _do_text(self, node): | |||||
| '''_do_text(self, node) -> None | |||||
| Process a text or CDATA node. Render various special characters | |||||
| as their C14N entity representations.''' | |||||
| if not _in_subset(self.subset, node): return | |||||
| s = node.data \ | |||||
| .replace("&", "&") \ | |||||
| .replace("<", "<") \ | |||||
| .replace(">", ">") \ | |||||
| .replace("\015", "
") | |||||
| if s: self.write(s) | |||||
| handlers[Node.TEXT_NODE] = _do_text | |||||
| handlers[Node.CDATA_SECTION_NODE] = _do_text | |||||
| def _do_pi(self, node): | |||||
| '''_do_pi(self, node) -> None | |||||
| Process a PI node. Render a leading or trailing #xA if the | |||||
| document order of the PI is greater or lesser (respectively) | |||||
| than the document element. | |||||
| ''' | |||||
| if not _in_subset(self.subset, node): return | |||||
| W = self.write | |||||
| if self.documentOrder == _GreaterElement: W('\n') | |||||
| W('<?') | |||||
| W(node.nodeName) | |||||
| s = node.data | |||||
| if s: | |||||
| W(' ') | |||||
| W(s) | |||||
| W('?>') | |||||
| if self.documentOrder == _LesserElement: W('\n') | |||||
| handlers[Node.PROCESSING_INSTRUCTION_NODE] = _do_pi | |||||
| def _do_comment(self, node): | |||||
| '''_do_comment(self, node) -> None | |||||
| Process a comment node. Render a leading or trailing #xA if the | |||||
| document order of the comment is greater or lesser (respectively) | |||||
| than the document element. | |||||
| ''' | |||||
| if not _in_subset(self.subset, node): return | |||||
| if self.comments: | |||||
| W = self.write | |||||
| if self.documentOrder == _GreaterElement: W('\n') | |||||
| W('<!--') | |||||
| W(node.data) | |||||
| W('-->') | |||||
| if self.documentOrder == _LesserElement: W('\n') | |||||
| handlers[Node.COMMENT_NODE] = _do_comment | |||||
| def _do_attr(self, n, value): | |||||
| ''''_do_attr(self, node) -> None | |||||
| Process an attribute.''' | |||||
| W = self.write | |||||
| W(' ') | |||||
| W(n) | |||||
| W('="') | |||||
| s = value \ | |||||
| .replace("&", "&") \ | |||||
| .replace("<", "<") \ | |||||
| .replace('"', '"') \ | |||||
| .replace('\011', '	') \ | |||||
| .replace('\012', '
') \ | |||||
| .replace('\015', '
') | |||||
| W(s) | |||||
| W('"') | |||||
| def _do_element(self, node, initial_other_attrs = []): | |||||
| '''_do_element(self, node, initial_other_attrs = []) -> None | |||||
| Process an element (and its children).''' | |||||
| # Get state (from the stack) make local copies. | |||||
| # ns_parent -- NS declarations in parent | |||||
| # ns_rendered -- NS nodes rendered by ancestors | |||||
| # xml_attrs -- Attributes in XML namespace from parent | |||||
| # ns_local -- NS declarations relevant to this element | |||||
| ns_parent, ns_rendered, xml_attrs = \ | |||||
| self.state[0], self.state[1][:], self.state[2][:] | |||||
| ns_local = ns_parent.copy() | |||||
| # Divide attributes into NS, XML, and others. | |||||
| other_attrs = initial_other_attrs[:] | |||||
| in_subset = _in_subset(self.subset, node) | |||||
| for a in _attrs(node): | |||||
| if a.namespaceURI == XMLNS.BASE: | |||||
| n = a.nodeName | |||||
| if n == "xmlns:": n = "xmlns" # DOM bug workaround | |||||
| ns_local[n] = a.nodeValue | |||||
| elif a.namespaceURI == XMLNS.XML: | |||||
| if self.unsuppressedPrefixes is None or in_subset: | |||||
| xml_attrs.append(a) | |||||
| else: | |||||
| other_attrs.append(a) | |||||
| # Render the node | |||||
| W, name = self.write, None | |||||
| if in_subset: | |||||
| name = node.nodeName | |||||
| W('<') | |||||
| W(name) | |||||
| # Create list of NS attributes to render. | |||||
| ns_to_render = [] | |||||
| for n,v in ns_local.items(): | |||||
| pval = ns_parent.get(n) | |||||
| # If default namespace is XMLNS.BASE or empty, skip | |||||
| if n == "xmlns" \ | |||||
| and v in [ XMLNS.BASE, '' ] and pval in [ XMLNS.BASE, '' ]: | |||||
| continue | |||||
| # "omit namespace node with local name xml, which defines | |||||
| # the xml prefix, if its string value is | |||||
| # http://www.w3.org/XML/1998/namespace." | |||||
| if n == "xmlns:xml" \ | |||||
| and v in [ 'http://www.w3.org/XML/1998/namespace' ]: | |||||
| continue | |||||
| # If different from parent, or parent didn't render | |||||
| # and if not exclusive, or this prefix is needed or | |||||
| # not suppressed | |||||
| if (v != pval or n not in ns_rendered) \ | |||||
| and (self.unsuppressedPrefixes is None or \ | |||||
| _utilized(n, node, other_attrs, self.unsuppressedPrefixes)): | |||||
| ns_to_render.append((n, v)) | |||||
| # Sort and render the ns, marking what was rendered. | |||||
| ns_to_render.sort(_sorter_ns) | |||||
| for n,v in ns_to_render: | |||||
| self._do_attr(n, v) | |||||
| ns_rendered.append(n) | |||||
| # Add in the XML attributes (don't pass to children, since | |||||
| # we're rendering them), sort, and render. | |||||
| other_attrs.extend(xml_attrs) | |||||
| xml_attrs = [] | |||||
| other_attrs.sort(_sorter) | |||||
| for a in other_attrs: | |||||
| self._do_attr(a.nodeName, a.value) | |||||
| W('>') | |||||
| # Push state, recurse, pop state. | |||||
| state, self.state = self.state, (ns_local, ns_rendered, xml_attrs) | |||||
| for c in _children(node): | |||||
| _implementation.handlers[c.nodeType](self, c) | |||||
| self.state = state | |||||
| if name: W('</%s>' % name) | |||||
| handlers[Node.ELEMENT_NODE] = _do_element | |||||
| def Canonicalize(node, output=None, **kw): | |||||
| '''Canonicalize(node, output=None, **kw) -> UTF-8 | |||||
| Canonicalize a DOM document/element node and all descendents. | |||||
| Return the text; if output is specified then output.write will | |||||
| be called to output the text and None will be returned | |||||
| Keyword parameters: | |||||
| nsdict: a dictionary of prefix:uri namespace entries | |||||
| assumed to exist in the surrounding context | |||||
| comments: keep comments if non-zero (default is 0) | |||||
| subset: Canonical XML subsetting resulting from XPath | |||||
| (default is []) | |||||
| unsuppressedPrefixes: do exclusive C14N, and this specifies the | |||||
| prefixes that should be inherited. | |||||
| ''' | |||||
| if output: | |||||
| if _implementation2 is None: | |||||
| _implementation(node, output.write, **kw) | |||||
| else: | |||||
| apply(_implementation2, (node, output.write), kw) | |||||
| else: | |||||
| s = StringIO.StringIO() | |||||
| if _implementation2 is None: | |||||
| _implementation(node, s.write, **kw) | |||||
| else: | |||||
| apply(_implementation2, (node, s.write), kw) | |||||
| return s.getvalue() | |||||
| if __name__ == '__main__': print _copyright | |||||
| @@ -0,0 +1,85 @@ | |||||
| #! /usr/bin/env python | |||||
| """Logging""" | |||||
| import sys | |||||
| class ILogger: | |||||
| '''Logger interface, by default this class | |||||
| will be used and logging calls are no-ops. | |||||
| ''' | |||||
| level = 0 | |||||
| def __init__(self, msg): | |||||
| return | |||||
| def warning(self, *args): | |||||
| return | |||||
| def debug(self, *args): | |||||
| return | |||||
| def error(self, *args): | |||||
| return | |||||
| def setLevel(cls, level): | |||||
| cls.level = level | |||||
| setLevel = classmethod(setLevel) | |||||
| _LoggerClass = ILogger | |||||
| class BasicLogger(ILogger): | |||||
| def __init__(self, msg, out=sys.stdout): | |||||
| self.msg, self.out = msg, out | |||||
| def warning(self, msg, *args): | |||||
| if self.level < 1: return | |||||
| print >>self, self.WARN, self.msg, | |||||
| print >>self, msg %args | |||||
| WARN = 'WARN' | |||||
| def debug(self, msg, *args): | |||||
| if self.level < 2: return | |||||
| print >>self, self.DEBUG, self.msg, | |||||
| print >>self, msg %args | |||||
| DEBUG = 'DEBUG' | |||||
| def error(self, msg, *args): | |||||
| print >>self, self.ERROR, self.msg, | |||||
| print >>self, msg %args | |||||
| ERROR = 'ERROR' | |||||
| def write(self, *args): | |||||
| '''Write convenience function; writes strings. | |||||
| ''' | |||||
| for s in args: self.out.write(s) | |||||
| def setBasicLogger(): | |||||
| '''Use Basic Logger. | |||||
| ''' | |||||
| setLoggerClass(BasicLogger) | |||||
| BasicLogger.setLevel(0) | |||||
| def setBasicLoggerWARN(): | |||||
| '''Use Basic Logger. | |||||
| ''' | |||||
| setLoggerClass(BasicLogger) | |||||
| BasicLogger.setLevel(1) | |||||
| def setBasicLoggerDEBUG(): | |||||
| '''Use Basic Logger. | |||||
| ''' | |||||
| setLoggerClass(BasicLogger) | |||||
| BasicLogger.setLevel(2) | |||||
| def setLoggerClass(loggingClass): | |||||
| '''Set Logging Class. | |||||
| ''' | |||||
| assert issubclass(loggingClass, ILogger), 'loggingClass must subclass ILogger' | |||||
| global _LoggerClass | |||||
| _LoggerClass = loggingClass | |||||
| def setLevel(level=0): | |||||
| '''Set Global Logging Level. | |||||
| ''' | |||||
| ILogger.level = level | |||||
| def getLogger(msg): | |||||
| '''Return instance of Logging class. | |||||
| ''' | |||||
| return _LoggerClass(msg) | |||||
| @@ -0,0 +1,5 @@ | |||||
| #! /usr/bin/env python | |||||
| """wstools.WSDLTools.WSDLReader tests directory.""" | |||||
| import utils | |||||
| @@ -0,0 +1,20 @@ | |||||
| ############################################################################ | |||||
| # Joshua R. Boverhof, David W. Robertson, LBNL | |||||
| # See LBNLCopyright for copyright notice! | |||||
| ########################################################################### | |||||
| import unittest | |||||
| import test_wsdl | |||||
| import utils | |||||
| def makeTestSuite(): | |||||
| suite = unittest.TestSuite() | |||||
| suite.addTest(test_wsdl.makeTestSuite("services_by_file")) | |||||
| return suite | |||||
| def main(): | |||||
| loader = utils.MatchTestLoader(True, None, "makeTestSuite") | |||||
| unittest.main(defaultTest="makeTestSuite", testLoader=loader) | |||||
| if __name__ == "__main__" : main() | |||||
| @@ -0,0 +1,160 @@ | |||||
| #!/usr/bin/env python | |||||
| ############################################################################ | |||||
| # Joshua R. Boverhof, David W. Robertson, LBNL | |||||
| # See LBNLCopyright for copyright notice! | |||||
| ########################################################################### | |||||
| import sys, unittest | |||||
| import ConfigParser | |||||
| from ZSI.wstools.Utility import DOM | |||||
| from ZSI.wstools.WSDLTools import WSDLReader | |||||
| from ZSI.wstools.TimeoutSocket import TimeoutError | |||||
| class WSDLToolsTestCase(unittest.TestCase): | |||||
| def __init__(self, methodName='runTest'): | |||||
| unittest.TestCase.__init__(self, methodName) | |||||
| def setUp(self): | |||||
| self.path = nameGenerator.next() | |||||
| print self.path | |||||
| sys.stdout.flush() | |||||
| def __str__(self): | |||||
| teststr = unittest.TestCase.__str__(self) | |||||
| if hasattr(self, "path"): | |||||
| return "%s: %s" % (teststr, self.path ) | |||||
| else: | |||||
| return "%s" % (teststr) | |||||
| def checkWSDLCollection(self, tag_name, component, key='name'): | |||||
| if self.wsdl is None: | |||||
| return | |||||
| definition = self.wsdl.document.documentElement | |||||
| version = DOM.WSDLUriToVersion(definition.namespaceURI) | |||||
| nspname = DOM.GetWSDLUri(version) | |||||
| for node in DOM.getElements(definition, tag_name, nspname): | |||||
| name = DOM.getAttr(node, key) | |||||
| comp = component[name] | |||||
| self.failUnlessEqual(eval('comp.%s' %key), name) | |||||
| def checkXSDCollection(self, tag_name, component, node, key='name'): | |||||
| for cnode in DOM.getElements(node, tag_name): | |||||
| name = DOM.getAttr(cnode, key) | |||||
| component[name] | |||||
| def test_all(self): | |||||
| try: | |||||
| if self.path[:7] == 'http://': | |||||
| self.wsdl = WSDLReader().loadFromURL(self.path) | |||||
| else: | |||||
| self.wsdl = WSDLReader().loadFromFile(self.path) | |||||
| except TimeoutError: | |||||
| print "connection timed out" | |||||
| sys.stdout.flush() | |||||
| return | |||||
| except: | |||||
| self.path = self.path + ": load failed, unable to start" | |||||
| raise | |||||
| try: | |||||
| self.checkWSDLCollection('service', self.wsdl.services) | |||||
| except: | |||||
| self.path = self.path + ": wsdl.services" | |||||
| raise | |||||
| try: | |||||
| self.checkWSDLCollection('message', self.wsdl.messages) | |||||
| except: | |||||
| self.path = self.path + ": wsdl.messages" | |||||
| raise | |||||
| try: | |||||
| self.checkWSDLCollection('portType', self.wsdl.portTypes) | |||||
| except: | |||||
| self.path = self.path + ": wsdl.portTypes" | |||||
| raise | |||||
| try: | |||||
| self.checkWSDLCollection('binding', self.wsdl.bindings) | |||||
| except: | |||||
| self.path = self.path + ": wsdl.bindings" | |||||
| raise | |||||
| try: | |||||
| self.checkWSDLCollection('import', self.wsdl.imports, key='namespace') | |||||
| except: | |||||
| self.path = self.path + ": wsdl.imports" | |||||
| raise | |||||
| try: | |||||
| for key in self.wsdl.types.keys(): | |||||
| schema = self.wsdl.types[key] | |||||
| self.failUnlessEqual(key, schema.getTargetNamespace()) | |||||
| definition = self.wsdl.document.documentElement | |||||
| version = DOM.WSDLUriToVersion(definition.namespaceURI) | |||||
| nspname = DOM.GetWSDLUri(version) | |||||
| for node in DOM.getElements(definition, 'types', nspname): | |||||
| for snode in DOM.getElements(node, 'schema'): | |||||
| tns = DOM.findTargetNS(snode) | |||||
| schema = self.wsdl.types[tns] | |||||
| self.schemaAttributesDeclarations(schema, snode) | |||||
| self.schemaAttributeGroupDeclarations(schema, snode) | |||||
| self.schemaElementDeclarations(schema, snode) | |||||
| self.schemaTypeDefinitions(schema, snode) | |||||
| except: | |||||
| self.path = self.path + ": wsdl.types" | |||||
| raise | |||||
| if self.wsdl.extensions: | |||||
| print 'No check for WSDLTools(%s) Extensions:' %(self.wsdl.name) | |||||
| for ext in self.wsdl.extensions: print '\t', ext | |||||
| def schemaAttributesDeclarations(self, schema, node): | |||||
| self.checkXSDCollection('attribute', schema.attr_decl, node) | |||||
| def schemaAttributeGroupDeclarations(self, schema, node): | |||||
| self.checkXSDCollection('group', schema.attr_groups, node) | |||||
| def schemaElementDeclarations(self, schema, node): | |||||
| self.checkXSDCollection('element', schema.elements, node) | |||||
| def schemaTypeDefinitions(self, schema, node): | |||||
| self.checkXSDCollection('complexType', schema.types, node) | |||||
| self.checkXSDCollection('simpleType', schema.types, node) | |||||
| def setUpOptions(section): | |||||
| cp = ConfigParser.ConfigParser() | |||||
| cp.read('config.txt') | |||||
| if not cp.sections(): | |||||
| print 'fatal error: configuration file config.txt not present' | |||||
| sys.exit(0) | |||||
| if not cp.has_section(section): | |||||
| print '%s section not present in configuration file, exiting' % section | |||||
| sys.exit(0) | |||||
| return cp, len(cp.options(section)) | |||||
| def getOption(cp, section): | |||||
| for name, value in cp.items(section): | |||||
| yield value | |||||
| def makeTestSuite(section='services_by_file'): | |||||
| global nameGenerator | |||||
| cp, numTests = setUpOptions(section) | |||||
| nameGenerator = getOption(cp, section) | |||||
| suite = unittest.TestSuite() | |||||
| for i in range(0, numTests): | |||||
| suite.addTest(unittest.makeSuite(WSDLToolsTestCase, 'test_')) | |||||
| return suite | |||||
| def main(): | |||||
| unittest.main(defaultTest="makeTestSuite") | |||||
| if __name__ == "__main__" : main() | |||||
| @@ -0,0 +1,37 @@ | |||||
| #!/usr/bin/env python | |||||
| ############################################################################ | |||||
| # Joshua R. Boverhof, David W. Robertson, LBNL | |||||
| # See LBNLCopyright for copyright notice! | |||||
| ########################################################################### | |||||
| import unittest, tarfile, os, ConfigParser | |||||
| import test_wsdl | |||||
| SECTION='files' | |||||
| CONFIG_FILE = 'config.txt' | |||||
| def extractFiles(section, option): | |||||
| config = ConfigParser.ConfigParser() | |||||
| config.read(CONFIG_FILE) | |||||
| archives = config.get(section, option) | |||||
| archives = eval(archives) | |||||
| for file in archives: | |||||
| tar = tarfile.open(file) | |||||
| if not os.access(tar.membernames[0], os.R_OK): | |||||
| for i in tar.getnames(): | |||||
| tar.extract(i) | |||||
| def makeTestSuite(): | |||||
| suite = unittest.TestSuite() | |||||
| suite.addTest(test_wsdl.makeTestSuite("services_by_file")) | |||||
| return suite | |||||
| def main(): | |||||
| extractFiles(SECTION, 'archives') | |||||
| unittest.main(defaultTest="makeTestSuite") | |||||
| if __name__ == "__main__" : main() | |||||
| @@ -0,0 +1,20 @@ | |||||
| #!/usr/bin/env python | |||||
| ############################################################################ | |||||
| # Joshua R. Boverhof, David W. Robertson, LBNL | |||||
| # See LBNLCopyright for copyright notice! | |||||
| ########################################################################### | |||||
| import unittest | |||||
| import test_wsdl | |||||
| def makeTestSuite(): | |||||
| suite = unittest.TestSuite() | |||||
| suite.addTest(test_wsdl.makeTestSuite("services_by_http")) | |||||
| return suite | |||||
| def main(): | |||||
| unittest.main(defaultTest="makeTestSuite") | |||||
| if __name__ == "__main__" : main() | |||||
| @@ -0,0 +1,14 @@ | |||||
| # $Id: TODO,v 1.6 2003/12/23 10:19:12 warnes Exp $ | |||||
| - figure out why parsing rules are broken | |||||
| - generate a test harness that will run all of the test code. | |||||
| - create unit-tests for all features, as well as for reported bugs. | |||||
| - write better documentation (!!!) | |||||
| - topics: WSDL, Globus, Authentication, ... | |||||
| - general introduction article | |||||
| - ... | |||||
| @@ -0,0 +1,291 @@ | |||||
| #!/usr/bin/env python | |||||
| import getopt | |||||
| import sys | |||||
| import string | |||||
| import re | |||||
| import time | |||||
| sys.path.insert(1,"..") | |||||
| from SOAPpy import SOAP | |||||
| import traceback | |||||
| DEFAULT_SERVERS_FILE = './inventory.servers' | |||||
| DEFAULT_METHODS = ('SimpleBuy', 'RequestForQuote','Buy','Ping') | |||||
| def usage (error = None): | |||||
| sys.stdout = sys.stderr | |||||
| if error != None: | |||||
| print error | |||||
| print """usage: %s [options] [server ...] | |||||
| If a long option shows an argument is mandatory, it's mandatory for the | |||||
| equivalent short option also. | |||||
| -?, --help display this usage | |||||
| -d, --debug turn on debugging in the SOAP library | |||||
| -i, --invert test servers *not* in the list of servers given | |||||
| -m, --method=METHOD#[,METHOD#...] | |||||
| call only the given methods, specify a METHOD# of ? | |||||
| for the list of method numbers | |||||
| -o, --output=TYPE turn on output, TYPE is one or more of s(uccess), | |||||
| f(ailure), n(ot implemented), F(ailed (as expected)), | |||||
| a(ll) | |||||
| [f] | |||||
| -s, --servers=FILE use FILE as list of servers to test [%s] | |||||
| -t, --stacktrace print a stack trace on each unexpected failure | |||||
| -T, --always-stacktrace | |||||
| print a stack trace on any failure | |||||
| """ % (sys.argv[0], DEFAULT_SERVERS_FILE), | |||||
| sys.exit (0) | |||||
| def methodUsage (): | |||||
| sys.stdout = sys.stderr | |||||
| print "Methods are specified by number. Multiple methods can be " \ | |||||
| "specified using a\ncomma-separated list of numbers or ranges. " \ | |||||
| "For example 1,4-6,8 specifies\nmethods 1, 4, 5, 6, and 8.\n" | |||||
| print "The available methods are:\n" | |||||
| half = (len (DEFAULT_METHODS) + 1) / 2 | |||||
| for i in range (half): | |||||
| print "%4d. %-25s" % (i + 1, DEFAULT_METHODS[i]), | |||||
| if i + half < len (DEFAULT_METHODS): | |||||
| print "%4d. %-25s" % (i + 1 + half, DEFAULT_METHODS[i + half]), | |||||
| sys.exit (0) | |||||
| def readServers (file): | |||||
| servers = [] | |||||
| f = open (file, 'r') | |||||
| while 1: | |||||
| line = f.readline () | |||||
| if line == '': | |||||
| break | |||||
| if line[0] in ('#', '\n') or line[0] in string.whitespace: | |||||
| continue | |||||
| cur = {'nonfunctional': {}} | |||||
| tag = None | |||||
| servers.append (cur) | |||||
| while 1: | |||||
| if line[0] in string.whitespace: | |||||
| if tag == 'nonfunctional': | |||||
| value = method + ' ' + cur[tag][method] | |||||
| else: | |||||
| value = cur[tag] | |||||
| value += ' ' + line.strip () | |||||
| else: | |||||
| tag, value = line.split (':', 1) | |||||
| tag = tag.strip ().lower () | |||||
| value = value.strip () | |||||
| if value[0] == '"' and value[-1] == '"': | |||||
| value = value[1:-1] | |||||
| if tag == 'nonfunctional': | |||||
| value = value.split (' ', 1) + [''] | |||||
| method = value[0] | |||||
| cur[tag][method] = value[1] | |||||
| else: | |||||
| cur[tag] = value | |||||
| line = f.readline () | |||||
| if line == '' or line[0] == '\n': | |||||
| break | |||||
| return servers | |||||
| def str2list (s): | |||||
| l = {} | |||||
| for i in s.split (','): | |||||
| if i.find ('-') != -1: | |||||
| i = i.split ('-') | |||||
| for i in range (int (i[0]),int (i[1]) + 1): | |||||
| l[i] = 1 | |||||
| else: | |||||
| l[int (i)] = 1 | |||||
| l = l.keys () | |||||
| l.sort () | |||||
| return l | |||||
| def SimpleBuy(serv, sa, epname): | |||||
| serv = serv._sa (sa % {'methodname':'SimpleBuy'}) | |||||
| return serv.SimpleBuy(ProductName="widget", Quantity = 50, Address = "this is my address") #JHawk, Phalanx require this order of params | |||||
| def RequestForQuote(serv, sa, epname): | |||||
| serv = serv._sa (sa % {'methodname':'RequestForQuote'}) | |||||
| return serv.RequestForQuote(Quantity=3, ProductName = "thing") # for Phalanx, JHawk | |||||
| def Buy(serv, sa, epname): | |||||
| import copy | |||||
| serv = serv._sa (sa % {'methodname':'Buy'}) | |||||
| billTo_d = {"name":"Buyer One", "address":"1 1st Street", | |||||
| "city":"New York", "state":"NY", "zipCode":"10000"} | |||||
| shipTo_d = {"name":"Buyer One ", "address":"1 1st Street ", | |||||
| "city":"New York ", "state":"NY ", "zipCode":"10000 "} | |||||
| for k,v in shipTo_d.items(): | |||||
| shipTo_d[k] = v[:-1] | |||||
| itemd1 = SOAP.structType( {"name":"widg1","quantity":200,"price":SOAP.decimalType(45.99), "_typename":"LineItem"}) | |||||
| itemd2 = SOAP.structType( {"name":"widg2","quantity":400,"price":SOAP.decimalType(33.45), "_typename":"LineItem"}) | |||||
| items_d = SOAP.arrayType( [itemd1, itemd2] ) | |||||
| items_d._ns = "http://www.soapinterop.org/Bid" | |||||
| po_d = SOAP.structType( data = {"poID":"myord","createDate":SOAP.dateTimeType(),"shipTo":shipTo_d, "billTo":billTo_d, "items":items_d}) | |||||
| try: | |||||
| # it's called PO by MST (MS SOAP Toolkit), JHawk (.NET Remoting), | |||||
| # Idoox WASP, Paul (SOAP::Lite), PranishK (ATL), GLUE, Aumsoft, | |||||
| # HP, EasySoap, and Jake (Frontier). [Actzero accepts either] | |||||
| return serv.Buy(PO=po_d) | |||||
| except: | |||||
| # called PurchaseOrder by KeithBa | |||||
| return serv.Buy(PurchaseOrder=po_d) | |||||
| def Ping(serv, sa, epname): | |||||
| serv = serv._sa (sa % {'methodname':'Ping'}) | |||||
| return serv.Ping() | |||||
| def main(): | |||||
| servers = DEFAULT_SERVERS_FILE | |||||
| methodnums = None | |||||
| output = 'f' | |||||
| invert = 0 | |||||
| succeed = 0 | |||||
| printtrace = 0 | |||||
| stats = 1 | |||||
| total = 0 | |||||
| fail = 0 | |||||
| failok = 0 | |||||
| notimp = 0 | |||||
| try: | |||||
| opts,args = getopt.getopt (sys.argv[1:], '?dm:io:s:t', | |||||
| ['help', 'method', 'debug', 'invert', | |||||
| 'output', 'servers=']) | |||||
| for opt, arg in opts: | |||||
| if opt in ('-?', '--help'): | |||||
| usage () | |||||
| elif opt in ('-d', '--debug'): | |||||
| SOAP.Config.debug = 1 | |||||
| elif opt in ('-i', '--invert'): | |||||
| invert = 1 | |||||
| elif opt in ('-m', '--method'): | |||||
| if arg == '?': | |||||
| methodUsage () | |||||
| methodnums = str2list (arg) | |||||
| elif opt in ('-o', '--output'): | |||||
| output = arg | |||||
| elif opt in ('-s', '--servers'): | |||||
| servers = arg | |||||
| else: | |||||
| raise AttributeError, \ | |||||
| "Recognized but unimplemented option `%s'" % opt | |||||
| except SystemExit: | |||||
| raise | |||||
| except: | |||||
| usage (sys.exc_info ()[1]) | |||||
| if 'a' in output: | |||||
| output = 'fFns' | |||||
| servers = readServers(servers) | |||||
| if methodnums == None: | |||||
| methodnums = range (1, len (DEFAULT_METHODS) + 1) | |||||
| limitre = re.compile ('|'.join (args), re.IGNORECASE) | |||||
| for s in servers: | |||||
| if (not not limitre.match (s['name'])) == invert: | |||||
| continue | |||||
| serv = SOAP.SOAPProxy(s['endpoint'], namespace = s['namespace']) | |||||
| for num in (methodnums): | |||||
| if num > len(DEFAULT_METHODS): | |||||
| break | |||||
| total += 1 | |||||
| name = DEFAULT_METHODS[num - 1] | |||||
| title = '%s: %s (#%d)' % (s['name'], name, num) | |||||
| try: | |||||
| fn = globals ()[name] | |||||
| except KeyboardInterrupt: | |||||
| raise | |||||
| except: | |||||
| if 'n' in output: | |||||
| print title, "test not yet implemented" | |||||
| notimp += 1 | |||||
| continue | |||||
| try: | |||||
| res = fn (serv, s['soapaction'], s['name']) | |||||
| if s['nonfunctional'].has_key (name): | |||||
| print title, "succeeded despite marked nonfunctional" | |||||
| elif 's' in output: | |||||
| print title, "succeeded " | |||||
| succeed += 1 | |||||
| except KeyboardInterrupt: | |||||
| print "fail" | |||||
| raise | |||||
| except: | |||||
| if s['nonfunctional'].has_key (name): | |||||
| if 'F' in output: | |||||
| t = 'as expected' | |||||
| if s['nonfunctional'][name] != '': | |||||
| t += ', ' + s['nonfunctional'][name] | |||||
| print title, "failed (%s) -" %t, sys.exc_info()[1] | |||||
| failok += 1 | |||||
| else: | |||||
| if 'f' in output: | |||||
| print title, "failed -", str (sys.exc_info()[1]) | |||||
| fail += 1 | |||||
| if stats: | |||||
| print " Tests ended at:", time.ctime (time.time()) | |||||
| if stats > 0: | |||||
| print " Total tests: %d" % total | |||||
| print " Successes: %d (%3.2f%%)" % \ | |||||
| (succeed, 100.0 * succeed / total) | |||||
| if stats > 0 or fail > 0: | |||||
| print "Failed unexpectedly: %d (%3.2f%%)" % \ | |||||
| (fail, 100.0 * fail / total) | |||||
| if stats > 0: | |||||
| print " Failed as expected: %d (%3.2f%%)" % \ | |||||
| (failok, 100.0 * failok / total) | |||||
| if stats > 0 or notimp > 0: | |||||
| print " Not implemented: %d (%3.2f%%)" % \ | |||||
| (notimp, 100.0 * notimp / total) | |||||
| return fail + notimp | |||||
| if __name__ == "__main__": | |||||
| main() | |||||
| @@ -0,0 +1,149 @@ | |||||
| #!/usr/bin/env python | |||||
| # Copyright (c) 2001, actzero, inc. | |||||
| import sys | |||||
| sys.path.insert(1,"..") | |||||
| from SOAPpy import SOAP | |||||
| #SOAP.Config.debug = 1 | |||||
| serverstring = "SOAP.py (actzero.com) running "+sys.platform | |||||
| NUMBUYS = 0 | |||||
| NUMSIMPLEBUYS = 0 | |||||
| NUMREQUESTS = 0 | |||||
| NUMPINGS = 0 | |||||
| def SimpleBuy(Address, ProductName, Quantity): | |||||
| # currently, this type-checks the params, and makes sure | |||||
| # the strings are of len > 0 | |||||
| global NUMSIMPLEBUYS | |||||
| NUMSIMPLEBUYS += 1 | |||||
| if Quantity < 1: raise ValueError, "must order at least one" | |||||
| else: return "Receipt for %d %s(s) bought from %s" % (int(Quantity), ProductName, serverstring) | |||||
| def RequestForQuote(ProductName, Quantity): | |||||
| # type-checks and makes sure Quantity >= 1 | |||||
| global NUMREQUESTS | |||||
| NUMREQUESTS += 1 | |||||
| if Quantity < 1: raise ValueError, "must order at least 1" | |||||
| else: | |||||
| import whrandom | |||||
| mult = whrandom.random() | |||||
| times = 0 | |||||
| while mult > 0.25: | |||||
| mult = mult - 0.25 | |||||
| times += 1 | |||||
| mult += 0.5 | |||||
| mult = round(mult, 3) | |||||
| print mult, times | |||||
| return SOAP.doubleType(round(mult*int(Quantity),2)) | |||||
| def Buy(**kw): | |||||
| global NUMBUYS | |||||
| NUMBUYS += 1 | |||||
| try: | |||||
| PurchaseOrder = kw["PurchaseOrder"] | |||||
| except: | |||||
| PurchaseOrder = kw["PO"] | |||||
| try: | |||||
| POkeys = PurchaseOrder['_keyord'] | |||||
| POkeys.sort() | |||||
| POkeys_expected = ["shipTo","billTo","items","poID","createDate"] | |||||
| POkeys_expected.sort() | |||||
| if POkeys != POkeys_expected: | |||||
| raise ValueError, "struct 'PurchaseOrder' needs %s, %s, %s, %s, and %s" % tuple(POkeys_expected) | |||||
| except: | |||||
| raise TypeError, "'PurchaseOrder' missing one or more element(s)" | |||||
| try: | |||||
| btkeys = PurchaseOrder["billTo"]["_keyord"] | |||||
| btkeys.sort() | |||||
| btkeys_expected = ["address","zipCode","name","state","city"] | |||||
| btkeys_expected.sort() | |||||
| except: | |||||
| raise TypeError, "'billTo' missing one or more elements" | |||||
| try: | |||||
| stkeys = PurchaseOrder["shipTo"]["_keyord"] | |||||
| stkeys.sort() | |||||
| stkeys_expected = ["address","zipCode","name","state","city"] | |||||
| stkeys_expected.sort() | |||||
| except: | |||||
| raise TypeError, "'shipTo' missing one or more elements" | |||||
| try: | |||||
| items = PurchaseOrder["items"].__dict__ | |||||
| data = items["data"] | |||||
| retstring = "" | |||||
| for item in data: | |||||
| itemdict = item["_asdict"] | |||||
| q = itemdict["quantity"] | |||||
| p = itemdict["price"] | |||||
| name = itemdict["name"] | |||||
| if retstring != "": | |||||
| retstring += ", " | |||||
| else: | |||||
| retstring = "bought " | |||||
| retstring += "%d %s(s) for %.2f" % (q,name,p) | |||||
| retstring += " from "+serverstring | |||||
| return retstring | |||||
| except: | |||||
| raise TypeError, "items must be an array of 'item' structs" | |||||
| def Ping(): | |||||
| global NUMPINGS | |||||
| NUMPINGS += 1 | |||||
| return | |||||
| def Monitor(str): | |||||
| if str=="actzero": | |||||
| global NUMBUYS | |||||
| global NUMREQUESTS | |||||
| global NUMSIMPLEBUYS | |||||
| global NUMPINGS | |||||
| return "(Buys, RequestForQuote(s),SimpleBuy(s), Ping(s)) = " + \ | |||||
| repr( (NUMBUYS,NUMREQUESTS,NUMSIMPLEBUYS, NUMPINGS) ) | |||||
| else: | |||||
| raise ValueError, "not the right string" | |||||
| def Clear(str): | |||||
| if str=="actzero": | |||||
| global NUMBUYS | |||||
| global NUMREQUESTS | |||||
| global NUMSIMPLEBUYS | |||||
| global NUMPINGS | |||||
| NUMBUYS = 0 | |||||
| NUMREQUESTS = 0 | |||||
| NUMSIMPLEBUYS = 0 | |||||
| NUMPINGS = 0 | |||||
| return "(Buys, RequestForQuote(s),SimpleBuy(s), Ping(s)) = " + \ | |||||
| repr( (NUMBUYS,NUMREQUESTS,NUMSIMPLEBUYS, NUMPINGS) ) | |||||
| else: | |||||
| raise ValueError, "not the right string" | |||||
| if __name__ == "__main__": | |||||
| if len(sys.argv) > 1: | |||||
| try: | |||||
| port = int(sys.argv[1]) | |||||
| if port not in range(2000,15000): raise ValueError | |||||
| except: | |||||
| print "port must be a number between 2000 and 15000" | |||||
| sys.exit(1) | |||||
| else: port = 9000 | |||||
| namespace = "http://www.soapinterop.org/Bid" | |||||
| server = SOAP.SOAPServer( ('zoo',port) ) | |||||
| server.registerKWFunction(SimpleBuy, namespace ) | |||||
| server.registerKWFunction(RequestForQuote, namespace ) | |||||
| server.registerKWFunction(Buy, namespace ) | |||||
| server.registerKWFunction(Ping, namespace ) | |||||
| server.registerKWFunction(Monitor, namespace ) | |||||
| server.registerKWFunction(Clear, namespace ) | |||||
| try: | |||||
| server.serve_forever() | |||||
| except KeyboardInterrupt: | |||||
| pass | |||||
| @@ -0,0 +1,50 @@ | |||||
| from SOAPpy import SOAP | |||||
| import sys | |||||
| import getopt | |||||
| def usage(): | |||||
| print """usage: %s [options] | |||||
| -m, --method=METHOD#[,METHOD#...] specify METHOD# of ? for the list | |||||
| -p, --port=PORT# allows to specify PORT# of server | |||||
| """ | |||||
| sys.exit(1) | |||||
| def methodUsage(): | |||||
| print "The available methods are:" | |||||
| print "1. Monitor \t\t2. Clear" | |||||
| sys.exit(0) | |||||
| port = 12080 | |||||
| methodnum = 1 | |||||
| try: | |||||
| opts, args = getopt.getopt (sys.argv[1:], 'p:m:', ['method','port']) | |||||
| for opt, arg in opts: | |||||
| if opt in ('-m','--method'): | |||||
| if arg == '?': | |||||
| methodUsage() | |||||
| methodnum = int(arg) | |||||
| elif opt in ('-p', '--port'): | |||||
| port = int(arg) | |||||
| else: | |||||
| raise AttributeError, "Recognized but unimpl option '%s'" % opt | |||||
| except SystemExit: | |||||
| raise | |||||
| except: | |||||
| usage () | |||||
| ep = "http://208.177.157.221:%d/xmethodsInterop" % (port) | |||||
| sa = "urn:soapinterop" | |||||
| ns = "http://www.soapinterop.org/Bid" | |||||
| serv = SOAP.SOAPProxy(ep, namespace =ns, soapaction = sa) | |||||
| if methodnum == 1: | |||||
| print serv.Monitor(str="actzero") | |||||
| elif methodnum == 2: | |||||
| print serv.Clear(str="actzero") | |||||
| else: | |||||
| print "invalid methodnum" | |||||
| methodUsage() | |||||
| @@ -0,0 +1,19 @@ | |||||
| #!/usr/bin/env python | |||||
| import time | |||||
| from SOAPpy import SOAP | |||||
| srv = SOAP.SOAPProxy('http://localhost:10080/') | |||||
| for p in ('good param', 'ok param'): | |||||
| ret = srv.badparam(p) | |||||
| if isinstance(ret, SOAP.faultType): | |||||
| print ret | |||||
| else: | |||||
| print 'ok' | |||||
| dt = SOAP.dateTimeType(time.localtime(time.time())) | |||||
| print srv.dt(dt) | |||||
| @@ -0,0 +1,233 @@ | |||||
| import http_server | |||||
| from SOAPpy.SOAP import * | |||||
| Fault = faultType | |||||
| import string, sys | |||||
| Config = SOAPConfig(debug=1) | |||||
| class soap_handler: | |||||
| def __init__(self, encoding='UTF-8', config=Config, namespace=None): | |||||
| self.namespace = namespace | |||||
| self.objmap = {} | |||||
| self.funcmap = {} | |||||
| self.config = config | |||||
| self.encoding = encoding | |||||
| def match (self, request): | |||||
| return 1 | |||||
| def handle_request (self, request): | |||||
| [path, params, query, fragment] = request.split_uri() | |||||
| if request.command == 'post': | |||||
| request.collector = collector(self, request) | |||||
| else: | |||||
| request.error(400) | |||||
| def continue_request(self, data, request): | |||||
| # Everthing that follows is cripped from do_POST(). | |||||
| if self.config.debug: | |||||
| print "\n***RECEIVING***\n", data, "*" * 13 + "\n" | |||||
| sys.stdout.flush() | |||||
| try: | |||||
| r, header, body = parseSOAPRPC(data, header=1, body=1) | |||||
| method = r._name | |||||
| args = r._aslist | |||||
| kw = r._asdict | |||||
| ns = r._ns | |||||
| resp = "" | |||||
| # For faults messages | |||||
| if ns: | |||||
| nsmethod = "%s:%s" % (ns, method) | |||||
| else: | |||||
| nsmethod = method | |||||
| try: | |||||
| # First look for registered functions | |||||
| if self.funcmap.has_key(ns) and \ | |||||
| self.funcmap[ns].has_key(method): | |||||
| f = self.funcmap[ns][method] | |||||
| else: # Now look at registered objects | |||||
| # Check for nested attributes | |||||
| if method.find(".") != -1: | |||||
| t = self.objmap[ns] | |||||
| l = method.split(".") | |||||
| for i in l: | |||||
| t = getattr(t,i) | |||||
| f = t | |||||
| else: | |||||
| f = getattr(self.objmap[ns], method) | |||||
| except: | |||||
| if self.config.debug: | |||||
| import traceback | |||||
| traceback.print_exc () | |||||
| resp = buildSOAP(Fault("%s:Client" % NS.ENV_T, | |||||
| "No method %s found" % nsmethod, | |||||
| "%s %s" % tuple(sys.exc_info()[0:2])), | |||||
| encoding = self.encoding, config = self.config) | |||||
| status = 500 | |||||
| else: | |||||
| try: | |||||
| # If it's wrapped to indicate it takes keywords | |||||
| # send it keywords | |||||
| if header: | |||||
| x = HeaderHandler(header) | |||||
| if isinstance(f,MethodSig): | |||||
| c = None | |||||
| if f.context: # Build context object | |||||
| c = SOAPContext(header, body, d, self.connection, self.headers, | |||||
| self.headers["soapaction"]) | |||||
| if f.keywords: | |||||
| tkw = {} | |||||
| # This is lame, but have to de-unicode keywords | |||||
| for (k,v) in kw.items(): | |||||
| tkw[str(k)] = v | |||||
| if c: | |||||
| tkw["_SOAPContext"] = c | |||||
| fr = apply(f,(),tkw) | |||||
| else: | |||||
| if c: | |||||
| fr = apply(f,args,{'_SOAPContext':c}) | |||||
| else: | |||||
| fr = apply(f,args,{}) | |||||
| else: | |||||
| fr = apply(f,args,{}) | |||||
| if type(fr) == type(self) and isinstance(fr, voidType): | |||||
| resp = buildSOAP(kw = {'%sResponse' % method:fr}, | |||||
| encoding = self.encoding, | |||||
| config = self.config) | |||||
| else: | |||||
| resp = buildSOAP(kw = | |||||
| {'%sResponse' % method:{'Result':fr}}, | |||||
| encoding = self.encoding, | |||||
| config = self.config) | |||||
| except Fault, e: | |||||
| resp = buildSOAP(e, config = self.config) | |||||
| status = 500 | |||||
| except: | |||||
| if self.config.debug: | |||||
| import traceback | |||||
| traceback.print_exc () | |||||
| resp = buildSOAP(Fault("%s:Server" % NS.ENV_T, \ | |||||
| "Method %s failed." % nsmethod, | |||||
| "%s %s" % tuple(sys.exc_info()[0:2])), | |||||
| encoding = self.encoding, | |||||
| config = self.config) | |||||
| status = 500 | |||||
| else: | |||||
| status = 200 | |||||
| except Fault,e: | |||||
| resp = buildSOAP(e, encoding = self.encoding, | |||||
| config = self.config) | |||||
| status = 500 | |||||
| except: | |||||
| # internal error, report as HTTP server error | |||||
| if self.config.debug: | |||||
| import traceback | |||||
| traceback.print_exc () | |||||
| request.error(500) | |||||
| #self.send_response(500) | |||||
| #self.end_headers() | |||||
| else: | |||||
| request['Content-Type'] = 'text/xml; charset="%s"' % self.encoding | |||||
| request.push(resp) | |||||
| request.done() | |||||
| # got a valid SOAP response | |||||
| #self.send_response(status) | |||||
| #self.send_header("Content-type", | |||||
| # 'text/xml; charset="%s"' % self.encoding) | |||||
| #self.send_header("Content-length", str(len(resp))) | |||||
| #self.end_headers() | |||||
| if self.config.debug: | |||||
| print "\n***SENDING***\n", resp, "*" * 13 + "\n" | |||||
| sys.stdout.flush() | |||||
| """ | |||||
| # We should be able to shut down both a regular and an SSL | |||||
| # connection, but under Python 2.1, calling shutdown on an | |||||
| # SSL connections drops the output, so this work-around. | |||||
| # This should be investigated more someday. | |||||
| if self.config.SSLserver and \ | |||||
| isinstance(self.connection, SSL.Connection): | |||||
| self.connection.set_shutdown(SSL.SSL_SENT_SHUTDOWN | | |||||
| SSL.SSL_RECEIVED_SHUTDOWN) | |||||
| else: | |||||
| self.connection.shutdown(1) | |||||
| """ | |||||
| def registerObject(self, object, namespace = ''): | |||||
| if namespace == '': namespace = self.namespace | |||||
| self.objmap[namespace] = object | |||||
| def registerFunction(self, function, namespace = '', funcName = None): | |||||
| if not funcName : funcName = function.__name__ | |||||
| if namespace == '': namespace = self.namespace | |||||
| if self.funcmap.has_key(namespace): | |||||
| self.funcmap[namespace][funcName] = function | |||||
| else: | |||||
| self.funcmap[namespace] = {funcName : function} | |||||
| class collector: | |||||
| "gathers input for POST and PUT requests" | |||||
| def __init__ (self, handler, request): | |||||
| self.handler = handler | |||||
| self.request = request | |||||
| self.data = '' | |||||
| # make sure there's a content-length header | |||||
| cl = request.get_header ('content-length') | |||||
| if not cl: | |||||
| request.error (411) | |||||
| else: | |||||
| cl = string.atoi (cl) | |||||
| # using a 'numeric' terminator | |||||
| self.request.channel.set_terminator (cl) | |||||
| def collect_incoming_data (self, data): | |||||
| self.data = self.data + data | |||||
| def found_terminator (self): | |||||
| # set the terminator back to the default | |||||
| self.request.channel.set_terminator ('\r\n\r\n') | |||||
| self.handler.continue_request (self.data, self.request) | |||||
| if __name__ == '__main__': | |||||
| import asyncore | |||||
| import http_server | |||||
| class Thing: | |||||
| def badparam(self, param): | |||||
| if param == 'good param': | |||||
| return 1 | |||||
| else: | |||||
| return Fault(faultstring='bad param') | |||||
| def dt(self, aDateTime): | |||||
| return aDateTime | |||||
| thing = Thing() | |||||
| soaph = soap_handler() | |||||
| soaph.registerObject(thing) | |||||
| hs = http_server.http_server('', 10080) | |||||
| hs.install_handler(soaph) | |||||
| asyncore.loop() | |||||
| @@ -0,0 +1,186 @@ | |||||
| Getting Started | |||||
| =============== | |||||
| NEW: | |||||
| Mark Pilgrims' online book _Dive Into Python_ at | |||||
| http://diveintopython.org includes a nice tutorial for SOAPpy in | |||||
| Chapter 12. "SOAP Web Services" at | |||||
| http://diveintopython.org/soap_web_services. | |||||
| The easiest way to get up to speed is to run and read the scripts in the | |||||
| tests directory. Better documentation is coming. | |||||
| Here are some examples of how to use SOAPpy: | |||||
| CLIENT EXAMPLES: | |||||
| ## CODE | |||||
| from SOAPpy import SOAPProxy | |||||
| server = SOAPProxy("http://localhost:8080/") | |||||
| print server.echo("Hello world") | |||||
| ## /CODE | |||||
| This opens a connection to the server listening on localhost:8080, calls the | |||||
| method echo with the ordered parameter of "Hello World", and prints the | |||||
| results. | |||||
| ## CODE | |||||
| from SOAPpy import SOAPProxy | |||||
| server = SOAPProxy("https://localhost:8443/") | |||||
| print server.echo("Hello world") | |||||
| ## /CODE | |||||
| This opens a secure connection to the SSL server listening on | |||||
| localhost:8443, calls the method echo with the ordered parameter of | |||||
| "Hello World" and prints the results. Python must be built with OpenSSL. | |||||
| ## CODE | |||||
| from SOAPpy import SOAPProxy | |||||
| server = SOAPProxy("http://services.xmethods.com/soap", | |||||
| namespace = "urn:xmethods-delayed-quotes") | |||||
| print server.getQuote(symbol = "IBM") | |||||
| ## /CODE | |||||
| This calls method getQuote that is in the namespace URI of | |||||
| urn:xmethods-delayed-quotes on server services.xmethods.com. getQuote is | |||||
| passed a named parameter, symbol. | |||||
| ## CODE | |||||
| from SOAPpy import SOAPProxy | |||||
| server = SOAPProxy("http://services.xmethods.com/soap") | |||||
| print server._ns("urn:xmethods-delayed-quotes").getQuote(symbol = "IBM") | |||||
| ## /CODE | |||||
| This does the same thing as the previous example, however namespace is | |||||
| specified inline on a per call basis rather than at the server level. | |||||
| ## CODE | |||||
| from SOAPpy import SOAPProxy | |||||
| server = SOAPProxy("http://services.xmethods.com/soap", | |||||
| soapaction = "http://somesite.com/myaction") | |||||
| print server._ns("urn:xmethods-delayed-quotes").getQuote(symbol = "IBM") | |||||
| ## /CODE | |||||
| This is the same quote call with a soapaction specified. | |||||
| ## CODE | |||||
| from SOAPpy import SOAPProxy | |||||
| server = SOAPProxy("http://services.xmethods.com:80/soap") | |||||
| ns = "urn:xmethods-delayed-quotes") | |||||
| sa = "http://somesite.com/myaction" | |||||
| my_call = server._ns(ns)._sa(sa) | |||||
| my_call.getQuote(symbol = "IBM") | |||||
| my_call.getQuote(symbol = "IBM") | |||||
| my_call.getQuote(symbol = "IBM") | |||||
| ## /CODE | |||||
| The same example, this time with both the soapaction and the namespace | |||||
| specified inline and saved in a local variable for getQuote to be called | |||||
| against. | |||||
| ** What SOAPpy does with the results of a call could seem surprising. If | |||||
| there is only one element in the structType that has the return value and | |||||
| unwrap_results is turned on (the default) it will bubble up the single | |||||
| attribute, otherwise it will return you a structType object with all of the | |||||
| attributes. | |||||
| SERVER EXAMPLES: | |||||
| ## CODE | |||||
| from SOAPpy import SOAPServer | |||||
| def echo(s): | |||||
| return s + s # repeats a string twice | |||||
| server = SOAPServer(("localhost", 8080)) | |||||
| server.registerFunction(echo) | |||||
| server.serve_forever() | |||||
| ## /CODE | |||||
| This exposes the function echo (that takes an unnamed arguement) on a server | |||||
| running on localhost:8080. | |||||
| ## CODE | |||||
| from SOAPpy import SOAPServer | |||||
| def echo(s): | |||||
| return s + s # repeats a string twice | |||||
| server = SOAPServer() | |||||
| server.registerFunction(echo, "echo-space") | |||||
| server.serve_forever() | |||||
| ## /CODE | |||||
| The same as above, but this time the method is available in the namespace | |||||
| "echo-space". | |||||
| ## CODE | |||||
| from SOAPpy import SOAPServer | |||||
| class echoBuilder: | |||||
| def echo(self, val): | |||||
| return val + val | |||||
| server = SOAPServer() | |||||
| e = echoBuilder() | |||||
| server.registerObject(e) | |||||
| server.serve_forever() | |||||
| ## /CODE | |||||
| This registers the whole instance of the object echoBuilder, e. Every | |||||
| method of the instance is exposed on the server. | |||||
| ## CODE | |||||
| from SOAPpy import SOAPServer | |||||
| def echo(**kw): | |||||
| return kw['first'] + kw['second'] + kw['third'] | |||||
| server = SOAPServer() | |||||
| server.registerKWFunction(echo) | |||||
| server.serve_forever() | |||||
| ## /CODE | |||||
| This time the method echo is exposed and it expects named arguments. The | |||||
| main thing to notice here is the use of the method registerKWFunction over | |||||
| registerFunction. | |||||
| ## CODE | |||||
| from SOAPpy import SOAPServer | |||||
| from M2Crypto import SSL | |||||
| def echo(s): | |||||
| return s+s # repeats a string twice | |||||
| ssl_context = SSL.Context() | |||||
| ssl_context.load_cert('server.pem') | |||||
| server = SOAPServer(("localhost",8443), ssl_context = ssl_context) | |||||
| server.registerFunction(echo) | |||||
| server.serve_forever() | |||||
| ## /CODE | |||||
| This exposes the function echo (taking an unnamed arguement) on a server | |||||
| accepting SSL connections at localhost:8443. Ng Pheng Siong's M2Crypto | |||||
| package (available at <http://www.pobox.org.sg/home/ngps/m2/>) must be | |||||
| installed. Also see tests/silabserver.py. | |||||
| $Id: GettingStarted.txt,v 1.4 2005/02/21 20:09:29 warnes Exp $ | |||||
| @@ -0,0 +1,97 @@ | |||||
| Globus Support | |||||
| ============== | |||||
| Extensions have been added to the SOAPpy module to allow the use of the | |||||
| Globus Toolkit v2 for secure transport of SOAP calls. These extensions are | |||||
| possible by using the Globus Toolkit (http://www.globus.org) and the | |||||
| pyGlobus software (http://www-itg.lbl.gov/gtg/projects/pyGlobus/), which | |||||
| exposes the Globus Toolkit via a set of Python interfaces. This enables | |||||
| bi-directional PKI authentication so that the server and client are both | |||||
| guaranteed of the identity of the other. Using PKI this way also allows a | |||||
| more robust authorization solution above the SOAP hosting layer, which | |||||
| provides better application level authorization control. These tools are | |||||
| used by the Access Grid Project (http://www.accessgrid.org) to build a | |||||
| Grid-based, Web Services based, real-time collaboration environment. | |||||
| In order to use the SOAPpy module with the Globus Toolkit, you must first | |||||
| obtain and install the Globus Toolkit and pyGlobus software. Information on | |||||
| how to do that is at the respective web sites listed below. In order to use | |||||
| the Globus Toolkit it is necessary to have an x509 identity certificate. | |||||
| Information on how to obtain one of those is available on the web as well. | |||||
| To use GSI with an authorization method, set the SOAPConfig.authMethod = | |||||
| "methodname". You must have this method defined on any objects you register | |||||
| with SOAPpy, and/or as a registered method. It should return 0 or 1 to | |||||
| indicate if authorization is allowed or not. | |||||
| Once the software is installed, you have obtained your certificate, and the | |||||
| SOAPpy module is installed, the following code shows how to run a GSI | |||||
| secured SOAP server (These snippets are directly from the echoServer.py and | |||||
| echoClient.py in the test directory). | |||||
| Server | |||||
| ------ | |||||
| def _authorize(self, *args, **kw): | |||||
| return 1 | |||||
| Config.authMethod = "_authorize" | |||||
| addr = ('localhost', 9900) | |||||
| from SOAPpy.GSIServer import GSISOAPServer | |||||
| server = GSISOAPServer(addr) | |||||
| server.registerFunction(_authorize) | |||||
| server.registerFunction(echo) | |||||
| Then you use the server like the SSL server or the standard server. | |||||
| Client | |||||
| ------ | |||||
| import pyGlobus | |||||
| # The httpg distinguishes this as a GSI TCP connection, so after | |||||
| # this you can use the SOAP proxy as you would any other SOAP Proxy. | |||||
| server = SOAPProxy("httpg://localhost:9900/") | |||||
| print server.echo("moo") | |||||
| Globus Toolkit http://www.globus.org | |||||
| ------------------------------------ | |||||
| The Globus Toolkit is an open source software toolkit used for | |||||
| building grids. It is being developed by the Globus Alliance and | |||||
| many others all over the world. A growing number of projects and | |||||
| companies are using the Globus Toolkit to unlock the potential | |||||
| of grids for their cause. | |||||
| PyGlobus http://www-itg.lbl.gov/gtg/projects/pyGlobus/ | |||||
| ------------------------------------------------------ | |||||
| The goal of this project is to allow the use of the entire | |||||
| Globus toolkit from Python, a high-level scripting | |||||
| language. SWIG is used to generate the necessary interface | |||||
| code. Currently a substantial subset of the 2.2.4 and 2.4 | |||||
| versions of the Globus toolkit has been wrapped. | |||||
| The Access Grid http://www.accessgrid.org/ | |||||
| ------------------------------------------ | |||||
| The Access GridT is an ensemble of resources including | |||||
| multimedia large-format displays, presentation and interactive | |||||
| environments, and interfaces to Grid middleware and to | |||||
| visualization environments. These resources are used to support | |||||
| group-to-group interactions across the Grid. For example, the | |||||
| Access Grid (AG) is used for large-scale distributed meetings, | |||||
| collaborative work sessions, seminars, lectures, tutorials, and | |||||
| training. The Access Grid thus differs from desktop-to-desktop | |||||
| tools that focus on individual communication. | |||||
| - Submitted 2004-01-08 by Ivan R. Judson <mailto:judson@mcs.anl.gov> | |||||
| $Id: GlobusSupport.txt,v 1.3 2005/02/21 20:09:32 warnes Exp $ | |||||
| @@ -0,0 +1,71 @@ | |||||
| Experimental method for handing ordered vs named method parameters | |||||
| ------------------------------------------------------------------ | |||||
| There is an incompatibility with the way that Python and SOAP handle | |||||
| method arguments: SOAP requires that all arguments have names and that | |||||
| they are presented in the same order as the method signature. Python | |||||
| (like other scripting languages, notably the S language) has the | |||||
| concept of unnamed arguments. Further Python does not preserve the | |||||
| order of named arguments, since they are handled using the dictionary | |||||
| data type. It seems to me that this makes it impossible to fully meet | |||||
| the SOAP specification without significant modifications to the Python | |||||
| method of handling named arguments or to the Python dictionary class. | |||||
| Historically SOAPpy has attempted to work around this issue by | |||||
| handling all arguments as unnamed unless the method or function was | |||||
| explicitly flagged, in which case all arguments were considered named. | |||||
| This has resulted in a several problems, particularly for a SOAPpy | |||||
| client communicating with a SOAPpy server. First, when named | |||||
| arguments were used in call to a non-flagged function, the argument | |||||
| would silently be reordered by the sender (since they were stored | |||||
| using a Python dictionary), *and* the names would be ignored by the | |||||
| receiver, which assumed that the parameters were unnamed and only the | |||||
| order was significant. This results in incorrect argument matching. | |||||
| This problem also occurred with mixed named and unnamed arguments. | |||||
| For my primary SOAP application, it is not reasonable to flag all of | |||||
| the SOAPpy methods as requiring named arguments, for a variety of | |||||
| reasons. One reason is that the available methods are not known | |||||
| apriori by the client software, hence the names of the arguments are | |||||
| not known. Second, many of the methods provide a large number of | |||||
| optional arguments, making it impractical to specify them all. | |||||
| In an attempt to overcome this problem, I implemented an experimental | |||||
| and non-standard method of handling named and unnamed arguments. This | |||||
| mechanism is enabled in SOAPpy by setting | |||||
| SOAPpy.SOAP.Config.specialArgs=1, and disabled by setting | |||||
| SOAPpy.SOAP.Config.specialArgs=0. | |||||
| When enabled, parameters with names of the form v#### (i.e., matching | |||||
| the regexp "^v[0-9]+$") are assumed to be unnamed parameters and are | |||||
| passed to the method in numeric order. All other parameters are | |||||
| assumed to be named and are passed using the name. Outgoing SOAP | |||||
| method calls now always generate names in this way--whether or not | |||||
| specialArgs is enabled. | |||||
| I selected the form v#### because it is a valid XML name, but is | |||||
| unlikely to be used as a parameter name. | |||||
| [As it turns out, this choice was fortitous because Apache's SOAP tool | |||||
| uses the same system.] | |||||
| In my testing, this mechanism for handling method parameter names | |||||
| works fine between a SOAPpy client and a SOAPpy server, and resolves | |||||
| the parameter reordering problems I was experiencing. This system | |||||
| seems unlikely to have any negative side effects on other SOAP | |||||
| applications, except in the (hopefully) rare case when v#### might be | |||||
| used as an actual parameter name. | |||||
| **In version 0.9.9-pre1, this feature is enabled by default.** Please | |||||
| let me know if there are situations where this causes problems. | |||||
| Note that this mechanism is only a partial solution, since it is still | |||||
| impossible to return named parameters in a specified order using | |||||
| SOAPpy. SOAP applications or implementations which require this | |||||
| feature are simply not compatible with SOAPpy. | |||||
| -Greg Warnes <Gregory.R.Warnes@Pfizer.com> | |||||
| 2003-03-07 (updated 2003-11-14) | |||||
| @@ -0,0 +1,104 @@ | |||||
| Using Headers | |||||
| ============= | |||||
| SOAPpy has a Header class to hold data for the header of a SOAP message. | |||||
| Each Header instance has methods to set/get the MustUnderstand attribute, and | |||||
| methods to set/get the Actor attribute. | |||||
| SOAPpy also has a SOAPContext class so that each server method can be | |||||
| implemented in such a way that it gets the context of the connecting client. | |||||
| This includes both common SOAP information and connection information (see | |||||
| below for an example). | |||||
| CLIENT EXAMPLES | |||||
| --------------- | |||||
| ## CODE | |||||
| import SOAPpy | |||||
| test = 42 | |||||
| server = SOAPpy.SOAPProxy("http://localhost:8888") | |||||
| server = server._sa ("urn:soapinterop") | |||||
| hd = SOAPpy.Header() | |||||
| hd.InteropTestHeader ='This should fault, as you don\'t understand the header.' | |||||
| hd._setMustUnderstand ('InteropTestHeader', 0) | |||||
| hd._setActor ('InteropTestHeader','http://schemas.xmlsoap.org/soap/actor/next') | |||||
| server = server._hd (hd) | |||||
| print server.echoInteger (test) | |||||
| ## /CODE | |||||
| This should succeed (provided the server has defined echoInteger), as it | |||||
| builds a valid header into this client with MustUnderstand set to 0 | |||||
| and then sends the SOAP with this header. | |||||
| ## CODE | |||||
| import SOAPpy | |||||
| test = 42 | |||||
| server = SOAPpy.SOAPProxy("http://localhost:8888") | |||||
| server = server._sa ("urn:soapinterop") | |||||
| #Header | |||||
| hd = SOAPpy.Header() | |||||
| hd.InteropTestHeader = 'This should fault,as you don\'t understand the header.' | |||||
| hd._setMustUnderstand ('InteropTestHeader', 1) | |||||
| hd._setActor ('InteropTestHeader','http://schemas.xmlsoap.org/soap/actor/next') | |||||
| server = server._hd (hd) | |||||
| print server.echoInteger (test) | |||||
| ## /CODE | |||||
| This should fail (even if the server has defined 'echoInteger'), as it | |||||
| builds a valid header into this client, but sets MustUnderstand to 1 | |||||
| for a message that the server presumably won't understand before sending. | |||||
| SERVER EXAMPLES | |||||
| --------------- | |||||
| ## CODE | |||||
| import SOAPpy | |||||
| def echoInteger (inputInteger): | |||||
| return inputInteger | |||||
| server = SOAPpy.SOAPServer ( ('localhost', 8080) ) | |||||
| server.registerFunction (echoInteger) | |||||
| server.serve_forever() | |||||
| ## /CODE | |||||
| This is a simple server designed to work with the first 2 clients above. | |||||
| ## CODE | |||||
| import SOAPpy | |||||
| def echoInteger (inputInteger, _SOAPContext): | |||||
| c = _SOAPContext | |||||
| print c.xmldata | |||||
| print c.header | |||||
| print c.body | |||||
| print c.connection.getpeername() | |||||
| print c.soapaction | |||||
| print c.httpheaders | |||||
| return inputInteger | |||||
| host = 'localhost' | |||||
| port = 8888 | |||||
| server = SOAPpy.SOAPServer ( (host, port) ) | |||||
| server.registerFunction (SOAPpy.MethodSig(echoInteger, keywords=0,context=1)) | |||||
| server.serve_forever() | |||||
| ## /CODE | |||||
| This is a server which shows off the SOAPContext feature. This | |||||
| server gets a context from the client that has connected to it, and | |||||
| prints some of the pertinent aspects of that client before | |||||
| returning. This server should also work with the code for the two | |||||
| clients written above. | |||||
| $Id: UsingHeaders.txt,v 1.1 2005/02/18 15:36:12 warnes Exp $ | |||||
| @@ -0,0 +1,22 @@ | |||||
| WSDL NOTES: | |||||
| Release 0.9.9 and later include logic for dealing with web service | |||||
| description language (WSDL) files. | |||||
| - SOAPpy.WSDL provides a SOAP Proxy object that parses a WSDL file | |||||
| and provides access to the listed services: | |||||
| url = 'http://www.xmethods.org/sd/2001/TemperatureService.wsdl' | |||||
| zip = '01072' | |||||
| proxy = SOAPpy.WSDL.Proxy(url) | |||||
| temp = proxy.getTemp(zip) | |||||
| print 'Temperature at', zip, 'is', temp | |||||
| - On the server, you can allow the client to download the WSDL for | |||||
| a service by sending a request of the form by adding a do_GET | |||||
| method to the SOAPRequestHandler. [Not yet working when | |||||
| debug=FALSE. Add example here when working] | |||||
| $Id: WSDL.txt,v 1.2 2005/02/21 20:09:34 warnes Exp $ | |||||
| @@ -0,0 +1,15 @@ | |||||
| Using SOAPpy Attributes | |||||
| ======================= | |||||
| All SOAPpy data classes implement methods to access and mutate | |||||
| individual attributes. | |||||
| The _setAttr method has as parameters a 'tag', the attribute name, and the | |||||
| value to which the attribute should be set. | |||||
| The _getAttrs method simply has the 'tag' parameter. | |||||
| $Id: attrs.txt,v 1.2 2005/02/18 15:40:46 warnes Exp $ | |||||
| @@ -0,0 +1,19 @@ | |||||
| COMPLEX TYPES HOWTO | |||||
| =================== | |||||
| The easiest way (at the moment) to create complex SOAP typs is to | |||||
| use the SOAPpy.structType class, which allows you to create an | |||||
| object with named arguments of arbitraty types. For example: | |||||
| >>> in0 = SOAPpy.structType() | |||||
| >>> in0._addItem('outwardDate', dep) | |||||
| >>> in0._addItem('returnDate', ret) | |||||
| >>> in0._addItem('originAirport', 'den') | |||||
| >>> in0._addItem('destinationAirport', 'iad') | |||||
| SOAPpy has code for declaring structured object templates including | |||||
| the type for each component, but this broke sometime in the past and | |||||
| has not yet been corrected. (See tests/TCtypes.py to see how it | |||||
| should work.) | |||||
| @@ -0,0 +1,220 @@ | |||||
| Simple Types HOWTO | |||||
| ================== | |||||
| The easiest way to understand use of data types is look at and run the examples | |||||
| already written (in tests/, validate/ and bid/) , and to write your own | |||||
| clients, looking at the xml as it is sent (by setting SOAP.Config.debug=1). | |||||
| As far as the built-in types are concerned, SOAP.py will preserve type | |||||
| as expected. That is: python integer will be of type integer, and | |||||
| equivalently for string and float. To access more than just these types, | |||||
| there are classes in SOAP.py. These allow invoking a certain type by making | |||||
| an instance of the corresponding class. | |||||
| The SOAPBuilder in SOAP.py will automatically convert python lists to Arrays | |||||
| and python dictionaries to Structs- these are two of the most frequently used | |||||
| data types. | |||||
| CLIENT EXAMPLES | |||||
| --------------- | |||||
| ## CODE | |||||
| import SOAP | |||||
| server = SOAP.SOAPProxy("http://localhost:8080/") | |||||
| print server.echo("Hello world") | |||||
| ## /CODE | |||||
| This example (taken from quickstart.txt) sends an ordered parameter of type | |||||
| string. | |||||
| ## CODE | |||||
| import SOAP | |||||
| import time | |||||
| #SOAP.Config.debug = 1 | |||||
| test = time.gmtime (time.time ()) | |||||
| server = SOAP.SOAPProxy("http://localhost:8080/") | |||||
| print server.echoDate (inputDate = SOAP.DateTime(test)) | |||||
| ## /CODE | |||||
| This test calls echoDate with the named parameter inputDate, which is a | |||||
| TimeInstant. It prints the the result. | |||||
| **Note: The reason that it is a TimeInstant and not a DateTime | |||||
| is that SOAP.py uses the 1999 schema intead of the 2001 schema. To make it | |||||
| a DateTime, one would just use SOAP.dateTimeType() in place of SOAP.DateTime(). | |||||
| ** | |||||
| ## CODE | |||||
| import SOAP | |||||
| server = SOAP.SOAPProxy("http://localhost:8080/") | |||||
| test = [0, 1, -1, 3853] | |||||
| print server.echoIntegerArray (inputIntegerArray = test) | |||||
| ## /CODE | |||||
| This calls echoIntegerArray with the named parameter inputIntegerArray, which | |||||
| is a four-member array of type int. It prints the result. | |||||
| ## CODE | |||||
| import SOAP | |||||
| test = {'varFloat': 2.256, 'varInt': 474, 'varString': 'Utah'} | |||||
| server = SOAP.SOAPProxy("http://localhost:8080/") | |||||
| print server.echoStruct (inputStruct = test) | |||||
| ## /CODE | |||||
| This code calls the method echoStruct with the named parameter inputStruct, | |||||
| which is of type Struct. It then prints the result. | |||||
| ## CODE | |||||
| import SOAP | |||||
| item1 = SOAP.Struct( data = {"name":"widget","quantity":200,"price":SOAP.decimalType(45.99), "_typename":"LineItem"}) | |||||
| items = SOAP.Array ( data = [item1] ) | |||||
| items._ns = "http://www.soapinterop.org/Bid" | |||||
| server = SOAP.SOAPProxy("http://localhost:8080") | |||||
| server = server._sa ("http://www.soapinterop.org/Buy") | |||||
| server = server._ns ("http://www.soapinterop.org/Bid") | |||||
| po = SOAP.Struct( data = {"poID":"Order 1234", "createDate": SOAP.dateTimeType(), "items": items} ) | |||||
| print server.Buy(PurchaseOrder = po) | |||||
| ## /CODE | |||||
| A few new things here. | |||||
| -First, we are creating an Array, 'items', with components of (made up) type | |||||
| 'LineItem'. (Notice the use of "_typename" to specify type). | |||||
| -This code associates a namespace with the Array, rather than use the default. | |||||
| -SOAP.dateTimeType() is called directly to get a dateTime instead of SOAP.py's | |||||
| default, 'timeInstant'. | |||||
| -Note that when creating a Struct or Array, the data must be passed in as a | |||||
| named 'data' param (as the first param, by order, is 'name'). | |||||
| -The proxy is instantiated and then the values for its namespace (_ns) and | |||||
| soapaction (_sa) are assigned. | |||||
| -This call will work for a server expecting a parameter with the same | |||||
| components as those in the variable 'po' above. It will work whether the | |||||
| server has a named param 'PurchaseOrder' or has an unnamed param, but will | |||||
| not work if the server expects a named param with a name of anything but | |||||
| 'PurchaseOrder'. | |||||
| SERVER EXAMPLES | |||||
| --------------- | |||||
| ## CODE | |||||
| import SOAP | |||||
| def echo(s): | |||||
| return s + s # repeats a string twice | |||||
| server = SOAP.SOAPServer(("localhost", 8080)) | |||||
| server.registerFunction(echo) | |||||
| server.serve_forever() | |||||
| ## /CODE | |||||
| This server example, from quickstart.txt, echoes (as type string) the | |||||
| string that is passed in, s. | |||||
| ## CODE | |||||
| import SOAP | |||||
| def echoDate (inputDate): | |||||
| return SOAP.DateTime(inputDate) | |||||
| server = SOAP.SOAPServer(("localhost", 8080)) | |||||
| server.registerKWFunction(echoDate ) | |||||
| server.serve_forever() | |||||
| ## /CODE | |||||
| This code accepts an inputDate and returns the same date, ensuring that it | |||||
| is of type TimeInstant by returning an instance of DateTime instead of | |||||
| simply returning the value. | |||||
| ## CODE | |||||
| import SOAP | |||||
| def echoIntegerArray (inputIntegerArray): | |||||
| if type(inputIntegerArray) != type([]) or len(inputIntegerArray) != 4: | |||||
| for elem in inputIntegerArray: | |||||
| if type(elem) != type(1): | |||||
| raise TypeError, "expected 4-member Array of ints" | |||||
| return inputIntegerArray | |||||
| server = SOAP.SOAPServer(("localhost", 8080)) | |||||
| server.registerKWFunction(echoIntegerArray ) | |||||
| server.serve_forever() | |||||
| ## /CODE | |||||
| This server supports the method echoIntegerArray, requiring the named parameter | |||||
| inputIntegerArray, which must be a four-member array of type int. | |||||
| ## CODE | |||||
| import SOAP | |||||
| def echoStruct (inputStruct): | |||||
| myfloat = inputStruct["varFloat"] | |||||
| mystr = inputStruct["varString"] | |||||
| myint = inputStruct["varInt"] | |||||
| return inputStruct | |||||
| server = SOAP.SOAPServer(("localhost", 8080)) | |||||
| server.registerKWFunction(echoStruct ) | |||||
| server.serve_forever() | |||||
| ## /CODE | |||||
| This code creates a server with a method echoStruct, which requires that the | |||||
| incoming Struct have elements named varFloat, varString, and varInt. That is, | |||||
| the server will fault if the incoming Struct does not have any of those | |||||
| elements. **Note, this server code does NOT require that these be the only | |||||
| elements in the struct- just that they be present**. This method simply | |||||
| returns the Struct passed in. | |||||
| ## CODE | |||||
| import sys | |||||
| import SOAP | |||||
| serverstring = "SOAP.py (actzero.com) running "+sys.platform | |||||
| def Buy(**kw): | |||||
| try: | |||||
| PurchaseOrder = kw["PurchaseOrder"] | |||||
| except: | |||||
| PurchaseOrder = kw["PO"] | |||||
| POkeys = PurchaseOrder['_keyord'] | |||||
| POkeys.sort() | |||||
| POkeys_expected = ["items","poID","createDate"] | |||||
| POkeys_expected.sort() | |||||
| if POkeys != POkeys_expected: | |||||
| raise ValueError, "struct 'PurchaseOrder' needs %s, %s, and %s" % tuple(POkeys_expected) | |||||
| items = PurchaseOrder["items"].__dict__ | |||||
| data = items["data"] | |||||
| retstring = "" | |||||
| for item in data: | |||||
| itemdict = item["_asdict"] | |||||
| q = itemdict["quantity"] | |||||
| p = itemdict["price"] | |||||
| name = itemdict["name"] | |||||
| if retstring != "": | |||||
| retstring += ", " | |||||
| else: | |||||
| retstring = "bought " | |||||
| retstring += "%d %s(s) for %.2f" % (q,name,p) | |||||
| retstring += " from "+serverstring | |||||
| return retstring | |||||
| server = SOAP.SOAPServer(("localhost", 8080)) | |||||
| namespace = "http://www.soapinterop.org/Bid" | |||||
| server.registerKWFunction(Buy, namespace ) | |||||
| server.serve_forever() | |||||
| ## /CODE | |||||
| This example creates a server to implement 'Buy', which takes a parameter | |||||
| named either PurchaseOrder or PO. (Notice the use of **kw as the input | |||||
| parameter to the method for this functionality). | |||||
| The server gets the names of the Struct's members by using the '_keyord' | |||||
| key of the Struct-as-dictionary. It checks these names against what it | |||||
| expects from the client, and raises a fault if the two are not the same. | |||||
| By using the __dict__ attribute, the server gets the 'items' (an elemnent of | |||||
| the PurchaseOrder Struct) as a dictionary. Then it checks that 'items' is | |||||
| formatted as expected. Finally, it returns a confirmation of what was bought. | |||||
| $Id: simpleTypes.txt,v 1.2 2005/02/21 20:09:39 warnes Exp $ | |||||
| @@ -0,0 +1,29 @@ | |||||
| #!/usr/bin/env python | |||||
| # | |||||
| # $Id: setup.py,v 1.11 2005/02/15 16:32:22 warnes Exp $ | |||||
| CVS=0 | |||||
| from distutils.core import setup, Command, Extension | |||||
| from SOAPpy.version import __version__ | |||||
| url="http://pywebsvcs.sf.net/" | |||||
| long_description="SOAPpy provides tools for building SOAP clients and servers. For more information see " + url | |||||
| if CVS: | |||||
| import time | |||||
| __version__ += "_CVS_" + time.strftime('%Y_%m_%d') | |||||
| setup(name="SOAPpy", | |||||
| version=__version__, | |||||
| description="SOAP Services for Python", | |||||
| maintainer="Gregory Warnes", | |||||
| maintainer_email="Gregory.R.Warnes@Pfizer.com", | |||||
| url = url, | |||||
| long_description=long_description, | |||||
| packages=['SOAPpy','SOAPpy/wstools'] | |||||
| ) | |||||
| @@ -0,0 +1,32 @@ | |||||
| #!/usr/bin/env python | |||||
| ident = '$Id: BabelfishWSDLTest.py,v 1.1 2003/07/18 15:58:28 warnes Exp $' | |||||
| import os, re | |||||
| import sys | |||||
| sys.path.insert(1, "..") | |||||
| from SOAPpy import WSDL | |||||
| # Check for a web proxy definition in environment | |||||
| try: | |||||
| proxy_url=os.environ['http_proxy'] | |||||
| phost, pport = re.search('http://([^:]+):([0-9]+)', proxy_url).group(1,2) | |||||
| proxy = "%s:%s" % (phost, pport) | |||||
| except: | |||||
| proxy = None | |||||
| server = WSDL.Proxy('http://www.xmethods.net/sd/2001/BabelFishService.wsdl', | |||||
| http_proxy=proxy) | |||||
| english = "Hi Friend!" | |||||
| print "Babelfish Translations" | |||||
| print "------------------------" | |||||
| print "English: '%s'" % english | |||||
| print "French: '%s'" % server.BabelFish('en_fr',english) | |||||
| print "Spanish: '%s'" % server.BabelFish('en_es',english) | |||||
| print "Italian: '%s'" % server.BabelFish('en_it',english) | |||||
| print "German: '%s'" % server.BabelFish('en_de',english) | |||||
| print "Done." | |||||
| @@ -0,0 +1,75 @@ | |||||
| """ | |||||
| Check handing of unicode. | |||||
| """ | |||||
| import sys | |||||
| sys.path.insert(1, "..") | |||||
| from SOAPpy import * | |||||
| # Uncomment to see outgoing HTTP headers and SOAP and incoming | |||||
| #Config.debug = 1 | |||||
| #Config.dumpHeadersIn = 1 | |||||
| #Config.dumpSOAPIn = 1 | |||||
| #Config.dumpSOAPOut = 1 | |||||
| # ask for returned SOAP responses to be converted to basic python types | |||||
| Config.simplify_objects = 1 | |||||
| #Config.BuildWithNoType = 1 | |||||
| #Config.BuildWithNoNamespacePrefix = 1 | |||||
| def headers(): | |||||
| '''Return a soap header containing all the needed information.''' | |||||
| hd = Types.headerType() | |||||
| hd.useragent = Types.stringType("foo") | |||||
| return hd | |||||
| server = SOAPProxy("http://localhost:9900/",header=headers()) | |||||
| adgroupid = 197497504 | |||||
| keyword1 = { 'status': 'Moderate', | |||||
| 'adGroupId': 197497504, | |||||
| 'destinationURL': None, | |||||
| 'language': '', | |||||
| 'text': 'does not work', | |||||
| 'negative': bool(0), | |||||
| 'maxCpc': 50000, | |||||
| 'type': 'Keyword', | |||||
| 'id': 1 } | |||||
| keyword2 = { 'status': 'Moderate', | |||||
| 'adGroupId': 197497504, | |||||
| 'destinationURL': None, | |||||
| 'language': '', | |||||
| 'text': 'yes it does not', | |||||
| 'negative': bool(0), | |||||
| 'maxCpc': 50000, | |||||
| 'type': 'Keyword', | |||||
| 'id': 2 } | |||||
| keylist = [keyword1, keyword2] | |||||
| # Check that the data goes through properly | |||||
| retval = server.echo_simple(adgroupid, keylist) | |||||
| kw1 = retval[1][0] | |||||
| kw2 = retval[1][1] | |||||
| assert(retval[0] == adgroupid) | |||||
| for key in kw1.keys(): | |||||
| assert(kw1[key]==keyword1[key]) | |||||
| for key in kw2.keys(): | |||||
| assert(kw2[key]==keyword2[key]) | |||||
| # Check that the header is preserved | |||||
| retval = server.echo_header((adgroupid, keylist)) | |||||
| assert(retval[1].has_key('useragent')) | |||||
| assert(retval[1]['useragent'] == 'foo') | |||||
| server.quit() | |||||
| print "Success!" | |||||
| @@ -0,0 +1,43 @@ | |||||
| """ | |||||
| Check handing of unicode. | |||||
| """ | |||||
| import sys | |||||
| sys.path.insert(1, "..") | |||||
| from SOAPpy import * | |||||
| # Uncomment to see outgoing HTTP headers and SOAP and incoming | |||||
| #Config.debug = 1 | |||||
| #Config.dumpHeadersIn = 1 | |||||
| #Config.dumpSOAPIn = 1 | |||||
| #Config.dumpSOAPOut = 1 | |||||
| # ask for returned SOAP responses to be converted to basic python types | |||||
| Config.simplify_objects = 0 | |||||
| #Config.BuildWithNoType = 1 | |||||
| #Config.BuildWithNoNamespacePrefix = 1 | |||||
| server = SOAPProxy("http://localhost:9900/") | |||||
| x = u'uMOO' # Single unicode string | |||||
| y = server.echo_simple((x,)) | |||||
| assert( x==y[0] ) | |||||
| x = [u'uMoo1',u'uMoo2'] # array of unicode strings | |||||
| y = server.echo_simple(x) | |||||
| assert( x[0] == y[0] ) | |||||
| assert( x[1] == y[1] ) | |||||
| x = { | |||||
| u'A':1, | |||||
| u'B':u'B', | |||||
| 'C':u'C', | |||||
| 'D':'D' | |||||
| } | |||||
| y = server.echo_simple(x) | |||||
| for key in x.keys(): | |||||
| assert( x[key] == y[0][key] ) | |||||
| print "Success" | |||||
| @@ -0,0 +1,38 @@ | |||||
| import sys | |||||
| sys.path.insert(1, "..") | |||||
| from SOAPpy import * | |||||
| detailed_fault = \ | |||||
| """ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.microsoft.com/soap/encoding/clr/1.0 http://schemas.xmlsoap.org/soap/encoding/" xmlns:a1="http://schemas.microsoft.com/clr/ns/System.Runtime.Serialization.Formatters"> | |||||
| <SOAP-ENV:Body> | |||||
| <SOAP-ENV:Fault id="ref-1"> | |||||
| <faultcode>soapenv:Server.generalException</faultcode> | |||||
| <faultstring>Exception thrown on Server</faultstring> | |||||
| <detail> | |||||
| <loginFailureFault href="#id0"/> | |||||
| <exceptionName xsi:type="xsd:string">...</exceptionName> | |||||
| </detail> | |||||
| </SOAP-ENV:Fault> | |||||
| <multiRef id="id0"> | |||||
| <description xsi:type="xsd:string">Login failure (504):Unknown User</description> | |||||
| <module xsi:type="xsd:string"> ... </module> | |||||
| <timestamp xsi:type="xsd:string">...</timestamp> | |||||
| <faultcode xsi:type="xsd:string"> ...</faultcode> | |||||
| <parameter xsi:type="xsd:string"> ... </parameter> | |||||
| </multiRef> | |||||
| </SOAP-ENV:Body> | |||||
| </SOAP-ENV:Envelope> | |||||
| """ | |||||
| z = parseSOAPRPC(detailed_fault.strip() ) | |||||
| assert(z.__class__==faultType) | |||||
| assert(z.faultstring=="Exception thrown on Server") | |||||
| assert(z.detail.loginFailureFault.description=='Login failure (504):Unknown User') | |||||
| print "Success" | |||||
| @@ -0,0 +1,26 @@ | |||||
| import sys | |||||
| sys.path.insert(1, "..") | |||||
| import SOAPpy | |||||
| import time | |||||
| dep = SOAPpy.dateTimeType((2004, 3, 24, 12, 30, 59, 4, 86, 0)) | |||||
| ret = SOAPpy.dateTimeType((2004, 3, 26, 12, 30, 59, 4, 86, 0)) | |||||
| in0 = SOAPpy.structType() | |||||
| in0._addItem('outwardDate', dep) | |||||
| in0._addItem('returnDate', ret) | |||||
| in0._addItem('originAirport', 'den') | |||||
| in0._addItem('destinationAirport', 'iad') | |||||
| x = SOAPpy.buildSOAP( | |||||
| in0, | |||||
| method="getAirFareQuote", | |||||
| namespace="urn:SBGAirFareQuotes.sbg.travel.ws.dsdata.co.uk" | |||||
| ) | |||||
| wsdl = 'http://www.xmethods.net/sd/2001/TemperatureService.wsdl' | |||||
| proxy = SOAPpy.WSDL.Proxy(wsdl) | |||||
| @@ -0,0 +1,11 @@ | |||||
| from SOAPpy import WSDL | |||||
| server = WSDL.Proxy('/home/warneg/src/google/googleapi/GoogleSearch.wsdl') | |||||
| key = "6k0oDPZQFHL0zpjy6ZO6ufUVFKBgvqTo" | |||||
| results = server.doGoogleSearch(key, 'warnes', 0, 10, False, "", | |||||
| False, "", "utf-8", "utf-8") | |||||
| for i in range(len(results.resultElements)): | |||||
| res = results.resultElements[i] | |||||
| print '%d: %s --> %s' % ( i, res.title, res.URL ) | |||||
| @@ -0,0 +1,147 @@ | |||||
| #!/usr/bin/env python | |||||
| import sys, unittest | |||||
| sys.path.insert(1, "..") | |||||
| from SOAPpy import * | |||||
| Config.debug=1 | |||||
| class ClientTestCase(unittest.TestCase): | |||||
| def testParseRules(self): | |||||
| x = """<?xml version="1.0" encoding="utf-8"?> | |||||
| <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" | |||||
| xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" | |||||
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |||||
| xmlns:xsd="http://www.w3.org/2001/XMLSchema"> | |||||
| <soap:Body | |||||
| soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> | |||||
| <SomeMethod> | |||||
| <Result> | |||||
| <Book> | |||||
| <title>My Life and Work</title> | |||||
| </Book> | |||||
| <Person> | |||||
| <name>Henry Ford</name> | |||||
| <age> 49 </age> | |||||
| <height> 5.5 </height> | |||||
| </Person> | |||||
| </Result> | |||||
| </SomeMethod> | |||||
| </soap:Body> | |||||
| </soap:Envelope> | |||||
| """ | |||||
| def negfloat(x): | |||||
| return float(x) * -1.0 | |||||
| # parse rules | |||||
| pr = {'SomeMethod': | |||||
| {'Result': | |||||
| { | |||||
| 'Book': {'title':'string'}, | |||||
| 'Person': {'age':'int', | |||||
| 'height':negfloat} | |||||
| } | |||||
| } | |||||
| } | |||||
| y = parseSOAPRPC(x, rules=pr) | |||||
| assert y.Result.Person.age == 49 | |||||
| assert y.Result.Person.height == -5.5 | |||||
| x = '''<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> | |||||
| <Bounds> | |||||
| <param> | |||||
| <item>12</item> | |||||
| <item>23</item> | |||||
| <item>0</item> | |||||
| <item>-31</item> | |||||
| </param> | |||||
| <param1 xsi:null="1"></param1> | |||||
| </Bounds> | |||||
| </SOAP-ENV:Body> | |||||
| </SOAP-ENV:Envelope> | |||||
| ''' | |||||
| # parse rules | |||||
| pr = {'Bounds': | |||||
| {'param': 'arrayType=string[]', | |||||
| } | |||||
| } | |||||
| pr2 = {'Bounds': | |||||
| {'param': 'arrayType=int[4]', | |||||
| } | |||||
| } | |||||
| y = parseSOAPRPC(x, rules=pr) | |||||
| assert y.param[1]=='23' | |||||
| y = parseSOAPRPC(x, rules=pr2) | |||||
| assert y.param[1]==23 | |||||
| x = '''<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> | |||||
| <Bounds> | |||||
| <param> | |||||
| <item xsi:type="xsd:int">12</item> | |||||
| <item xsi:type="xsd:string">23</item> | |||||
| <item xsi:type="xsd:float">0</item> | |||||
| <item xsi:type="xsd:int">-31</item> | |||||
| </param> | |||||
| <param1 xsi:null="1"></param1> | |||||
| </Bounds> | |||||
| </SOAP-ENV:Body> | |||||
| </SOAP-ENV:Envelope> | |||||
| ''' | |||||
| pr = {'Bounds': | |||||
| {'param': 'arrayType=ur-type[]' | |||||
| } | |||||
| } | |||||
| y = parseSOAPRPC(x, rules=pr) | |||||
| assert y.param[0]==12 | |||||
| assert y.param[1]=='23' | |||||
| assert y.param[2]==float(0) | |||||
| assert y.param[3]==-31 | |||||
| # Try the reverse, not implemented yet. | |||||
| def testBuildObject(self): | |||||
| class Book(structType): | |||||
| def __init__(self): | |||||
| self.title = "Title of a book" | |||||
| class Person(structType): | |||||
| def __init__(self): | |||||
| self.age = "49" | |||||
| self.height = "5.5" | |||||
| class Library(structType): | |||||
| def __init__(self): | |||||
| self._name = "Result" | |||||
| self.Book = Book() | |||||
| self.Person = Person() | |||||
| obj = Library() | |||||
| x = buildSOAP( kw={'Library':obj} ) | |||||
| print(x) | |||||
| if __name__ == '__main__': | |||||
| unittest.main() | |||||
| @@ -0,0 +1,33 @@ | |||||
| <?xml version="1.0"?> | |||||
| <definitions name="TemperatureService" targetNamespace="http://www.xmethods.net/sd/TemperatureService.wsdl" xmlns:tns="http://www.xmethods.net/sd/TemperatureService.wsdl" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/"> | |||||
| <message name="getTempRequest"> | |||||
| <part name="zipcode" type="xsd:string"/> | |||||
| </message> | |||||
| <message name="getTempResponse"> | |||||
| <part name="return" type="xsd:float"/> | |||||
| </message> | |||||
| <portType name="TemperaturePortType"> | |||||
| <operation name="getTemp"> | |||||
| <input message="tns:getTempRequest"/> | |||||
| <output message="tns:getTempResponse"/> | |||||
| </operation> | |||||
| </portType> | |||||
| <binding name="TemperatureBinding" type="tns:TemperaturePortType"> | |||||
| <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> | |||||
| <operation name="getTemp"> | |||||
| <soap:operation soapAction=""/> | |||||
| <input> | |||||
| <soap:body use="encoded" namespace="urn:xmethods-Temperature" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> | |||||
| </input> | |||||
| <output> | |||||
| <soap:body use="encoded" namespace="urn:xmethods-Temperature" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> | |||||
| </output> | |||||
| </operation> | |||||
| </binding> | |||||
| <service name="TemperatureService"> | |||||
| <documentation>Returns current temperature in a given U.S. zipcode </documentation> | |||||
| <port name="TemperaturePort" binding="tns:TemperatureBinding"> | |||||
| <soap:address location="http://services.xmethods.net:80/soap/servlet/rpcrouter"/> | |||||
| </port> | |||||
| </service> | |||||
| </definitions> | |||||
| @@ -0,0 +1,8 @@ | |||||
| import sys | |||||
| sys.path.insert(1, "..") | |||||
| from SOAPpy import * | |||||
| one = typedArrayType(data=[1],typed=type(1)) | |||||
| tmp = typedArrayType(data=[], typed=type(1)) | |||||
| print buildSOAP( one ) | |||||
| print buildSOAP( tmp ) | |||||
| @@ -0,0 +1,34 @@ | |||||
| #!/usr/bin/env python | |||||
| # Copyright (c) 2001 actzero, inc. All rights reserved. | |||||
| ident = '$Id: alanbushTest.py,v 1.5 2003/05/21 14:52:37 warnes Exp $' | |||||
| import os, re,sys | |||||
| # add local SOAPpy code to search path | |||||
| sys.path.insert(1, "..") | |||||
| from SOAPpy import * | |||||
| Config.debug=0 | |||||
| # Check for a web proxy definition in environment | |||||
| try: | |||||
| proxy_url=os.environ['http_proxy'] | |||||
| phost, pport = re.search('http://([^:]+):([0-9]+)', proxy_url).group(1,2) | |||||
| proxy = "%s:%s" % (phost, pport) | |||||
| except: | |||||
| proxy = None | |||||
| SoapEndpointURL = 'http://www.alanbushtrust.org.uk/soap/compositions.asp' | |||||
| MethodNamespaceURI = 'urn:alanbushtrust-org-uk:soap.methods' | |||||
| SoapAction = MethodNamespaceURI + ".GetCategories" | |||||
| server = SOAPProxy(SoapEndpointURL, | |||||
| namespace=MethodNamespaceURI, | |||||
| soapaction=SoapAction, | |||||
| http_proxy=proxy | |||||
| ) | |||||
| for category in server.GetCategories(): | |||||
| print category | |||||
| @@ -0,0 +1,30 @@ | |||||
| #!/usr/bin/env python | |||||
| # Copyright (c) 2001 actzero, inc. All rights reserved. | |||||
| import sys | |||||
| sys.path.insert (1, '..') | |||||
| from SOAPpy import * | |||||
| ident = '$Id: cardClient.py,v 1.4 2004/02/18 21:22:13 warnes Exp $' | |||||
| endpoint = "http://localhost:12027/xmethodsInterop" | |||||
| sa = "urn:soapinterop" | |||||
| ns = "http://soapinterop.org/" | |||||
| serv = SOAPProxy(endpoint, namespace=ns, soapaction=sa) | |||||
| try: hand = serv.dealHand(NumberOfCards = 13, StringSeparator = '\n') | |||||
| except: print "no dealHand"; hand = 0 | |||||
| try: sortedhand = serv.dealArrangedHand(NumberOfCards=13,StringSeparator='\n') | |||||
| except: print "no sorted"; sortedhand = 0 | |||||
| try: card = serv.dealCard() | |||||
| except: print "no card"; card = 0 | |||||
| print "*****hand****\n",hand,"\n*********" | |||||
| print "******sortedhand*****\n",sortedhand,"\n*********" | |||||
| print "card:",card | |||||
| serv.quit() | |||||
| @@ -0,0 +1,112 @@ | |||||
| #!/usr/bin/env python | |||||
| # Copyright (c) 2001 actzero, inc. All rights reserved. | |||||
| import string | |||||
| import sys | |||||
| sys.path.insert (1, '..') | |||||
| from SOAPpy import * | |||||
| ident = '$Id: cardServer.py,v 1.4 2004/02/18 21:22:13 warnes Exp $' | |||||
| # create the list of all cards, and keep strings for each suit | |||||
| __cs = "Clubs" | |||||
| __ds = "Diamonds" | |||||
| __hs = "Hearts" | |||||
| __ss = "Spades" | |||||
| __cards = [] | |||||
| for suit in [__cs, __ds, __hs, __ss]: | |||||
| for num in range(9): | |||||
| num += 1 | |||||
| __cards.append(str(num+1)+" of "+suit) | |||||
| for face in ["ace","King","Queen","Jack"]: | |||||
| __cards.append(face+" of "+suit) | |||||
| def deal(num): | |||||
| if num not in range(1,53): | |||||
| return -1 | |||||
| else: | |||||
| alreadydealt = [] | |||||
| ignore = 0 | |||||
| handdealt = [] | |||||
| import whrandom | |||||
| while num > 0: | |||||
| idx = int(str(whrandom.random())[2:4]) | |||||
| if idx in range(52) and idx not in alreadydealt: | |||||
| handdealt.append(__cards[idx]) | |||||
| alreadydealt.append(idx) | |||||
| num -= 1 | |||||
| else: | |||||
| ignore += 1 | |||||
| continue | |||||
| return handdealt | |||||
| def arrangeHand(hand): | |||||
| c = [] | |||||
| d = [] | |||||
| h = [] | |||||
| s = [] | |||||
| import string | |||||
| for card in hand: | |||||
| if string.find(card, __cs) != -1: | |||||
| c.append(card) | |||||
| elif string.find(card, __ds) != -1: | |||||
| d.append(card) | |||||
| elif string.find(card, __hs) != -1: | |||||
| h.append(card) | |||||
| elif string.find(card, __ss) != -1: | |||||
| s.append(card) | |||||
| for cards, str in ((c, __cs),(d, __ds),(h,__hs), (s,__ss)): | |||||
| cards.sort() | |||||
| idx = 0 | |||||
| if "10 of "+str in cards: | |||||
| cards.remove("10 of "+str) | |||||
| if "Jack of "+str in cards: idx += 1 | |||||
| if "Queen of "+str in cards: idx += 1 | |||||
| if "King of "+str in cards: idx += 1 | |||||
| if "ace of "+str in cards: idx +=1 | |||||
| cards.insert(len(cards)-idx,"10 of "+str) | |||||
| if "King of "+str in cards: | |||||
| cards.remove("King of "+str) | |||||
| if "ace of "+str in cards: cards.insert(len(cards)-1,"King of "+str) | |||||
| else: cards.append("King of "+str) | |||||
| return c+d+h+s | |||||
| def dealHand (NumberOfCards, StringSeparator): | |||||
| hand = deal(NumberOfCards) | |||||
| return string.join(hand,StringSeparator) | |||||
| def dealArrangedHand (NumberOfCards, StringSeparator): | |||||
| if NumberOfCards < 1 or NumberOfCards > 52: | |||||
| raise ValueError, "NumberOfCards must be between 1 and 52" | |||||
| unarranged = deal(NumberOfCards) | |||||
| hand = arrangeHand(unarranged) | |||||
| return string.join(hand, StringSeparator) | |||||
| def dealCard (): | |||||
| return deal(1)[0] | |||||
| run = 1 | |||||
| def quit(): | |||||
| global run | |||||
| run=0; | |||||
| namespace = 'http://soapinterop.org/' | |||||
| server = SOAPServer (("localhost", 12027)) | |||||
| server.registerKWFunction (dealHand, namespace) | |||||
| server.registerKWFunction (dealArrangedHand, namespace) | |||||
| server.registerKWFunction (dealCard, namespace) | |||||
| server.registerKWFunction (quit, namespace) | |||||
| try: | |||||
| while run: | |||||
| server.handle_request() | |||||
| except KeyboardInterrupt: | |||||
| pass | |||||
| @@ -0,0 +1,102 @@ | |||||
| #!/usr/bin/env python | |||||
| # Copyright (c) 2001 actzero, inc. All rights reserved. | |||||
| import sys | |||||
| sys.path.insert(1, "..") | |||||
| from SOAPpy import * | |||||
| # Uncomment to see outgoing HTTP headers and SOAP and incoming | |||||
| #Config.debug = 1 | |||||
| #Config.dumpHeadersIn = 1 | |||||
| #Config.dumpSOAPIn = 1 | |||||
| #Config.dumpSOAPOut = 1 | |||||
| # ask for returned SOAP responses to be converted to basic python types | |||||
| Config.simplify_objects = 1 | |||||
| #Config.BuildWithNoType = 1 | |||||
| #Config.BuildWithNoNamespacePrefix = 1 | |||||
| if len(sys.argv) > 1 and sys.argv[1] == '-s': | |||||
| # Use secure http | |||||
| pathserver = SOAPProxy("https://localhost:9900/pathtest") | |||||
| server = SOAPProxy("https://localhost:9900") | |||||
| elif len(sys.argv) > 1 and sys.argv[1] == '-g': | |||||
| # use Globus for communication | |||||
| import pyGlobus | |||||
| pathserver = SOAPProxy("httpg://localhost:9900/pathtest") | |||||
| server = SOAPProxy("httpg://localhost:9900") | |||||
| else: | |||||
| # Default: use standard http | |||||
| pathserver = SOAPProxy("http://localhost:9900/pathtest") | |||||
| server = SOAPProxy("http://localhost:9900") | |||||
| # Echo... | |||||
| try: | |||||
| print server.echo("MOO") | |||||
| except Exception, e: | |||||
| print "Caught exception: ", e | |||||
| try: | |||||
| print pathserver.echo("MOO") | |||||
| except Exception, e: | |||||
| print "Caught exception: ", e | |||||
| # ...in an object | |||||
| try: | |||||
| print server.echo_ino("moo") | |||||
| except Exception, e: | |||||
| print "Caught exception: ", e | |||||
| try: | |||||
| print pathserver.echo_ino("cow") | |||||
| except Exception, e: | |||||
| print "Caught exception: ", e | |||||
| # ...in an object in an object | |||||
| try: | |||||
| print server.prop.echo2("moo") | |||||
| except Exception, e: | |||||
| print "Caught exception: ", e | |||||
| try: | |||||
| print pathserver.prop.echo2("cow") | |||||
| except Exception, e: | |||||
| print "Caught exception: ", e | |||||
| # ...with keyword arguments | |||||
| try: | |||||
| print server.echo_wkw(third = "three", first = "one", second = "two") | |||||
| except Exception, e: | |||||
| print "Caught exception: ", e | |||||
| try: | |||||
| print pathserver.echo_wkw(third = "three", first = "one", second = "two") | |||||
| except Exception, e: | |||||
| print "Caught exception: ", e | |||||
| # ...with a context object | |||||
| try: | |||||
| print server.echo_wc("moo") | |||||
| except Exception, e: | |||||
| print "Caught exception: ", e | |||||
| try: | |||||
| print pathserver.echo_wc("cow") | |||||
| except Exception, e: | |||||
| print "Caught exception: ", e | |||||
| # ...with a header | |||||
| hd = headerType(data = {"mystring": "Hello World"}) | |||||
| try: | |||||
| print server._hd(hd).echo_wc("moo") | |||||
| except Exception, e: | |||||
| print "Caught exception: ", e | |||||
| try: | |||||
| print pathserver._hd(hd).echo_wc("cow") | |||||
| except Exception, e: | |||||
| print "Caught exception: ", e | |||||
| # close down server | |||||
| server.quit() | |||||
| @@ -0,0 +1,23 @@ | |||||
| #!/usr/bin/env python | |||||
| # Copyright (c) 2001 actzero, inc. All rights reserved. | |||||
| import sys | |||||
| sys.path.insert(1, "..") | |||||
| from SOAPpy import * | |||||
| # Uncomment to see outgoing HTTP headers and SOAP and incoming | |||||
| #Config.debug = 1 | |||||
| Config.BuildWithNoType = 1 | |||||
| Config.BuildWithNoNamespacePrefix = 1 | |||||
| hd = headerType(data = {"mystring": "Hello World"}) | |||||
| server = SOAPProxy("http://localhost:9900/", header=hd) | |||||
| print server.echo("Hello world") | |||||
| server.quit() | |||||
| @@ -0,0 +1,198 @@ | |||||
| #!/usr/bin/env python | |||||
| # | |||||
| # Copyright (c) 2001 actzero, inc. All rights reserved. | |||||
| import sys | |||||
| sys.path.insert(1, "..") | |||||
| from SOAPpy import * | |||||
| # Uncomment to see outgoing HTTP headers and SOAP and incoming | |||||
| Config.dumpSOAPIn = 1 | |||||
| Config.dumpSOAPOut = 1 | |||||
| Config.debug = 1 | |||||
| # specify name of authorization function | |||||
| Config.authMethod = "_authorize" | |||||
| # Set this to 0 to test authorization | |||||
| allowAll = 1 | |||||
| # ask for returned SOAP responses to be converted to basic python types | |||||
| Config.simplify_objects = 1 | |||||
| # provide a mechanism to stop the server | |||||
| run = 1 | |||||
| def quit(): | |||||
| global run | |||||
| run=0; | |||||
| if Config.SSLserver: | |||||
| from M2Crypto import SSL | |||||
| def _authorize(*args, **kw): | |||||
| global allowAll, Config | |||||
| if Config.debug: | |||||
| print "Authorize (function) called! (result = %d)" % allowAll | |||||
| print "Arguments: %s" % kw | |||||
| if allowAll: | |||||
| return 1 | |||||
| else: | |||||
| return 0 | |||||
| # Simple echo | |||||
| def echo(s): | |||||
| global Config | |||||
| # Test of context retrieval | |||||
| ctx = Server.GetSOAPContext() | |||||
| if Config.debug: | |||||
| print "SOAP Context: ", ctx | |||||
| return s + s | |||||
| # An echo class | |||||
| class echoBuilder2: | |||||
| def echo2(self, val): | |||||
| return val * 3 | |||||
| # A class that has an instance variable which is an echo class | |||||
| class echoBuilder: | |||||
| def __init__(self): | |||||
| self.prop = echoBuilder2() | |||||
| def echo_ino(self, val): | |||||
| return val + val | |||||
| def _authorize(self, *args, **kw): | |||||
| global allowAll, Config | |||||
| if Config.debug: | |||||
| print "Authorize (method) called with arguments:" | |||||
| print "*args=%s" % str(args) | |||||
| print "**kw =%s" % str(kw) | |||||
| print "Approved -> %d" % allowAll | |||||
| if allowAll: | |||||
| return 1 | |||||
| else: | |||||
| return 0 | |||||
| # Echo with context | |||||
| def echo_wc(s, _SOAPContext): | |||||
| global Config | |||||
| c = _SOAPContext | |||||
| sep = '-' * 72 | |||||
| # The Context object has extra info about the call | |||||
| if Config.debug: | |||||
| print "-- XML", sep[7:] | |||||
| # The original XML request | |||||
| print c.xmldata | |||||
| print "-- Header", sep[10:] | |||||
| # The SOAP Header or None if not present | |||||
| print c.header | |||||
| if c.header: | |||||
| print "-- Header.mystring", sep[19:] | |||||
| # An element of the SOAP Header | |||||
| print c.header.mystring | |||||
| print "-- Body", sep[8:] | |||||
| # The whole Body object | |||||
| print c.body | |||||
| print "-- Peer", sep[8:] | |||||
| if not GSI: | |||||
| # The socket object, useful for | |||||
| print c.connection.getpeername() | |||||
| else: | |||||
| # The socket object, useful for | |||||
| print c.connection.get_remote_address() | |||||
| ctx = c.connection.get_security_context() | |||||
| print ctx.inquire()[0].display() | |||||
| print "-- SOAPAction", sep[14:] | |||||
| # The SOAPaction HTTP header | |||||
| print c.soapaction | |||||
| print "-- HTTP headers", sep[16:] | |||||
| # All the HTTP headers | |||||
| print c.httpheaders | |||||
| return s + s | |||||
| # Echo with keyword arguments | |||||
| def echo_wkw(**kw): | |||||
| return kw['first'] + kw['second'] + kw['third'] | |||||
| # Simple echo | |||||
| def echo_simple(*arg): | |||||
| return arg | |||||
| def echo_header(s, _SOAPContext): | |||||
| global Config | |||||
| c = _SOAPContext | |||||
| return s, c.header | |||||
| addr = ('localhost', 9900) | |||||
| GSI = 0 | |||||
| SSL = 0 | |||||
| if len(sys.argv) > 1 and sys.argv[1] == '-s': | |||||
| SSL = 1 | |||||
| if not Config.SSLserver: | |||||
| raise RuntimeError, \ | |||||
| "this Python installation doesn't have OpenSSL and M2Crypto" | |||||
| ssl_context = SSL.Context() | |||||
| ssl_context.load_cert('validate/server.pem') | |||||
| server = SOAPServer(addr, ssl_context = ssl_context) | |||||
| prefix = 'https' | |||||
| elif len(sys.argv) > 1 and sys.argv[1] == '-g': | |||||
| GSI = 1 | |||||
| from SOAPpy.GSIServer import GSISOAPServer | |||||
| server = GSISOAPServer(addr) | |||||
| prefix = 'httpg' | |||||
| else: | |||||
| server = SOAPServer(addr) | |||||
| prefix = 'http' | |||||
| print "Server listening at: %s://%s:%d/" % (prefix, addr[0], addr[1]) | |||||
| # register the method | |||||
| server.registerFunction(echo) | |||||
| server.registerFunction(echo, path = "/pathtest") | |||||
| server.registerFunction(_authorize) | |||||
| server.registerFunction(_authorize, path = "/pathtest") | |||||
| # Register a whole object | |||||
| o = echoBuilder() | |||||
| server.registerObject(o, path = "/pathtest") | |||||
| server.registerObject(o) | |||||
| # Register a function which gets called with the Context object | |||||
| server.registerFunction(MethodSig(echo_wc, keywords = 0, context = 1), | |||||
| path = "/pathtest") | |||||
| server.registerFunction(MethodSig(echo_wc, keywords = 0, context = 1)) | |||||
| # Register a function that takes keywords | |||||
| server.registerKWFunction(echo_wkw, path = "/pathtest") | |||||
| server.registerKWFunction(echo_wkw) | |||||
| server.registerFunction(echo_simple) | |||||
| server.registerFunction(MethodSig(echo_header, keywords=0, context=1)) | |||||
| server.registerFunction(quit) | |||||
| # Start the server | |||||
| try: | |||||
| while run: | |||||
| server.handle_request() | |||||
| except KeyboardInterrupt: | |||||
| pass | |||||
| @@ -0,0 +1,71 @@ | |||||
| #!/usr/bin/python2 | |||||
| #standard imports | |||||
| import syslog, sys | |||||
| #domain specific imports | |||||
| sys.path.insert (1, '..') | |||||
| import SOAPpy | |||||
| SOAPpy.Config.simplify_objects=1 | |||||
| ## def test_integer(self,pass_integer): | |||||
| ## def test_string(self,pass_string): | |||||
| ## def test_float(self,pass_float): | |||||
| ## def test_tuple(self,pass_tuple): | |||||
| ## def test_list(self,pass_list): | |||||
| ## def test_dictionary(self,pass_dictionary): | |||||
| if __name__ == "__main__": | |||||
| server = SOAPpy.SOAPProxy("http://localhost:9999") | |||||
| original_integer = 5 | |||||
| result_integer = server.test_integer(original_integer) | |||||
| print "original_integer %s" % original_integer | |||||
| print "result_integer %s" % result_integer | |||||
| assert(result_integer==original_integer) | |||||
| original_string = "five" | |||||
| result_string = server.test_string(original_string) | |||||
| print "original_string %s" % original_string | |||||
| print "result_string %s" % result_string | |||||
| assert(result_string==original_string) | |||||
| original_float = 5.0 | |||||
| result_float = server.test_float(original_float) | |||||
| print "original_float %s" % original_float | |||||
| print "result_float %s" % result_float | |||||
| assert(result_float==original_float) | |||||
| original_tuple = (1,2,"three","four",5) | |||||
| result_tuple = server.test_tuple(original_tuple) | |||||
| print "original_tuple %s" % str(original_tuple) | |||||
| print "result_tuple %s" % str(result_tuple) | |||||
| assert(tuple(result_tuple)==original_tuple) | |||||
| original_list = [5,4,"three",2,1] | |||||
| result_list = server.test_list(original_list) | |||||
| print "original_list %s" % original_list | |||||
| print "result_list %s" % result_list | |||||
| assert(result_list==original_list) | |||||
| original_dictionary = { | |||||
| 'one': 1, | |||||
| "two": 2, | |||||
| "three": 3, | |||||
| "four": 4, | |||||
| "five": 5, | |||||
| } | |||||
| result_dictionary = server.test_dictionary(original_dictionary) | |||||
| print "original_dictionary %s" % original_dictionary | |||||
| print "result_dictionary %s" % result_dictionary | |||||
| assert(result_dictionary==original_dictionary) | |||||
| server.quit() | |||||
| @@ -0,0 +1,48 @@ | |||||
| #!/usr/bin/python2 | |||||
| #standard imports | |||||
| import syslog, sys | |||||
| #domain specific imports | |||||
| sys.path.insert (1, '..') | |||||
| import SOAPpy | |||||
| class test_service: | |||||
| run = 1 | |||||
| def test_integer(self,pass_integer): | |||||
| print type(pass_integer) | |||||
| return pass_integer | |||||
| def test_string(self,pass_string): | |||||
| print type(pass_string) | |||||
| return pass_string | |||||
| def test_float(self,pass_float): | |||||
| print type(pass_float) | |||||
| return pass_float | |||||
| def test_tuple(self,pass_tuple): | |||||
| print type(pass_tuple), pass_tuple | |||||
| return pass_tuple | |||||
| def test_list(self,pass_list): | |||||
| print type(pass_list), pass_list | |||||
| return pass_list | |||||
| def test_dictionary(self,pass_dictionary): | |||||
| print type(pass_dictionary), pass_dictionary | |||||
| return pass_dictionary | |||||
| def quit(self): | |||||
| self.run = 0 | |||||
| server = SOAPpy.SOAPServer(("localhost",9999)) | |||||
| SOAPpy.Config.simplify_objects=1 | |||||
| access_object = test_service() | |||||
| server.registerObject(access_object) | |||||
| while access_object.run: | |||||
| server.handle_request() | |||||
| @@ -0,0 +1,18 @@ | |||||
| #!/usr/bin/env python | |||||
| import sys | |||||
| sys.path.insert(1, "..") | |||||
| from SOAPpy import * | |||||
| server = SOAPProxy("http://206.135.217.234:8000/") | |||||
| server.COM_SetProperty("Visible", 1) | |||||
| server.Workbooks.Open("c:\\test.xls") | |||||
| server.COM_NestedCall('ActiveSheet.Range("A2").EntireRow.Delete()') | |||||
| server.quit() | |||||
| @@ -0,0 +1,50 @@ | |||||
| #!/usr/bin/env python | |||||
| # Copyright (c) 2001 actzero, inc. All rights reserved. | |||||
| import sys | |||||
| sys.path.insert(1, "..") | |||||
| from SOAPpy import * | |||||
| from SOAPpy import Parser | |||||
| # Uncomment to see outgoing HTTP headers and SOAP and incoming | |||||
| #Config.debug = 1 | |||||
| if len(sys.argv) > 1 and sys.argv[1] == '-s': | |||||
| server = SOAPProxy("https://localhost:9900") | |||||
| else: | |||||
| server = SOAPProxy("http://localhost:9900") | |||||
| # BIG data: | |||||
| big = repr('.' * (1<<18) ) | |||||
| # ...in an object | |||||
| print "server.echo_ino(big):..", | |||||
| tmp = server.echo_ino(big) | |||||
| print "done" | |||||
| # ...in an object in an object | |||||
| print "server.prop.echo2(big)..", | |||||
| tmp = server.prop.echo2(big) | |||||
| print "done" | |||||
| # ...with keyword arguments | |||||
| print 'server.echo_wkw(third = big, first = "one", second = "two")..', | |||||
| tmp = server.echo_wkw(third = big, first = "one", second = "two") | |||||
| print "done" | |||||
| # ...with a context object | |||||
| print "server.echo_wc(big)..", | |||||
| tmp = server.echo_wc(big) | |||||
| print "done" | |||||
| # ...with a header | |||||
| hd = headerType(data = {"mystring": "Hello World"}) | |||||
| print "server._hd(hd).echo_wc(big)..", | |||||
| tmp = server._hd(hd).echo_wc(big) | |||||
| print "done" | |||||
| server.quit() | |||||
| @@ -0,0 +1,46 @@ | |||||
| #!/usr/bin/env python | |||||
| ident = '$Id: newsTest.py,v 1.4 2003/05/21 14:52:37 warnes Exp $' | |||||
| import os, re | |||||
| import sys | |||||
| sys.path.insert(1, "..") | |||||
| from SOAPpy import SOAPProxy | |||||
| # Check for a web proxy definition in environment | |||||
| try: | |||||
| proxy_url=os.environ['http_proxy'] | |||||
| phost, pport = re.search('http://([^:]+):([0-9]+)', proxy_url).group(1,2) | |||||
| proxy = "%s:%s" % (phost, pport) | |||||
| except: | |||||
| proxy = None | |||||
| SoapEndpointURL = 'http://www22.brinkster.com/prasads/BreakingNewsService.asmx?WSDL' | |||||
| MethodNamespaceURI = 'http://tempuri.org/' | |||||
| # Three ways to do namespaces, force it at the server level | |||||
| server = SOAPProxy(SoapEndpointURL, namespace = MethodNamespaceURI, | |||||
| soapaction='http://tempuri.org/GetCNNNews', encoding = None, | |||||
| http_proxy=proxy) | |||||
| print "[server level CNN News call]" | |||||
| print server.GetCNNNews() | |||||
| # Do it inline ala SOAP::LITE, also specify the actually ns (namespace) and | |||||
| # sa (soapaction) | |||||
| server = SOAPProxy(SoapEndpointURL, encoding = None) | |||||
| print "[inline CNNNews call]" | |||||
| print server._ns('ns1', | |||||
| MethodNamespaceURI)._sa('http://tempuri.org/GetCNNNews').GetCNNNews() | |||||
| # Create an instance of your server with specific namespace and then use | |||||
| # inline soapactions for each call | |||||
| dq = server._ns(MethodNamespaceURI) | |||||
| print "[namespaced CNNNews call]" | |||||
| print dq._sa('http://tempuri.org/GetCNNNews').GetCNNNews() | |||||
| print "[namespaced CBSNews call]" | |||||
| print dq._sa('http://tempuri.org/GetCBSNews').GetCBSNews() | |||||
| @@ -0,0 +1,40 @@ | |||||
| #!/usr/bin/env python | |||||
| # Copyright (c) 2001 actzero, inc. All rights reserved. | |||||
| ident = '$Id: quoteTest.py,v 1.5 2003/12/18 06:31:50 warnes Exp $' | |||||
| import os, re | |||||
| import sys | |||||
| sys.path.insert(1, "..") | |||||
| from SOAPpy import SOAPProxy | |||||
| # Check for a web proxy definition in environment | |||||
| try: | |||||
| proxy_url=os.environ['http_proxy'] | |||||
| phost, pport = re.search('http://([^:]+):([0-9]+)', proxy_url).group(1,2) | |||||
| proxy = "%s:%s" % (phost, pport) | |||||
| except: | |||||
| proxy = None | |||||
| # Three ways to do namespaces, force it at the server level | |||||
| server = SOAPProxy("http://services.xmethods.com:9090/soap", | |||||
| namespace = 'urn:xmethods-delayed-quotes', | |||||
| http_proxy=proxy) | |||||
| print "IBM>>", server.getQuote(symbol = 'IBM') | |||||
| # Do it inline ala SOAP::LITE, also specify the actually ns | |||||
| server = SOAPProxy("http://services.xmethods.com:9090/soap", | |||||
| http_proxy=proxy) | |||||
| print "IBM>>", server._ns('ns1', | |||||
| 'urn:xmethods-delayed-quotes').getQuote(symbol = 'IBM') | |||||
| # Create a namespaced version of your server | |||||
| dq = server._ns('urn:xmethods-delayed-quotes') | |||||
| print "IBM>>", dq.getQuote(symbol='IBM') | |||||
| print "ORCL>>", dq.getQuote(symbol='ORCL') | |||||
| print "INTC>>", dq.getQuote(symbol='INTC') | |||||
| @@ -0,0 +1,10 @@ | |||||
| import sys | |||||
| sys.path.insert(1, "..") | |||||
| import SOAPpy | |||||
| url = 'http://www.xmethods.org/sd/2001/TemperatureService.wsdl' | |||||
| zip = '06340' | |||||
| proxy = SOAPpy.WSDL.Proxy(url) | |||||
| temp = proxy.getTemp(zip) | |||||
| print 'Temperature at', zip, 'is', temp | |||||
| @@ -0,0 +1,83 @@ | |||||
| #!/usr/bin/env python | |||||
| ident = '$Id: speedTest.py,v 1.4 2003/05/21 14:52:37 warnes Exp $' | |||||
| import time | |||||
| import sys | |||||
| sys.path.insert(1, "..") | |||||
| x='''<SOAP-ENV:Envelope | |||||
| xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" | |||||
| xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" | |||||
| xmlns:xsd="http://www.w3.org/1999/XMLSchema"> | |||||
| <SOAP-ENV:Body> | |||||
| <ns1:getRate xmlns:ns1="urn:demo1:exchange" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> | |||||
| <country1 xsi:type="xsd:string">USA</country1> | |||||
| <country2 xsi:type="xsd:string">japan</country2> | |||||
| </ns1:getRate> | |||||
| </SOAP-ENV:Body> | |||||
| </SOAP-ENV:Envelope>''' | |||||
| x2='''<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.microsoft.com/soap/encoding/clr/1.0 http://schemas.xmlsoap.org/soap/encoding/" xmlns:i3="http://soapinterop.org/xsd" xmlns:i2="http://soapinterop.org/"> | |||||
| <SOAP-ENV:Body> | |||||
| <i2:echoStructArray id="ref-1"> | |||||
| <return href="#ref-4"/> | |||||
| </i2:echoStructArray> | |||||
| <SOAP-ENC:Array id="ref-4" SOAP-ENC:arrayType="i3:SOAPStruct[3]"> | |||||
| <item href="#ref-5"/> | |||||
| <item href="#ref-6"/> | |||||
| <item href="#ref-7"/> | |||||
| </SOAP-ENC:Array> | |||||
| <i3:SOAPStruct id="ref-5"> | |||||
| <varString xsi:type="xsd:string">West Virginia</varString> | |||||
| <varInt xsi:type="xsd:int">-546</varInt> | |||||
| <varFloat xsi:type="xsd:float">-5.398</varFloat> | |||||
| </i3:SOAPStruct> | |||||
| <i3:SOAPStruct id="ref-6"> | |||||
| <varString xsi:type="xsd:string">New Mexico</varString> | |||||
| <varInt xsi:type="xsd:int">-641</varInt> | |||||
| <varFloat xsi:type="xsd:float">-9.351</varFloat> | |||||
| </i3:SOAPStruct> | |||||
| <i3:SOAPStruct id="ref-7"> | |||||
| <varString xsi:type="xsd:string">Missouri</varString> | |||||
| <varInt xsi:type="xsd:int">-819</varInt> | |||||
| <varFloat xsi:type="xsd:float">1.495</varFloat> | |||||
| </i3:SOAPStruct> | |||||
| </SOAP-ENV:Body> | |||||
| </SOAP-ENV:Envelope> | |||||
| ''' | |||||
| # Import in function, because for some reason they slow each other | |||||
| # down in same namespace ??? | |||||
| def SOAPParse(inxml): | |||||
| from SOAPpy import parseSOAPRPC | |||||
| t= time.time() | |||||
| parseSOAPRPC(inxml) | |||||
| return time.time()-t | |||||
| def SAXParse(inxml): | |||||
| import xml.sax | |||||
| y = xml.sax.handler.ContentHandler() | |||||
| t= time.time() | |||||
| xml.sax.parseString(inxml,y) | |||||
| return time.time()-t | |||||
| def DOMParse(inxml): | |||||
| import xml.dom.minidom | |||||
| t= time.time() | |||||
| xml.dom.minidom.parseString(inxml) | |||||
| return time.time()-t | |||||
| # Wierd but the SAX parser runs really slow the first time. | |||||
| # Probably got to load a c module or something | |||||
| SAXParse(x) | |||||
| print "Simple XML" | |||||
| print "SAX Parse, no marshalling ", SAXParse(x) | |||||
| print "SOAP Parse, and marshalling ", SOAPParse(x) | |||||
| print "DOM Parse, no marshalling ", DOMParse(x) | |||||
| print "Complex XML (references)" | |||||
| print "SAX Parse, no marshalling ", SAXParse(x2) | |||||
| print "SOAP Parse, and marshalling ", SOAPParse(x2) | |||||
| print "DOM Parse, no marshalling ", DOMParse(x2) | |||||
| @@ -0,0 +1,126 @@ | |||||
| #!/usr/bin/env python | |||||
| ident = '$Id: storageTest.py,v 1.6 2005/02/16 04:24:54 warnes Exp $' | |||||
| import sys, os, time, signal, re | |||||
| sys.path.insert(1, "..") | |||||
| from SOAPpy import SOAPProxy, SOAPConfig, SOAPUserAgent | |||||
| # Check for a web proxy definition in environment | |||||
| try: | |||||
| proxy_url=os.environ['http_proxy'] | |||||
| phost, pport = re.search('http://([^:]+):([0-9]+)', proxy_url).group(1,2) | |||||
| http_proxy = "%s:%s" % (phost, pport) | |||||
| except: | |||||
| http_proxy = None | |||||
| PROXY="http://www.soapware.org/xmlStorageSystem" | |||||
| EMAIL="SOAPpy@actzero.com" | |||||
| NAME="test_user" | |||||
| PASSWORD="mypasswd" | |||||
| SERIAL=1123214 | |||||
| MY_PORT=15600 | |||||
| def resourceChanged (url): | |||||
| print "\n##### NOTIFICATION MESSAGE: Resource %s has changed #####\n" % url | |||||
| return booleanType(1) | |||||
| def printstatus (cmd, stat): | |||||
| if stat.flError: | |||||
| print "### %s failed: %s ###" % (cmd, stat.message) | |||||
| else: | |||||
| print "### %s successful: %s ###" % (cmd, stat.message) | |||||
| return not stat.flError | |||||
| server = SOAPProxy(encoding="US-ASCII", | |||||
| proxy=PROXY, | |||||
| soapaction="/xmlStorageSystem", | |||||
| http_proxy=http_proxy, | |||||
| # config=SOAPConfig(debug=1) | |||||
| ) | |||||
| # Register as a new user or update user information | |||||
| reg = server.registerUser(email=EMAIL, name=NAME, password=PASSWORD, | |||||
| clientPort=MY_PORT, userAgent=SOAPUserAgent(), | |||||
| serialnumber=SERIAL) | |||||
| printstatus("registerUser", reg) | |||||
| # See what this server can do | |||||
| reg = server.getServerCapabilities (email=EMAIL, password=PASSWORD) | |||||
| if printstatus("getServerCapabilities", reg): | |||||
| print "Legal file extensions: " + str(reg.legalFileExtensions) | |||||
| print "Maximum file size: " + str(reg.maxFileSize) | |||||
| print "Maximum bytes per user: " + str(reg.maxBytesPerUser) | |||||
| print "Number of bytes in use by the indicated user: " + str(reg.ctBytesInUse) | |||||
| print "URL of the folder containing your files: " + str(reg.yourUpstreamFolderUrl) | |||||
| # Store some files | |||||
| reg = server.saveMultipleFiles (email=EMAIL, password=PASSWORD, | |||||
| relativepathList=['index.html','again.html'], | |||||
| fileTextList=['<html><title>bennett@actzero.com home page</title><body>' + | |||||
| '<a href=again.html>Hello Earth</a></body></html>', | |||||
| '<html><title>bennett@actzero.com home page</title><body>' + | |||||
| '<a href=index.html>Hello Earth Again</a></body></html>']) | |||||
| if printstatus("saveMultipleFiles", reg): | |||||
| print "Files stored:" | |||||
| for file in reg.urlList: | |||||
| print " %s" % file | |||||
| # Save this for call to test pleaseNotify | |||||
| mylist = reg.urlList | |||||
| else: | |||||
| mylist = [] | |||||
| # Check to see what files are stored | |||||
| reg = server.getMyDirectory (email=EMAIL, password=PASSWORD) | |||||
| if printstatus("getMyDirectory", reg): | |||||
| i = 1 | |||||
| while hasattr(reg.directory, "file%05d" % i): | |||||
| d = getattr(reg.directory, "file%05d" % i) | |||||
| print "Relative Path: %s" % d.relativePath | |||||
| print "Size: %d" % d.size | |||||
| print "Created: %s" % d.whenCreated | |||||
| print "Last Uploaded: %s" % d.whenLastUploaded | |||||
| print "URL: %s" % d.url | |||||
| i += 1 | |||||
| # Set up notification | |||||
| reg = server.pleaseNotify(notifyProcedure="resourceChanged", port=MY_PORT, path="/", protocol="soap", urlList=mylist) | |||||
| printstatus("notifyProcedure", reg) | |||||
| pid = os.fork() | |||||
| if pid == 0: | |||||
| # I am a child process. Set up SOAP server to receive notification | |||||
| print "## Starting notification server ##" | |||||
| s = SOAPServer(('localhost', MY_PORT)) | |||||
| s.registerFunction(resourceChanged) | |||||
| s.serve_forever() | |||||
| else: | |||||
| def handler(signum, frame): | |||||
| # Kill child process | |||||
| print "Killing child process %d" % pid | |||||
| os.kill(pid, signal.SIGINT) | |||||
| signal.signal(signal.SIGINT, handler) | |||||
| # I am a parent process | |||||
| # Change some files | |||||
| time.sleep(3) | |||||
| reg = server.saveMultipleFiles (email=EMAIL, password=PASSWORD, | |||||
| relativepathList=['index.html'], | |||||
| fileTextList=['<html><title>bennett@actzero.com home page</title><body>' + | |||||
| '<a href=again.html>Hello Bennett</a></body></html>']) | |||||
| if printstatus("saveMultipleFiles", reg): | |||||
| print "Files stored:" | |||||
| for file in reg.urlList: | |||||
| print " %s" % file | |||||
| os.waitpid(pid, 0) | |||||
| @@ -0,0 +1,118 @@ | |||||
| import gc | |||||
| import socket | |||||
| import threading | |||||
| import time | |||||
| import unittest | |||||
| import sys | |||||
| sys.path.insert(1, "..") | |||||
| import SOAPpy | |||||
| #SOAPpy.Config.debug=1 | |||||
| # global to shut down server | |||||
| quit = 0 | |||||
| def echoDateTime(dt): | |||||
| return dt | |||||
| def echo(s): | |||||
| """repeats a string twice""" | |||||
| return s + s | |||||
| def kill(): | |||||
| """tell the server to quit""" | |||||
| global quit | |||||
| quit = 1 | |||||
| def server1(): | |||||
| """start a SOAP server on localhost:8000""" | |||||
| print "Starting SOAP Server...", | |||||
| server = SOAPpy.Server.SOAPServer(addr=('127.0.0.1', 8000)) | |||||
| server.registerFunction(echoDateTime) | |||||
| server.registerFunction(echo) | |||||
| server.registerFunction(kill) | |||||
| print "Done." | |||||
| global quit | |||||
| while not quit: | |||||
| server.handle_request() | |||||
| quit = 0 | |||||
| print "Server shut down." | |||||
| class ClientTestCase(unittest.TestCase): | |||||
| server = None | |||||
| startup_timeout = 5 # seconds | |||||
| def setUp(self): | |||||
| '''This is run once before each unit test.''' | |||||
| serverthread = threading.Thread(target=server1, name="SOAPServer") | |||||
| serverthread.start() | |||||
| start = time.time() | |||||
| connected = False | |||||
| server = None | |||||
| while not connected and time.time() - start < self.startup_timeout: | |||||
| print "Trying to connect to the SOAP server...", | |||||
| try: | |||||
| server = SOAPpy.Client.SOAPProxy('127.0.0.1:8000') | |||||
| server.echo('Hello World') | |||||
| except socket.error, e: | |||||
| print "Failure:", e | |||||
| time.sleep(0.5) | |||||
| else: | |||||
| connected = True | |||||
| self.server = server | |||||
| print "Success." | |||||
| if not connected: raise 'Server failed to start.' | |||||
| def tearDown(self): | |||||
| '''This is run once after each unit test.''' | |||||
| print "Trying to shut down SOAP server..." | |||||
| if self.server is not None: | |||||
| self.server.kill() | |||||
| time.sleep(5) | |||||
| return 1 | |||||
| def testEcho(self): | |||||
| '''Test echo function.''' | |||||
| server = SOAPpy.Client.SOAPProxy('127.0.0.1:8000') | |||||
| s = 'Hello World' | |||||
| self.assertEquals(server.echo(s), s+s) | |||||
| def testNamedEcho(self): | |||||
| '''Test echo function.''' | |||||
| server = SOAPpy.Client.SOAPProxy('127.0.0.1:8000') | |||||
| s = 'Hello World' | |||||
| self.assertEquals(server.echo(s=s), s+s) | |||||
| def testEchoDateTime(self): | |||||
| '''Test passing DateTime objects.''' | |||||
| server = SOAPpy.Client.SOAPProxy('127.0.0.1:8000') | |||||
| dt = SOAPpy.Types.dateTimeType(data=time.time()) | |||||
| dt_return = server.echoDateTime(dt) | |||||
| self.assertEquals(dt_return, dt) | |||||
| # def testNoLeak(self): | |||||
| # '''Test for memory leak.''' | |||||
| # gc.set_debug(gc.DEBUG_SAVEALL) | |||||
| # for i in range(400): | |||||
| # server = SOAPpy.Client.SOAPProxy('127.0.0.1:8000') | |||||
| # s = 'Hello World' | |||||
| # server.echo(s) | |||||
| # gc.collect() | |||||
| # self.assertEquals(len(gc.garbage), 0) | |||||
| if __name__ == '__main__': | |||||
| unittest.main() | |||||
| @@ -0,0 +1,112 @@ | |||||
| #!/usr/bin/env python | |||||
| import unittest | |||||
| import os, re | |||||
| import sys | |||||
| sys.path.insert (1, '..') | |||||
| import SOAPpy | |||||
| ident = '$Id: testWSDL.py,v 1.2 2003/05/09 12:46:11 warnes Exp $' | |||||
| # Check for a web proxy definition in environment | |||||
| try: | |||||
| proxy_url=os.environ['http_proxy'] | |||||
| phost, pport = re.search('http://([^:]+):([0-9]+)', proxy_url).group(1,2) | |||||
| http_proxy = "%s:%s" % (phost, pport) | |||||
| except: | |||||
| http_proxy = None | |||||
| class IntegerArithmenticTestCase(unittest.TestCase): | |||||
| def setUp(self): | |||||
| self.wsdlstr1 = '''<?xml version="1.0"?> | |||||
| <definitions name="TemperatureService" targetNamespace="http://www.xmethods.net/sd/TemperatureService.wsdl" xmlns:tns="http://www.xmethods.net/sd/TemperatureService.wsdl" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/"> | |||||
| <message name="getTempRequest"> | |||||
| <part name="zipcode" type="xsd:string"/> | |||||
| </message> | |||||
| <message name="getTempResponse"> | |||||
| <part name="return" type="xsd:float"/> | |||||
| </message> | |||||
| <portType name="TemperaturePortType"> | |||||
| <operation name="getTemp"> | |||||
| <input message="tns:getTempRequest"/> | |||||
| <output message="tns:getTempResponse"/> | |||||
| </operation> | |||||
| </portType> | |||||
| <binding name="TemperatureBinding" type="tns:TemperaturePortType"> | |||||
| <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> | |||||
| <operation name="getTemp"> | |||||
| <soap:operation soapAction=""/> | |||||
| <input> | |||||
| <soap:body use="encoded" namespace="urn:xmethods-Temperature" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> | |||||
| </input> | |||||
| <output> | |||||
| <soap:body use="encoded" namespace="urn:xmethods-Temperature" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> | |||||
| </output> | |||||
| </operation> | |||||
| </binding> | |||||
| <service name="TemperatureService"> | |||||
| <documentation>Returns current temperature in a given U.S. zipcode </documentation> | |||||
| <port name="TemperaturePort" binding="tns:TemperatureBinding"> | |||||
| <soap:address location="http://services.xmethods.net:80/soap/servlet/rpcrouter"/> | |||||
| </port> | |||||
| </service> | |||||
| </definitions> | |||||
| ''' | |||||
| def testParseWsdlString(self): | |||||
| '''Parse XMethods TemperatureService wsdl from a string.''' | |||||
| wsdl = SOAPpy.WSDL.Proxy(self.wsdlstr1, http_proxy=http_proxy) | |||||
| self.assertEquals(len(wsdl.methods), 1) | |||||
| method = wsdl.methods.values()[0] | |||||
| self.assertEquals(method.methodName, 'getTemp') | |||||
| self.assertEquals(method.namespace, 'urn:xmethods-Temperature') | |||||
| self.assertEquals(method.location, | |||||
| 'http://services.xmethods.net:80/soap/servlet/rpcrouter') | |||||
| def testParseWsdlFile(self): | |||||
| '''Parse XMethods TemperatureService wsdl from a file.''' | |||||
| # figure out path to the test directory | |||||
| dir = os.path.abspath('.') | |||||
| fname = './TemperatureService.wsdl' | |||||
| try: | |||||
| f = file(fname) | |||||
| except (IOError, OSError): | |||||
| self.assert_(0, 'Cound not find wsdl file "%s"' % file) | |||||
| wsdl = SOAPpy.WSDL.Proxy(fname, http_proxy=http_proxy) | |||||
| self.assertEquals(len(wsdl.methods), 1) | |||||
| method = wsdl.methods.values()[0] | |||||
| self.assertEquals(method.methodName, 'getTemp') | |||||
| self.assertEquals(method.namespace, 'urn:xmethods-Temperature') | |||||
| self.assertEquals(method.location, | |||||
| 'http://services.xmethods.net:80/soap/servlet/rpcrouter') | |||||
| def testParseWsdlUrl(self): | |||||
| '''Parse XMethods TemperatureService wsdl from a url.''' | |||||
| wsdl = SOAPpy.WSDL.Proxy('http://www.xmethods.net/sd/2001/TemperatureService.wsdl', http_proxy=http_proxy) | |||||
| self.assertEquals(len(wsdl.methods), 1) | |||||
| method = wsdl.methods.values()[0] | |||||
| self.assertEquals(method.methodName, 'getTemp') | |||||
| self.assertEquals(method.namespace, 'urn:xmethods-Temperature') | |||||
| self.assertEquals(method.location, | |||||
| 'http://services.xmethods.net:80/soap/servlet/rpcrouter') | |||||
| def testGetTemp(self): | |||||
| '''Parse TemperatureService and call getTemp.''' | |||||
| zip = '01072' | |||||
| proxy = SOAPpy.WSDL.Proxy(self.wsdlstr1, http_proxy=http_proxy) | |||||
| temp = proxy.getTemp(zip) | |||||
| print 'Temperature at', zip, 'is', temp | |||||
| if __name__ == '__main__': | |||||
| unittest.main() | |||||
| @@ -0,0 +1,21 @@ | |||||
| #!/usr/bin/python | |||||
| import sys | |||||
| sys.path.insert(1, "..") | |||||
| import SOAPpy | |||||
| import time | |||||
| import gc | |||||
| import types | |||||
| gc.set_debug(gc.DEBUG_SAVEALL) | |||||
| for i in range(400): | |||||
| try: | |||||
| t = SOAPpy.SOAP.parseSOAPRPC('bad soap payload') | |||||
| except: pass | |||||
| gc.collect() | |||||
| if len(gc.garbage): | |||||
| print 'still leaking' | |||||
| else: | |||||
| print 'no leak' | |||||
| @@ -0,0 +1,25 @@ | |||||
| #!/usr/bin/env python | |||||
| # Copyright (c) 2001 actzero, inc. All rights reserved. | |||||
| ident = '$Id: translateTest.py,v 1.5 2003/05/21 14:52:37 warnes Exp $' | |||||
| import os, re | |||||
| import sys | |||||
| sys.path.insert(1, "..") | |||||
| from SOAPpy import SOAPProxy | |||||
| # Check for a web proxy definition in environment | |||||
| try: | |||||
| proxy_url=os.environ['http_proxy'] | |||||
| phost, pport = re.search('http://([^:]+):([0-9]+)', proxy_url).group(1,2) | |||||
| proxy = "%s:%s" % (phost, pport) | |||||
| except: | |||||
| proxy = None | |||||
| server = SOAPProxy("http://services.xmethods.com:80/perl/soaplite.cgi", | |||||
| http_proxy=proxy) | |||||
| babel = server._ns('urn:xmethodsBabelFish#BabelFish') | |||||
| print babel.BabelFish(translationmode = "en_fr", | |||||
| sourcedata = "The quick brown fox did something or other") | |||||
| @@ -0,0 +1,25 @@ | |||||
| #!/usr/bin/env python | |||||
| ident = '$Id: weatherTest.py,v 1.4 2003/05/21 14:52:37 warnes Exp $' | |||||
| import os, re | |||||
| import sys | |||||
| sys.path.insert(1, "..") | |||||
| from SOAPpy import SOAPProxy | |||||
| # Check for a web proxy definition in environment | |||||
| try: | |||||
| proxy_url=os.environ['http_proxy'] | |||||
| phost, pport = re.search('http://([^:]+):([0-9]+)', proxy_url).group(1,2) | |||||
| proxy = "%s:%s" % (phost, pport) | |||||
| except: | |||||
| proxy = None | |||||
| SoapEndpointURL = 'http://services.xmethods.net:80/soap/servlet/rpcrouter' | |||||
| MethodNamespaceURI = 'urn:xmethods-Temperature' | |||||
| # Do it inline ala SOAP::LITE, also specify the actually ns | |||||
| server = SOAPProxy(SoapEndpointURL, http_proxy=proxy) | |||||
| print "inline", server._ns('ns1', MethodNamespaceURI).getTemp(zipcode='94063') | |||||
| @@ -0,0 +1,25 @@ | |||||
| #!/usr/bin/env python | |||||
| ident = '$Id: whoisTest.py,v 1.4 2003/05/21 14:52:37 warnes Exp $' | |||||
| import os, re | |||||
| import sys | |||||
| sys.path.insert(1, "..") | |||||
| from SOAPpy import SOAPProxy | |||||
| # Check for a web proxy definition in environment | |||||
| try: | |||||
| proxy_url=os.environ['http_proxy'] | |||||
| phost, pport = re.search('http://([^:]+):([0-9]+)', proxy_url).group(1,2) | |||||
| proxy = "%s:%s" % (phost, pport) | |||||
| except: | |||||
| proxy = None | |||||
| server = SOAPProxy("http://www.SoapClient.com/xml/SQLDataSoap.WSDL", | |||||
| http_proxy=proxy) | |||||
| print "whois>>", server.ProcessSRL(SRLFile="WHOIS.SRI", | |||||
| RequestName="whois", | |||||
| key = "microsoft.com") | |||||
| @@ -0,0 +1,34 @@ | |||||
| #!/usr/bin/env python | |||||
| # Copyright (c) 2001 actzero, inc. All rights reserved. | |||||
| ident = '$Id: xmethods.py,v 1.4 2003/12/18 06:31:50 warnes Exp $' | |||||
| import os, re | |||||
| import sys | |||||
| sys.path.insert(1, "..") | |||||
| from SOAPpy import SOAPProxy | |||||
| # Check for a web proxy definition in environment | |||||
| try: | |||||
| proxy_url=os.environ['http_proxy'] | |||||
| phost, pport = re.search('http://([^:]+):([0-9]+)', proxy_url).group(1,2) | |||||
| proxy = "%s:%s" % (phost, pport) | |||||
| except: | |||||
| proxy = None | |||||
| print "##########################################" | |||||
| print " SOAP services registered at xmethods.net" | |||||
| print "##########################################" | |||||
| server = SOAPProxy("http://www.xmethods.net/interfaces/query", | |||||
| namespace = 'urn:xmethods-delayed-quotes', | |||||
| http_proxy=proxy) | |||||
| names = server.getAllServiceNames() | |||||
| for item in names: | |||||
| print 'name:', item['name'] | |||||
| print 'id :', item['id'] | |||||
| @@ -0,0 +1,76 @@ | |||||
| #!/usr/bin/env python | |||||
| import string | |||||
| import cgi | |||||
| ident = '$Id: interop2html.py,v 1.1.1.1 2001/06/27 21:36:14 cullman Exp $' | |||||
| lines = open('output.txt').readlines() | |||||
| #preserve the tally | |||||
| tally = lines[-6:] | |||||
| #whack the tally from lines | |||||
| lines = lines[:-6] | |||||
| table={} | |||||
| for line in lines: | |||||
| if line[:3] == ' ' or line == '>\n' : continue | |||||
| line = line[:-1] #delete end of line char | |||||
| row = [line[:line.find(': ')], line[line.find(': ')+2:]] #split server name from rest of line | |||||
| restofrow = row[1].split(' ',3) #break out method name, number, status code, status comment | |||||
| if len(restofrow) > 3: | |||||
| if restofrow[3].find('as expected') != -1: | |||||
| restofrow[2] = restofrow[2] + ' (as expected)' | |||||
| elif restofrow[3][:2] == '- ' : | |||||
| restofrow[3] = restofrow[3][2:] | |||||
| try: table[row[0]].append([restofrow[0],restofrow[2:]]) | |||||
| except KeyError: table[row[0]] = [[restofrow[0],restofrow[2:]]] | |||||
| print "<html><body>" | |||||
| print "<script>function popup(text) {" | |||||
| print "text = '<html><head><title>Test Detail</title></head><body><p>' + text + '</p></body></html>';" | |||||
| print "newWin=window.open('','win1','location=no,menubar=no,width=400,height=200');" | |||||
| print "newWin.document.open();" | |||||
| print "newWin.document.write(text);" | |||||
| print "newWin.focus(); } </script>" | |||||
| print "<br><table style='font-family: Arial; color: #cccccc'><tr><td colspan=2><font face=arial color=#cccccc><b>Summary</b></font></td></tr>" | |||||
| for x in tally: | |||||
| z = x[:-1].split(":",1) | |||||
| print "<tr><td><font face=arial color=#cccccc>",z[0],"</font></td><td><font face=arial color=#cccccc>",z[1],"</font></td></tr>" | |||||
| print "</table><br>" | |||||
| c = 0 | |||||
| totalmethods = len(table[table.keys()[0]]) | |||||
| while c < totalmethods: | |||||
| print "<br><table width='95%' style='font-family: Arial'>" | |||||
| print "<tr><td width='27%' bgcolor='#cccccc'></td>" | |||||
| cols = [c, c + 1, c + 2] | |||||
| if c != 16: | |||||
| cols += [c + 3] | |||||
| for i in cols: | |||||
| try: header = table[table.keys()[0]][i][0] | |||||
| except: break | |||||
| print "<td width ='17%' align='center' bgcolor='#cccccc'><b>",header,"</b></td>" | |||||
| print "</tr>" | |||||
| l = table.keys() | |||||
| l.sort() | |||||
| for key in l: | |||||
| print "<tr><td bgcolor='#cccccc'>", key , "</td>" | |||||
| for i in cols: | |||||
| try: status = table[key][i][1][0] | |||||
| except: break | |||||
| if status.find("succeed") != -1: | |||||
| bgcolor = "#339900" | |||||
| status = "Pass" | |||||
| elif status.find("expected") != -1: | |||||
| bgcolor = "#FF9900" | |||||
| hreftitle = table[key][i][1][1].replace("'","") # remove apostrophes from title properties | |||||
| popuphtml = '"' + cgi.escape(cgi.escape(table[key][i][1][1]).replace("'","'").replace('"',""")) + '"' | |||||
| status = "<a title='" + hreftitle + "' href='javascript:popup(" + popuphtml + ")'>Failed (expected)</a>" | |||||
| else: | |||||
| bgcolor = "#CC0000" | |||||
| hreftitle = table[key][i][1][1].replace("'","") # remove apostrophes from title properties | |||||
| popuphtml = '"' + cgi.escape(cgi.escape(table[key][i][1][1]).replace("'","'").replace('"',""")) + '"' | |||||
| status = "<a title='" + hreftitle + "' href='javascript:popup(" + popuphtml + ")'>Failed</a>" | |||||
| print "<td align='center' bgcolor=" , bgcolor , ">" , status , "</td>" | |||||
| print "</tr>" | |||||
| print "</table>" | |||||
| c = c + len(cols) | |||||
| print "</body></html>" | |||||
| @@ -0,0 +1,60 @@ | |||||
| $Id: server.pem,v 1.1.1.1 2001/06/27 21:36:14 cullman Exp $ | |||||
| # Test certificate generated using CA.pl written by Steve Hensen | |||||
| # bundled with OpenSSL. | |||||
| # | |||||
| # Steps used to generate server.pem : | |||||
| # a)CA.pl -newca (creates a new CA heirarchy) | |||||
| # b)CA.pl -newreq (creates a new certificate request) | |||||
| # c)CA.pl -sign (sign the certificate request) | |||||
| # d)openssl rsa <newreq.pem >newkey.pem (unencrypt the private key) | |||||
| # e)Copy the certificate from newcert.pem, the unencrypted RSA | |||||
| # private key from newkey.pem and the certificate request from | |||||
| # newreq.pem and create server.pem to contain all three of them. | |||||
| -----BEGIN CERTIFICATE----- | |||||
| MIIDhjCCAu+gAwIBAgIBATANBgkqhkiG9w0BAQQFADCBgDELMAkGA1UEBhMCVVMx | |||||
| CzAJBgNVBAgTAkNBMQswCQYDVQQHEwJSQzEQMA4GA1UEChMHYWN0emVybzETMBEG | |||||
| A1UECxMKdGVjaG5vbG9neTEPMA0GA1UEAxMGc3lzYWRtMR8wHQYJKoZIhvcNAQkB | |||||
| FhBpbmZvQGFjdHplcm8uY29tMB4XDTAxMDUxNjIyMzkwM1oXDTAyMDUxNjIyMzkw | |||||
| M1owgYAxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTELMAkGA1UEBxMCUkMxEDAO | |||||
| BgNVBAoTB2FjdHplcm8xEzARBgNVBAsTCnRlY2hub2xvZ3kxDzANBgNVBAMTBnN5 | |||||
| c2FkbTEfMB0GCSqGSIb3DQEJARYQaW5mb0BhY3R6ZXJvLmNvbTCBnzANBgkqhkiG | |||||
| 9w0BAQEFAAOBjQAwgYkCgYEAyRBB6l+DI3aMNeYf7IuodvZ9nNxnfQHVnGyRtwhb | |||||
| 1g2tugTwFsE67oHA5qvwaDBILtsqkr9agXYDbZwJmV58xtBY675tibf7/1R8mcDO | |||||
| d4Dremdn0CMyk4+n6Z8GpLJ59TZ3y98DXUOqbLvzzltDz0si2XVa8G7f4K5k/xxB | |||||
| GZcCAwEAAaOCAQwwggEIMAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5T | |||||
| U0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBT/DGQzyXlwLXMWMaT4 | |||||
| lp9O928tvzCBrQYDVR0jBIGlMIGigBSdjwZua1AI3XoUtwLyW0Optc/4O6GBhqSB | |||||
| gzCBgDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMQswCQYDVQQHEwJSQzEQMA4G | |||||
| A1UEChMHYWN0emVybzETMBEGA1UECxMKdGVjaG5vbG9neTEPMA0GA1UEAxMGc3lz | |||||
| YWRtMR8wHQYJKoZIhvcNAQkBFhBpbmZvQGFjdHplcm8uY29tggEAMA0GCSqGSIb3 | |||||
| DQEBBAUAA4GBABQodV+rrwMsvTEEza08EeS1Rf2ISuzh6e9VbfiJLVB5Xv1SeEt1 | |||||
| sOv8ETZyN/4OXvZWQG/5md/5NNkf5K6CeKiwctztkyKTXdPIFS6FJVZdduWhiWPF | |||||
| 6gutQgOogtpCHTLwdSDk75n5MXFlnehORqOREMqqCJtFlHMEV1211Ssi | |||||
| -----END CERTIFICATE----- | |||||
| -----BEGIN RSA PRIVATE KEY----- | |||||
| MIICWwIBAAKBgQDJEEHqX4Mjdow15h/si6h29n2c3Gd9AdWcbJG3CFvWDa26BPAW | |||||
| wTrugcDmq/BoMEgu2yqSv1qBdgNtnAmZXnzG0Fjrvm2Jt/v/VHyZwM53gOt6Z2fQ | |||||
| IzKTj6fpnwaksnn1NnfL3wNdQ6psu/POW0PPSyLZdVrwbt/grmT/HEEZlwIDAQAB | |||||
| AoGALcho6gBjsRCObrt+63MFokkQY0aAviNLy7mhGIdrufsVYvU64kOPsr2S+jOO | |||||
| o3rTBPBc6ltuNWp072GHggfU61y4Bvfqxq2IRRDVH+yjmsdKSPYoBSIs3ZKjwJGx | |||||
| pFAT1nfNP05MfqUwZm8HbTnqqakrWm0p53Zvv6NP3vNjmzECQQD6EK5a7bD7VSVz | |||||
| MawUgUkZGZUtForbZL5nwIo1j94/TbnxUuuwej0MiCJ0MQsPCY/LML/gYaxTdQOg | |||||
| qYkGyIAPAkEAzdXbgTc81FflECxc5CXw9Yi1g0+nMkH5drlk+sct5dCzokPJZBQ3 | |||||
| oxIaQcJP/rUMgG0A2mSpOnbAHNHX+z/F+QJAEQGbafGqTJ1wy5HAOzDDsOJNg+B5 | |||||
| lwwV6uZsP9JF8hYuJBxYjQrzJewIM9C2CNLEpbPuCKt71b0qfv2opP5zvwJAMyjh | |||||
| WveAvgJuo5tzJx2rC0wEWXPVya8OMw0XZSFWbhV2YHFav+4qefSI5ClIurUDO3Rc | |||||
| TuvQCAD19PPPK9qI+QJADpbLUWw8NsMaHpJgeigXVIsRtJcroDw2r87bJxsgcgQz | |||||
| CsIH32VLvFOmpJdwnji6GX+vD2i0UH4ythnMCq4NUg== | |||||
| -----END RSA PRIVATE KEY----- | |||||
| -----BEGIN CERTIFICATE REQUEST----- | |||||
| MIIBwTCCASoCAQAwgYAxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTELMAkGA1UE | |||||
| BxMCUkMxEDAOBgNVBAoTB2FjdHplcm8xEzARBgNVBAsTCnRlY2hub2xvZ3kxDzAN | |||||
| BgNVBAMTBnN5c2FkbTEfMB0GCSqGSIb3DQEJARYQaW5mb0BhY3R6ZXJvLmNvbTCB | |||||
| nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAyRBB6l+DI3aMNeYf7IuodvZ9nNxn | |||||
| fQHVnGyRtwhb1g2tugTwFsE67oHA5qvwaDBILtsqkr9agXYDbZwJmV58xtBY675t | |||||
| ibf7/1R8mcDOd4Dremdn0CMyk4+n6Z8GpLJ59TZ3y98DXUOqbLvzzltDz0si2XVa | |||||
| 8G7f4K5k/xxBGZcCAwEAAaAAMA0GCSqGSIb3DQEBBAUAA4GBAIoUVScm4lAkfo1o | |||||
| n4b2Mpq3oV+dZnnTgYog4vmn/2UF0OSSTWlWPvINVkRtfg0iskZsbcWGn+RDY5e/ | |||||
| aTqN7Xz+BV5XlbQLZzuQdKPsfBcZ766El1chmUuO5tELpFtQkmlAgAXRMuh0Xeb+ | |||||
| A9wmVNyCMU6/+ajqwO642nSPOLM0 | |||||
| -----END CERTIFICATE REQUEST----- | |||||
| @@ -0,0 +1,264 @@ | |||||
| # This list of servers was taken from the SOAPBuilders Interoperability Lab | |||||
| # (http://www.xmethods.net/ilab/ilab.html) 4/23/01. | |||||
| # | |||||
| # $Id: silab.servers,v 1.1.1.1 2001/06/27 21:36:14 cullman Exp $ | |||||
| Name: SOAP.py 0.9.6 (1999) | |||||
| Endpoint: http://208.177.157.221:9595/xmethodsInterop | |||||
| SOAPAction: "urn:soapinterop" | |||||
| Namespace: http://soapinterop.org/ | |||||
| Name: SOAP.py 0.9.6 (2001) | |||||
| Like: SOAP.py 0.9.6 (1999) | |||||
| Style: 2001 | |||||
| Name: Apache 2.1 | |||||
| WSDL: http://www.xmethods.net/sd/interop/ApacheInterop11.wsdl | |||||
| Endpoint: http://nagoya.apache.org:5089/soap/servlet/rpcrouter | |||||
| SOAPAction: "urn:soapinterop" | |||||
| Namespace: http://soapinterop.org/ | |||||
| Nonfunctional: echoFloatINF server returns 'Infinity' instead of 'INF' | |||||
| Nonfunctional: echoFloatNegINF server returns '-Infinity' instead of '-INF' | |||||
| Nonfunctional: echoStruct WSDL specifies 'inputStruct' parameter, method | |||||
| takes 'echoStruct' parameter | |||||
| Nonfunctional: echoDate not implemented by server | |||||
| Nonfunctional: echoBase64 not implemented by server | |||||
| Name: EasySoap++ | |||||
| WSDL: http://easysoap.sourceforge.net/interop.wsdl | |||||
| Endpoint: http://www.xmethods.net/c/easysoap.cgi | |||||
| SOAPAction: "urn:soapinterop" | |||||
| Namespace: http://soapinterop.org/ | |||||
| Nonfunctional: actorShouldFail server doesn't fail when mustUnderstand=1 | |||||
| Nonfunctional: mustUnderstandEqualsOne server doesn't fail when | |||||
| mustUnderstand=1 | |||||
| Name: eSoapServer | |||||
| Endpoint: http://www.connecttel.com/cgi-bin/esoapserver.cgi | |||||
| SOAPAction: "urn:soapinterop" | |||||
| Namespace: http://soapinterop.org/ | |||||
| Name: Frontier 7.0b43 | |||||
| Endpoint: http://www.soapware.org:80/xmethodsInterop | |||||
| SOAPAction: "/xmethodsInterop" | |||||
| Namespace: http://soapinterop.org/ | |||||
| Style: 2001 | |||||
| Name: 4S4C 1.3.3 | |||||
| WSDL: http://soap.4s4c.com/ilab/soap.asp?WSDL | |||||
| Endpoint: http://soap.4s4c.com/ilab/soap.asp | |||||
| SOAPAction: "urn:soapinterop" | |||||
| Namespace: http://soapinterop.org/ | |||||
| Nonfunctional: echoFloatINF server doesn't understand 'INF' | |||||
| Nonfunctional: echoFloatNaN server doesn't understand 'NaN' | |||||
| Nonfunctional: echoFloatNegINF server doesn't understand '-INF' | |||||
| Name: GLUE | |||||
| WSDL: http://209.61.190.164:8004/glue/http://soapinterop.org/.wsdl | |||||
| Endpoint: http://209.61.190.164:8004/glue/http://soapinterop.org/ | |||||
| SOAPAction: "urn:soapinterop" | |||||
| Namespace: http://soapinterop.org/ | |||||
| Nonfunctional: actorShouldFail server doesn't fail when mustUnderstand=1 | |||||
| Nonfunctional: mustUnderstandEqualsOne server doesn't fail when | |||||
| mustUnderstand=1 | |||||
| Name: HP SOAP | |||||
| Page: http://soap.bluestone.com/interop/ | |||||
| WSDL: http://soap.bluestone.com:80/interop/EchoService/EchoService.wsdl | |||||
| Endpoint: http://soap.bluestone.com:80/scripts/SaISAPI.dll/SaServletEngine.class/hp-soap/soap/rpc/interop/EchoService | |||||
| SOAPAction: "urn:soapinterop" | |||||
| Namespace: http://soapinterop.org/ | |||||
| Name: IDOOX WASP 1.0 | |||||
| Page: http://soap.idoox.net:7080/IopResults/jsp/index.jsp | |||||
| WSDL: http://soap.idoox.net:7080/soap/services/ilab.wsdl | |||||
| Endpoint: http://soap.idoox.net:7080/soap/servlet/soap/ilab | |||||
| SOAPAction: "urn:soapinterop" | |||||
| Namespace: http://soapinterop.org/ | |||||
| Name: Kafka XSLT Interop Service | |||||
| Page: http://www.vbxml.com/soapworkshop/services/kafka10/services/interop.htm | |||||
| WSDL: http://www.vbxml.com/soapworkshop/services/kafka10/services/endpoint.asp?service=ilab&type=wsdl | |||||
| Endpoint: http://www.vbxml.com/soapworkshop/services/kafka10/services/endpoint.asp?service=ilab | |||||
| SOAPAction: "urn:soapinterop" | |||||
| Namespace: http://soapinterop.org/ | |||||
| Nonfunctional: actorShouldFail server doesn't fail when mustUnderstand=1 | |||||
| Nonfunctional: echoDate not implemented by server | |||||
| Nonfunctional: echoBase64 not implemented by server | |||||
| Nonfunctional: mustUnderstandEqualsOne server doesn't fail when | |||||
| mustUnderstand=1 | |||||
| Name: MS ATL Server | |||||
| WSDL: http://4.34.185.52/ilab/ilab.wsdl | |||||
| Endpoint: http://4.34.185.52/ilab/ilab.dll?Handler=Default | |||||
| SOAPAction: "urn:soapinterop" | |||||
| Namespace: http://soapinterop.org/ | |||||
| Style: 2001 | |||||
| Typed: no | |||||
| Name: MS SOAP Toolkit 2.0 (typed) | |||||
| Page: http://www.mssoapinterop.org/stk/ilab.htm | |||||
| WSDL: http://www.mssoapinterop.org/stk/InteropTyped.wsdl | |||||
| Endpoint: http://www.mssoapinterop.org/stk/InteropTyped.wsdl | |||||
| SOAPAction: "urn:soapinterop" | |||||
| Namespace: http://soapinterop.org/ | |||||
| Nonfunctional: echoBase64 return value doesn't have a type | |||||
| Nonfunctional: echoFloatINF server doesn't understand 'INF' | |||||
| Nonfunctional: echoFloatNaN server doesn't understand 'NaN' | |||||
| Nonfunctional: echoFloatNegINF server doesn't understand '-INF' | |||||
| Name: MS SOAP Toolkit 2.0 (untyped) | |||||
| Like: MS SOAP Toolkit 2.0 (typed) | |||||
| WSDL: http://www.mssoapinterop.org/stk/Interop.wsdl | |||||
| Endpoint: http://www.mssoapinterop.org/stk/Interop.wsdl | |||||
| Typed: no | |||||
| Functional: echoBase64 | |||||
| Name: MS .NET Beta 2 (typed) | |||||
| WSDL: http://www.mssoapinterop.org/test/typed.asmx?WSDL | |||||
| Endpoint: http://www.mssoapinterop.org/test/typed.asmx | |||||
| SOAPAction: "http://soapinterop.org/%(methodname)s" | |||||
| Namespace: http://soapinterop.org/ | |||||
| Nonfunctional: actorShouldFail server doesn't fail when mustUnderstand=1 | |||||
| Nonfunctional: mustUnderstandEqualsOne server doesn't fail when | |||||
| mustUnderstand=1 | |||||
| Nonfunctional: echoDate server doesn't recognize time zone of Z | |||||
| Nonfunctional: echoBase64 not implemented by server | |||||
| Name: MS .NET Beta 2 (untyped) | |||||
| Like: MS .NET Beta 2 (typed) | |||||
| WSDL: http://www.mssoapinterop.org/test/simple.asmx?WSDL | |||||
| Endpoint: http://www.mssoapinterop.org/test/simple.asmx | |||||
| Typed: no | |||||
| Name: MS .NET Remoting (1999 typed) | |||||
| WSDL: http://www.mssoapinterop.org/DotNetRemoting1999Typed/InteropService.WSDL | |||||
| Endpoint: http://www.mssoapinterop.org/DotNetRemoting1999Typed/InteropService.soap | |||||
| SOAPAction: "urn:soapinterop" | |||||
| Namespace: http://soapinterop.org/ | |||||
| Name: MS .NET Remoting (1999 untyped) | |||||
| WSDL: http://www.mssoapinterop.org/DotNetRemoting1999/InteropService.WSDL | |||||
| Endpoint: http://www.mssoapinterop.org/DotNetRemoting1999/InteropService.soap | |||||
| SOAPAction: "urn:soapinterop" | |||||
| Namespace: http://soapinterop.org/ | |||||
| Typed: no | |||||
| Name: MS .NET Remoting (2001 typed) | |||||
| WSDL: http://www.mssoapinterop.org/DotNetRemoting2001Typed/InteropService.WSDL | |||||
| Endpoint: http://www.mssoapinterop.org/DotNetRemoting2001Typed/InteropService.soap | |||||
| SOAPAction: "urn:soapinterop" | |||||
| Namespace: http://soapinterop.org/ | |||||
| Style: 2001 | |||||
| Name: MS .NET Remoting (2001 untyped) | |||||
| WSDL: http://www.mssoapinterop.org/DotNetRemoting2001/InteropService.WSDL | |||||
| Endpoint: http://www.mssoapinterop.org/DotNetRemoting2001/InteropService.soap | |||||
| SOAPAction: "urn:soapinterop" | |||||
| Namespace: http://soapinterop.org/ | |||||
| Typed: no | |||||
| Style: 2001 | |||||
| Name: Phalanx | |||||
| WSDL: http://www.phalanxsys.com/interop/interop.wsdl | |||||
| Endpoint: http://www.phalanxsys.com/interop/listener.asp | |||||
| SOAPAction: "urn:soapinterop" | |||||
| Namespace: http://soapinterop.org/ | |||||
| Style: 2001 | |||||
| Name: SOAP::Lite | |||||
| WSDL: http://services.soaplite.com/interop.wsdl | |||||
| Endpoint: http://services.soaplite.com/interop.cgi | |||||
| SOAPAction: "urn:soapinterop" | |||||
| Namespace: http://soapinterop.org/ | |||||
| Name: SOAPR4 (1999) | |||||
| Endpoint: http://www.jin.gr.jp/~nahi/Ruby/SOAP4R/SOAPBuildersInterop/1999/ | |||||
| SOAPAction: "urn:soapinterop" | |||||
| Namespace: http://soapinterop.org/ | |||||
| Nonfunctional: actorShouldFail server doesn't fail when mustUnderstand=1 | |||||
| Nonfunctional: mustUnderstandEqualsOne server doesn't fail when | |||||
| mustUnderstand=1 | |||||
| Nonfunctional: echoVoid server return nil element instead of no elements | |||||
| Name: SOAPR4 (2001) | |||||
| Like: SOAPR4 (1999) | |||||
| Endpoint: http://www.jin.gr.jp/~nahi/Ruby/SOAP4R/SOAPBuildersInterop/ | |||||
| Style: 2001 | |||||
| Name: SOAPx4 for PHP | |||||
| Endpoint: http://dietrich.ganx4.com/soapx4/soap.php | |||||
| SOAPAction: "urn:soapinterop" | |||||
| Namespace: http://soapinterop.org/ | |||||
| Nonfunctional: actorShouldPass server returns type with no namespace | |||||
| Nonfunctional: actorShouldFail server doesn't fail when mustUnderstand=1 | |||||
| Nonfunctional: echoDate not implemented by server | |||||
| Nonfunctional: echoBase64 not implemented by server | |||||
| Nonfunctional: echoFloat server returns type with no namespace | |||||
| Nonfunctional: echoFloatArray server returns array elements as strings | |||||
| Nonfunctional: echoFloatINF server returns type with no namespace | |||||
| Nonfunctional: echoFloatNaN server returns type with no namespace | |||||
| Nonfunctional: echoFloatNegINF returns float 0 instead of -INF and type | |||||
| has no namespace | |||||
| Nonfunctional: echoFloatNegZero returns 0 instead of -0 and type has no | |||||
| namespace | |||||
| Nonfunctional: echoInteger server returns type with no namespace | |||||
| Nonfunctional: echoIntegerArray server returns array elements as strings | |||||
| Nonfunctional: echoString server responds with fault when sent '<&>" | |||||
| Nonfunctional: echoStringArray server responds with fault when an array | |||||
| element is '<&>" | |||||
| Nonfunctional: echoVeryLargeFloat server returns type with no namespace | |||||
| Nonfunctional: echoVerySmallFloat server returns type with no namespace | |||||
| Nonfunctional: echoVoid server doesn't return anything | |||||
| Nonfunctional: mustUnderstandEqualsOne server doesn't fail when | |||||
| mustUnderstand=1 | |||||
| Nonfunctional: mustUnderstandEqualsZero server returns type with no namespace | |||||
| Name: SoapRMI | |||||
| Endpoint: http://rainier.extreme.indiana.edu:1568 | |||||
| SOAPAction: "urn:soapinterop" | |||||
| Namespace: http://soapinterop.org/ | |||||
| Nonfunctional: echoDate not implemented by server | |||||
| Nonfunctional: echoBase64 not implemented by server | |||||
| Name: SQLData SOAP Server | |||||
| WSDL: http://www.SoapClient.com/interop/SQLDataInterop.wsdl | |||||
| Endpoint: http://www.soapclient.com/interop/sqldatainterop.wsdl | |||||
| SOAPAction: "urn:soapinterop" | |||||
| Namespace: http://soapinterop.org/ | |||||
| Name: White Mesa SOAP RPC 2.2 (1999) | |||||
| WSDL: http://www.whitemesa.net/wsdl/interop.wsdl | |||||
| Endpoint: http://www.whitemesa.net/interop | |||||
| SOAPAction: "urn:soapinterop" | |||||
| Namespace: http://soapinterop.org/ | |||||
| Nonfunctional: echoFloatINF server doesn't understand 'INF' | |||||
| Nonfunctional: echoFloatNaN server doesn't understand 'NaN' | |||||
| Nonfunctional: echoFloatNegINF server doesn't understand '-INF' | |||||
| Nonfunctional: echoDate not implemented by server | |||||
| Nonfunctional: echoBase64 server returns data containing control character | |||||
| Style: 1999 | |||||
| Typed: no | |||||
| Name: White Mesa SOAP RPC 2.2 (2001) | |||||
| WSDL: http://www.whitemesa.net/wsdl/std/interop.wsdl | |||||
| Endpoint: http://www.whitemesa.net/interop/std | |||||
| SOAPAction: http://soapinterop.org/ | |||||
| Namespace: http://soapinterop.org/ | |||||
| Nonfunctional: echoFloatINF server doesn't understand 'INF' | |||||
| Nonfunctional: echoFloatNaN server doesn't understand 'NaN' | |||||
| Nonfunctional: echoFloatNegINF server doesn't understand '-INF' | |||||
| Nonfunctional: echoDate not implemented by server | |||||
| Nonfunctional: echoBase64 server returns data containing control character | |||||
| Style: 2001 | |||||
| Typed: no | |||||
| Name: Zolera SOAP Infrastructure | |||||
| Endpoint: http://63.142.188.184:7000/ | |||||
| SOAPAction: urn:soapinterop | |||||
| Namespace: http://soapinterop.org/ | |||||
| Style: 2001 | |||||
| Nonfunctional: actorShouldPass server claims message is unparsable | |||||
| Nonfunctional: echoBase64 server returns data with invalid type | |||||
| Nonfunctional: echoVoid server doesn't return an empty return value | |||||
| Nonfunctional: mustUnderstandEqualsZero server claims message is unparsable | |||||
| @@ -0,0 +1,699 @@ | |||||
| #!/usr/bin/env python | |||||
| # Copyright (c) 2001 actzero, inc. All rights reserved. | |||||
| # This set of clients validates when run against the servers in | |||||
| # silab.servers. | |||||
| import copy | |||||
| import fileinput | |||||
| import getopt | |||||
| import re | |||||
| import string | |||||
| import sys | |||||
| import time | |||||
| import traceback | |||||
| sys.path.insert (1, '..') | |||||
| from SOAPpy import SOAP | |||||
| SOAP.Config.typesNamespace = SOAP.NS.XSD3 | |||||
| SOAP.Config.typesNamespace = SOAP.NS.XSD3 | |||||
| ident = '$Id: silabclient.py,v 1.2 2003/03/08 05:10:01 warnes Exp $' | |||||
| DEFAULT_SERVERS_FILE = 'silab.servers' | |||||
| DEFAULT_METHODS = \ | |||||
| ( | |||||
| 'actorShouldPass', 'actorShouldFail', | |||||
| 'echoDate', 'echoBase64', | |||||
| 'echoFloat', 'echoFloatArray', | |||||
| 'echoFloatINF', 'echoFloatNaN', | |||||
| 'echoFloatNegINF', 'echoFloatNegZero', | |||||
| 'echoInteger', 'echoIntegerArray', | |||||
| 'echoString', 'echoStringArray', | |||||
| 'echoStruct', 'echoStructArray', | |||||
| 'echoVeryLargeFloat', 'echoVerySmallFloat', | |||||
| 'echoVoid', | |||||
| 'mustUnderstandEqualsOne', 'mustUnderstandEqualsZero', | |||||
| ) | |||||
| def usage (error = None): | |||||
| sys.stdout = sys.stderr | |||||
| if error != None: | |||||
| print error | |||||
| print """usage: %s [options] [server ...] | |||||
| If a long option shows an argument is mandatory, it's mandatory for the | |||||
| equivalent short option also. | |||||
| -?, --help display this usage | |||||
| -d, --debug turn on debugging in the SOAP library | |||||
| -e, --exit-on-failure exit on the first (unexpected) failure | |||||
| -h, --harsh turn on harsh testing: | |||||
| - look for the documented error code from | |||||
| mustUnderstand failures | |||||
| - use non-ASCII strings in the string tests | |||||
| -i, --invert test servers *not* in the list of servers given | |||||
| -m, --method=METHOD#[,METHOD#...] | |||||
| call only the given methods, specify a METHOD# of ? | |||||
| for the list of method numbers | |||||
| -n, --no-stats, --no-statistics | |||||
| don't display success and failure statistics | |||||
| -N, --no-boring-stats, --no-boring-statistics | |||||
| only display unexpected failures and unimplemented | |||||
| tests, and only if non-zero | |||||
| -o, --output=TYPE turn on output, TYPE is one or more of s(uccess), | |||||
| f(ailure), n(ot implemented), F(ailed (as expected)), | |||||
| a(ll) | |||||
| [f] | |||||
| -s, --servers=FILE use FILE as list of servers to test [%s] | |||||
| -t, --stacktrace print a stack trace on each unexpected failure | |||||
| -T, --always-stacktrace | |||||
| print a stack trace on any failure | |||||
| """ % (sys.argv[0], DEFAULT_SERVERS_FILE), | |||||
| sys.exit (0) | |||||
| def methodUsage (): | |||||
| sys.stdout = sys.stderr | |||||
| print "Methods are specified by number. Multiple methods can be " \ | |||||
| "specified using a\ncomma-separated list of numbers or ranges. " \ | |||||
| "For example 1,4-6,8 specifies\nmethods 1, 4, 5, 6, and 8.\n" | |||||
| print "The available methods are:\n" | |||||
| half = (len (DEFAULT_METHODS) + 1) / 2 | |||||
| for i in range (half): | |||||
| print "%4d. %-25s" % (i + 1, DEFAULT_METHODS[i]), | |||||
| if i + half < len (DEFAULT_METHODS): | |||||
| print "%4d. %-25s" % (i + 1 + half, DEFAULT_METHODS[i + half]), | |||||
| sys.exit (0) | |||||
| # as borrowed from jake.soapware.org for float compares. | |||||
| def nearlyeq (a, b, prec = 1e-7): | |||||
| return abs (a - b) <= abs (a) * prec | |||||
| def readServers (file): | |||||
| servers = [] | |||||
| names = {} | |||||
| cur = None | |||||
| f = fileinput.input(file) | |||||
| for line in f: | |||||
| if line[0] == '#': | |||||
| continue | |||||
| if line == '' or line[0] == '\n': | |||||
| cur = None | |||||
| continue | |||||
| if cur == None: | |||||
| cur = {'nonfunctional': {}, '_line': f.filelineno(), | |||||
| '_file': f.filename()} | |||||
| tag = None | |||||
| servers.append (cur) | |||||
| if line[0] in string.whitespace: | |||||
| if tag == 'nonfunctional': | |||||
| value = method + ' ' + cur[tag][method] | |||||
| else: | |||||
| value = cur[tag] | |||||
| value += ' ' + line.strip () | |||||
| elif line[0] == '_': | |||||
| raise ValueError, \ | |||||
| "%s, line %d: can't have a tag starting with `_'" % \ | |||||
| (f.filename(), f.filelineno()) | |||||
| else: | |||||
| tag, value = line.split (':', 1) | |||||
| tag = tag.strip ().lower () | |||||
| value = value.strip () | |||||
| if value[0] == '"' and value[-1] == '"': | |||||
| value = value[1:-1] | |||||
| if tag == 'typed': | |||||
| if value.lower() in ('0', 'no', 'false'): | |||||
| value = 0 | |||||
| elif value.lower() in ('1', 'yes', 'false'): | |||||
| value = 1 | |||||
| else: | |||||
| raise ValueError, \ | |||||
| "%s, line %d: unknown typed value `%s'" % \ | |||||
| (f.filename(), f.filelineno(), value) | |||||
| elif tag == 'name': | |||||
| if names.has_key(value): | |||||
| old = names[value] | |||||
| raise ValueError, \ | |||||
| "%s, line %d: already saw a server named `%s' " \ | |||||
| "(on line %d of %s)" % \ | |||||
| (f.filename(), f.filelineno(), value, | |||||
| old['_line'], old['_file']) | |||||
| names[value] = cur | |||||
| if tag == 'nonfunctional': | |||||
| value = value.split (' ', 1) + [''] | |||||
| method = value[0] | |||||
| cur[tag][method] = value[1] | |||||
| elif tag == 'functional': | |||||
| try: | |||||
| del cur['nonfunctional'][value] | |||||
| except: | |||||
| raise ValueError, \ | |||||
| "%s, line %d: `%s' not marked nonfunctional" % \ | |||||
| (f.filename(), f.filelineno(), value) | |||||
| elif tag == 'like': | |||||
| try: | |||||
| new = copy.deepcopy(names[value]) | |||||
| except: | |||||
| raise ValueError, \ | |||||
| "%s, line %d: don't know about a server named `%s'" % \ | |||||
| (f.filename(), f.filelineno(), value) | |||||
| # This is so we don't lose the nonfunctional methods in new or | |||||
| # in cur | |||||
| new['nonfunctional'].update(cur['nonfunctional']) | |||||
| del cur['nonfunctional'] | |||||
| new.update(cur) | |||||
| # This is because servers and possibly names has a reference to | |||||
| # cur, so we have to keep working with cur so changes are | |||||
| # reflected in servers and names. | |||||
| cur.update(new) | |||||
| else: | |||||
| cur[tag] = value | |||||
| return servers | |||||
| def str2list (s): | |||||
| l = {} | |||||
| for i in s.split (','): | |||||
| if i.find ('-') != -1: | |||||
| i = i.split ('-') | |||||
| for i in range (int (i[0]),int (i[1]) + 1): | |||||
| l[i] = 1 | |||||
| else: | |||||
| l[int (i)] = 1 | |||||
| l = l.keys () | |||||
| l.sort () | |||||
| return l | |||||
| def testActorShouldPass (server, action, harsh): | |||||
| test = 42 | |||||
| server = server._sa (action % {'methodname': 'echoInteger'}) | |||||
| hd = SOAP.headerType () | |||||
| hd.InteropTestHeader = SOAP.stringType ("This shouldn't fault because " | |||||
| "the mustUnderstand attribute is 0") | |||||
| hd.InteropTestHeader._setMustUnderstand (0) | |||||
| hd.InteropTestHeader._setActor ( | |||||
| 'http://schemas.xmlsoap.org/soap/actor/next') | |||||
| server = server._hd (hd) | |||||
| result = server.echoInteger (inputInteger = test) | |||||
| if not SOAP.Config.typed: | |||||
| result = int (result) | |||||
| if result != test: | |||||
| raise Exception, "expected %s, got %s" % (test, result) | |||||
| def testActorShouldFail (server, action, harsh): | |||||
| test = 42 | |||||
| server = server._sa (action % {'methodname': 'echoInteger'}) | |||||
| hd = SOAP.headerType () | |||||
| hd.InteropTestHeader = SOAP.stringType ("This should fault because " | |||||
| "the mustUnderstand attribute is 1") | |||||
| hd.InteropTestHeader._setMustUnderstand (1) | |||||
| hd.InteropTestHeader._setActor ( | |||||
| 'http://schemas.xmlsoap.org/soap/actor/next') | |||||
| server = server._hd (hd) | |||||
| try: | |||||
| result = server.echoInteger (inputInteger = test) | |||||
| except SOAP.faultType, e: | |||||
| if harsh and e.faultcode != 'SOAP-ENV:MustUnderstand': | |||||
| raise AttributeError, "unexpected faultcode %s" % e.faultcode | |||||
| return | |||||
| raise Exception, "should fail, succeeded with %s" % result | |||||
| def testEchoFloat (server, action, harsh): | |||||
| server = server._sa (action % {'methodname': 'echoFloat'}) | |||||
| for test in (0.0, 1.0, -1.0, 3853.33333333): | |||||
| result = server.echoFloat (inputFloat = test) | |||||
| if not SOAP.Config.typed: | |||||
| result = float (result) | |||||
| if not nearlyeq (result, test): | |||||
| raise Exception, "expected %.8f, got %.8f" % (test, result) | |||||
| def testEchoFloatArray (server, action, harsh): | |||||
| test = [0.0, 1.0, -1.0, 3853.33333333] | |||||
| server = server._sa (action % {'methodname': 'echoFloatArray'}) | |||||
| result = server.echoFloatArray (inputFloatArray = test) | |||||
| for i in range (len (test)): | |||||
| if not SOAP.Config.typed: | |||||
| result[i] = float (result[i]) | |||||
| if not nearlyeq (result[i], test[i]): | |||||
| raise Exception, "@ %d expected %s, got %s" % \ | |||||
| (i, repr (test), repr (result)) | |||||
| def testEchoFloatINF (server, action, harsh): | |||||
| try: | |||||
| test = float ('INF') | |||||
| except: | |||||
| test = float (1e300**2) | |||||
| server = server._sa (action % {'methodname': 'echoFloat'}) | |||||
| result = server.echoFloat (inputFloat = test) | |||||
| if not SOAP.Config.typed: | |||||
| result = float (result) | |||||
| if result != test: | |||||
| raise Exception, "expected %.8f, got %.8f" % (test, result) | |||||
| def testEchoFloatNaN (server, action, harsh): | |||||
| try: | |||||
| test = float ('NaN') | |||||
| except: | |||||
| test = float (0.0) | |||||
| server = server._sa (action % {'methodname': 'echoFloat'}) | |||||
| result = server.echoFloat (inputFloat = test) | |||||
| if not SOAP.Config.typed: | |||||
| result = float (result) | |||||
| if result != test: | |||||
| raise Exception, "expected %.8f, got %.8f" % (test, result) | |||||
| def testEchoFloatNegINF (server, action, harsh): | |||||
| try: | |||||
| test = float ('-INF') | |||||
| except: | |||||
| test = float (-1e300**2) | |||||
| server = server._sa (action % {'methodname': 'echoFloat'}) | |||||
| result = server.echoFloat (inputFloat = test) | |||||
| if not SOAP.Config.typed: | |||||
| result = float (result) | |||||
| if result != test: | |||||
| raise Exception, "expected %.8f, got %.8f" % (test, result) | |||||
| def testEchoFloatNegZero (server, action, harsh): | |||||
| test = float ('-0.0') | |||||
| server = server._sa (action % {'methodname': 'echoFloat'}) | |||||
| result = server.echoFloat (inputFloat = test) | |||||
| if not SOAP.Config.typed: | |||||
| result = float (result) | |||||
| if result != test: | |||||
| raise Exception, "expected %.8f, got %.8f" % (test, result) | |||||
| def testEchoInteger (server, action, harsh): | |||||
| server = server._sa (action % {'methodname': 'echoInteger'}) | |||||
| for test in (0, 1, -1, 3853): | |||||
| result = server.echoInteger (inputInteger = test) | |||||
| if not SOAP.Config.typed: | |||||
| result = int (result) | |||||
| if result != test: | |||||
| raise Exception, "expected %.8f, got %.8f" % (test, result) | |||||
| def testEchoIntegerArray (server, action, harsh): | |||||
| test = [0, 1, -1, 3853] | |||||
| server = server._sa (action % {'methodname': 'echoIntegerArray'}) | |||||
| result = server.echoIntegerArray (inputIntegerArray = test) | |||||
| for i in range (len (test)): | |||||
| if not SOAP.Config.typed: | |||||
| result[i] = int (result[i]) | |||||
| if result[i] != test[i]: | |||||
| raise Exception, "@ %d expected %s, got %s" % \ | |||||
| (i, repr (test), repr (result)) | |||||
| relaxedStringTests = ['', 'Hello', '\'<&>"',] | |||||
| relaxedStringTests = ['Hello', '\'<&>"',] | |||||
| harshStringTests = ['', 'Hello', '\'<&>"', | |||||
| u'\u0041', u'\u00a2', u'\u0141', u'\u2342', | |||||
| u'\'<\u0041&>"', u'\'<\u00a2&>"', u'\'<\u0141&>"', u'\'<\u2342&>"',] | |||||
| def testEchoString (server, action, harsh): | |||||
| if harsh: | |||||
| test = harshStringTests | |||||
| else: | |||||
| test = relaxedStringTests | |||||
| server = server._sa (action % {'methodname': 'echoString'}) | |||||
| for test in test: | |||||
| result = server.echoString (inputString = test) | |||||
| if result != test: | |||||
| raise Exception, "expected %s, got %s" % \ | |||||
| (repr (test), repr (result)) | |||||
| def testEchoStringArray (server, action, harsh): | |||||
| if harsh: | |||||
| test = harshStringTests | |||||
| else: | |||||
| test = relaxedStringTests | |||||
| server = server._sa (action % {'methodname': 'echoStringArray'}) | |||||
| result = server.echoStringArray (inputStringArray = test) | |||||
| if result != test: | |||||
| raise Exception, "expected %s, got %s" % (repr (test), repr (result)) | |||||
| def testEchoStruct (server, action, harsh): | |||||
| test = {'varFloat': 2.256, 'varInt': 474, 'varString': 'Utah'} | |||||
| server = server._sa (action % {'methodname': 'echoStruct'}) | |||||
| result = server.echoStruct (inputStruct = test) | |||||
| if not SOAP.Config.typed: | |||||
| result.varFloat = float (result.varFloat) | |||||
| result.varInt = int (result.varInt) | |||||
| if not nearlyeq (test['varFloat'], result.varFloat): | |||||
| raise Exception, ".varFloat expected %s, got %s" % \ | |||||
| (i, repr (test['varFloat']), repr (result.varFloat)) | |||||
| for i in test.keys (): | |||||
| if i == 'varFloat': | |||||
| continue | |||||
| if test[i] != getattr (result, i): | |||||
| raise Exception, ".%s expected %s, got %s" % \ | |||||
| (i, repr (test[i]), repr (getattr (result, i))) | |||||
| def testEchoStructArray (server, action, harsh): | |||||
| test = [{'varFloat': -5.398, 'varInt': -546, 'varString': 'West Virginia'}, | |||||
| {'varFloat': -9.351, 'varInt': -641, 'varString': 'New Mexico'}, | |||||
| {'varFloat': 1.495, 'varInt': -819, 'varString': 'Missouri'}] | |||||
| server = server._sa (action % {'methodname': 'echoStructArray'}) | |||||
| result = server.echoStructArray (inputStructArray = test) | |||||
| for s in range (len (test)): | |||||
| if not SOAP.Config.typed: | |||||
| result[s].varFloat = float (result[s].varFloat) | |||||
| result[s].varInt = int (result[s].varInt) | |||||
| if not nearlyeq (test[s]['varFloat'], result[s].varFloat): | |||||
| raise Exception, \ | |||||
| "@ %d.varFloat expected %s, got %s" % \ | |||||
| (s, repr (test[s]['varFloat']), repr (result[s].varFloat)) | |||||
| for i in test[s].keys (): | |||||
| if i == 'varFloat': | |||||
| continue | |||||
| if test[s][i] != getattr (result[s], i): | |||||
| raise Exception, "@ %d.%s expected %s, got %s" % \ | |||||
| (s, i, repr (test[s][i]), repr (getattr (result[s], i))) | |||||
| def testEchoVeryLargeFloat (server, action, harsh): | |||||
| test = 2.2535e29 | |||||
| server = server._sa (action % {'methodname': 'echoFloat'}) | |||||
| result = server.echoFloat (inputFloat = test) | |||||
| if not SOAP.Config.typed: | |||||
| result = float (result) | |||||
| if not nearlyeq (result, test): | |||||
| raise Exception, "expected %s, got %s" % (repr (test), repr (result)) | |||||
| def testEchoVerySmallFloat (server, action, harsh): | |||||
| test = 2.2535e29 | |||||
| server = server._sa (action % {'methodname': 'echoFloat'}) | |||||
| result = server.echoFloat (inputFloat = test) | |||||
| if not SOAP.Config.typed: | |||||
| result = float (result) | |||||
| if not nearlyeq (result, test): | |||||
| raise Exception, "expected %s, got %s" % (repr (test), repr (result)) | |||||
| def testEchoVoid (server, action, harsh): | |||||
| server = server._sa (action % {'methodname': 'echoVoid'}) | |||||
| result = server.echoVoid () | |||||
| for k in result.__dict__.keys (): | |||||
| if k[0] != '_': | |||||
| raise Exception, "expected an empty structType, got %s" % \ | |||||
| repr (result.__dict__) | |||||
| def testMustUnderstandEqualsOne (server, action, harsh): | |||||
| test = 42 | |||||
| server = server._sa (action % {'methodname': 'echoInteger'}) | |||||
| hd = SOAP.headerType () | |||||
| hd.MustUnderstandThis = SOAP.stringType ("This should fault because " | |||||
| "the mustUnderstand attribute is 1") | |||||
| hd.MustUnderstandThis._setMustUnderstand (1) | |||||
| server = server._hd (hd) | |||||
| try: | |||||
| result = server.echoInteger (inputInteger = test) | |||||
| except SOAP.faultType, e: | |||||
| if harsh and e.faultcode != 'SOAP-ENV:MustUnderstand': | |||||
| raise AttributeError, "unexpected faultcode %s" % e.faultcode | |||||
| return | |||||
| raise Exception, "should fail, succeeded with %s" % result | |||||
| def testMustUnderstandEqualsZero (server, action, harsh): | |||||
| test = 42 | |||||
| server = server._sa (action % {'methodname': 'echoInteger'}) | |||||
| hd = SOAP.headerType () | |||||
| hd.MustUnderstandThis = SOAP.stringType ("This shouldn't fault because " | |||||
| "the mustUnderstand attribute is 0") | |||||
| hd.MustUnderstandThis._setMustUnderstand (0) | |||||
| server = server._hd (hd) | |||||
| result = server.echoInteger (inputInteger = test) | |||||
| if not SOAP.Config.typed: | |||||
| result = int (result) | |||||
| if result != test: | |||||
| raise Exception, "expected %s, got %s" % (test, result) | |||||
| def testEchoDate (server, action, harsh): | |||||
| test = time.gmtime (time.time ()) | |||||
| server = server._sa (action % {'methodname': 'echoDate'}) | |||||
| if SOAP.Config.namespaceStyle == '1999': | |||||
| result = server.echoDate (inputDate = SOAP.timeInstantType (test)) | |||||
| else: | |||||
| result = server.echoDate (inputDate = SOAP.dateTimeType (test)) | |||||
| if not SOAP.Config.typed and type (result) in (type (''), type (u'')): | |||||
| p = SOAP.SOAPParser() | |||||
| result = p.convertDateTime(result, 'timeInstant') | |||||
| if result != test[:6]: | |||||
| raise Exception, "expected %s, got %s" % (repr (test), repr (result)) | |||||
| def testEchoBase64 (server, action, harsh): | |||||
| test = '\x00\x10\x20\x30\x40\x50\x60\x70\x80\x90\xa0\xb0\xc0\xd0\xe0\xf0' | |||||
| server = server._sa (action % {'methodname': 'echoBase64'}) | |||||
| result = server.echoBase64 (inputBase64 = SOAP.base64Type (test)) | |||||
| if not SOAP.Config.typed: | |||||
| import base64 | |||||
| result = base64.decodestring(result) | |||||
| if result != test: | |||||
| raise Exception, "expected %s, got %s" % (repr (test), repr (result)) | |||||
| def main (): | |||||
| stats = 1 | |||||
| total = 0 | |||||
| fail = 0 | |||||
| failok = 0 | |||||
| succeed = 0 | |||||
| exitonfailure = 0 | |||||
| harsh = 0 | |||||
| invert = 0 | |||||
| printtrace = 0 | |||||
| methodnums = None | |||||
| notimp = 0 | |||||
| output = 'f' | |||||
| servers = DEFAULT_SERVERS_FILE | |||||
| started = time.time () | |||||
| try: | |||||
| opts, args = getopt.getopt (sys.argv[1:], '?dehim:nNo:s:tT', | |||||
| ['help', 'debug', 'exit-on-failure', 'harsh', 'invert', | |||||
| 'method', 'no-stats', 'no-statistics', | |||||
| 'no-boring-statistics', 'no-boring-stats', 'output', | |||||
| 'servers=', 'stacktrace', 'always-stacktrace']) | |||||
| for opt, arg in opts: | |||||
| if opt in ('-?', '--help'): | |||||
| usage () | |||||
| elif opt in ('-d', '--debug'): | |||||
| SOAP.Config.debug = 1 | |||||
| elif opt in ('-h', '--harsh'): | |||||
| harsh = 1 | |||||
| elif opt in ('-i', '--invert'): | |||||
| invert = 1 | |||||
| elif opt in ('-e', '--exit-on-failure'): | |||||
| exitonfailure = 1 | |||||
| elif opt in ('-m', '--method'): | |||||
| if arg == '?': | |||||
| methodUsage () | |||||
| methodnums = str2list (arg) | |||||
| elif opt in ('-n', '--no-stats', '--no-statistics'): | |||||
| stats = 0 | |||||
| elif opt in ('-N', '--no-boring-stats', '--no-boring-statistics'): | |||||
| stats = -1 | |||||
| elif opt in ('-o', '--output'): | |||||
| output = arg | |||||
| elif opt in ('-s', '--servers'): | |||||
| servers = arg | |||||
| elif opt in ('-t', '--stacktrace'): | |||||
| printtrace = 1 | |||||
| elif opt in ('-T', '--always-stacktrace'): | |||||
| printtrace = 2 | |||||
| else: | |||||
| raise AttributeError, \ | |||||
| "Recognized but unimplemented option `%s'" % opt | |||||
| except SystemExit: | |||||
| raise | |||||
| except: | |||||
| usage (sys.exc_info ()[1]) | |||||
| if 'a' in output: | |||||
| output = 'fFns' | |||||
| servers = readServers (servers) | |||||
| if methodnums == None: | |||||
| methodnums = range (1, len (DEFAULT_METHODS) + 1) | |||||
| limitre = re.compile ('|'.join (args), re.IGNORECASE) | |||||
| for s in servers: | |||||
| if (not not limitre.match (s['name'])) == invert: | |||||
| continue | |||||
| try: typed = s['typed'] | |||||
| except: typed = 1 | |||||
| try: style = s['style'] | |||||
| except: style = 1999 | |||||
| SOAP.Config.typed = typed | |||||
| SOAP.Config.namespaceStyle = style | |||||
| server = SOAP.SOAPProxy (s['endpoint'], ("m", s['namespace'])) | |||||
| for num in (methodnums): | |||||
| if num > len (DEFAULT_METHODS): | |||||
| break | |||||
| total += 1 | |||||
| name = DEFAULT_METHODS[num - 1] | |||||
| title = '%s: %s (#%d)' % (s['name'], name, num) | |||||
| if SOAP.Config.debug: | |||||
| print "%s:" % title | |||||
| try: | |||||
| fn = globals ()['test' + name[0].upper () + name[1:]] | |||||
| except KeyboardInterrupt: | |||||
| raise | |||||
| except: | |||||
| if 'n' in output: | |||||
| print title, "test not yet implemented" | |||||
| notimp += 1 | |||||
| continue | |||||
| try: | |||||
| fn (server, s['soapaction'], harsh) | |||||
| if s['nonfunctional'].has_key (name): | |||||
| print title, \ | |||||
| "succeeded despite being marked nonfunctional" | |||||
| if 's' in output: | |||||
| print title, "succeeded" | |||||
| succeed += 1 | |||||
| except KeyboardInterrupt: | |||||
| raise | |||||
| except: | |||||
| fault = str (sys.exc_info ()[1]) | |||||
| if fault[-1] == '\n': | |||||
| fault = fault[:-1] | |||||
| if s['nonfunctional'].has_key (name): | |||||
| if 'F' in output: | |||||
| t = 'as expected' | |||||
| if s['nonfunctional'][name] != '': | |||||
| t += ', ' + s['nonfunctional'][name] | |||||
| print title, "failed (%s) -" % t, fault | |||||
| if printtrace > 1: | |||||
| traceback.print_exc () | |||||
| failok += 1 | |||||
| else: | |||||
| if 'f' in output: | |||||
| print title, "failed -", fault | |||||
| if printtrace: | |||||
| traceback.print_exc () | |||||
| fail += 1 | |||||
| if exitonfailure: | |||||
| return -1 | |||||
| if stats: | |||||
| print " Tests started at:", time.ctime (started) | |||||
| if stats > 0: | |||||
| print " Total tests: %d" % total | |||||
| print " Successes: %d (%3.2f%%)" % \ | |||||
| (succeed, 100.0 * succeed / total) | |||||
| if stats > 0 or fail > 0: | |||||
| print "Failed unexpectedly: %d (%3.2f%%)" % \ | |||||
| (fail, 100.0 * fail / total) | |||||
| if stats > 0: | |||||
| print " Failed as expected: %d (%3.2f%%)" % \ | |||||
| (failok, 100.0 * failok / total) | |||||
| if stats > 0 or notimp > 0: | |||||
| print " Not implemented: %d (%3.2f%%)" % \ | |||||
| (notimp, 100.0 * notimp / total) | |||||
| return fail + notimp | |||||
| if __name__ == '__main__': | |||||
| try: | |||||
| sys.exit (main ()) | |||||
| except KeyboardInterrupt: | |||||
| sys.exit (0) | |||||
| @@ -0,0 +1,141 @@ | |||||
| #!/usr/bin/env python | |||||
| # Copyright (c) 2001 actzero, inc. All rights reserved. | |||||
| # This is a server for the XMethods matrix | |||||
| # (http://jake.soapware.org/currentXmethodsResults). | |||||
| import getopt | |||||
| import sys | |||||
| sys.path.insert (1, '..') | |||||
| from SOAPpy import SOAP | |||||
| if SOAP.Config.SSLserver: | |||||
| from M2Crypto import SSL | |||||
| ident = '$Id: silabserver.py,v 1.2 2003/03/08 05:10:01 warnes Exp $' | |||||
| def echoFloat (inputFloat): | |||||
| return inputFloat | |||||
| def echoFloatArray (inputFloatArray): | |||||
| return inputFloatArray | |||||
| def echoInteger (inputInteger): | |||||
| return inputInteger | |||||
| def echoIntegerArray (inputIntegerArray): | |||||
| return inputIntegerArray | |||||
| def echoString (inputString): | |||||
| return inputString | |||||
| def echoStringArray (inputStringArray): | |||||
| return inputStringArray | |||||
| def echoStruct (inputStruct): | |||||
| return inputStruct | |||||
| def echoStructArray (inputStructArray): | |||||
| return inputStructArray | |||||
| def echoVoid (): | |||||
| return SOAP.voidType() | |||||
| def echoDate (inputDate): | |||||
| return SOAP.dateTimeType (inputDate) | |||||
| def echoBase64 (inputBase64): | |||||
| return SOAP.binaryType (inputBase64) | |||||
| namespace = 'http://soapinterop.org/' | |||||
| DEFAULT_HOST = 'localhost' | |||||
| DEFAULT_HTTP_PORT = 8080 | |||||
| DEFAULT_HTTPS_PORT = 8443 | |||||
| def usage (error = None): | |||||
| sys.stdout = sys.stderr | |||||
| if error != None: | |||||
| print error | |||||
| print """usage: %s [options] | |||||
| If a long option shows an argument is mandatory, it's mandatory for the | |||||
| equivalent short option also. The default (if any) is shown in brackets. | |||||
| -?, --help display this usage | |||||
| -h, --host=HOST use HOST in the address to listen on [%s] | |||||
| -p, --port=PORT listen on PORT [%d] | |||||
| """ % (sys.argv[0], DEFAULT_HOST, DEFAULT_HTTP_PORT), | |||||
| if SOAP.Config.SSLserver: | |||||
| print " -s, --ssl serve using SSL" | |||||
| sys.exit (0) | |||||
| def main (): | |||||
| host = DEFAULT_HOST | |||||
| port = None | |||||
| ssl = 0 | |||||
| try: | |||||
| opts = '?h:p:' | |||||
| args = ['help', 'host', 'port'] | |||||
| if SOAP.Config.SSLserver: | |||||
| opts += 's' | |||||
| args += ['ssl'] | |||||
| opts, args = getopt.getopt (sys.argv[1:], opts, args) | |||||
| for opt, arg in opts: | |||||
| if opt in ('-?', '--help'): | |||||
| usage () | |||||
| elif opt in ('-h', '--host'): | |||||
| host = arg | |||||
| elif opt in ('-p', '--port'): | |||||
| port = int (arg) | |||||
| elif opt in ('-s', '--ssl'): | |||||
| ssl = 1 | |||||
| else: | |||||
| raise AttributeError, \ | |||||
| "Recognized but unimplemented option `%s'" % opt | |||||
| except SystemExit: | |||||
| raise | |||||
| except: | |||||
| usage (sys.exc_info ()[1]) | |||||
| if port == None: | |||||
| port = [DEFAULT_HTTP_PORT, DEFAULT_HTTPS_PORT][ssl] | |||||
| if ssl: | |||||
| ssl_context = SSL.Context() | |||||
| ssl_context.load_cert('server.pem') | |||||
| else: | |||||
| ssl_context = None | |||||
| server = SOAP.SOAPServer ((host, port), namespace = namespace, | |||||
| ssl_context = ssl_context) | |||||
| server.registerFunction (echoFloat) | |||||
| server.registerFunction (echoFloatArray) | |||||
| server.registerFunction (echoInteger) | |||||
| server.registerFunction (echoIntegerArray) | |||||
| server.registerFunction (echoString) | |||||
| server.registerFunction (echoStringArray) | |||||
| server.registerFunction (echoStruct) | |||||
| server.registerFunction (echoStructArray) | |||||
| server.registerFunction (echoVoid) | |||||
| server.registerFunction (echoDate) | |||||
| server.registerFunction (echoBase64) | |||||
| server.serve_forever() | |||||
| if __name__ == '__main__': | |||||
| try: | |||||
| sys.exit (main ()) | |||||
| except KeyboardInterrupt: | |||||
| sys.exit (0) | |||||
| @@ -0,0 +1,118 @@ | |||||
| #!/usr/bin/env python | |||||
| # This server validates as of 4/23/01 when run with UserLand's SOAP validator | |||||
| # (http://validator.soapware.org/). | |||||
| import getopt | |||||
| import sys | |||||
| sys.path.insert (1, '..') | |||||
| from SOAPpy import SOAP | |||||
| ident = '$Id: soapware.py,v 1.2 2003/03/08 05:10:01 warnes Exp $' | |||||
| def whichToolkit (): | |||||
| return SOAP.SOAPUserAgent () | |||||
| def countTheEntities (s): | |||||
| counts = {'ctLeftAngleBrackets': 0, 'ctRightAngleBrackets': 0, | |||||
| 'ctAmpersands': 0, 'ctApostrophes': 0, 'ctQuotes': 0} | |||||
| for i in s: | |||||
| if i == '<': | |||||
| counts['ctLeftAngleBrackets'] += 1 | |||||
| elif i == '>': | |||||
| counts['ctRightAngleBrackets'] += 1 | |||||
| elif i == '&': | |||||
| counts['ctAmpersands'] += 1 | |||||
| elif i == "'": | |||||
| counts['ctApostrophes'] += 1 | |||||
| elif i == '"': | |||||
| counts['ctQuotes'] += 1 | |||||
| return counts | |||||
| def easyStructTest (stooges): | |||||
| return stooges['larry'] + stooges['moe'] + stooges['curly'] | |||||
| def echoStructTest (myStruct): | |||||
| return myStruct | |||||
| def manyTypesTest (num, bool, state, doub, dat, bin): | |||||
| return [num, SOAP.booleanType (bool), state, doub, | |||||
| SOAP.dateTimeType (dat), bin] | |||||
| def moderateSizeArrayCheck (myArray): | |||||
| return myArray[0] + myArray[-1] | |||||
| def nestedStructTest (myStruct): | |||||
| return easyStructTest (myStruct.year2000.month04.day01) | |||||
| def simpleStructReturnTest (myNumber): | |||||
| return {'times10': myNumber * 10, 'times100': myNumber * 100, | |||||
| 'times1000': myNumber * 1000} | |||||
| namespace = 'http://www.soapware.org/' | |||||
| DEFAULT_HOST = 'localhost' | |||||
| DEFAULT_PORT = 8080 | |||||
| def usage (error = None): | |||||
| sys.stdout = sys.stderr | |||||
| if error != None: | |||||
| print error | |||||
| print """usage: %s [options] | |||||
| If a long option shows an argument is mandatory, it's mandatory for the | |||||
| equivalent short option also. The default (if any) is shown in brackets. | |||||
| -?, --help display this usage | |||||
| -h, --host=HOST use HOST in the address to listen on [%s] | |||||
| -p, --port=PORT listen on PORT [%d] | |||||
| """ % (sys.argv[0], DEFAULT_HOST, DEFAULT_PORT), | |||||
| sys.exit (0) | |||||
| def main (): | |||||
| host = DEFAULT_HOST | |||||
| port = DEFAULT_PORT | |||||
| try: | |||||
| opts, args = getopt.getopt (sys.argv[1:], '?h:p:', | |||||
| ['help', 'host', 'port']) | |||||
| for opt, arg in opts: | |||||
| if opt in ('-?', '--help'): | |||||
| usage () | |||||
| elif opt in ('-h', '--host'): | |||||
| host = arg | |||||
| elif opt in ('-p', '--port'): | |||||
| port = int (arg) | |||||
| else: | |||||
| raise AttributeError, \ | |||||
| "Recognized but unimplemented option `%s'" % opt | |||||
| except SystemExit: | |||||
| raise | |||||
| except: | |||||
| usage (sys.exc_info ()[1]) | |||||
| server = SOAP.SOAPServer ((host, port)) | |||||
| server.registerFunction (whichToolkit, namespace) | |||||
| server.registerFunction (countTheEntities) | |||||
| server.registerFunction (easyStructTest) | |||||
| server.registerFunction (echoStructTest) | |||||
| server.registerFunction (manyTypesTest) | |||||
| server.registerFunction (moderateSizeArrayCheck) | |||||
| server.registerFunction (nestedStructTest) | |||||
| server.registerFunction (simpleStructReturnTest) | |||||
| server.serve_forever() | |||||
| if __name__ == '__main__': | |||||
| try: | |||||
| sys.exit (main ()) | |||||
| except KeyboardInterrupt: | |||||
| sys.exit (0) | |||||