Connexion: Exception when calling flask.abort() with mod_wsgi and connexion 1.1.6+

Created on 5 Apr 2017  Â·  7Comments  Â·  Source: zalando/connexion

Description

After upgrading to connexion 1.1.6 and 1.1.7 from connexion 1.1.5, I get an exception (error 500) when calling flask.abort(...) on servers using mod_wsgi + Apache + Python 3.4. I cannot reproduce the problem in my local development machine (I don't have Apache installed, tried with uwsgi and flask development server and it works fine on both of them).

Expected behaviour

Return a nice error message, example:

{
    "detail": "Please authenticate first (send authorization header with a valid token or apikey)", 
    "status": 401, 
    "title": "Unauthorized", 
    "type": "about:blank"
}

Actual behaviour

[Wed Apr 05 00:56:11.722938 2017] [:error] [pid 8604] (Dummy-1) connexion.apis.flask_api - DEBUG - Getting data and status code
[Wed Apr 05 00:56:11.723226 2017] [:error] [pid 8604] (Dummy-1) connexion.apis.flask_api - DEBUG - Got data and status code (401)
[Wed Apr 05 00:56:11.723547 2017] [:error] [pid 8604] [remote 172.31.8.224:11951] mod_wsgi (pid=8604): Exception occurred processing WSGI script '/opt/python/current/app/application.py'.
[Wed Apr 05 00:56:11.723581 2017] [:error] [pid 8604] [remote 172.31.8.224:11951] Traceback (most recent call last):
[Wed Apr 05 00:56:11.723631 2017] [:error] [pid 8604] [remote 172.31.8.224:11951]   File "/opt/python/run/venv/lib/python3.4/site-packages/flask/app.py", line 1997, in __call__
[Wed Apr 05 00:56:11.723636 2017] [:error] [pid 8604] [remote 172.31.8.224:11951]     return self.wsgi_app(environ, start_response)
[Wed Apr 05 00:56:11.723657 2017] [:error] [pid 8604] [remote 172.31.8.224:11951]   File "/opt/python/run/venv/lib/python3.4/site-packages/flask/app.py", line 1989, in wsgi_app
[Wed Apr 05 00:56:11.723661 2017] [:error] [pid 8604] [remote 172.31.8.224:11951]     return response(environ, start_response)
[Wed Apr 05 00:56:11.723695 2017] [:error] [pid 8604] [remote 172.31.8.224:11951]   File "/opt/python/run/venv/lib/python3.4/site-packages/werkzeug/wrappers.py", line 1277, in __call__
[Wed Apr 05 00:56:11.723701 2017] [:error] [pid 8604] [remote 172.31.8.224:11951]     start_response(status, headers)
[Wed Apr 05 00:56:11.723719 2017] [:error] [pid 8604] [remote 172.31.8.224:11951] ValueError: status message was not supplied

Steps to reproduce

  • Use mod_wsgi
  • Call flask.abort()

Additional info:

As soon as I have more information, I update this post.

Output of the commands:

  • python --version

Python 3.4.3

  • pip show connexion | grep "^Version\:"

Version: 1.1.6

bug

All 7 comments

Shot in the dark here, but I've seen similar issues in other libraries before which stemmed from propagate exceptions being turned on in the development server, but off during production. Are you running with app.debug=True on your development​ setup? If you turn that to false, do you get the same errors you do in your production server?

Ok, I think I've found the problem. Connexion 1.1.6+ omits the HTTP Reason-Phrase (only when calling flask.abort() or connexion.problem()).

Before (1.1.5):

$ curl -v 127.0.0.1:8080/v1/playlists
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
> GET /v1/playlists HTTP/1.1
> Host: 127.0.0.1:8080
> User-Agent: curl/7.50.1
> Accept: */*
> 
* HTTP 1.0, assume close after body
< HTTP/1.0 401 UNAUTHORIZED
< Content-Type: application/problem+json
< Content-Length: 170
< Access-Control-Allow-Origin: *
< Server: Werkzeug/0.12.1 Python/3.5.2+
< Date: Wed, 05 Apr 2017 02:08:35 GMT
< 
{
  "detail": "Please authenticate first (send authorization header with a valid token or apikey)",
  "status": 401,
  "title": "Unauthorized",
  "type": "about:blank"
}
* Closing connection 0

After (1.1.7):

$ curl -v 127.0.0.1:8080/v1/playlists
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
> GET /v1/playlists HTTP/1.1
> Host: 127.0.0.1:8080
> User-Agent: curl/7.50.1
> Accept: */*
> 
* HTTP 1.0, assume close after body
< HTTP/1.0 401 
< Content-Type: application/problem+json
< Content-Length: 170
< Access-Control-Allow-Origin: *
< Server: Werkzeug/0.12.1 Python/3.5.2+
< Date: Wed, 05 Apr 2017 02:09:06 GMT
< 
{
  "detail": "Please authenticate first (send authorization header with a valid token or apikey)",
  "status": 401,
  "title": "Unauthorized",
  "type": "about:blank"
}
* Closing connection 0

Look at HTTP/1.0 401 line.
mod_wsgi throws an error when there is no HTTP reason message.
Is this expected behavior from connexion?

EDIT:
This is the source of my exception: https://github.com/GrahamDumpleton/mod_wsgi/blob/3.5/mod_wsgi.c#L3071

Changing this line fixes my problem:
https://github.com/zalando/connexion/blob/1.1.7/connexion/apis/flask_api.py#L187

From:

if status_code is not None:
    flask_response.status = str(status_code)

To:

if status_code is not None:
    flask_response.status_code = status_code

@hjalves thanks, do you mind doing a PR?

@hjalves What version of Werkzeug are you using? Changing the line your mentioned break many tests.

@rafaelcaricio I'm using Werkzeug==0.12.1.

@rafaelcaricio Really? Did you change flask_response.status or flask_response.status_code?
Changing flask_response.status causes many errors, as status is expected to be a string.

@hjalves I didn't change the status -> status_code. Thank you for the PR! 😉

Was this page helpful?
0 / 5 - 0 ratings