gunicorn
gunicorn copied to clipboard
Gunicorn generates exception for malformed Client chunked request
Description
The server is a simple Flask application using werkzeug and gunicorn. I am using telnet for the client. When the client sends a malformed request, Werkzeug does not return 400. Instead, it generates an exception and causes an 500 to be returned.
Note: a similar bug for werkzeug is reported in https://github.com/pallets/werkzeug/issues/2469
Reproducing
- Install Flask and gunicorn using
python3 -m pip install flask gunicorn
- Copy the following to
myproject.py
:from flask import Flask, request app = Flask(__name__) @app.route("/", methods=['POST']) def hello(): return "Hello %s" % ('file' in request.files) if __name__ == "__main__": app.run()
- Copy the following to
wsgi.py
:from myproject import app if __name__ == "__main__": app.run()
- Run
python3 -m gunicorn wsgi:app
to start gunicorn - Run
telnet 127.0.0.1 8000
, copy the following content to telnet, then press Enter a few timesPOST / HTTP/1.1 Host: localhost:8000 User-Agent: curl/7.79.1 Accept: */* Transfer-Encoding: chunked Content-Type: multipart/form-data; boundary=----abcd Expect: 100-continue ----abcd
- See 500 from telnet
- See traceback in Flask below
[2022-07-25 22:45:00,850] ERROR in app: Exception on / [POST]
Traceback (most recent call last):
File "/usr/local/lib/python3.10/dist-packages/gunicorn/http/body.py", line 90, in parse_chunk_size
chunk_size = int(chunk_size, 16)
ValueError: invalid literal for int() with base 16: b'----abcd'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/local/lib/python3.10/dist-packages/flask/app.py", line 2073, in wsgi_app
response = self.full_dispatch_request()
File "/usr/local/lib/python3.10/dist-packages/flask/app.py", line 1519, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/usr/local/lib/python3.10/dist-packages/flask/app.py", line 1517, in full_dispatch_request
rv = self.dispatch_request()
File "/usr/local/lib/python3.10/dist-packages/flask/app.py", line 1503, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
File "/myproject.py", line 6, in hello
return "Hello %s" % ('file' in request.files)
File "/usr/local/lib/python3.10/dist-packages/werkzeug/utils.py", line 109, in __get__
value = self.fget(obj) # type: ignore
File "/usr/local/lib/python3.10/dist-packages/werkzeug/wrappers/request.py", line 480, in files
self._load_form_data()
File "/usr/local/lib/python3.10/dist-packages/flask/wrappers.py", line 112, in _load_form_data
super()._load_form_data()
File "/usr/local/lib/python3.10/dist-packages/werkzeug/wrappers/request.py", line 266, in _load_form_data
data = parser.parse(
File "/usr/local/lib/python3.10/dist-packages/werkzeug/formparser.py", line 263, in parse
return parse_func(self, stream, mimetype, content_length, options)
File "/usr/local/lib/python3.10/dist-packages/werkzeug/formparser.py", line 140, in wrapper
return f(self, stream, *args, **kwargs)
File "/usr/local/lib/python3.10/dist-packages/werkzeug/formparser.py", line 290, in _parse_multipart
form, files = parser.parse(stream, boundary, content_length)
File "/usr/local/lib/python3.10/dist-packages/werkzeug/formparser.py", line 418, in parse
for data in iterator:
File "/usr/local/lib/python3.10/dist-packages/werkzeug/wsgi.py", line 691, in _make_chunk_iter
item = _read(buffer_size)
File "/usr/local/lib/python3.10/dist-packages/gunicorn/http/body.py", line 215, in read
data = self.reader.read(1024)
File "/usr/local/lib/python3.10/dist-packages/gunicorn/http/body.py", line 30, in read
self.buf.write(next(self.parser))
File "/usr/local/lib/python3.10/dist-packages/gunicorn/http/body.py", line 58, in parse_chunked
(size, rest) = self.parse_chunk_size(unreader)
File "/usr/local/lib/python3.10/dist-packages/gunicorn/http/body.py", line 92, in parse_chunk_size
raise InvalidChunkSize(chunk_size)
gunicorn.http.errors.InvalidChunkSize: Invalid chunk size: b'----abcd'
Expected behavior
400 should be returned to the client, because the client sends a bad request.
Environment
- Python version: 3.10.4
- Gunicorn version: 20.1.0
- All packages installed by pip:
Jinja2-3.1.2 MarkupSafe-2.1.1 Werkzeug-2.2.0 click-8.1.3 flask-2.1.3 itsdangerous-2.1.2 gunicorn-20.1.0