Projet

Général

Profil

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

Josué Kouka, 27 septembre 2016 11:08

Télécharger (7,46 ko)

Voir les différences:

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

 passerelle/contrib/iparapheur/models.py | 49 +++++++++++++++++++++++----------
 passerelle/contrib/iparapheur/soap.py   | 19 ++++++++++---
 tests/test_iparapheur.py                | 21 ++++++++++++++
 3 files changed, 71 insertions(+), 18 deletions(-)
passerelle/contrib/iparapheur/models.py
28 28
from passerelle.utils.api import endpoint
29 29

  
30 30
from .soap import get_client
31
from suds import WebFault
32

  
31 33

  
32 34
def format_type(t):
33 35
    return {'id': unicode(t), 'text': unicode(t)}
......
44 46
    http_status = 404
45 47

  
46 48

  
49
class InvalidResponseContent(Exception):
50
    http_status = 200
51
    log_error = False
52

  
53

  
54
class ServiceError(Exception):
55
    http_status = 200
56
    log_error = False
57

  
58

  
47 59
class IParapheur(BaseResource):
48 60
    wsdl_url = models.CharField(max_length=128, blank=False,
49 61
            verbose_name=_('WSDL URL'),
......
71 83
    def get_verbose_name(cls):
72 84
        return cls._meta.verbose_name
73 85

  
86
    def call(self, service, *args, **kwargs):
87
        client = get_client(self)
88
        try:
89
            result = getattr(client.service, service)(*args, **kwargs)
90
        except(WebFault,) as e:
91
            # Remote Service Error: <SOAP-ENV:Fault> in response
92
            raise ServiceError(e.args[0])
93
        except(Exception,) as e:
94
            # Exception different from suds.tranport.TransportError
95
            if not(e.args) or not isinstance(e.args[0], tuple):
96
                raise e
97
            # TransportError Exception
98
            raise InvalidResponseContent(e.args[0])
99
        return result
100

  
74 101
    @endpoint(serializer_type='json-api')
75 102
    def types(self, request):
76
        c = get_client(self)
77
        return [format_type(t) for t in c.service.GetListeTypes()]
103
        return [format_type(t) for t in self.call('GetListeTypes')]
78 104

  
79 105
    @endpoint(serializer_type='json-api')
80 106
    def ping(self, request):
81
        c = get_client(self)
82
        return c.service.echo('ping')
107
        return self.call('echo', 'ping')
83 108

  
84 109
    @endpoint(serializer_type='json-api')
85 110
    def subtypes(self, request, type=None):
86
        c = get_client(self)
87 111
        if type:
88
            return [format_type(t) for t in c.service.GetListeSousTypes(type)]
89
        return [format_type(t) for t in c.service.GetListeSousTypes()]
112
            return [format_type(t) for t in self.call('GetListeSousTypes', type)]
113
        return [format_type(t) for t in self.call('GetListeSousTypes')]
90 114

  
91 115
    @endpoint(serializer_type='json-api')
92 116
    def files(self, status=None):
93
        c = get_client(self)
94 117
        if status:
95
            return [format_status(f) for f in c.service.RechercherDossiers(Status=status)]
96
        return [format_status(f) for f in c.service.RechercherDossiers()]
118
            return [format_status(f) for f in self.call('RechercherDossiers', Status=status)]
119
        return [format_status(f) for f in self.call('RechercherDossiers')]
97 120

  
98 121
    @endpoint(serializer_type='json-api', name='create-file', methods=['post'])
99 122
    def create_file(self, request, email=None):
......
131 154

  
132 155
    @endpoint(serializer_type='json-api', name='get-file', pattern='(?P<file_id>[\w-]+)')
133 156
    def get_file(self, request, file_id):
134
        client = get_client(self)
135
        resp = client.service.GetDossier(file_id)
157
        resp = self.call('GetDossier', file_id)
136 158
        if resp.MessageRetour.codeRetour == 'KO':
137 159
            if 'inconnu' in resp.MessageRetour.message:
138 160
                raise Http404(resp.MessageRetour.message)
......
144 166

  
145 167
    @endpoint(serializer_type='json-api', name='get-file-status', pattern='(?P<file_id>[\w-]+)')
146 168
    def get_file_status(self, request, file_id):
147
        c = get_client(self)
148
        resp = c.service.GetHistoDossier(file_id)
169
        resp = self.call('GetHistoDossier', file_id)
149 170
        if resp.MessageRetour.codeRetour == 'KO':
150 171
            if 'inconnu' in resp.MessageRetour.message:
151 172
                raise Http404(resp.MessageRetour.message)
passerelle/contrib/iparapheur/soap.py
23 23

  
24 24
from suds.client import Client
25 25
from suds.transport.http import HttpAuthenticated
26
from suds.transport import Reply
26
from suds.transport import Reply, TransportError
27 27
from suds.plugin import MessagePlugin, DocumentPlugin
28 28

  
29
from suds.sudsobject import asdict
29
from requests.execptions import RequestException
30 30

  
31 31

  
32 32
class Filter(MessagePlugin):
......
73 73
    def send(self, request):
74 74
        request.message = request.message.replace("contentType", "xm:contentType")
75 75
        self.addcredentials(request)
76
        resp = self.model.requests.post(request.url, data=request.message,
76
        try:
77
            resp = self.model.requests.post(request.url, data=request.message,
77 78
                headers=request.headers, **self.get_requests_kwargs())
78
        return Reply(resp.status_code, resp.headers, resp.content)
79
        except(RequestException,) as e:
80
            raise TransportError(e.message.message, None)
81

  
82
        if resp.status_code in (202, 204):
83
            return None
84
        elif not resp.ok:
85
            raise TransportError(
86
                resp.reason,
87
                resp.status_code, fp=StringIO.StringIO(resp.content))
88
        else:
89
            return Reply(resp.status_code, resp.headers, resp.content)
79 90

  
80 91
def get_client(instance):
81 92
    transport = Transport(instance)
tests/test_iparapheur.py
154 154
    file_sent = os.path.join(os.path.dirname(__file__), 'data/iparapheur_test.pdf')
155 155
    assert resp.headers['Content-Type'] == 'application/pdf'
156 156
    assert hashlib.md5(resp.body[:8192]).hexdigest() == hashlib.md5(file(file_sent).read()[:8192]).hexdigest()
157

  
158

  
159
@mock.patch('passerelle.utils.LoggedRequest.get')
160
@mock.patch('passerelle.utils.LoggedRequest.post')
161
@mock.patch('passerelle.contrib.iparapheur.soap.HttpAuthenticated.open')
162
def test_invalid_response(http_open, mocked_post, mocked_get, setup, xmlmime, wsdl_file):
163
    app, conn = setup
164
    file_id = str(uuid.uuid4())
165

  
166
    http_open.return_value = file(xmlmime)
167
    mocked_get.return_value = mock.Mock(content = file(wsdl_file).read(),
168
                                            status_code=200)
169
    mocked_post.return_value = mock.Mock(status_code=502,
170
            content='<p>Bad Gateway</p>', reason='Bad Gateway', ok=False)
171
    url = reverse('generic-endpoint', kwargs={'slug': conn.slug,
172
                'connector': 'iparapheur', 'endpoint': 'get-file-status',
173
                'rest': file_id})
174
    resp = app.get(url)
175

  
176
    assert 'x-error-code' in dict(resp.headers)
177
    assert resp.json['err_desc'] == 'Invalid Response Content, XML expected'
157
-