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