Projet

Général

Profil

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

Josué Kouka, 20 juillet 2017 10:17

Télécharger (9,36 ko)

Voir les différences:

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

 passerelle/contrib/iparapheur/models.py | 50 ++++++++++++++++++++++---------
 passerelle/contrib/iparapheur/soap.py   | 19 +++++++++---
 tests/test_iparapheur.py                | 53 +++++++++++++++++++++++++++++++++
 3 files changed, 104 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

  
......
52 55
    http_status = 404
53 56

  
54 57

  
58
class InvalidResponseContent(Exception):
59
    http_status = 200
60
    log_error = False
61

  
62

  
63
class ServiceError(Exception):
64
    http_status = 200
65
    log_error = False
66

  
67

  
55 68
class IParapheur(BaseResource):
56 69
    wsdl_url = models.CharField(max_length=128, blank=False,
57 70
            verbose_name=_('WSDL URL'),
......
75 88
    def get_verbose_name(cls):
76 89
        return cls._meta.verbose_name
77 90

  
91
    def call(self, service_name, *args, **kwargs):
92
        client = get_client(self)
93
        try:
94
            result = getattr(client.service, service_name)(*args, **kwargs)
95
        except(WebFault,) as exc:
96
            # Remote Service Error: <SOAP-ENV:Fault> in response
97
            raise APIError('ServiceError: %s' % exc)
98
        except(Exception,) as exc:
99
            # Exception different from suds.tranport.TransportError
100
            if not exc.args or not isinstance(exc.args[0], tuple):
101
                raise exc
102
            # TransportError Exception
103
            raise APIError('Transport Error: %s' % exc)
104
        return result
105

  
78 106
    @endpoint(perm='can_access')
79 107
    def types(self, request):
80
        c = get_client(self)
81
        return {'data': [format_type(t) for t in c.service.GetListeTypes()]}
108
        return {'data': [format_type(t) for t in self.call('GetListeTypes')]}
82 109

  
83 110
    @endpoint(perm='can_access')
84 111
    def ping(self, request):
85
        c = get_client(self)
86
        return {'data': c.service.echo('ping')}
112
        return {'data': self.call('echo', 'ping')}
87 113

  
88 114
    @endpoint(perm='can_access')
89 115
    def subtypes(self, request, type=None):
90
        c = get_client(self)
91 116
        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()]}
117
            return {'data': [format_type(t) for t in self.call('GetListeSousTypes', type)]}
118
        return {'data': [format_type(t) for t in self.call('GetListeSousTypes')]}
94 119

  
95 120
    @endpoint(perm='can_access')
96 121
    def files(self, request, status=None):
97
        c = get_client(self)
98 122
        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()]}
123
            return {'data': [format_file(f) for f in self.call('RechercherDossiers', Status=status)]}
124
        return {'data': [format_file(f) for f in self.call('RechercherDossiers')]}
101 125

  
102 126
    @endpoint(perm='can_access', name='create-file', methods=['post'])
103 127
    def create_file(self, request, email=None):
......
134 158

  
135 159
    @endpoint(perm='can_access', name='get-file', pattern='(?P<file_id>[\w-]+)')
136 160
    def get_file(self, request, file_id):
137
        client = get_client(self)
138
        resp = client.service.GetDossier(file_id)
161
        resp = self.call('GetDossier', file_id)
139 162
        if resp.MessageRetour.codeRetour == 'KO':
140 163
            if 'inconnu' in resp.MessageRetour.message:
141 164
                raise Http404(resp.MessageRetour.message)
......
146 169

  
147 170
    @endpoint(perm='can_access', name='get-file-status', pattern='(?P<file_id>[\w-]+)')
148 171
    def get_file_status(self, request, file_id):
149
        c = get_client(self)
150
        resp = c.service.GetHistoDossier(file_id)
172
        resp = self.call('GetHistoDossier', file_id)
151 173
        if resp.MessageRetour.codeRetour == 'KO':
152 174
            if 'inconnu' in resp.MessageRetour.message:
153 175
                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
-