0002-misc-allow-fixing-prefix-characters-in-SOAP-response.patch
passerelle/utils/soap.py | ||
---|---|---|
36 | 36 |
""" |
37 | 37 |
def __init__(self, resource, **kwargs): |
38 | 38 |
wsdl_url = kwargs.pop('wsdl_url', None) or resource.wsdl_url |
39 |
transport_kwargs = kwargs.pop('transport_kwargs', {}) |
|
39 | 40 |
transport_class = getattr(resource, 'soap_transport_class', SOAPTransport) |
40 |
transport = transport_class(resource, wsdl_url, session=resource.requests, cache=InMemoryCache()) |
|
41 |
transport = transport_class(resource, wsdl_url, |
|
42 |
session=resource.requests, |
|
43 |
cache=InMemoryCache(), **transport_kwargs) |
|
41 | 44 |
super(SOAPClient, self).__init__(wsdl_url, transport=transport, **kwargs) |
42 | 45 | |
43 | 46 | |
47 |
class ResponseFixContentWrapper: |
|
48 |
def __init__(self, response): |
|
49 |
self.response = response |
|
50 | ||
51 |
def __getattr__(self, name): |
|
52 |
return getattr(self.response, name) |
|
53 | ||
54 |
@property |
|
55 |
def content(self): |
|
56 |
content = self.response.content |
|
57 |
if 'multipart/related' not in self.response.headers.get('Content-Type', ''): |
|
58 |
try: |
|
59 |
first_left_than_sign = content.index(b'<') |
|
60 |
content = content[first_left_than_sign:] |
|
61 |
except ValueError: |
|
62 |
pass |
|
63 |
return content |
|
64 | ||
65 | ||
44 | 66 |
class SOAPTransport(Transport): |
45 | 67 |
"""Wrapper around zeep.Transport |
46 | 68 | |
47 | 69 |
disable basic_authentication hosts unrelated to wsdl's endpoints |
48 | 70 |
""" |
49 |
def __init__(self, resource, wsdl_url, **kwargs): |
|
71 |
def __init__(self, resource, wsdl_url, remove_first_bytes_for_xml=False, **kwargs):
|
|
50 | 72 |
self.resource = resource |
51 | 73 |
self.wsdl_host = urlparse.urlparse(wsdl_url).netloc |
74 |
# fix content for servers returning unexpected characters before XML document start |
|
75 |
self.remove_first_bytes_for_xml = remove_first_bytes_for_xml |
|
52 | 76 |
super(SOAPTransport, self).__init__(**kwargs) |
53 | 77 | |
54 | 78 |
def _load_remote_data(self, url): |
... | ... | |
60 | 84 |
return super(SOAPTransport, self)._load_remote_data(url) |
61 | 85 |
except RequestException as e: |
62 | 86 |
raise SOAPError('SOAP service is down, location %r cannot be loaded: %s' % (url, e), exception=e, url=url) |
87 | ||
88 |
def post_xml(self, *args, **kwargs): |
|
89 |
response = super().post_xml(*args, **kwargs) |
|
90 | ||
91 |
if self.remove_first_bytes_for_xml: |
|
92 |
return ResponseFixContentWrapper(response) |
|
93 | ||
94 |
return response |
|
95 |
tests/test_soap.py | ||
---|---|---|
19 | 19 |
import requests |
20 | 20 |
from zeep import Settings |
21 | 21 |
from zeep.plugins import Plugin |
22 |
from zeep.exceptions import XMLParseError |
|
22 |
from zeep.exceptions import XMLParseError, TransportError
|
|
23 | 23 | |
24 | 24 |
from passerelle.utils.soap import SOAPClient |
25 | 25 | |
... | ... | |
78 | 78 |
assert len(result) == 2 |
79 | 79 |
assert result['skipMe'] is None |
80 | 80 |
assert result['price'] == 4.2 |
81 | ||
82 | ||
83 |
@mock.patch('requests.sessions.Session.post') |
|
84 |
def test_remove_first_bytes_for_xml(mocked_post): |
|
85 |
response = requests.Response() |
|
86 |
response.status_code = 200 |
|
87 |
response._content = force_bytes('''blabla <?xml version='1.0' encoding='utf-8'?> |
|
88 |
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"> |
|
89 |
<soap-env:Body> |
|
90 |
<ns0:TradePrice xmlns:ns0="http://example.com/stockquote.xsd"> |
|
91 |
<skipMe>1.2</skipMe> |
|
92 |
<price>4.20</price> |
|
93 |
</ns0:TradePrice> |
|
94 |
</soap-env:Body> |
|
95 |
</soap-env:Envelope>''') |
|
96 |
mocked_post.return_value = response |
|
97 | ||
98 |
soap_resource = SOAPResource() |
|
99 | ||
100 |
client = SOAPClient(soap_resource) |
|
101 |
with pytest.raises(TransportError): |
|
102 |
client.service.GetLastTradePrice(tickerSymbol='banana') |
|
103 | ||
104 |
client = SOAPClient(soap_resource, |
|
105 |
transport_kwargs={'remove_first_bytes_for_xml': True}) |
|
106 |
result = client.service.GetLastTradePrice(tickerSymbol='banana') |
|
107 |
assert len(result) == 2 |
|
108 |
assert result['skipMe'] == 1.2 |
|
109 |
assert result['price'] == 4.2 |
|
110 | ||
81 |
- |