toulouse-maelis: do not crash on tomcat unavailability (#74621) #256

Merged
nroche merged 1 commits from wip/74621-parsifal-receiving-html-content into main 2023-07-07 14:09:33 +02:00
3 changed files with 64 additions and 1 deletions

View File

@ -67,6 +67,10 @@ class SOAPValidationError(SOAPError):
http_status = 400
class SOAPInvalidContent(SOAPError):
log_error = False
class OperationProxyWrapper(OperationProxy):
def __call__(self, *args, **kwargs):
client = self._proxy._client
@ -82,6 +86,8 @@ class OperationProxyWrapper(OperationProxy):
raise SOAPValidationError(validation_error)
except ZeepError as zeep_error:
raise SOAPError(str(zeep_error))
except AttributeError as attribute_error:
raise SOAPInvalidContent(attribute_error)
class ServiceProxyWrapper(ServiceProxy):
@ -106,7 +112,10 @@ class SOAPClient(Client):
transport = transport_class(
resource, wsdl_url, session=session, cache=InMemoryCache(), **transport_kwargs
)
super().__init__(wsdl_url, transport=transport, **kwargs)
try:
super().__init__(wsdl_url, transport=transport, **kwargs)
except AttributeError as attribute_error:
raise SOAPInvalidContent(attribute_error)
def bind(self, *args, **kwargs):
service = super().bind(*args, **kwargs)

View File

@ -0,0 +1,15 @@
<!doctype html>

Il me semble qu’il y a eu erreur dans le copier-coller ici, un mélange du payload SOAP de la requête et de la réponse html de Tomcat. On a un <?xml …> suivi d’un bout de réponse serveur http 404.

Il me semble qu’il y a eu erreur dans le copier-coller ici, un mélange du payload SOAP de la requête et de la réponse html de Tomcat. On a un `<?xml …>` suivi d’un bout de réponse serveur http 404.

Oui, le bon header étant : <!doctype html>
Il est encore visible dans les logs sur le ticket lié.
j'ai dénaturé la réponse en la passant de mon linter, et du coup j'ai mal traité l'erreur.

J'ai corrigé, merci.
A noter que la sentry donne un cas où la 404 est envoyé après avoir reçu le WSDL (elle plante sur call).
Ici j'en ai profité pour ajouter aussi le cas où l'on a la 404 dès la réception du WSDL.

Oui, le bon header étant : <!doctype html> Il est encore visible dans les logs sur le ticket lié. j'ai dénaturé la réponse en la passant de mon linter, et du coup j'ai mal traité l'erreur. J'ai corrigé, merci. A noter que la sentry donne un cas où la 404 est envoyé après avoir reçu le WSDL (elle plante sur __call__). Ici j'en ai profité pour ajouter aussi le cas où l'on a la 404 dès la réception du WSDL.
<html lang="fr">
<head>
<title>État HTTP 404 Not Found</title>
<style type="text/css">...</style>
</head>
<body>
<h1>État HTTP 404 Not Found</h1>
<hr class="line"/>
<p><b>Type</b> Rapport d''état</p>
<p><b>description</b> La ressource demandée n''est pas disponible.</p>
<hr class="line"/>
<h3>Apache Tomcat/8.5.28</h3>
</body>
</html>

View File

@ -68,6 +68,7 @@ APE_SERVICE_WSDL = FakedResponse(content=get_wsdl_file('ApeService.wsdl'), statu
FAILED_AUTH = FakedResponse(content=get_xml_file('R_failed_authentication.xml'), status_code=500)
ISWSRUNNING_TRUE = FakedResponse(content=get_xml_file('R_is_ws_running.xml') % b'true', status_code=200)
ISWSRUNNING_FALSE = FakedResponse(content=get_xml_file('R_is_ws_running.xml') % b'false', status_code=200)
TOMCAT_ERROR = FakedResponse(content=get_xml_file('R_tomcat_error.html'), status_code=404)
def get_endpoint(name):
@ -354,6 +355,44 @@ def test_call_with_wrong_wsdl_url(mocked_get, con):
assert e.value.url == 'https://example.org/FamilyService?wsdl'
@mock.patch('passerelle.utils.Request.get')
def test_call_with_wrong_wsdl_content(mocked_get, con):
mocked_get.return_value = TOMCAT_ERROR
with pytest.raises(APIError, match="'NoneType' object has no attribute 'getroottree'"):
con.call('Family', 'isWSRunning')
@mock.patch('passerelle.utils.Request.get')
def test_call_with_wrong_wsdl_content_bis(mocked_get, con, app):
mocked_get.return_value = TOMCAT_ERROR
url = get_endpoint('get-baskets')
resp = app.get(url + '?family_id=1312')
assert resp.json['err'] == 1
assert resp.json['err_class'] == 'passerelle.utils.soap.SOAPInvalidContent'
assert "'NoneType' object has no attribute 'getroottree'" in resp.json['err_desc']
@mock.patch('passerelle.utils.Request.get')
@mock.patch('passerelle.utils.Request.post')
def test_call_with_wrong_soap_content(mocked_post, mocked_get, con):
mocked_get.return_value = FAMILY_SERVICE_WSDL
mocked_post.return_value = TOMCAT_ERROR
with pytest.raises(APIError, match="'NoneType' object has no attribute 'getroottree'"):
con.call('Family', 'isWSRunning')
@mock.patch('passerelle.utils.Request.get')
@mock.patch('passerelle.utils.Request.post')
def test_call_with_wrong_soap_content_bis(mocked_post, mocked_get, con, app):
mocked_get.return_value = ACTIVITY_SERVICE_WSDL
mocked_post.return_value = TOMCAT_ERROR
url = get_endpoint('get-baskets')
resp = app.get(url + '?family_id=1312')
assert resp.json['err'] == 1
assert resp.json['err_class'] == 'passerelle.utils.soap.SOAPInvalidContent'
assert "'NoneType' object has no attribute 'getroottree'" in resp.json['err_desc']
def test_call_with_wrong_credentials(family_service, con):
family_service.add_soap_response('isWSRunning', get_xml_file('R_failed_authentication.xml'), status=500)
with pytest.raises(