Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-multipart for openSUSE:Factory checked in at 2026-10-26 10:02:08 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-multipart (Old) and /work/SRC/openSUSE:Factory/.python-multipart.new.2252680 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-multipart" Mon Oct 26 10:02:08 2026 rev:6 rq:1392510 version:2.0.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-multipart/python-multipart.changes 2026-09-18 22:08:29.574507887 +0200 +++ /work/SRC/openSUSE:Factory/.python-multipart.new.2252680/python-multipart.changes 2026-10-26 10:03:39.444911102 +0100 @@ -1,0 +2,7 @@ +Sun Oct 25 19:08:01 UTC 2026 - Dirk Müller <[email protected]> + +- update to 2.0.1: + * **Full Changelog**: + https://github.com/defnull/multipart/compare/v2.0.0...v2.0.1 + +------------------------------------------------------------------- Old: ---- multipart-2.0.0.tar.gz New: ---- multipart-2.0.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-multipart.spec ++++++ --- /var/tmp/diff_new_pack.904ZsM/_old 2026-10-26 10:03:40.337948553 +0100 +++ /var/tmp/diff_new_pack.904ZsM/_new 2026-10-26 10:03:40.340948679 +0100 @@ -17,7 +17,7 @@ Name: python-multipart -Version: 2.0.0 +Version: 2.0.1 Release: 0 Summary: Parser for multipart/form-data License: MIT ++++++ multipart-2.0.0.tar.gz -> multipart-2.0.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/multipart-2.0.0/PKG-INFO new/multipart-2.0.1/PKG-INFO --- old/multipart-2.0.0/PKG-INFO 1970-01-01 01:00:00.000000000 +0100 +++ new/multipart-2.0.1/PKG-INFO 1970-01-01 01:00:00.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: multipart -Version: 2.0.0 +Version: 2.0.1 Summary: Parser for multipart/form-data Author-email: Marcel Hellkamp <[email protected]> Requires-Python: >=3.10 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/multipart-2.0.0/multipart.py new/multipart-2.0.1/multipart.py --- old/multipart-2.0.0/multipart.py 2026-07-18 17:55:17.538727300 +0200 +++ new/multipart-2.0.1/multipart.py 2026-09-25 16:00:54.872112000 +0200 @@ -11,7 +11,7 @@ """ __author__ = "Marcel Hellkamp" -__version__ = '2.0.0' +__version__ = '2.0.1' __license__ = "MIT" __all__ = [ "MultipartError", @@ -733,8 +733,10 @@ if line[0] in b" \t": # Multi-line header value if not self._segment_headerlist or self.strict: raise StrictParserError("Unexpected segment header continuation") + if line.isspace(): + raise StrictParserError("Empty segment header continuation") prev = ": ".join(self._segment_headerlist.pop()) - line = prev.encode(self.header_charset) + b" " + line.strip() + line = prev.encode(self.header_charset) + b" " + line[1:] # Enforce header limits if len(line) > self.max_header_size: @@ -753,7 +755,7 @@ name = name.strip().title() if name not in _KNOWN_HEADERS and not _re_hname.fullmatch(name): raise ParserError("Invalid segment header name") - value = value.strip() + value = value.lstrip(" \t") if name == "Content-Length": if self._segment_limit >= 0: @@ -1264,7 +1266,9 @@ if not boundary: raise ParserError("Missing boundary for multipart/form-data") - for part in MultipartParser(stream, boundary, content_length, **kwargs): + for part in MultipartParser( + stream, boundary, content_length, strict=strict, **kwargs + ): if part.filename or not part.is_buffered(): files.append(part.name, part) else: # TODO: Big form-fields go into the files dict. Really? diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/multipart-2.0.0/test/test_push_parser.py new/multipart-2.0.1/test/test_push_parser.py --- old/multipart-2.0.0/test/test_push_parser.py 2026-07-18 17:30:50.590764500 +0200 +++ new/multipart-2.0.1/test/test_push_parser.py 2026-09-25 15:46:25.248683200 +0200 @@ -241,6 +241,36 @@ with self.assertParseError("Maximum segment header length exceeded"): self.parse(b"\tmoooooooooooooooooooooooooore value\r\n") + def test_header_continuation_empty(self): + self.reset(max_header_size=64) + self.parse(b"--boundary\r\n") + self.parse(b"Content-Disposition: form-data; name=foo\r\n") + with self.assertRaises(multipart.StrictParserError): + self.parse(b" \r\n") + + def test_header_continuation_unicode_whitespace_only(self): + self.reset(max_header_size=64) + self.parse(b"--boundary\r\n") + self.parse(b"Content-Disposition: form-data; name=foo\r\n") + with self.assertRaises(multipart.StrictParserError): + self.parse(b" \r\n") + + def test_header_continuation_long_whitespace_padded(self): + self.reset(max_header_size=64) + self.parse(b"--boundary\r\n") + self.parse(b"Content-Disposition: form-data; name=foo\r\n") + with self.assertRaises(multipart.ParserLimitReached): + self.parse(b" " * 65 + b"value\r\n") + + def test_header_continuation_many_unicode_whitespace(self): + self.reset(max_header_size=64) + self.parse(b"--boundary\r\n") + self.parse(b"Content-Disposition: form-data; name=foo\r\n") + # This bypasses the strict whitespace-only checks inside continuation + # logic which operate on bytes, but should still hit the header size limit. + with self.assertRaises(multipart.ParserLimitReached): + self.parse(b" \xc2\xa0\r\n" * 32) + def test_header_no_colon(self): with self.assertParseError("Malformed segment header"): self.parse(b"--boundary\r\nno-colon\r\n\r\ndata\r\n--boundary--") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/multipart-2.0.0/test/test_wsgi_parser.py new/multipart-2.0.1/test/test_wsgi_parser.py --- old/multipart-2.0.0/test/test_wsgi_parser.py 2026-06-13 13:57:03.346465300 +0200 +++ new/multipart-2.0.1/test/test_wsgi_parser.py 2026-09-23 08:28:42.440691200 +0200 @@ -26,6 +26,19 @@ self.assertEqual(files['file1'].name, 'file1') self.assertEqual(files['file1'].content_type, 'image/png') + def test_multipart_strict_passed_to_parser(self): + self.write( + "--foo\r\n", + "Content-Disposition: form-data;\r\n", # no name + '\tname="text1"\r\n', + "\r\n", + "abc", + "\r\n--foo--", + ) + + with self.assertRaises(multipart.StrictParserError): + self.parse_form_data(strict=True) + def test_empty(self): self.write_end() forms, files = self.parse_form_data()
