aws / aws/aws-xray-sdk-python

Flask middleware errors when an earlier Flask extension throws an exception in a before_request method

Abierto
#405 1 comentario 1 reacción 0 asignados Ver en GitHub
Lenguaje dominante
Python
Estrellas
338
Forks
147
Métricas de merge de PR
Sin PR fusionados en 30 d

Descripción

If the Flask middleware is configured after another extension, and that extension throws an exception in a before_request method, the Flask middleware throws an exception in its after_request method.

```
File "/home/sam/.pyenv/versions/3.9.7/envs/flask-test-2-3.9.7/lib/python3.9/site-packages/flask/app.py", line 1508, in finalize_request
response = self.process_response(response)
File "/home/sam/.pyenv/versions/3.9.7/envs/flask-test-2-3.9.7/lib/python3.9/site-packages/flask/app.py", line 2002, in process_response
response = self.ensure_sync(func)(response)
File "/home/sam/.pyenv/versions/3.9.7/envs/flask-test-2-3.9.7/lib/python3.9/site-packages/aws_xray_sdk/ext/flask/middleware.py", line 74, in _after_request
segment.put_http_meta(http.STATUS, response.status_code)
AttributeError: 'NoneType' object has no attribute 'put_http_meta'
cannot find the current segment/subsegment, please make sure you have a segment open
```

This does not happen if the Flask middleware is configured before other extensions.

The root cause appears to be that when an extension throws an exception in a before_request method, processing of subsequent before request methods is suppressed, but after_request methods are still executed.

I think there's two things needed to do to resolve this:

* Make it clear in https://docs.aws.amazon.com/xray-sdk-for-python/latest/reference/frameworks.html#flask that Flask should be the first extension configured.
* In the [after_request handler](https://github.com/aws/aws-xray-sdk-python/blob/2976b25750d04ebe6dc7d0a3e399444896e82cae/aws_xray_sdk/ext/flask/middleware.py#L69), handle the current segment or subsegment being None without raising an exception.

Note that even if the after_request handler doesn't raise an exception, having other middleware prevent the Flask middleware's before_request method from executing is a problem, because it means that you will not get X-Ray traces when this happens. I suggest that the after_request handler should log a warning or error explaining the problem if the current segment or subsegment is None.

I've attached [a reproduction](https://github.com/aws/aws-xray-sdk-python/files/12655504/reproduction.zip). This relies on the fact that Flask-WTF throws an exception to indicate a bad request when a CSRF token is missing from a request that requires one. To reproduce the bug:

* Unzip the zip to a directory.
* Install the requirements using pip install -r requirements.txt.
* In one shell, build and run the local X-Ray agent using `docker build -t xray-daemon . && docker run --rm --attach STDOUT -v ~/.aws/:/root/.aws/:ro --net=host -e AWS_PROFILE=PROFILE_NAME--name xray-daemon -p 2000:2000/udp xray-daemon -o` where PROFILE_NAME is a valid AWS profile that can talk to X-Ray (obviously skip this if you have a better way to get a local X-Ray daemon running).
* In another shell, run the Flask application using `gunicorn -b 0.0.0.0:8080 app:app`.
* In a third shell, make a POST command using `curl -X POST http://localhost:8080/post`.
* You will see the exception in the Flask application.

You can see that ordering matters by swapping the following two lines in app.py:

```
csrf = CSRFProtect(app)
XRayMiddleware(app, xray_recorder)
```

If the XRayMiddleware is initialised first, the request will succeed, and you'll see the Bad Request error that you should (because the request does not have a CSRF token).

Guía de contribución

Abrir la guía de contribución

Línea de trabajo

Comienza con aws_xray_sdk/ext/flask/middleware.py alrededor del handler after_request enlazado; después, revisa el comportamiento del orden de las extensiones de Flask descrito en el issue y la documentación enlazada. Ejecuta la reproducción adjunta con app.py y sus requirements para confirmar el fallo. Se considera terminado cuando la solicitud se completa con la respuesta Bad Request esperada y la guía de Flask cubre el problema de orden.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
aws, docker, flask, python
Área
backend, documentation, observability-sre
Tipo de issue
Error
Dificultad
4/5
Tiempo estimado
3-5 días
Estado de actividad
Estancado
Claridad
Bastante claro
Aptitud para principiantes
45/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.