0002-iparapheur-add-handling-of-invalid-response-content.patch
passerelle/contrib/iparapheur/models.py | ||
---|---|---|
24 | 24 |
from django.utils.translation import ugettext_lazy as _ |
25 | 25 |
from django.http import HttpResponse, Http404 |
26 | 26 | |
27 |
from suds import WebFault |
|
28 | ||
27 | 29 |
from passerelle.base.models import BaseResource |
28 | 30 |
from passerelle.utils.api import endpoint |
29 | 31 |
from passerelle.utils.jsonresponse import APIError |
... | ... | |
37 | 39 |
except ConnectionError as e: |
38 | 40 |
raise APIError('i-Parapheur error: %s' % e) |
39 | 41 | |
42 | ||
40 | 43 |
def format_type(t): |
41 | 44 |
return {'id': unicode(t), 'text': unicode(t)} |
42 | 45 | |
... | ... | |
75 | 78 |
def get_verbose_name(cls): |
76 | 79 |
return cls._meta.verbose_name |
77 | 80 | |
81 |
def call(self, service_name, *args, **kwargs): |
|
82 |
client = get_client(self) |
|
83 |
try: |
|
84 |
result = getattr(client.service, service_name)(*args, **kwargs) |
|
85 |
except(WebFault,) as exc: |
|
86 |
# Remote Service Error: <SOAP-ENV:Fault> in response |
|
87 |
raise APIError('ServiceError: %s' % exc) |
|
88 |
except(Exception,) as exc: |
|
89 |
# Exception different from suds.tranport.TransportError |
|
90 |
if not exc.args or not isinstance(exc.args[0], tuple): |
|
91 |
raise exc |
|
92 |
# TransportError Exception |
|
93 |
raise APIError('Transport Error: %s' % exc) |
|
94 |
return result |
|
95 | ||
78 | 96 |
@endpoint(perm='can_access') |
79 | 97 |
def types(self, request): |
80 |
c = get_client(self) |
|
81 |
return {'data': [format_type(t) for t in c.service.GetListeTypes()]} |
|
98 |
return {'data': [format_type(t) for t in self.call('GetListeTypes')]} |
|
82 | 99 | |
83 | 100 |
@endpoint(perm='can_access') |
84 | 101 |
def ping(self, request): |
85 |
c = get_client(self) |
|
86 |
return {'data': c.service.echo('ping')} |
|
102 |
return {'data': self.call('echo', 'ping')} |
|
87 | 103 | |
88 | 104 |
@endpoint(perm='can_access') |
89 | 105 |
def subtypes(self, request, type=None): |
90 |
c = get_client(self) |
|
91 | 106 |
if type: |
92 |
return {'data': [format_type(t) for t in c.service.GetListeSousTypes(type)]}
|
|
93 |
return {'data': [format_type(t) for t in c.service.GetListeSousTypes()]}
|
|
107 |
return {'data': [format_type(t) for t in self.call('GetListeSousTypes', type)]}
|
|
108 |
return {'data': [format_type(t) for t in self.call('GetListeSousTypes')]}
|
|
94 | 109 | |
95 | 110 |
@endpoint(perm='can_access') |
96 | 111 |
def files(self, request, status=None): |
97 |
c = get_client(self) |
|
98 | 112 |
if status: |
99 |
return {'data': [format_file(f) for f in c.service.RechercherDossiers(Status=status)]}
|
|
100 |
return {'data': [format_file(f) for f in c.service.RechercherDossiers()]}
|
|
113 |
return {'data': [format_file(f) for f in self.call('RechercherDossiers', Status=status)]}
|
|
114 |
return {'data': [format_file(f) for f in self.call('RechercherDossiers')]}
|
|
101 | 115 | |
102 | 116 |
@endpoint(perm='can_access', name='create-file', methods=['post']) |
103 | 117 |
def create_file(self, request, email=None): |
... | ... | |
134 | 148 | |
135 | 149 |
@endpoint(perm='can_access', name='get-file', pattern='(?P<file_id>[\w-]+)') |
136 | 150 |
def get_file(self, request, file_id, appendix=None): |
137 |
client = get_client(self) |
|
138 |
resp = client.service.GetDossier(file_id) |
|
151 |
resp = self.call('GetDossier', file_id) |
|
139 | 152 |
filename = None |
153 | ||
140 | 154 |
if resp.MessageRetour.codeRetour == 'KO': |
141 | 155 |
if 'inconnu' in resp.MessageRetour.message: |
142 | 156 |
raise Http404(resp.MessageRetour.message) |
... | ... | |
171 | 185 | |
172 | 186 |
@endpoint(perm='can_access', name='get-file-status', pattern='(?P<file_id>[\w-]+)') |
173 | 187 |
def get_file_status(self, request, file_id): |
174 |
c = get_client(self) |
|
175 |
resp = c.service.GetHistoDossier(file_id) |
|
188 |
resp = self.call('GetHistoDossier', file_id) |
|
176 | 189 |
if resp.MessageRetour.codeRetour == 'KO': |
177 | 190 |
if 'inconnu' in resp.MessageRetour.message: |
178 | 191 |
raise Http404(resp.MessageRetour.message) |
passerelle/contrib/iparapheur/soap.py | ||
---|---|---|
22 | 22 | |
23 | 23 |
from suds.client import Client |
24 | 24 |
from suds.transport.http import HttpAuthenticated |
25 |
from suds.transport import Reply |
|
25 |
from suds.transport import Reply, TransportError
|
|
26 | 26 |
from suds.plugin import MessagePlugin, DocumentPlugin |
27 | 27 | |
28 |
from suds.sudsobject import asdict
|
|
28 |
from requests.exceptions import RequestException
|
|
29 | 29 | |
30 | 30 | |
31 | 31 |
class Filter(MessagePlugin): |
... | ... | |
72 | 72 |
def send(self, request): |
73 | 73 |
request.message = request.message.replace("contentType", "xm:contentType") |
74 | 74 |
self.addcredentials(request) |
75 |
resp = self.model.requests.post(request.url, data=request.message, |
|
75 |
try: |
|
76 |
resp = self.model.requests.post(request.url, data=request.message, |
|
76 | 77 |
headers=request.headers, **self.get_requests_kwargs()) |
77 |
return Reply(resp.status_code, resp.headers, resp.content) |
|
78 |
except(RequestException,) as e: |
|
79 |
raise TransportError(e.message.message, None) |
|
80 | ||
81 |
if resp.status_code in (202, 204): |
|
82 |
return None |
|
83 |
elif not resp.ok: |
|
84 |
raise TransportError( |
|
85 |
resp.reason, |
|
86 |
resp.status_code, fp=StringIO.StringIO(resp.content)) |
|
87 |
else: |
|
88 |
return Reply(resp.status_code, resp.headers, resp.content) |
|
78 | 89 | |
79 | 90 |
def get_client(instance): |
80 | 91 |
transport = Transport(instance) |
tests/test_iparapheur.py | ||
---|---|---|
275 | 275 |
assert 'filename=iParapheur_impression_dossier.pdf' in resp.headers['Content-Disposition'] |
276 | 276 |
assert 'filename*=UTF-8\'\'iParapheur_impression_dossier.pdf' in resp.headers['Content-Disposition'] |
277 | 277 |
assert resp.body == 'Test Document Appendix' |
278 | ||
279 | ||
280 |
@mock.patch('passerelle.utils.LoggedRequest.get') |
|
281 |
@mock.patch('passerelle.utils.LoggedRequest.post') |
|
282 |
@mock.patch('passerelle.contrib.iparapheur.soap.HttpAuthenticated.open') |
|
283 |
def test_invalid_response(http_open, mocked_post, mocked_get, setup, xmlmime, wsdl_file): |
|
284 |
app, conn = setup |
|
285 |
file_id = str(uuid.uuid4()) |
|
286 | ||
287 |
http_open.return_value = file(xmlmime) |
|
288 |
mocked_get.return_value = mock.Mock(content=file(wsdl_file).read(), |
|
289 |
status_code=200) |
|
290 |
mocked_post.return_value = mock.Mock(status_code=502, |
|
291 |
content='<p>Bad Gateway</p>', reason='Bad Gateway', ok=False) |
|
292 |
url = reverse('generic-endpoint', kwargs={'slug': conn.slug, |
|
293 |
'connector': 'iparapheur', 'endpoint': 'get-file-status', 'rest': file_id}) |
|
294 |
url += '?apikey=%s' % API_KEY |
|
295 |
resp = app.get(url) |
|
296 |
assert resp.json['err_desc'] == "Transport Error: (502, u'Bad Gateway')" |
|
297 | ||
298 | ||
299 |
@mock.patch('passerelle.utils.LoggedRequest.get') |
|
300 |
@mock.patch('passerelle.utils.LoggedRequest.post') |
|
301 |
@mock.patch('passerelle.contrib.iparapheur.soap.HttpAuthenticated.open') |
|
302 |
def test_webfault_response(http_open, mocked_post, mocked_get, setup, xmlmime, wsdl_file): |
|
303 |
app, conn = setup |
|
304 |
file_id = str(uuid.uuid4()) |
|
305 |
url = reverse('generic-endpoint', kwargs={'slug': conn.slug, |
|
306 |
'connector': 'iparapheur', 'endpoint': 'get-file-status', 'rest': file_id}) |
|
307 |
url += '?apikey=%s' % API_KEY |
|
308 | ||
309 |
http_open.return_value = file(xmlmime) |
|
310 |
mocked_get.return_value = mock.Mock(content=file(wsdl_file).read(), |
|
311 |
status_code=200) |
|
312 |
webfault_response = """ |
|
313 |
<?xml version='1.0' encoding='UTF-8'?> |
|
314 |
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/XMLSchema"> |
|
315 |
<SOAP-ENV:Body> |
|
316 |
<SOAP-ENV:Fault> |
|
317 |
<faultcode xsi:type="xsd:string">SOAP-ENV:Client</faultcode> |
|
318 |
<faultstring xsi:type="xsd:string"> |
|
319 |
Test server error |
|
320 |
</faultstring> |
|
321 |
</SOAP-ENV:Fault> |
|
322 |
</SOAP-ENV:Body> |
|
323 |
</SOAP-ENV:Envelope>""" |
|
324 | ||
325 |
mocked_post.return_value = mock.Mock( |
|
326 |
status_code=200, content=webfault_response, |
|
327 |
ok=True) |
|
328 |
resp = app.get(url) |
|
329 |
assert 'ServiceError' in resp.json['err_desc'] |
|
330 |
assert 'Test server error' in resp.json['err_desc'] |
|
278 |
- |