From 06e8df4f450c1696aead4a8ebc5ea427a62f7306 Mon Sep 17 00:00:00 2001 From: David Lord Date: Fri, 28 Apr 2023 06:15:09 -0700 Subject: max_content_length only with wsgi.input_terminated --- CHANGES.rst | 2 ++ src/werkzeug/wsgi.py | 20 ++++++++++++-------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index cc01125a..e47232fe 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -6,6 +6,8 @@ Version 2.3.2 Unreleased - Parse the cookie ``Expires`` attribute correctly in the test client. :issue:`2669` +- ``max_content_length`` can only be enforced on streaming requests if the server + sets ``wsgi.input_terminated``. :issue:`2668` Version 2.3.1 diff --git a/src/werkzeug/wsgi.py b/src/werkzeug/wsgi.py index f5bb2d13..8c50ecdd 100644 --- a/src/werkzeug/wsgi.py +++ b/src/werkzeug/wsgi.py @@ -147,9 +147,9 @@ def get_input_stream( server handles terminating the stream, so it is safe to read directly. For example, a server that knows how to handle chunked requests safely would set this. - If ``max_content_length`` is set, that limit is used even if ``Content-Length`` or - ``wsgi.input_terminated`` are set. If none of these are set, then an empty stream is - returned unless the user explicitly disables this safe fallback. + If ``max_content_length`` is set, it can be enforced on streams if + ``wsgi.input_terminated`` is set. Otherwise, an empty stream is returned unless the + user explicitly disables this safe fallback. If the limit is reached before the underlying stream is exhausted (such as a file that is too large, or an infinite stream), the remaining contents of the stream @@ -173,14 +173,18 @@ def get_input_stream( if content_length is not None and max_content_length is not None: if content_length > max_content_length: raise RequestEntityTooLarge() - elif max_content_length is not None: - return t.cast( - t.IO[bytes], LimitedStream(stream, max_content_length, is_max=True) - ) # A WSGI server can set this to indicate that it terminates the input stream. In - # that case the stream is safe without wrapping. + # that case the stream is safe without wrapping, or can enforce a max length. if "wsgi.input_terminated" in environ: + if max_content_length is not None: + # If this is moved above, it can cause the stream to hang if a read attempt + # is made when the client sends no data. For example, the development server + # does not handle buffering except for chunked encoding. + return t.cast( + t.IO[bytes], LimitedStream(stream, max_content_length, is_max=True) + ) + return stream # No limit given, return an empty stream unless the user explicitly allows the -- cgit v1.2.1