From 218f48f2d411938699a0f09ce35c56821263d841 Mon Sep 17 00:00:00 2001 From: Josue Kouka Date: Wed, 7 Sep 2016 10:42:29 +0200 Subject: [PATCH 1/3] iparapheur: add handling of invalid response content --- passerelle/contrib/iparapheur/models.py | 36 ++++++++++++++++++++------------- passerelle/contrib/iparapheur/soap.py | 12 +++++++++-- tests/test_iparapheur.py | 21 +++++++++++++++++++ 3 files changed, 53 insertions(+), 16 deletions(-) diff --git a/passerelle/contrib/iparapheur/models.py b/passerelle/contrib/iparapheur/models.py index 5b23ef5..4c0a80e 100644 --- a/passerelle/contrib/iparapheur/models.py +++ b/passerelle/contrib/iparapheur/models.py @@ -16,6 +16,7 @@ import base64 import json import magic +from xml.sax._exceptions import SAXParseException from django.db import models @@ -44,6 +45,11 @@ class FileNotFoundError(Exception): http_status = 404 +class InvalidResponseContent(Exception): + http_status = 200 + log_error = False + + class IParapheur(BaseResource): wsdl_url = models.CharField(max_length=128, blank=False, verbose_name=_('WSDL URL'), @@ -71,29 +77,33 @@ class IParapheur(BaseResource): def get_verbose_name(cls): return cls._meta.verbose_name + def call(self, service, *args, **kwargs): + client = get_client(self) + try: + result = getattr(client.service, service)(*args, **kwargs) + except(Exception,) as e: + raise InvalidResponseContent('Invalid Response Content, XML expected') + return result + @endpoint(serializer_type='json-api') def types(self, request): - c = get_client(self) - return [format_type(t) for t in c.service.GetListeTypes()] + return [format_type(t) for t in self.call('GetListeTypes')] @endpoint(serializer_type='json-api') def ping(self, request): - c = get_client(self) - return c.service.echo('ping') + return self.call('echo', 'ping') @endpoint(serializer_type='json-api') def subtypes(self, request, type=None): - c = get_client(self) if type: - return [format_type(t) for t in c.service.GetListeSousTypes(type)] - return [format_type(t) for t in c.service.GetListeSousTypes()] + return [format_type(t) for t in self.call('GetListeSousTypes', type)] + return [format_type(t) for t in self.call('GetListeSousTypes')] @endpoint(serializer_type='json-api') def files(self, status=None): - c = get_client(self) if status: - return [format_status(f) for f in c.service.RechercherDossiers(Status=status)] - return [format_status(f) for f in c.service.RechercherDossiers()] + return [format_status(f) for f in self.call('RechercherDossiers', Status=status)] + return [format_status(f) for f in self.call('RechercherDossiers')] @endpoint(serializer_type='json-api', name='create-file', methods=['post']) def create_file(self, request, email=None): @@ -131,8 +141,7 @@ class IParapheur(BaseResource): @endpoint(serializer_type='json-api', name='get-file', pattern='(?P[\w-]+)') def get_file(self, request, file_id): - client = get_client(self) - resp = client.service.GetDossier(file_id) + resp = self.call('GetDossier', file_id) if resp.MessageRetour.codeRetour == 'KO': if 'inconnu' in resp.MessageRetour.message: raise Http404(resp.MessageRetour.message) @@ -144,8 +153,7 @@ class IParapheur(BaseResource): @endpoint(serializer_type='json-api', name='get-file-status', pattern='(?P[\w-]+)') def get_file_status(self, request, file_id): - c = get_client(self) - resp = c.service.GetHistoDossier(file_id) + resp = self.call('GetHistoDossier', file_id) if resp.MessageRetour.codeRetour == 'KO': if 'inconnu' in resp.MessageRetour.message: raise Http404(resp.MessageRetour.message) diff --git a/passerelle/contrib/iparapheur/soap.py b/passerelle/contrib/iparapheur/soap.py index f2bf80a..e0aa111 100644 --- a/passerelle/contrib/iparapheur/soap.py +++ b/passerelle/contrib/iparapheur/soap.py @@ -23,7 +23,7 @@ import StringIO from suds.client import Client from suds.transport.http import HttpAuthenticated -from suds.transport import Reply +from suds.transport import Reply, TransportError from suds.plugin import MessagePlugin, DocumentPlugin from suds.sudsobject import asdict @@ -75,7 +75,15 @@ class Transport(HttpAuthenticated): self.addcredentials(request) resp = self.model.requests.post(request.url, data=request.message, headers=request.headers, **self.get_requests_kwargs()) - return Reply(resp.status_code, resp.headers, resp.content) + + if resp.status_code in (202, 204): + return None + elif not resp.ok: + raise TransportError( + resp.reason, + resp.status_code, fp=StringIO.StringIO(resp.content)) + else: + return Reply(resp.status_code, resp.headers, resp.content) def get_client(instance): transport = Transport(instance) diff --git a/tests/test_iparapheur.py b/tests/test_iparapheur.py index 134aad6..1edb68d 100644 --- a/tests/test_iparapheur.py +++ b/tests/test_iparapheur.py @@ -154,3 +154,24 @@ def test_get_file(http_open, mocked_post, mocked_get, setup, xmlmime, wsdl_file) file_sent = os.path.join(os.path.dirname(__file__), 'data/iparapheur_test.pdf') assert resp.headers['Content-Type'] == 'application/pdf' assert hashlib.md5(resp.body[:8192]).hexdigest() == hashlib.md5(file(file_sent).read()[:8192]).hexdigest() + + +@mock.patch('passerelle.utils.LoggedRequest.get') +@mock.patch('passerelle.utils.LoggedRequest.post') +@mock.patch('passerelle.contrib.iparapheur.soap.HttpAuthenticated.open') +def test_invalid_response(http_open, mocked_post, mocked_get, setup, xmlmime, wsdl_file): + app, conn = setup + file_id = str(uuid.uuid4()) + + http_open.return_value = file(xmlmime) + mocked_get.return_value = mock.Mock(content = file(wsdl_file).read(), + status_code=200) + mocked_post.return_value = mock.Mock(status_code=502, + content='

Bad Gateway

', reason='Bad Gateway', ok=False) + url = reverse('generic-endpoint', kwargs={'slug': conn.slug, + 'connector': 'iparapheur', 'endpoint': 'get-file-status', + 'rest': file_id}) + resp = app.get(url) + + assert 'x-error-code' in dict(resp.headers) + assert resp.json['err_desc'] == 'Invalid Response Content, XML expected' -- 2.9.3