Projet

Général

Profil

Development #40974

Greco (suds) : gérer les erreurs de transport http

Ajouté par Thomas Noël il y a environ 4 ans. Mis à jour il y a environ 4 ans.

Statut:
Fermé
Priorité:
Normal
Assigné à:
-
Version cible:
-
Début:
24 mars 2020
Echéance:
% réalisé:

0%

Temps estimé:
Patch proposed:
Oui
Planning:
Non

Description

En cas de pépin http (par exemple 502), suds renvoie juste None et ça n'aide pas à la compréhension du soucis par l'appelant.


Fichiers

Révisions associées

Révision 54c64ec7 (diff)
Ajouté par Thomas Noël il y a environ 4 ans

greco: raise APIError on http transport error (#40974)

Historique

#1

Mis à jour par Thomas Noël il y a environ 4 ans

Ce patch est la seule idée que j'ai : en cas de pépin autre qu'une erreur SOAP normale (500), on créée une pseudo-erreur SOAP...

Mais
  • ça ne donne pas le code d'erreur tel quel (et donc ce n'est pas ce qui est demandé) :
{'err': 1, 'err_desc': "error: Server raised fault: 'http transport error 503'", 'data': None, 'err_class': u'passerelle.utils.jsonresponse.APIError'}
  • et surtout le test ajouté montre aussi que Greco ne passe par en py3 :
      File "/home/thomas/dev/publik/src/passerelle/passerelle/contrib/greco/models.py", line 125, in send
        request.message = request.message.replace("contentType", "xm:contentType")
    TypeError: a bytes-like object is required, not 'str'
    

et donc c'est plutôt une piste qu'une solution. Qu'en pensez-vous ?

#3

Mis à jour par Emmanuel Cazenave il y a environ 4 ans

