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

Allow chunk request #1126

Merged
merged 2 commits into from
Jun 9, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ Werkzeug Changelog
Version 0.13
------------

Released on May 16 2017
unreleased

- Raise `TypeError` when port is not an integer.
- Fully deprecate `werkzeug.script`. Use `click`
(http://click.pocoo.org) instead.
- Raise ``TypeError`` when port is not an integer.
- Fully deprecate ``werkzeug.script``. Use `Click <http://click.pocoo.org>`_
instead.
- ``response.age`` is parsed as a ``timedelta``. Previously, it was incorrectly
treated as a ``datetime``. The header value is an integer number of seconds,
not a date string. (``#414``)
Expand All @@ -21,11 +21,16 @@ Released on May 16 2017
``BaseResponse`` has a new attribute ``max_cookie_size`` and ``dump_cookie``
has a new argument ``max_size`` to configure this. (`#780`_, `#1109`_)
- Fix a TypeError in ``werkzeug.contrib.lint.GuardedIterator.close``.
- `BaseResponse.calculate_content_length` now correctly works for unicode
responses on Python 3. It first encodes using `iter_encoded`.
- ``BaseResponse.calculate_content_length`` now correctly works for unicode
responses on Python 3. It first encodes using ``iter_encoded``.
- ``Request.stream`` is limited to ``Request.max_content_length`` if it is set.
Otherwise, keeps the previous behavior of returning empty streams when
``Content-Length`` is not set. This allows chunk-encoded requests while
guarding against infinite streams. (`#1126`_)

.. _`#780`: https://github.com/pallets/werkzeug/pull/780
.. _`#1109`: https://github.com/pallets/werkzeug/pull/1109
.. _`#1126`: https://github.com/pallets/werkzeug/pull/1126


Version 0.12.2
Expand Down
11 changes: 9 additions & 2 deletions werkzeug/wrappers.py
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ def want_form_data_parsed(self):
return bool(self.environ.get('CONTENT_TYPE'))

def make_form_data_parser(self):
"""Creates the form data parser. Instanciates the
"""Creates the form data parser. Instantiates the
:attr:`form_data_parser_class` with some parameters.

.. versionadded:: 0.8
Expand Down Expand Up @@ -421,13 +421,20 @@ def stream(self):
internally always refer to this stream to read data which makes it
possible to wrap this object with a stream that does filtering.

.. versionchanged:: 0.13
The stream will be limited to :attr:`max_content_length` if the
request does not specify a content length or it is greater than the
configured max.

.. versionchanged:: 0.9
This stream is now always available but might be consumed by the
form parser later on. Previously the stream was only set if no
parsing happened.
"""
_assert_not_shallow(self)
return get_input_stream(self.environ)
return get_input_stream(
self.environ, max_content_length=self.max_content_length
)

input_stream = environ_property('wsgi.input', """
The WSGI input stream.
Expand Down
34 changes: 21 additions & 13 deletions werkzeug/wsgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ def get_host(environ, trusted_hosts=None):

def get_content_length(environ):
"""Returns the content length from the WSGI environment as
integer. If it's not available `None` is returned.
integer. If it's not available ``None`` is returned.

.. versionadded:: 0.9

Expand All @@ -179,19 +179,23 @@ def get_content_length(environ):
pass


def get_input_stream(environ, safe_fallback=True):
def get_input_stream(environ, safe_fallback=True, max_content_length=None):
"""Returns the input stream from the WSGI environment and wraps it
in the most sensible way possible. The stream returned is not the
raw WSGI stream in most cases but one that is safe to read from
without taking into account the content length.

.. versionchanged:: 0.13
Added the ``max_content_length`` parameter.

.. versionadded:: 0.9

:param environ: the WSGI environ to fetch the stream from.
:param safe: indicates whether the function should use an empty
stream as safe fallback or just return the original
WSGI input stream if it can't wrap it safely. The
default is to return an empty string in those cases.
:param safe_fallback: use an empty stream as a safe fallback when neither
the environ content length nor the max is set. Disabling this allows
infinite streams, which can be a denial-of-service risk.
:param max_content_length: if the environ does not set ``Content-Length``
or it is greater than this value, the stream is limited to this length.
"""
stream = environ['wsgi.input']
content_length = get_content_length(environ)
Expand All @@ -202,15 +206,19 @@ def get_input_stream(environ, safe_fallback=True):
if environ.get('wsgi.input_terminated'):
return stream

# If we don't have a content length we fall back to an empty stream
# in case of a safe fallback, otherwise we return the stream unchanged.
# The non-safe fallback is not recommended but might be useful in
# some situations.
if content_length is None:
# If the request doesn't specify a content length and there is no max
# length set, returning the stream is potentially dangerous because it
# could be infinite, maliciously or not. If safe_fallback is true, return
# an empty stream for safety instead.
if content_length is None and max_content_length is None:
return safe_fallback and _empty_stream or stream

# Otherwise limit the stream to the content length
return LimitedStream(stream, content_length)
# Otherwise limit the stream to the content length or max length,
# whichever is lower.
if max_content_length is not None:
return LimitedStream(stream, min(content_length, max_content_length))
else:
return LimitedStream(stream, content_length)


def get_query_string(environ):
Expand Down