3
from flask import Flask, request, jsonify
from werkzeug.utils import secure_filename


app = Flask(__name__)
app.config['MAX_CONTENT_LENGTH'] = 16 * 1000 * 1000


ALLOWED_EXTENSIONS = [".pdf", ".PDF"]


def allowed_file(filename):
    return "." in filename and filename.rsplit(".", 1)[1].lower() in ALLOWED_EXTENSIONS


@app.route("/upload-pdf", methods=["POST"])
def upload_pdf():
    # check if the post request has the file partx
    if "file" not in request.files:
        resp = jsonify({"message": "No file part in the request"})
        resp.status_code = 400
        return resp
    file = request.files["file"]
    if file.filename == "":
        resp = jsonify({"message": "No file selected for uploading"})
        resp.status_code = 400
        return resp
    if file and allowed_file(file.filename):
        filename = secure_filename(file.filename)
        print(type(filename))
        # file.save(os.path.join(app.config["UPLOAD_FOLDER"], filename))
        resp = jsonify({"message": "File successfully uploaded"})
        resp.status_code = 201
    else:
        resp = jsonify(
            {"message": "Allowed file types are pdf"}
        )
        resp.status_code = 400
    return resp


if __name__ == "__main__":
    app.run()

This is my code. BUt when I run python app.py and the curl command curl -d @it_return_2020_21.pdf http://127.0.0.1:5000/upload-pdf. I get <title>413 Request Entity Too Large</title>. The file I am trying to upload is 275 kb.

Echchama Nayak
  • 971
  • 3
  • 23
  • 44

2 Answers2

1

A careful reading of the documentation for request.files shows that this only works with multipart/form-data content. See the documentation excerpt below (emphasis mine)

property files: ImmutableMultiDict[str, FileStorage]

MultiDict object containing all uploaded files. Each key in files is the name from the . Each value in files is a Werkzeug FileStorage object.

It basically behaves like a standard file object you know from Python, with the difference that it also has a save() function that can store the file on the filesystem.

Note that files will only contain data if the request method was POST, PUT or PATCH and the that posted to the request had enctype="multipart/form-data". It will be empty otherwise.

See the MultiDict / FileStorage documentation for more details about the used data structure.

Using curl -d @filename URI as you indicated above sends a request with content-type application/x-www-form-urlencoded. Add a bunch of verbose flags to curl to see this (-vvv should do the trick).

If, instead, you use the form data flag -F it_return_2020_21.pdf=@it_return_2020_21.pdf, you should see your expected results.

I'm able to reproduce the error with some dummy data:

$ flask run
$ dd if=/dev/urandom of=file.pdf bytes=1024 count=2
$ curl -d @file.pdf http://localhost:5000/upload-pdf
$ # observe the error
$ curl -F file.pdf=@file.pdf http://localhost:5000/upload-pdf
$ # observe a 400 instead, because my data is malformed (expected, it's random bytes!)
Adam Smith
  • 52,157
  • 12
  • 73
  • 112
  • Looks like you could include a CONTENT_LENGTH header with your request to get around this, or just change your default configuration. – Adam Smith Jul 10 '23 at 06:12
1
curl -d @it_return_2020_21.pdf http://127.0.0.1:5000/upload-pdf

When you use -d or --data with curl, it sends the data as the request body with the content-type application/x-www-form-urlencoded, which is not appropriate for file uploads.

In contrast, Flask's request.files looks for files sent as multipart/form-data (as illustrated here).
You should use the -F or --form option in curl to send the file correctly:

curl -F "file=@it_return_2020_21.pdf" http://127.0.0.1:5000/upload-pdf

This command should correctly upload your file to the Flask application:

  • The -F option tells curl to POST data using the Content-Type multipart/form-data, which is the correct type for file uploads.
  • The file=@it_return_2020_21.pdf part tells curl to include a form field named file, and to read the content from the file it_return_2020_21.pdf.
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250