Pourquoi tu raises pas une APIError directement (ce qui permettrait d'avoir le statut dans le message)?

Pour py3 à part passer à SUDS, je vois pas.

#4

Mis à jour par Benjamin Dauvergne il y a environ 4 ans

Emmanuel Cazenave a écrit :

Pour py3 à part passer à SUDS, je vois pas.

Et mettre des b"" ?

#5

Mis à jour par Thomas Noël il y a environ 4 ans

Emmanuel Cazenave a écrit :

Pourquoi tu raises pas une APIError directement (ce qui permettrait d'avoir le statut dans le message)?

On est au fin fond de suds et je ne suis pas sûr que les exceptions remontent bien... mais en fait j'ai même pas testé ! Suis-je bête... j'y fonce.

Pour py3 à part passer à SUDS, je vois pas.

Passer à Zeep, tu veux dire ? Le problème est pas tellement là, c'est surtout que Greco c'est du SOAP bidouillé. Mais on va pas y couper, et sans doute que passer à Zeep serait bcp moins bête.

#6

Mis à jour par Thomas Noël il y a environ 4 ans

Voici donc une solution simple, APIError étant bien "remontée" tranquillement au travers de suds.

Mini patch 0001 pour que le test passe également en py3 (sans garantir que le connecteur dans son ensemble tourne en py3, la couverture est minimale, autre sujet, autre ticket, autre patch)

#7

Mis à jour par Frédéric Péters il y a environ 4 ans

Inclure également status_code dans le libellé de l'APIError ?

Une raison pour ignorer l'erreur 500 ?

#8

Mis à jour par Benjamin Dauvergne il y a environ 4 ans

Frédéric Péters a écrit :

Une raison pour ignorer l'erreur 500 ?

Ça peut contenir un vrai message (soap:Fault), mais doit y avoir moyen de différencier (genre juste chercher "Fault" dans le contenu de la réponse).

#9

Mis à jour par Thomas Noël il y a environ 4 ans

Benjamin Dauvergne a écrit :

Frédéric Péters a écrit :

Une raison pour ignorer l'erreur 500 ?

Ça peut contenir un vrai message (soap:Fault), mais doit y avoir moyen de différencier (genre juste chercher "Fault" dans le contenu de la réponse).

Ouaip, je vois mal comment ça pourrait arriver (une 500 c'est l'appli qui la produit, en général l'appli c'est le front SOAP) mais on ne sait jamais. J'ai donc ajouté le test proposé par Benjamin.

Ajouté aussi le status_code dans le message de l'APIError :

+                if resp.status_code >= 400 and resp.status_code != 500:
+                    raise APIError('HTTP Transport Error %s' % resp.status_code,
+                                   err_code='transport-error-%s' % resp.status_code)
+                elif resp.status_code == 500 and 'Fault' not in resp.content:
+                    raise APIError('Error 500, not a SOAP Fault',
+                                   err_code='transport-error-500')
#10

Mis à jour par Benjamin Dauvergne il y a environ 4 ans

Thomas Noël a écrit :

Ouaip, je vois mal comment ça pourrait arriver (une 500 c'est l'appli qui la produit, en général l'appli c'est le front SOAP) mais on ne sait jamais. J'ai donc ajouté le test proposé par Benjamin.

Y a visiblement des serveurs SOAP qui répondent une Fault dans une 500, si ça se trouve c'est même préconisé par la spec (je vais regarder).

PS: et oui https://www.ibm.com/support/pages/soap-faults-must-be-sent-http-500-error-code

Ajouté aussi le status_code dans le message de l'APIError :

[...]

Il me semble que resp.content en py3 c'est un bytes et donc 'Fault' in resp.content ne fonctionnera pas, b'Fault' in resp.content devrait fonctionner en py2 et py3.

#11

Mis à jour par Benjamin Dauvergne il y a environ 4 ans

  • Statut changé de Solution proposée à Information nécessaire
#12

Mis à jour par Thomas Noël il y a environ 4 ans

  • Statut changé de Information nécessaire à Solution proposée

C'est effectivement bien vu, j'ai envoyé sur la branche cet amendement :

@@ -183,7 +183,7 @@ class Greco(BaseResource):
                 if resp.status_code >= 400 and resp.status_code != 500:
                     raise APIError('HTTP Transport Error %s' % resp.status_code,
                                    err_code='transport-error-%s' % resp.status_code)
-                elif resp.status_code == 500 and 'Fault' not in resp.content:
+                elif resp.status_code == 500 and b'Fault' not in resp.content:
                     raise APIError('Error 500, not a SOAP Fault',
                                    err_code='transport-error-500')
                 return Reply(resp.status_code, resp.headers, resp.content)
#13

Mis à jour par Benjamin Dauvergne il y a environ 4 ans

  • Statut changé de Solution proposée à Solution validée
#14

Mis à jour par Benjamin Dauvergne il y a environ 4 ans

Dans le même style j'étais pas fan du force_text() inutile (voir remarque plus haut).

#15

Mis à jour par Thomas Noël il y a environ 4 ans

Benjamin Dauvergne a écrit :

Dans le même style j'étais pas fan du force_text() inutile (voir remarque plus haut).

Pas compris, je peux bien une explication (je suis pas encore bien doué sur ces affaires)

#16

Mis à jour par Benjamin Dauvergne il y a environ 4 ans

Thomas Noël a écrit :

Benjamin Dauvergne a écrit :

Dans le même style j'étais pas fan du force_text() inutile (voir remarque plus haut).

Pas compris, je peux bien une explication (je suis pas encore bien doué sur ces affaires)

Ici:

    request.message = request.message.replace("contentType", "xm:contentType")

Si request.message est toujours str/bytes (py2/py3) (j'en ai l'intuition peut-être fausse) alors on peut écrire :

    request.message = request.message.replace(b'contentType', b'xm:contentType')

C'est plus clair que force_text qui laisse à penser qu'on sait pas trop ce qu'on y trouve.

#17

Mis à jour par Thomas Noël il y a environ 4 ans

  • Statut changé de Solution validée à Résolu (à déployer)

Poussé avec :

-                request.message = request.message.replace("contentType", "xm:contentType")
+                request.message = request.message.replace(b"contentType", b"xm:contentType")

à la place du force_text, merci Benjamin.

commit 2069bcf80f212bc74a71521f00365dca2df7b80e
Author: Thomas NOEL <tnoel@entrouvert.com>
Date:   Wed Mar 25 01:51:18 2020 +0100

    greco: replace bytes in request.message

commit 54c64ec747f191ee485c15627e3e5ea33f00f238
Author: Thomas NOEL <tnoel@entrouvert.com>
Date:   Tue Mar 24 15:50:58 2020 +0100

    greco: raise APIError on http transport error (#40974)

#18

Mis à jour par Frédéric Péters il y a environ 4 ans

  • Statut changé de Résolu (à déployer) à Solution déployée

Formats disponibles : Atom PDF