Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unexpected 413 - RequestEntityTooLarge response #2930

Closed
FuryFiber opened this issue Aug 2, 2024 · 3 comments
Closed

Unexpected 413 - RequestEntityTooLarge response #2930

FuryFiber opened this issue Aug 2, 2024 · 3 comments
Milestone

Comments

@FuryFiber
Copy link

FuryFiber commented Aug 2, 2024

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:

  • Python version: 3.10.12
  • Flask version: 3.0.3
@Dart-net
Copy link

Dart-net commented Aug 4, 2024

Hi! Your code has mutliple problems:

  • application/x-www-form-urlencoded content type is for text-based form data, use text data for application/x-www-form-urlencoded or switch to application/octet-stream for binary data
  • b"\x80" is not valid UTF-8 encoded data. In UTF-8 encoding, bytes must follow specific patterns.
    Exception comes from werkzeug in the _parse_urlencoded() method with this text UnicodeDecodeError('utf-8', b'\x80', 0, 1, 'invalid start byte'). Guys, do we need handle this case, even invalid request was provided ?

@pallets pallets temporarily blocked Dart-net Aug 4, 2024
@davidism davidism transferred this issue from pallets/flask Aug 5, 2024
Dart-net added a commit to Dart-net/werkzeug that referenced this issue Aug 5, 2024
Dart-net added a commit to Dart-net/werkzeug that referenced this issue Aug 5, 2024
@FuryFiber
Copy link
Author

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 davidism added this to the 3.0.4 milestone Aug 14, 2024
davidism pushed a commit to Dart-net/werkzeug that referenced this issue Aug 20, 2024
@davidism
Copy link
Member

davidism commented Aug 20, 2024

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. check max_content_length consistently #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 Do not apply max_form_parts to non-multipart data #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.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Sep 4, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants