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