Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django - WebService with soaplib xml characters or ampersand scaping?

Well this is my fisrt Question here so I’ll try to do it the best I can.

I am trying to implement a WebService server in Python 2.6 and Django 1.4 with Soaplib 2.0.

The Webservice is working and Django is serving it ok in the Django development server.

Here is the code for the Django View and Urls:

views.py

from soaplib.core.service import rpc, DefinitionBase, soap
from soaplib.core.model.primitive import String, Integer, Boolean
from soaplib.core.model.clazz import Array
from soaplib.core import Application
from soaplib.core.server.wsgi import Application as WSGIApplication
from django.http import HttpResponse

class HelloWorldService(DefinitionBase):
    @soap(String,Integer,_returns=Array(String))
    def say_smello(self,name,times):
        results = []
        for i in range(0,times):
            results.append('Hello, %s'%name)
        return results
    @soap(String,_returns=Boolean)
    def xml(self,xml):
        result = xml
        return True
    @soap(String,_returns=String)
    def xml2(self,xml2):
        return xml2



class DjangoSoapApp(WSGIApplication):
    csrf_exempt = True

    def __init__(self, services, tns):
        """Create Django view for given SOAP soaplib services and
tns"""

        return super(DjangoSoapApp,
            self).__init__(Application(services, tns))

    def __call__(self, request):
        django_response = HttpResponse()

        def start_response(status, headers):
            django_response.status_code = int(status.split(' ', 1)[0])
            for header, value in headers:
                django_response[header] = value

        response = super(DjangoSoapApp, self).__call__(request.META,
            start_response)
        django_response.content = '\n'.join(response)

        return django_response

my_soap_service = DjangoSoapApp([HelloWorldService], __name__)

urls.py

url(r'^soap/wsdl$', 'soap.views.my_soap_service'),
url(r'^soap/$', 'soap.views.my_soap_service'),

The thing is, I want to pass to the WebService method xml or xml2 a XML and the do stuff with the info that comes in the XML. I get errors.

If I pass a simple string without characters like “&” everything works fine, for example:

First let's import suds and set suds to Debug:

from suds.client import Client
import logging
logging.basicConfig(level=logging.INFO)
logging.getLogger('suds.client').setLevel(logging.DEBUG)

And now lets start calling de WS:

WSDL = "http://server.test/soap/wsdl"
client = Client(WSDL)
client.service.xml('x and y')

works perfect, I get “True” and the logs of SUDS show me is doing this:

DEBUG:suds.client:sending to (http://server.test/soap/wsdl)
message:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:ns0="soap.views" xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Header/>
   <ns1:Body>
      <ns0:xml>
         <ns0:xml>x and y</ns0:xml>
      </ns0:xml>
   </ns1:Body>
</SOAP-ENV:Envelope>
DEBUG:suds.client:headers = {'SOAPAction': '"xml"', 'Content-Type': 'text/xml; charset=utf-8'}
DEBUG:suds.client:http succeeded:
<?xml version='1.0' encoding='utf-8'?>
<senv:Envelope xmlns:wsa="http://schemas.xmlsoap.org/ws/2003/03/addressing" xmlns:plink="http://schemas.xmlsoap.org/ws/2003/05/partner-link/" xmlns:xop="http://www.w3.org/2004/08/xop/include" xmlns:senc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s0="soap.views" xmlns:s12env="http://www.w3.org/2003/05/soap-envelope/" xmlns:s12enc="http://www.w3.org/2003/05/soap-encoding/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:senv="http://schemas.xmlsoap.org/soap/envelope/"  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"><senv:Body><s0:xmlResponse><s0:xml    Result>true</s0:xmlResult></s0:xmlResponse></senv:Body></senv:Envelope>
True

But if I do:

client.service.xml('x &  y')

is not working, it ends with a suds timeout and the server report a broken pipe, this is what the suds log tells me is pushing:

DEBUG:suds.client:sending to (http://server.test/soap/wsdl)
message:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:ns0="soap.views" xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Header/>
   <ns1:Body>
      <ns0:xml>
         <ns0:xml>x &amp;  y</ns0:xml>
      </ns0:xml>
   </ns1:Body>
</SOAP-ENV:Envelope>
DEBUG:suds.client:headers = {'SOAPAction': '"xml"', 'Content-Type': 'text/xml; charset=utf-8'}

And this is the error on suds:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.6/site-packages/suds/client.py", line 542, in __call__
    return client.invoke(args, kwargs)
  File "/usr/lib/python2.6/site-packages/suds/client.py", line 602, in invoke
    result = self.send(soapenv)
  File "/usr/lib/python2.6/site-packages/suds/client.py", line 643, in send
    reply = transport.send(request)
  File "/usr/lib/python2.6/site-packages/suds/transport/https.py", line 64, in send
    return  HttpTransport.send(self, request)
  File "/usr/lib/python2.6/site-packages/suds/transport/http.py", line 77, in send
    fp = self.u2open(u2request)
  File "/usr/lib/python2.6/site-packages/suds/transport/http.py", line 118, in u2open
    return url.open(u2request, timeout=tm)
  File "/usr/lib/python2.6/urllib2.py", line 391, in open
    response = self._open(req, data)
  File "/usr/lib/python2.6/urllib2.py", line 409, in _open
    '_open', req)
  File "/usr/lib/python2.6/urllib2.py", line 369, in _call_chain
    result = func(*args)
  File "/usr/lib/python2.6/urllib2.py", line 1190, in http_open
    return self.do_open(httplib.HTTPConnection, req)
  File "/usr/lib/python2.6/urllib2.py", line 1165, in do_open
    raise URLError(err)
urllib2.URLError: <urlopen error timed out>

Thanks to this link: http://grokbase.com/p/python/soap/125nhj9bdm/python-suds-xml-encoding-issue I discover that yes, if I post the WebService something like:

client.service.xml("x &amp;amp; y")

I get it right:

DEBUG:suds.client:sending to (http://server.test/soap/wsdl)
message:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:ns0="soap.views" xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Header/>
   <ns1:Body>
      <ns0:xml>
         <ns0:xml>x &amp;amp; y</ns0:xml>
      </ns0:xml>
   </ns1:Body>
</SOAP-ENV:Envelope>
DEBUG:suds.client:headers = {'SOAPAction': '"xml"', 'Content-Type': 'text/xml; charset=utf-8'}
True

If I use the method xml2 so I can see what returns the WebService is this:

client.service.xml2("x &amp;amp; y")

And the logs for Suds:

DEBUG:suds.client:sending to (http://server.test/soap/wsdl)
message:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:ns0="soap.views" xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Header/>
   <ns1:Body>
      <ns0:xml2>
         <ns0:xml2>x &amp;amp; y</ns0:xml2>
      </ns0:xml2>
   </ns1:Body>
</SOAP-ENV:Envelope>
DEBUG:suds.client:headers = {'SOAPAction': '"xml2"', 'Content-Type': 'text/xml; charset=utf-8'}


DEBUG:suds.client:http succeeded:
<?xml version='1.0' encoding='utf-8'?>
<senv:Envelope xmlns:wsa="http://schemas.xmlsoap.org/ws/2003/03/addressing" xmlns:plink="http://schemas.xmlsoap.org/ws/2003/05/partner-link/" xmlns:xop="http://www.w3.org/2004/08/xop/include" xmlns:senc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s0="soap.views" xmlns:s12env="http://www.w3.org/2003/05/soap-envelope/" xmlns:s12enc="http://www.w3.org/2003/05/soap-encoding/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:senv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"><senv:Body><s0:xml2Response><s0:xml2Result>x &amp; y</s0:xml2Result></s0:xml2Response></senv:Body></senv:Envelope>
x & y

but I don’t think the problem is in SUDS, because I use this version of suds to push XML to java WebServices, but I haven’t find a way this soaplib.

Any Ideas? This is driving me a bit crazy xD

My Final goal is to have the Webservice with Soaplib and push a XML to it from a soap client in Java.

Thanks

like image 583
Javier Vieira Avatar asked Dec 18 '12 16:12

Javier Vieira


2 Answers

Ok, solved :D

I could only change the server side, so I migrate my code to spyne and works like a Charm.

https://github.com/arskom/spyne

I found this on their web:

 Soaplib-2.0 was never released as a stable package, but the branch is still available

From soaplib they went to Rpclib and from there to Spyne.

Is true that I found a new bug, this time on suds, but suds I just used for testing, but if I use other clients, SoapUI or Java clientes, works perfect.

After Installing it with PIP, this is the Django code:

urls.py

url(r'^testws/\?wsdl$', 'testmo.views.ws_test'),
url(r'^testws/$', 'testmo.views.ws_test'),

views.py

from django.views.decorators.csrf import csrf_exempt
from spyne.server.django import DjangoApplication
from spyne.model.primitive import String
from spyne.service import ServiceBase
from spyne.interface.wsdl import Wsdl11
from spyne.protocol.soap import Soap11
from spyne.application import Application
from spyne.decorator import srpc



class ServiceWsTest(ServiceBase):
    @srpc(String, _returns=String)
    def testMethod(string):
        return string

ws_test = csrf_exempt(DjangoApplication(Application([ServiceWsTest],
    'http://example.com',
    in_protocol=Soap11(),
    out_protocol=Soap11(),
    interface=Wsdl11(),
)))

From now on, I'll keep working with this library

like image 144
Javier Vieira Avatar answered Nov 15 '22 07:11

Javier Vieira


Maybe you can wrap it, unescaped, in a cdata tag. More info at http://en.wikipedia.org/wiki/CDATA

<![CDATA[
x & y
]]>
like image 1
Matt Williamson Avatar answered Nov 15 '22 07:11

Matt Williamson