aws / aws/aws-xray-sdk-python

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

Offen
#405 1 Kommentar 1 Reaktion 0 zugewiesene Personen Auf GitHub ansehen
Vorherrschende Sprache
Python
Sterne
338
Forks
147
PR-Merge-Kennzahlen
Keine gemergten PRs in 30 T.

Beschreibung

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).

Beitragsleitfaden

Beitragsleitfaden öffnen

Rechercherichtung

Beginne mit aws_xray_sdk/ext/flask/middleware.py rund um den verlinkten after_request-Handler und überprüfe anschließend das im Issue beschriebene Verhalten bei der Reihenfolge von Flask-Erweiterungen sowie die verlinkte Dokumentation. Führe die beigefügte Reproduktion mit app.py und ihren requirements aus, um den Fehler zu bestätigen. Erledigt ist die Aufgabe, wenn die Anfrage mit der erwarteten Bad Request-Antwort abgeschlossen wird und die Flask-Anleitung das Problem mit der Reihenfolge abdeckt.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
aws, docker, flask, python
Bereich
backend, documentation, observability-sre
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Veraltet
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
45/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.