Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

soap.py 5.1KB

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. # -*- test-case-name: twisted.web.test.test_soap -*-
  2. # Copyright (c) Twisted Matrix Laboratories.
  3. # See LICENSE for details.
  4. """
  5. SOAP support for twisted.web.
  6. Requires SOAPpy 0.10.1 or later.
  7. Maintainer: Itamar Shtull-Trauring
  8. Future plans:
  9. SOAPContext support of some kind.
  10. Pluggable method lookup policies.
  11. """
  12. # SOAPpy
  13. import SOAPpy # type: ignore[import]
  14. from twisted.internet import defer
  15. # twisted imports
  16. from twisted.web import client, resource, server
  17. class SOAPPublisher(resource.Resource):
  18. """Publish SOAP methods.
  19. By default, publish methods beginning with 'soap_'. If the method
  20. has an attribute 'useKeywords', it well get the arguments passed
  21. as keyword args.
  22. """
  23. isLeaf = 1
  24. # override to change the encoding used for responses
  25. encoding = "UTF-8"
  26. def lookupFunction(self, functionName):
  27. """Lookup published SOAP function.
  28. Override in subclasses. Default behaviour - publish methods
  29. starting with soap_.
  30. @return: callable or None if not found.
  31. """
  32. return getattr(self, "soap_%s" % functionName, None)
  33. def render(self, request):
  34. """Handle a SOAP command."""
  35. data = request.content.read()
  36. p, header, body, attrs = SOAPpy.parseSOAPRPC(data, 1, 1, 1)
  37. methodName, args, kwargs = p._name, p._aslist, p._asdict
  38. # deal with changes in SOAPpy 0.11
  39. if callable(args):
  40. args = args()
  41. if callable(kwargs):
  42. kwargs = kwargs()
  43. function = self.lookupFunction(methodName)
  44. if not function:
  45. self._methodNotFound(request, methodName)
  46. return server.NOT_DONE_YET
  47. else:
  48. if hasattr(function, "useKeywords"):
  49. keywords = {}
  50. for k, v in kwargs.items():
  51. keywords[str(k)] = v
  52. d = defer.maybeDeferred(function, **keywords)
  53. else:
  54. d = defer.maybeDeferred(function, *args)
  55. d.addCallback(self._gotResult, request, methodName)
  56. d.addErrback(self._gotError, request, methodName)
  57. return server.NOT_DONE_YET
  58. def _methodNotFound(self, request, methodName):
  59. response = SOAPpy.buildSOAP(
  60. SOAPpy.faultType(
  61. "%s:Client" % SOAPpy.NS.ENV_T, "Method %s not found" % methodName
  62. ),
  63. encoding=self.encoding,
  64. )
  65. self._sendResponse(request, response, status=500)
  66. def _gotResult(self, result, request, methodName):
  67. if not isinstance(result, SOAPpy.voidType):
  68. result = {"Result": result}
  69. response = SOAPpy.buildSOAP(
  70. kw={"%sResponse" % methodName: result}, encoding=self.encoding
  71. )
  72. self._sendResponse(request, response)
  73. def _gotError(self, failure, request, methodName):
  74. e = failure.value
  75. if isinstance(e, SOAPpy.faultType):
  76. fault = e
  77. else:
  78. fault = SOAPpy.faultType(
  79. "%s:Server" % SOAPpy.NS.ENV_T, "Method %s failed." % methodName
  80. )
  81. response = SOAPpy.buildSOAP(fault, encoding=self.encoding)
  82. self._sendResponse(request, response, status=500)
  83. def _sendResponse(self, request, response, status=200):
  84. request.setResponseCode(status)
  85. if self.encoding is not None:
  86. mimeType = 'text/xml; charset="%s"' % self.encoding
  87. else:
  88. mimeType = "text/xml"
  89. request.setHeader("Content-type", mimeType)
  90. request.setHeader("Content-length", str(len(response)))
  91. request.write(response)
  92. request.finish()
  93. class Proxy:
  94. """A Proxy for making remote SOAP calls.
  95. Pass the URL of the remote SOAP server to the constructor.
  96. Use proxy.callRemote('foobar', 1, 2) to call remote method
  97. 'foobar' with args 1 and 2, proxy.callRemote('foobar', x=1)
  98. will call foobar with named argument 'x'.
  99. """
  100. # at some point this should have encoding etc. kwargs
  101. def __init__(self, url, namespace=None, header=None):
  102. self.url = url
  103. self.namespace = namespace
  104. self.header = header
  105. def _cbGotResult(self, result):
  106. result = SOAPpy.parseSOAPRPC(result)
  107. if hasattr(result, "Result"):
  108. return result.Result
  109. elif len(result) == 1:
  110. ## SOAPpy 0.11.6 wraps the return results in a containing structure.
  111. ## This check added to make Proxy behaviour emulate SOAPProxy, which
  112. ## flattens the structure by default.
  113. ## This behaviour is OK because even singleton lists are wrapped in
  114. ## another singleton structType, which is almost always useless.
  115. return result[0]
  116. else:
  117. return result
  118. def callRemote(self, method, *args, **kwargs):
  119. payload = SOAPpy.buildSOAP(
  120. args=args,
  121. kw=kwargs,
  122. method=method,
  123. header=self.header,
  124. namespace=self.namespace,
  125. )
  126. return client.getPage(
  127. self.url,
  128. postdata=payload,
  129. method="POST",
  130. headers={"content-type": "text/xml", "SOAPAction": method},
  131. ).addCallback(self._cbGotResult)