Auto-redirects breaks the connection
hbusul opened this issue · 4 comments
If you send a multi-part body request to the incorrect URL(when you forget a "/" at the end of URL eg), you will get redirected automatically. And it breaks the connection with uwsgi.
I believe because it does not read the whole request body and it is required by uwsgi that the application needs to read the request body.
I get the file upload from the examples for Flask:
import os
from flask import Flask, flash, request, redirect, url_for
from werkzeug.utils import secure_filename
import logging
UPLOAD_FOLDER = './upload'
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['SECRET_KEY'] = "Your_secret_string"
@app.route('/stg/', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
# check if the post request has the file part
if 'file' not in request.files:
flash('No file part')
app.logger.warning('no file part')
return redirect(request.url)
file = request.files['file']
# If the user does not select a file, the browser submits an
# empty file without a filename.
if file.filename == '':
flash('No selected file')
app.logger.warning('empty filename')
return redirect(request.url)
if file:
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return redirect(request.url)
return '''
<!doctype html>
<title>Upload new File</title>
<h1>Upload new File</h1>
<form method=post enctype=multipart/form-data>
<input type=file name=file>
<input type=submit value=Upload>
</form>
'''
Serve this using uWSGI, we had nginx in front of the uWSGI but I realized it does not matter
if you use the http mode in uWSGI as well. Then cURL a file:
curl -X POST -F "file=@yourfile.stg" http://localhost/stg
and in the nginx logs you get either a readv error
2023/11/03 15:02:45 [error] 397765#397765: *19 readv() failed (104: Connection reset by peer) while reading upstream, client: 127.0.0.1, server: , request: "POST /stg HTTP/1.1", upstream: "uwsgi://127.0.0.1:5555", host: "localhost"
or if you increase the file size a broken pipe
2023/11/03 15:02:53 [error] 397766#397766: *21 sendfile() failed (32: Broken pipe) while sending request to upstream, client: 127.0.0.1, server: , request: "POST /stg HTTP/1.1", upstream: "uwsgi://127.0.0.1:5555", host: "localhost"
Also if you use uWSGI in http mode, you get
[uwsgi-http key: localhost:5555 client_addr: 127.0.0.1 client_port: 11401] hr_instance_read(): Connection reset by peer [plugins/http/http.c line 647]
I would expect after the redirection that there would be no errors since there is no extraordinary situation here, the user just mistyped the URL(I realized this issue when I mistyped an URL)
Environment:
- Python version: 3.11.4
- Flask version: 2.3.3
Edit: First I thought it was an issue with some configuration we had etc so I asked it in, https://stackoverflow.com/questions/77411368/does-flask-consume-request-body-on-redirects but when I realize that it was possible to reproduce it with such a small example, I thought that it must be a bug or stg.
These notices are fine. The connection stopped because one side or other closed the connection and started something else. With curl, you also need to tell it to follow redirects with -L
, otherwise it just stops. And this seems like a uWSGI issue, it advertises to Flask that it terminates the input stream, so if it's not doing so report that there.
There's nothing for Flask to do there. Flask will not go farther than it already does to handle request bodies, you can search closed issues on Flask and Werkzeug to see the very long history and discussion.
Yeah, I know it does not follow redirects but doing -L
still does not change the fact that with large enough files client gets a 502. If I try it with -L
then I get
2023/11/03 15:36:46 [error] 397767#397767: *23 sendfile() failed (32: Broken pipe) while sending request to upstream, client: 127.0.0.1, server: , request: "POST /stg HTTP/1.1", upstream: "uwsgi://127.0.0.1:5555", host: "localhost"
and from the cURL
<html>
<head><title>502 Bad Gateway</title></head>
<body>
<center><h1>502 Bad Gateway</h1></center>
<hr><center>nginx/1.24.0</center>
</body>
</html>
Also quoting the uWSGI:
If an HTTP request has a body (like a POST request generated by a form), you have to read (consume) it in your application. If you do not do this, the communication socket with your webserver may be clobbered. If you are lazy you can use the post-buffering option that will automatically read data for you. For Rack applications this is automatically enabled.
Well I do not know if it is required specifically by uWSGI or is this requirement also part of the WSGI. Cause if latter, then it would make it a Flask bug I assume.
Our reading of the WSGI spec is that the WSGI server is in charge of handling connections and data in them. There is no way in general for Flask / the WSGI application to handle this without causing other issues, the WSGI server must.
I see, that's not a show-stopper for us since everything else works like a charm when using uWSGI. But thanks for clarification that I'm not doing anything wrong but this is somehow expected behavior when we use uWSGI with Flask. But to be fair, it is also kind of interesting as uWSGI makes that remark that the application must read it and here application makes the remark that they won't read it. Guess not much to do here, thanks for your time.