Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
Please login to access the resource
openSUSE:Step:15-SP4
python-Werkzeug.28362
0001-limit-the-maximum-number-of-multipart-form...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 0001-limit-the-maximum-number-of-multipart-form-parts.patch of Package python-Werkzeug.28362
From 1f1e2cff0f9b841485e47711b8fabb3abbc14c7f Mon Sep 17 00:00:00 2001 From: Darragh O'Reilly <doreilly@suse.com> Date: Fri, 10 Mar 2023 15:16:45 +0000 Subject: [PATCH] limit the maximum number of multipart form parts Backport of https://github.com/pallets/werkzeug/commit/fe899d0cdf767a7289a8bf746b7f72c2907a1b4b --- tests/test_formparser.py | 7 +++++++ werkzeug/formparser.py | 16 +++++++++++++--- werkzeug/wrappers.py | 9 ++++++++- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/tests/test_formparser.py b/tests/test_formparser.py index c140476b..be42d30f 100644 --- a/tests/test_formparser.py +++ b/tests/test_formparser.py @@ -101,6 +101,13 @@ class TestFormParser(object): req.max_form_memory_size = 400 strict_eq(req.form['foo'], u'Hello World') + req = Request.from_values(input_stream=BytesIO(data), + content_length=len(data), + content_type="multipart/form-data; boundary=foo", + method="POST") + req.max_form_parts = 1 + pytest.raises(RequestEntityTooLarge, lambda: req.form["foo"]) + def test_missing_multipart_boundary(self): data = (b'--foo\r\nContent-Disposition: form-field; name=foo\r\n\r\n' b'Hello World\r\n' diff --git a/werkzeug/formparser.py b/werkzeug/formparser.py index c56859e9..5248e14e 100644 --- a/werkzeug/formparser.py +++ b/werkzeug/formparser.py @@ -147,12 +147,14 @@ class FormDataParser(object): :param cls: an optional dict class to use. If this is not specified or `None` the default :class:`MultiDict` is used. :param silent: If set to False parsing errors will not be caught. + :param max_form_parts: The maximum number of parts to be parsed. If this is + exceeded, a :exc:`~exceptions.RequestEntityTooLarge` exception is raised. """ def __init__(self, stream_factory=None, charset='utf-8', errors='replace', max_form_memory_size=None, max_content_length=None, cls=None, - silent=True): + silent=True, max_form_parts=None): if stream_factory is None: stream_factory = default_stream_factory self.stream_factory = stream_factory @@ -164,6 +166,7 @@ class FormDataParser(object): cls = MultiDict self.cls = cls self.silent = silent + self.max_form_parts = max_form_parts def get_parse_func(self, mimetype, options): return self.parse_functions.get(mimetype) @@ -213,7 +216,7 @@ class FormDataParser(object): def _parse_multipart(self, stream, mimetype, content_length, options): parser = MultiPartParser(self.stream_factory, self.charset, self.errors, max_form_memory_size=self.max_form_memory_size, - cls=self.cls) + cls=self.cls, max_form_parts=self.max_form_parts) boundary = options.get('boundary') if boundary is None: raise ValueError('Missing boundary') @@ -295,10 +298,12 @@ _end = 'end' class MultiPartParser(object): def __init__(self, stream_factory=None, charset='utf-8', errors='replace', - max_form_memory_size=None, cls=None, buffer_size=64 * 1024): + max_form_memory_size=None, cls=None, buffer_size=64 * 1024, + max_form_parts=None): self.charset = charset self.errors = errors self.max_form_memory_size = max_form_memory_size + self.max_form_parts = max_form_parts self.stream_factory = default_stream_factory if stream_factory is None else stream_factory self.cls = MultiDict if cls is None else cls @@ -484,6 +489,7 @@ class MultiPartParser(object): ``('form', (name, val))`` parts. """ in_memory = 0 + parts_decoded = 0 for ellt, ell in self.parse_lines(file, boundary, content_length): if ellt == _begin_file: @@ -512,6 +518,10 @@ class MultiPartParser(object): self.in_memory_threshold_reached(in_memory) elif ellt == _end: + parts_decoded += 1 + if self.max_form_parts is not None and \ + parts_decoded > self.max_form_parts: + raise exceptions.RequestEntityTooLarge() if is_file: container.seek(0) yield ('file', diff --git a/werkzeug/wrappers.py b/werkzeug/wrappers.py index 92dfa5da..0671efeb 100644 --- a/werkzeug/wrappers.py +++ b/werkzeug/wrappers.py @@ -170,6 +170,12 @@ class BaseRequest(object): #: .. versionadded:: 0.5 max_form_memory_size = None + #: The maximum number of multipart parts to parse, passed to + #: :attr:`form_data_parser_class`. Parsing form data with more than this + #: many parts will raise :exc:`~.RequestEntityTooLarge`. + #: + max_form_parts = 1000 + #: the class to use for `args` and `form`. The default is an #: :class:`~werkzeug.datastructures.ImmutableMultiDict` which supports #: multiple values per key. alternatively it makes sense to use an @@ -359,7 +365,8 @@ class BaseRequest(object): self.encoding_errors, self.max_form_memory_size, self.max_content_length, - self.parameter_storage_class) + self.parameter_storage_class, + max_form_parts=self.max_form_parts) def _load_form_data(self): """Method used internally to retrieve submitted data. After calling -- 2.34.1
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor