forked from narken/p2pool-altcoins
-
Notifications
You must be signed in to change notification settings - Fork 0
/
soap.py
104 lines (85 loc) · 3.46 KB
/
soap.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
"""
This module is a SOAP client using twisted's deferreds.
It uses the SOAPpy package.
@author: Raphael Slinckx
@copyright: Copyright 2005
@license: LGPL
@contact: U{[email protected]<mailto:[email protected]>}
@version: 0.1.0
"""
__revision__ = "$id"
import SOAPpy, logging
from SOAPpy.Config import Config
from twisted.web import client, error
#General config
Config.typed = False
class SoapError(Exception):
"""
This is a SOAP error message, not an HTTP error message.
The content of this error is a SOAPpy structure representing the
SOAP error message.
"""
pass
class SoapProxy:
"""
Proxy for an url to which we send SOAP rpc calls.
"""
def __init__(self, url, prefix):
"""
Init the proxy, it will connect to the given url, using the
given soap namespace.
@param url: The url of the remote host to call
@param prefix: The namespace prefix to use, eg.
'urn:schemas-upnp-org:service:WANIPConnection:1'
"""
logging.debug("Soap Proxy: '%s', prefix: '%s'", url, prefix)
self._url = url
self._prefix = prefix
def call(self, method, **kwargs):
"""
Call the given remote method with the given arguments, as keywords.
Returns a deferred, called with SOAPpy structure representing
the soap response.
@param method: The method name to call, eg. 'GetExternalIP'
@param kwargs: The parameters of the call, as keywords
@return: A deferred called with the external ip address of this host
@rtype: L{twisted.internet.defer.Deferred}
"""
payload = SOAPpy.buildSOAP(method=method, config=Config, namespace=self._prefix, kw=kwargs)
# Here begins the nasty hack
payload = payload.replace(
# Upnp wants s: instead of SOAP-ENV
'SOAP-ENV','s').replace(
# Doesn't seem to like these encoding stuff
'xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"', '').replace(
'SOAP-ENC:root="1"', '').replace(
# And it wants u: instead of ns1 namespace for arguments..
'ns1','u')
logging.debug("SOAP Payload:\n%s", payload)
return client.getPage(self._url, postdata=payload, method="POST",
headers={'content-type': 'text/xml', 'SOAPACTION': '%s#%s' % (self._prefix, method)}
).addCallbacks(self._got_page, self._got_error)
def _got_page(self, result):
"""
The http POST command was successful, we parse the SOAP
answer, and return it.
@param result: the xml content
"""
parsed = SOAPpy.parseSOAPRPC(result)
logging.debug("SOAP Answer:\n%s", result)
logging.debug("SOAP Parsed Answer: %r", parsed)
return parsed
def _got_error(self, res):
"""
The HTTP POST command did not succeed, depending on the error type:
- it's a SOAP error, we parse it and return a L{SoapError}.
- it's another type of error (http, other), we raise it as is
"""
logging.debug("SOAP Error:\n%s", res)
if isinstance(res.value, error.Error):
try:
logging.debug("SOAP Error content:\n%s", res.value.response)
raise SoapError(SOAPpy.parseSOAPRPC(res.value.response)["detail"])
except:
raise
raise Exception(res.value)