@@ -22,14 +22,14 @@ DEBUG = False class SoapDispatcher(object): "Simple Dispatcher for SOAP Server" - - def __init__(self, name, documentation='', action='', location='', - namespace=None, prefix=False, - soap_uri="http://schemas.xmlsoap.org/soap/envelope/", + + def __init__(self, name, documentation='', action='', location='', + namespace=None, prefix=False, + soap_uri="http://schemas.xmlsoap.org/soap/envelope/", soap_ns='soap', **kwargs): self.methods = {} self.name = name self.documentation = documentation @@ -37,14 +37,14 @@ self.location = location self.namespace = namespace # targetNamespace self.prefix = prefix self.soap_ns = soap_ns self.soap_uri = soap_uri - + def register_function(self, name, fn, returns=None, args=None, doc=None): self.methods[name] = fn, returns, args, doc or getattr(fn,"__doc__","") - + def dispatch(self, xml, action=None): "Receive and proccess SOAP call" # default values: prefix = self.prefix ret = fault = None @@ -58,66 +58,66 @@ for k, v in request[:]: if v in ("http://schemas.xmlsoap.org/soap/envelope/", "http://www.w3.org/2003/05/soap-env",): soap_ns = request.attributes()[k].localName soap_uri = request.attributes()[k].value - + soap_fault_code = 'Client' - - # parse request message and get local method + + # parse request message and get local method method = request('Body', ns=soap_uri).children()(0) if action: - # method name = action + # method name = action name = action[len(self.action)+1:-1] prefix = self.prefix if not action or not name: # method name = input message name name = method.get_local_name() prefix = method.get_prefix() if DEBUG: print "dispatch method", name function, returns_types, args_types, doc = self.methods[name] - + # de-serialize parameters (if type definitions given) if args_types: args = method.children().unmarshall(args_types) elif args_types is None: args = {'request':method} # send raw request else: args = {} # no parameters - + soap_fault_code = 'Server' # execute function ret = function(**args) if DEBUG: print ret except Exception, e: import sys etype, evalue, etb = sys.exc_info() - if DEBUG: + if DEBUG: import traceback detail = ''.join(traceback.format_exception(etype, evalue, etb)) detail += '\n\nXML REQUEST\n\n' + xml else: detail = None - fault = {'faultcode': "%s.%s" % (soap_fault_code, etype.__name__), - 'faultstring': unicode(evalue), + fault = {'faultcode': "%s.%s" % (soap_fault_code, etype.__name__), + 'faultstring': unicode(evalue), 'detail': detail} # build response message if not prefix: - xml = """<%(soap_ns)s:Envelope xmlns:%(soap_ns)s="%(soap_uri)s"/>""" + xml = """<%(soap_ns)s:Envelope xmlns:%(soap_ns)s="%(soap_uri)s"/>""" else: xml = """<%(soap_ns)s:Envelope xmlns:%(soap_ns)s="%(soap_uri)s" - xmlns:%(prefix)s="%(namespace)s"/>""" - + xmlns:%(prefix)s="%(namespace)s"/>""" + xml = xml % {'namespace': self.namespace, 'prefix': prefix, 'soap_ns': soap_ns, 'soap_uri': soap_uri} response = SimpleXMLElement(xml, namespace=self.namespace, prefix=prefix) - + response['xmlns:xsi'] = "http://www.w3.org/2001/XMLSchema-instance" response['xmlns:xsd'] = "http://www.w3.org/2001/XMLSchema" body = response.add_child("%s:Body" % soap_ns, ns=False) if fault: @@ -144,11 +144,11 @@ # Introspection functions: def list_methods(self): "Return a list of aregistered operations" - return [(method, doc) for method, (function, returns, args, doc) in self.methods.items()] + return [(method, doc) for method, (function, returns, args, doc) in self.methods.items()] def help(self, method=None): "Generate sample request and response messages" (function, returns, args, doc) = self.methods[method] xml = """ @@ -183,11 +183,11 @@ def wsdl(self): "Generate Web Service Description v1.1" xml = """ - @@ -204,11 +204,11 @@ """ % {'namespace': self.namespace, 'name': self.name, 'documentation': self.documentation} wsdl = SimpleXMLElement(xml) for method, (function, returns, args, doc) in self.methods.items(): # create elements: - + def parse_element(name, values, array=False, complex=False): if not complex: element = wsdl('wsdl:types')('xsd:schema').add_child('xsd:element') complex = element.add_child("xsd:complexType") else: @@ -239,25 +239,25 @@ l = [] for d in v: l.extend(d.items()) parse_element(n, l, array=True, complex=True) t = "tns:%s" % n - elif isinstance(v, dict): + elif isinstance(v, dict): n="%s%s" % (name, k) parse_element(n, v.items(), complex=True) t = "tns:%s" % n e.add_attribute('type', t) - + parse_element("%s" % method, args and args.items()) parse_element("%sResponse" % method, returns and returns.items()) # create messages: for m,e in ('Input',''), ('Output','Response'): message = wsdl.add_child('wsdl:message') message['name'] = "%s%s" % (method, m) part = message.add_child("wsdl:part") - part[:] = {'name': 'parameters', + part[:] = {'name': 'parameters', 'element': 'tns:%s%s' % (method,e)} # create ports portType = wsdl.add_child('wsdl:portType') portType['name'] = "%sPortType" % self.name @@ -300,11 +300,11 @@ port["name"] = "%s" % self.name port["binding"] = "tns:%sBinding" % self.name soapaddress = port.add_child('soap:address') soapaddress["location"] = self.location return wsdl.as_xml(pretty=True) - + from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer class SOAPHandler(BaseHTTPRequestHandler): def do_GET(self): "User viewable help information and wsdl" @@ -320,11 +320,11 @@ # return supplied method help (?request or ?response messages) req, res, doc = self.server.dispatcher.help(args[0]) if len(args)==1 or args[1]=="request": response = req else: - response = res + response = res self.send_response(200) self.send_header("Content-type", "text/xml") self.end_headers() self.wfile.write(response) @@ -347,11 +347,11 @@ action = 'http://localhost:8008/', # SOAPAction namespace = "http://example.com/pysimplesoapsamle/", prefix="ns0", documentation = 'Example soap service using PySimpleSoap', trace = True, ns = True) - + def adder(p,c, dt=None): "Add several values" print c[0]['d'],c[1]['d'], import datetime dt = dt + datetime.timedelta(365) @@ -364,15 +364,15 @@ def echo(request): "Copy request->response (generic, any type)" return request.value dispatcher.register_function('Adder', adder, - returns={'AddResult': {'ab': int, 'dd': str } }, + returns={'AddResult': {'ab': int, 'dd': str } }, args={'p': {'a': int,'b': int}, 'dt': Date, 'c': [{'d': Decimal}]}) dispatcher.register_function('Dummy', dummy, - returns={'out0': str}, + returns={'out0': str}, args={'in0': str}) dispatcher.register_function('Echo', echo) if '--local' in sys.argv: @@ -383,11 +383,11 @@ try: testfile.write(wsdl) finally: testfile.close() # dummy local test (clasic soap dialect) - xml = """ + xml = """

12

5000000.1.2
20100724
@@ -410,11 +410,11 @@ """ print dispatcher.dispatch(xml) # echo local test (generic soap service) - xml = """ + xml = """ @@ -428,11 +428,11 @@ for method, doc in dispatcher.list_methods(): request, response, doc = dispatcher.help(method) ##print request ##print response - + if '--serve' in sys.argv: print "Starting server..." httpd = HTTPServer(("", 8008), SOAPHandler) httpd.dispatcher = dispatcher httpd.serve_forever() @@ -440,15 +440,16 @@ if '--consume' in sys.argv: from client import SoapClient client = SoapClient( location = "http://localhost:8008/", action = 'http://localhost:8008/', # SOAPAction - namespace = "http://example.com/sample.wsdl", + namespace = "http://example.com/sample.wsdl", soap_ns='soap', trace = True, ns = False) response = client.Adder(p={'a':1,'b':2},dt='20100724',c=[{'d':'1.20'},{'d':'2.01'}]) result = response.AddResult print int(result.ab) print str(result.dd) +