Introduction
The SOAP::CGI package allows you to provide SOAP web
services from Tcl scripts via the CGI script capabilities of your
web server. This document describes the use of this package with
the Apache httpd server but the package should be applicable to any
other server supporting the Common Gateway Interface.
The package provides a fairly comprehensive framework to deal
with hiding the details of the web service protocols. The Tcl
scripts implementing the service need to know nothing of XML nor
the RPC protocol in use. Errors are returned via the normal Tcl
error mechanism. The only special feature needed is variable type
hinting. It is not possible to distinguish between a string with
whitespace and a list in Tcl, so the rpcvar package is
used to provide the additional type information when required.
Installation
Installation really only requires placing a script into the http
servers cgi-bin directory and writing some service implementations.
A generic script is provided as cgi-bin/rpc with some
example services in cgi-bin/soap/. The package has four
variables to configure so that it can find the service
implementations:
package require SOAP::CGI
set SOAP::CGI::soapdir "../method-scripts"
set SOAP::CGI::soapmapfile "soapmap.dat"
set SOAP::CGI::xmlrpcdir "../method-scripts"
set SOAP::CGI::xmlrpcmapfile "xmlrpcmap.dat"
set SOAP::CGI::logfile "../logs/rpc.log"
SOAP::CGI::main
|
The SOAP and XML-RPC implementations can be the same, as above,
or placed into separate directories. The log file is optional
(unset the variable to disable logs) and will need to be writable
by the httpd user - this usually means it needs to be world
writable. The soapmap file is used to identify the
implementation script file from the SOAPAction header. There is
more information in the sample soapmap.dat file.
The script needs to be able to execute using tcl 8.3 or better
and needs to be able to find the TclSOAP package. Bear in mind that
the httpd process will not run with your environment (unless you
are working on Windows). The supplied script shows how you can set
the location of the package, should you need to. If you are using
the Windows Apache server then you can't set the environment before
execing tclsh so you need to manipulate the
auto_path variable from within the CGI script instead.
Writing Service Implementations
Upon receipt of an HTTP POST the CGI framework examines the data
and decides which RPC protocol should handle the request. The
handlers then retrieve the method name from the request and look
for a file with this name in the configured directory. This is
sourced and then evaluated with the arguments obtained from the
POST data. For example, the implementation for the square
service will be the file ../method-scripts/square with the
following code:
proc square {num} {
return [expr $num * $num]
}
Given the configuration shown above, this implementation will be
used for both SOAP and XML-RPC requests to the square
service. It is necessary to identify the commands that are
webservices to prevent clients from running arbitrary Tcl commands.
This is done by the use of the SOAP::export or the
corresponding XMLRPC::export commands. This means that the
actual implementation for the square webservice would be:
package require SOAP
package require XMLRPC
SOAP::export square
XMLRPC export square
proc square {num} {
return [expr $num * $num]
}
For more complex types such as structs, the reply will need to
be an rpcvar so that the RPC handler can package the
result correctly. So the implementation of the platform
service which returns a struct containing the
::tcl_platform variable information is as follows
package require rpcvar
package require SOAP
SOAP::export platform
proc platform {} {
return [rpcvar::rpcvar struct ::tcl_platform]
}
Structs are passed to the implementing procedure as a list of
name value pairs suitable for use with array set ...,
arrays are passed in as Tcl lists and everything else is passed in
as a string. If the result type cannot be guessed then you should
return a typed variable otherwise it will be assumed to be a
string. The only types that can be guessed are integer, double and
boolean (if expressed with true or false).
rpcvar to be done
Look in the cgi-bin/soap subdirectory in the TclSOAP
distribution for some examples of service implementations. There is
an implementation of the UserLand SOAP interoperability
suite that is used to ensure the package conforms to this
standard. These illustrate the use of arrays and structs fairly
comprehensively.
The client code for the validator suite is in
samples/validator.tcl. To test a server implementation,
source this script and run validate_soap url. This
will run the test suite against the server implementation at the
provided URL.
A similar client implementation of the XMethods Interoperability
Lab test suite is in soapinterop.tcl. To use, source this
file and execute soapinterop::validate url.