-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
werkzeug.serving.DechunkedInput.read returns more than what was asked for #2021
Comments
In fact, I don't understand why the implementation tries to fill the entirity of while not self._done and read < len(buf): This method is not |
Is this actually causing an issue? |
Yes, in my code I have a ring buffer which I want to fill as much as possible without writing so much that I start losing data. Because
I don't have a lot of domain knowledge here, but isn't the size is
This is debatable. PEP 3333 says it should behave like
How is it supposed to do that, if it needs to create a buffer which it can pass to
It might be, although it seems strange that it's (seemingly) creating a buffer larger than requested? |
With the information I have, I'm calling this a bug in |
b = PyByteArray_FromStringAndSize(NULL, n);
if (b == NULL)
return NULL;
res = PyObject_CallMethodObjArgs(self, _PyIO_str_readinto, b, NULL);
if (res == NULL || res == Py_None) {
Py_DECREF(b);
return res;
} I very much doubt alloc = size + 1;
new->ob_bytes = PyObject_Malloc(alloc); |
We only know the size of the buffer, that's the only thing we can use to know how much to read. |
The following from flask import Flask, request
SIZE = 320000
app = Flask('bug')
@app.route('/bug', methods=['POST'])
def bug():
chunk = bytearray(SIZE)
n = request.stream.readinto(chunk)
if n > SIZE:
raise ValueError(f'bug in {type(request.stream)}; read({SIZE}) returned {n} bytes')
return 'ok'
if __name__ == "__main__":
app.run() No To clarify, the problem is |
Great, thanks for reducing this to a minimal reproducible example. Happy to consider a PR since it seems like you're the most knowledgeable about this right now. I'm unlikely to have time to address this before 2.0 otherwise. A |
It appears import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('localhost', 5000))
s.listen(1)
c, _ = s.accept()
buffer = b''
while len(buffer) < 4096:
buffer += c.recv(4096)
print(buffer.decode()) ...and adjusted
This should make for a good testcase. |
I'd like to work on this. |
I believe this is a bug in werkzeug 1.0.1 and not Flask because the error is produced by
request.stream.read()
, which is awerkzeug.serving.DechunkedInput
instance. Please let me know if this actually belongs to Flask, and I will report it there instead. Note that I have used Flask in these examples for simplicity and because this is where I first found the issue.With Python 3.9 on Windows 10, given the following Flask app (
pip install flask==1.1.2
) asserver.py
:And the following
client.py
file (pip install aiohttp==3.7.3
):Running
python server.py
followed bypython client.py
in another terminal will eventually lead to the following error:I expected
read
to never return more thansize
, but it did. According to PEP 3333 - Input and Error Streams,read
is defined on theinput
stream with as follows (strong emphasis mine):And the Python Library Reference for
io.RawIOBase.read
reads:Note that it says "Read up to size", and not "Read at least size". Werkzeug behaviours seem to not behave as the documentation says it should, which I think is a bug.
Because the default
read
implementation delegates toreadinto
, the buggy implementation is likely here, although I have not investigated further:werkzeug/src/werkzeug/serving.py
Line 105 in 68b7cbd
The text was updated successfully, but these errors were encountered: