"""SOAP support for twisted.web.
Requires SOAPpy.
API Stability: unstable
Maintainer: U{Itamar Shtull-Trauring<mailto:twisted@itamarst.org}
Future plans:
SOAPContext support of some kind.
Pluggable method lookup policies.
Figure out why None doesn't work, and write tests.
"""
# SOAPpy
import SOAP
# fix 2.2 issues with SOAP
SOAP.SOAPBuilder.dump_str = SOAP.SOAPBuilder.dump_string
SOAP.SOAPBuilder.dump_dict = SOAP.SOAPBuilder.dump_dictionary
# twisted imports
from twisted.web import server,resource
from twisted.internet import defer
from twisted.python import log,failure
class SOAPPublisher(resource.Resource):
"""Publish methods beginning with 'soap_'.
If the method has an attribute 'useKeywords', it well get the
arguments passed as keyword args.
"""
isLeaf = 1
# override to change the encoding used for responses
encoding = "UTF-8"
def render(self, request):
"""Handle a SOAP command."""
data = request.content.read()
p, header, body, attrs = SOAP.parseSOAPRPC(data, 1, 1, 1)
method, args, kwargs, ns = p._name, p._aslist, p._asdict, p._ns
function = getattr(self, "soap_%s" % method, None)
if not function:
self._methodNotFound(request, method)
return server.NOT_DONE_YET
else:
try:
if hasattr(function, "useKeywords"):
keywords = {}
for k, v in kwargs.items():
keywords[str(k)] = v
result = function(**keywords)
else:
result = function(*args)
except:
f = failure.Failure()
log.err(f)
self._gotError(f, request, method)
return server.NOT_DONE_YET
if isinstance(result, defer.Deferred):
result.addCallback(self._gotResult, request, method)
result.addErrback(self._gotError, request, method)
else:
self._gotResult(result, request, method)
return server.NOT_DONE_YET
def _methodNotFound(self, request, methodName):
response = SOAP.buildSOAP(SOAP.faultType("%s:Client" % SOAP.NS.ENV_T,
"Method %s not found" % methodName),
encoding=self.encoding)
self._sendResponse(request, response, status=500)
def _gotResult(self, result, request, methodName):
if not isinstance(result, SOAP.voidType):
result = {"Result": result}
response = SOAP.buildSOAP(kw={'%sResponse' % methodName: result},
encoding=self.encoding)
self._sendResponse(request, response)
def _gotError(self, failure, request, methodName):
e = failure.value
if isinstance(e, SOAP.faultType):
fault = e
else:
fault = SOAP.faultType("%s:Server" % SOAP.NS.ENV_T, "Method %s failed." % methodName)
response = SOAP.buildSOAP(fault, encoding=self.encoding)
self._sendResponse(request, response, status=500)
def _sendResponse(self, request, response, status=200):
request.setResponseCode(status)
if self.encoding is not None:
mimeType = 'text/xml; charset="%s"' % self.encoding
else:
mimeType = "text/xml"
request.setHeader("Content-type", mimeType)
request.setHeader("Content-length", str(len(response)))
request.write(response)
request.finish()
|