pallets / werkzeug

The comprehensive WSGI web application library.
https://werkzeug.palletsprojects.com
BSD 3-Clause "New" or "Revised" License
6.66k stars 1.73k forks source link

Unexpected 413 - RequestEntityTooLarge response #2930

Closed FuryFiber closed 3 months ago

FuryFiber commented 3 months ago

Bug

When sending non utf-8 bytes into a form the flask server responds with 413 - RequestEntityTooLarge. This does not seem like the appropriate http error to return in this case. This happens when using a flask app however it might be a bug in werkzeug.

Reproduce unexpected behaviour:

app.py:

from flask import *

app = Flask(__name__)

@app.route("/", methods=["GET", "POST"])
def home():
    if request.method == "POST":
        print(request.form["name"])
        print(request.form["email"])

    return render_template("home.html")

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

home.html:

<h1>
    This is home.html
</h1>

<form method="post">

    Name: <input name="name"/>

    <br/><br/>

    Email: <input name="email"/>

    <br/><br/>

    <button type="submit">Submit</button>
</form>

bug.py:

import requests

if __name__ == '__main__':
    response1 = requests.post(
        'http://localhost:5000',
        b'\x80',
        headers={'Content-Type':'application/x-www-form-urlencoded', 'Content-Length':str(len(b'\x80'))}
    )
    print("response with only \x80 in content: " + str(response1.status_code) + "\n")
    response2 = requests.post(
        'http://localhost:5000',
        b'name=john&email=doe\x80',
        headers={'Content-Type': 'application/x-www-form-urlencoded', 'Content-Length': str(len(b'\x80'))}
    )
    print("response with \x80 added to correctly formatted response in content: " + str(response2.status_code))

Environment:

Dart-net commented 3 months ago

Hi! Your code has mutliple problems:

FuryFiber commented 3 months ago

Yes i am aware that what i do here is never really supposed to happen. However i still feel like the error that is returned is not the correct one.

davidism commented 3 months ago

After looking at the history of this code, and PR #2931 from @Dart-net, I've realized that this is a symptom of a different issue.

  1. 2620 updated the parser for both multipart/form-data and application/x-www-form-urlencoded to raise RequestEntityTooLarge if there were too many fields.

  2. It was later noted that urlencoded forms don't suffer the same parse issue as multipart and didn't need this limit. The limit argument was removed in #2694, but the except ValueError was kept.
  3. bytes.decode() can raise UnicodeDecodeError, which is a subclass of ValueError, so it was being caught and turned into a ReequestEntityTooLarge error incorrectly.
  4. But prior to all these changes, an outer method in the parser already discarded ValueError if silent=False (the default).

Therefore, to actually revert to the prior behavior, we should have remove the except ValueError: raise RequestEntityTooLarge, and the code would have gone back to ignoring completely invalid data.