| @@ -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) | |||