Skip to content

Flask.send_file incorrectly sends blank files #3358

Description

@ColdHeat

Flask.send_file sends blank files when using io.StringIO in Python 3. There is a warning that this is wrong but the response code is still 200 but with a blank file.

Testing this behavior with a test_client will however still result in output. Which doesn't really make sense.

Related Info:
https://stackoverflow.com/questions/35710361/python-flask-send-file-stringio-blank-files

Expected Behavior

  • Flask.send_file should accept an io.StringIO file object and send it to the browser properly
  • Flask.send_file should 500 on the the request instead of a blank file
  • app.test_client shouldn't have data in this setup

Test Case:
Run in Python 3

import sys
if sys.version_info >= (3, 0):
    from io import StringIO
else:
    from StringIO import StringIO

from flask import Flask, send_file
import csv
app = Flask(__name__)

@app.route('/')
def hello_world():
    temp = StringIO()
    writer = csv.writer(temp)
    header = ['test', 'test']
    writer.writerow(header)

    temp.seek(0)

    return send_file(
        temp,
        as_attachment=True,
        cache_timeout=-1,
        attachment_filename="test.csv"
    )

app.test_client()

with app.test_client() as c:
    rv = c.get('/')
    print(rv.data)

app.run(debug=True, threaded=True, host="127.0.0.1", port=4000)
❯ python3 test_case.py
b'test,test\r\n'
 * Serving Flask app "test_case" (lazy loading)
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://127.0.0.1:4000/ (Press CTRL+C to quit)
 * Restarting with stat
b'test,test\r\n'
 * Debugger is active!
 * Debugger PIN: 881-854-930
127.0.0.1 - - [10/Sep/2019 02:15:54] "GET / HTTP/1.1" 200 -
Error on request:
Traceback (most recent call last):
  File "/Users/kchung/.virtualenvs/ctfd3/lib/python3.7/site-packages/werkzeug/serving.py", line 303, in run_wsgi
    execute(self.server.app)
  File "/Users/kchung/.virtualenvs/ctfd3/lib/python3.7/site-packages/werkzeug/serving.py", line 294, in execute
    write(data)
  File "/Users/kchung/.virtualenvs/ctfd3/lib/python3.7/site-packages/werkzeug/serving.py", line 274, in write
    assert isinstance(data, bytes), "applications must write bytes"
AssertionError: applications must write bytes
❯ curl -vvv http://localhost:4000
* Rebuilt URL to: http://localhost:4000/
*   Trying ::1...
* TCP_NODELAY set
* Connection failed
* connect to ::1 port 4000 failed: Connection refused
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 4000 (#0)
> GET / HTTP/1.1
> Host: localhost:4000
> User-Agent: curl/7.54.0
> Accept: */*
>
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Content-Disposition: attachment; filename=test.csv
< Content-Type: text/csv; charset=utf-8
< Cache-Control: public, max-age=-1
< Expires: Tue, 10 Sep 2019 06:29:28 GMT
< Connection: close
< Server: Werkzeug/0.15.6 Python/3.7.4
< Date: Tue, 10 Sep 2019 06:29:29 GMT
<
* Closing connection 0

Actual Behavior

  • With Python 3 Hitting the endpoint in a browser results in an empty file but in the test_client there is a data response.

Environment

  • Python version: 3.7.4
  • Flask version: 1.1.1
  • Werkzeug version: 0.15.3

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions