[XML-SIG] SOAP in CGI-like environments

Rich Salz rsalz@zolera.com
Wed, 29 Aug 2001 23:21:09 -0400


This is a multi-part message in MIME format.
--------------2ED5E5B62C8B18B8FA985AC0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Yes, one of the things missing from ZSI is a dispatch framework.  There
are a couple of reasons for that.  First, I wanted to get some feedback
on usage models before "blessing" one particular style.  It's also a
result of my transport-neutral approach; ZOPE's dispatch style is
probably different from a dynamic application gateway, which is
different from a dedicated apache-based web service, etc.

> >From a pedagogic point of view, may I suggest you start your
> documentation with a SOAP "hello world." As in:
> 
> use SOAP::Transport::HTTP;
> 
> SOAP::Transport::HTTP::CGI -> dispatch_to('Demo') -> handle;
> 
> package Demo;
> sub hi { return "hello, world"; }
> sub bye { return "goodbye, cruel world"; }

Does this mean that an incoming message like
	<S:Envelope xmlns:S="....">
	 <S:Body><hi/></S:Body>
	</S:Envelope>
means that the &Demo::hi() is invoked and a return packet like
	<S:Envelope xmlns:S="....">
	<S:Body>
	<hiResponse xsi:type="xsd:string">hello, world</hiResponse>
	</S:Body></S:Envelope>
is sent back?

Welll...  I suppose I could do something like that. :)  I do have a
couple of questions, tho.  What if there is data in the sent <hi>
element?  Is that parsed and passed as parameters to the hi() method? 
Which must then check for parameters, or ignore them?
That is, can I do
	<S:Body><hi><p1>you stinking</p1><foo>mongrel</foo></hi></S:Body>
?

It turns out, I believe, that SOAP::Lite won't actually be able to parse
that message.  It requires the SOAP message to be fully typed.  But if
it *could* parse it, I assume the p1 and foo parameters would somehow be
made available (as a dictionary?) to Demo::hi.  But suppose hi takes no
parameters?  Does Demo::hi have to error-check and be ready to generate
faults?  More on this below...  I'm headed somewhere.

> I'm trying to work up a talk on how EASY it is to work with SOAP in
> scripting languages.

It's easy to be loose and sloppy, but I think it's actually hard to do
the right thing.  SOAP in RPC mode is really strongly-typed, and that
makes an interesting mix when you work with loosely-typed scripting
languages.  ZSI is different from other scripting SOAP implementations
-- it seems to be the only Python one that can work with typed and -- if
you have a "schema," in the form of ZSI "typecodes" -- completely
untyped messages.  ZSI enforces type-correctness at th SOAP message
level. If you want the "hi" method <hi>...</hi> to take any kind of
parameter, you must explicitly say "TC.Any()" and ZSI will try interpret
the message (provided it contains type information) or raise an
"Unparseable message" exception.

"Python ZSI" is intended to evoke "Java RMI", on purpose.

> I'll try to boil your example down to the barest
> essence and see how close it gets to SOAP::Lite. :-)

Attached is something that I could add to ZSI.  I think it works like
the SOAP::Lite dispatcher, or as close as it can without using 'eval'
:)  Not tested, but byte-compiled.
	/r$

-- 
Zolera Systems, Securing web services (XML, SOAP, Signatures,
Encryption)
http://www.zolera.com
--------------2ED5E5B62C8B18B8FA985AC0
Content-Type: text/plain; charset=us-ascii;
 name="cgizsi.py"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="cgizsi.py"

#! /usr/bin/env python
'''Simple CGI dispatching for ZSI.

Sample use:
    def hello(arg):
	"We accept (and ignore) any input arguments."
	return 'hello world'

    # Define any other functions that you wish to expose.

    from ZSI import CGI
    CGI.dispatch(__name__)
'''

from ZSI import *
import sys,types
from os import environ as ENV

def dispatch(parentmodulename):
    if ENV.get('REQUEST_METHOD', None) != 'POST':
	print """Status: 200 OK
Content-Type: text/xml

<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
  <SOAP-ENV:Body>
    <SOAP-ENV:Fault>
	<faultcode>Client</faultcode>
	<faultstring>Must use POST</faultstring>
    <SOAP-ENV:Fault>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
"""
	return

    # XXX We could look at ENV['CONTENT_TYPE'] and if its multipart
    # XXX we could create a CIDResolver and do SOAP with Attachments.
    # XXX Another time, perhaps.

    try:
	ps = ParsedSoap(sys.stdin.read(int(ENV['CONTENT_LENGTH'])))
	what = ps.body_root.localName
	caller = sys.modules[parentmodulename]
	if not callable(handler): raise TypeError, "Uncallable method"
	arg = ps.Parse(TC.Any())
	result = caller.what(arg)
	print """Status: 200 OK
Content-Type: text/xml

"""
	SoapWriter(sys.stdout).serialize(result, TC.Any())
    except Exception, e:
	# Something went wrong, send a fault.
	print """Status: 200 OK
Content-Type: text/xml

"""
	FaultFromException(e).AsSoap(sys.stdout)

--------------2ED5E5B62C8B18B8FA985AC0--