Projet

Général

Profil

0002-iparapheur-add-handling-of-invalid-response-content.patch

Josué Kouka, 20 juillet 2017 10:59

Télécharger (8,97 ko)

Voir les différences:

Subject: [PATCH 2/2] iparapheur: add handling of invalid response content

 passerelle/contrib/iparapheur/models.py | 40 ++++++++++++++++---------
 passerelle/contrib/iparapheur/soap.py   | 19 +++++++++---
 tests/test_iparapheur.py                | 53 +++++++++++++++++++++++++++++++++
 3 files changed, 94 insertions(+), 18 deletions(-)
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):
137
        client = get_client(self)
138
        resp = client.service.GetDossier(file_id)
151
        resp = self.call('GetDossier', file_id)
139 152
        if resp.MessageRetour.codeRetour == 'KO':
140 153
            if 'inconnu' in resp.MessageRetour.message:
141 154
                raise Http404(resp.MessageRetour.message)
......
146 159

  
147 160
    @endpoint(perm='can_access', name='get-file-status', pattern='(?P<file_id>[\w-]+)')
148 161
    def get_file_status(self, request, file_id):
149
        c = get_client(self)
150
        resp = c.service.GetHistoDossier(file_id)
162
        resp = self.call('GetHistoDossier', file_id)
151 163
        if resp.MessageRetour.codeRetour == 'KO':
152 164
            if 'inconnu' in resp.MessageRetour.message:
153 165
                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
207 207
    file_sent = os.path.join(os.path.dirname(__file__), 'data/iparapheur_test.pdf')
208 208
    assert resp.headers['Content-Type'] == 'application/pdf'
209 209
    assert hashlib.md5(resp.body[:8192]).hexdigest() == hashlib.md5(file(file_sent).read()[:8192]).hexdigest()
210

  
211

  
212
@mock.patch('passerelle.utils.LoggedRequest.get')
213
@mock.patch('passerelle.utils.LoggedRequest.post')
214
@mock.patch('passerelle.contrib.iparapheur.soap.HttpAuthenticated.open')
215
def test_invalid_response(http_open, mocked_post, mocked_get, setup, xmlmime, wsdl_file):
216
    app, conn = setup
217
    file_id = str(uuid.uuid4())
218

  
219
    http_open.return_value = file(xmlmime)
220
    mocked_get.return_value = mock.Mock(content=file(wsdl_file).read(),
221
                                        status_code=200)
222
    mocked_post.return_value = mock.Mock(status_code=502,
223
            content='<p>Bad Gateway</p>', reason='Bad Gateway', ok=False)
224
    url = reverse('generic-endpoint', kwargs={'slug': conn.slug,
225
                  'connector': 'iparapheur', 'endpoint': 'get-file-status', 'rest': file_id})
226
    url += '?apikey=%s' % API_KEY
227
    resp = app.get(url)
228
    assert resp.json['err_desc'] == "Transport Error: (502, u'Bad Gateway')"
229

  
230

  
231
@mock.patch('passerelle.utils.LoggedRequest.get')
232
@mock.patch('passerelle.utils.LoggedRequest.post')
233
@mock.patch('passerelle.contrib.iparapheur.soap.HttpAuthenticated.open')
234
def test_webfault_response(http_open, mocked_post, mocked_get, setup, xmlmime, wsdl_file):
235
    app, conn = setup
236
    file_id = str(uuid.uuid4())
237
    url = reverse('generic-endpoint', kwargs={'slug': conn.slug,
238
                  'connector': 'iparapheur', 'endpoint': 'get-file-status', 'rest': file_id})
239
    url += '?apikey=%s' % API_KEY
240

  
241
    http_open.return_value = file(xmlmime)
242
    mocked_get.return_value = mock.Mock(content=file(wsdl_file).read(),
243
                                        status_code=200)
244
    webfault_response = """
245
    <?xml version='1.0' encoding='UTF-8'?>
246
    <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">
247
        <SOAP-ENV:Body>
248
            <SOAP-ENV:Fault>
249
                <faultcode xsi:type="xsd:string">SOAP-ENV:Client</faultcode>
250
                    <faultstring xsi:type="xsd:string">
251
                        Test server error
252
                   </faultstring>
253
           </SOAP-ENV:Fault>
254
        </SOAP-ENV:Body>
255
     </SOAP-ENV:Envelope>"""
256

  
257
    mocked_post.return_value = mock.Mock(
258
        status_code=200, content=webfault_response,
259
        ok=True)
260
    resp = app.get(url)
261
    assert 'ServiceError' in resp.json['err_desc']
262
    assert 'Test server error' in resp.json['err_desc']
210
-