Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-tornado6 for openSUSE:Factory
checked in at 2026-08-24 12:01:42
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-tornado6 (Old)
and /work/SRC/openSUSE:Factory/.python-tornado6.new.1258 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-tornado6"
Mon Aug 24 12:01:42 2026 rev:26 rq:1373067 version:6.5.8
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-tornado6/python-tornado6.changes
2026-07-09 22:18:07.955581817 +0200
+++
/work/SRC/openSUSE:Factory/.python-tornado6.new.1258/python-tornado6.changes
2026-08-24 12:02:32.578603897 +0200
@@ -1,0 +2,19 @@
+Sat Aug 22 13:38:07 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 6.5.8 (bsc#1276210, bsc#1276211):
+ * Form-encoded POST bodies are now subject to a limit of 1000
+ arguments by default. This prevents a CPU and memory denial of
+ service attack. This limit can be overridden via the
+ set_parse_body_config function. Thanks to Arpit Jain for reporting
+ this issue.
+ * Multipart parsing now rejects requests with an excessive number of
+ parts earlier in the parsing process, limiting memory consumption.
+ Thanks to afldl for reporting this issue.
+ * The deprecated mixed-case arguments to RequestHandler.set_cookie
+ now enforce the same restrictions on invalid characters that were
+ introduced in Tornado 6.5.5 for the standard lowercase arguments.
+ Thanks to sec-reex and Arpit Jain for reporting this issue.
+- drop python-tornado6-Fix-test_strip_headers_on_redirects.patch
+ (upstream)
+
+-------------------------------------------------------------------
Old:
----
python-tornado6-Fix-test_strip_headers_on_redirects.patch
tornado-6.5.7.tar.gz
New:
----
tornado-6.5.8.tar.gz
----------(Old B)----------
Old: Thanks to sec-reex and Arpit Jain for reporting this issue.
- drop python-tornado6-Fix-test_strip_headers_on_redirects.patch
(upstream)
----------(Old E)----------
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-tornado6.spec ++++++
--- /var/tmp/diff_new_pack.rsQoJ8/_old 2026-08-24 12:02:33.602640024 +0200
+++ /var/tmp/diff_new_pack.rsQoJ8/_new 2026-08-24 12:02:33.605640130 +0200
@@ -18,7 +18,7 @@
%{?sle15_python_module_pythons}
Name: python-tornado6
-Version: 6.5.7
+Version: 6.5.8
Release: 0
Summary: Open source version of scalable, non-blocking web server that
power FriendFeed
License: Apache-2.0
@@ -29,8 +29,6 @@
Patch0: ignore-resourcewarning-doctests.patch
# PATCH-FIX-OPENSUSE increase compatibility with newer pycares versions
Patch1: pycares-getaddrinfo.patch
-# PATCH-FIX-UPSTREAM Fix test_strip_headers_on_redirect's
URL-embedded-credentials cases
-Patch2: python-tornado6-Fix-test_strip_headers_on_redirects.patch
BuildRequires: %{python_module base >= 3.9}
BuildRequires: %{python_module devel}
BuildRequires: %{python_module pip}
++++++ tornado-6.5.7.tar.gz -> tornado-6.5.8.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.5.7/PKG-INFO new/tornado-6.5.8/PKG-INFO
--- old/tornado-6.5.7/PKG-INFO 2026-06-08 19:18:41.907536000 +0200
+++ new/tornado-6.5.8/PKG-INFO 2026-08-07 03:57:05.611844300 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: tornado
-Version: 6.5.7
+Version: 6.5.8
Summary: Tornado is a Python web framework and asynchronous networking
library, originally developed at FriendFeed.
Home-page: http://www.tornadoweb.org/
Author: Facebook
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.5.7/docs/releases/v6.5.8.rst
new/tornado-6.5.8/docs/releases/v6.5.8.rst
--- old/tornado-6.5.7/docs/releases/v6.5.8.rst 1970-01-01 01:00:00.000000000
+0100
+++ new/tornado-6.5.8/docs/releases/v6.5.8.rst 2026-08-07 03:56:56.000000000
+0200
@@ -0,0 +1,26 @@
+What's new in Tornado 6.5.8
+===========================
+
+Aug 6, 2026
+-----------
+
+Security fixes
+~~~~~~~~~~~~~~
+
+- Form-encoded ``POST`` bodies are now subject to a limit of 1000 arguments by
default. This
+ prevents a CPU and memory denial of service attack. This limit can be
overridden via the
+ `.set_parse_body_config` function. Thanks to `Arpit Jain
<https://github.com/arpitjain099>`_
+ for reporting this issue.
+- Multipart parsing now rejects requests with an excessive number of parts
earlier in the parsing
+ process, limiting memory consumption. Thanks to `afldl
<https://github.com/afldl>`_ for
+ reporting this issue.
+- The deprecated mixed-case arguments to `.RequestHandler.set_cookie` now
enforce the same
+ restrictions on invalid characters that were introduced in Tornado 6.5.5 for
the standard
+ lowercase arguments. Thanks to `sec-reex <https://github.com/sec-reex>`_ and
+ `Arpit Jain <https://github.com/arpitjain099>`_ for reporting this issue.
+
+Deprecations
+~~~~~~~~~~~~
+
+- The `.OpenIdMixin` class is deprecated and will be removed in Tornado 6.7.
OpenID 2.0 is no
+ longer widely supported by identity providers.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.5.7/docs/releases.rst
new/tornado-6.5.8/docs/releases.rst
--- old/tornado-6.5.7/docs/releases.rst 2026-06-08 19:18:33.000000000 +0200
+++ new/tornado-6.5.8/docs/releases.rst 2026-08-07 03:56:56.000000000 +0200
@@ -4,6 +4,7 @@
.. toctree::
:maxdepth: 2
+ releases/v6.5.8
releases/v6.5.7
releases/v6.5.6
releases/v6.5.5
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.5.7/tornado/__init__.py
new/tornado-6.5.8/tornado/__init__.py
--- old/tornado-6.5.7/tornado/__init__.py 2026-06-08 19:18:33.000000000
+0200
+++ new/tornado-6.5.8/tornado/__init__.py 2026-08-07 03:56:56.000000000
+0200
@@ -22,8 +22,8 @@
# is zero for an official release, positive for a development branch,
# or negative for a release candidate or beta (after the base version
# number has been incremented)
-version = "6.5.7"
-version_info = (6, 5, 7, 0)
+version = "6.5.8"
+version_info = (6, 5, 8, 0)
import importlib
import typing
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.5.7/tornado/auth.py
new/tornado-6.5.8/tornado/auth.py
--- old/tornado-6.5.7/tornado/auth.py 2026-06-08 19:18:33.000000000 +0200
+++ new/tornado-6.5.8/tornado/auth.py 2026-08-07 03:56:56.000000000 +0200
@@ -98,8 +98,19 @@
Class attributes:
* ``_OPENID_ENDPOINT``: the identity provider's URI.
+
+ .. deprecated:: 6.6
+ OpenID 2.0 is no longer widely supported by identity providers.
+ This class will be removed in Tornado 6.7.
"""
+ def __init__(self) -> None:
+ warnings.warn(
+ "OpenIdMixin is deprecated and will be removed in Tornado 6.7",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+
def authenticate_redirect(
self,
callback_uri: Optional[str] = None,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.5.7/tornado/escape.py
new/tornado-6.5.8/tornado/escape.py
--- old/tornado-6.5.7/tornado/escape.py 2026-06-08 19:18:33.000000000 +0200
+++ new/tornado-6.5.8/tornado/escape.py 2026-08-07 03:56:56.000000000 +0200
@@ -171,7 +171,11 @@
def parse_qs_bytes(
- qs: Union[str, bytes], keep_blank_values: bool = False, strict_parsing:
bool = False
+ qs: Union[str, bytes],
+ keep_blank_values: bool = False,
+ strict_parsing: bool = False,
+ *,
+ max_num_fields: Optional[int] = None,
) -> Dict[str, List[bytes]]:
"""Parses a query string like urlparse.parse_qs,
but takes bytes and returns the values as byte strings.
@@ -179,13 +183,21 @@
Keys still become type str (interpreted as latin1 in python3!)
because it's too painful to keep them as byte strings in
python3 and in practice they're nearly always ascii anyway.
+
+ .. versionadded:: 6.5.8
+ The ``max_num_fields`` argument. ValueError is raised if this limit is
exceeded.
"""
# This is gross, but python3 doesn't give us another way.
# Latin1 is the universal donor of character encodings.
if isinstance(qs, bytes):
qs = qs.decode("latin1")
result = urllib.parse.parse_qs(
- qs, keep_blank_values, strict_parsing, encoding="latin1",
errors="strict"
+ qs,
+ keep_blank_values,
+ strict_parsing,
+ encoding="latin1",
+ errors="strict",
+ max_num_fields=max_num_fields,
)
encoded = {}
for k, v in result.items():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.5.7/tornado/httputil.py
new/tornado-6.5.8/tornado/httputil.py
--- old/tornado-6.5.7/tornado/httputil.py 2026-06-08 19:18:33.000000000
+0200
+++ new/tornado-6.5.8/tornado/httputil.py 2026-08-07 03:56:56.000000000
+0200
@@ -37,7 +37,6 @@
from tornado.escape import native_str, parse_qs_bytes, utf8, to_unicode
from tornado.util import ObjectDict, unicode_type
-
# responses is unused in this file, but we re-export it to other files.
# Reference it so pyflakes doesn't complain.
responses
@@ -949,6 +948,23 @@
@dataclasses.dataclass
+class ParseUrlEncodedConfig:
+ """This class configures the parsing of
``application/x-www-form-urlencoded`` request bodies.
+
+ Its primary purpose is to place limits on the size and complexity of
request messages
+ to avoid potential denial-of-service attacks.
+
+ .. versionadded:: 6.5.8
+ """
+
+ max_arguments: int = 1000
+ """The maximum number of arguments accepted in a urlencoded request.
+
+ Each ``<input>`` element in an HTML form corresponds to at least one
argument.
+ """
+
+
[email protected]
class ParseBodyConfig:
"""This class configures the parsing of request bodies.
@@ -958,6 +974,9 @@
multipart: ParseMultipartConfig = dataclasses.field(
default_factory=ParseMultipartConfig
)
+ urlencoded: ParseUrlEncodedConfig = dataclasses.field(
+ default_factory=ParseUrlEncodedConfig
+ )
"""Configuration for ``multipart/form-data`` request bodies."""
@@ -1016,7 +1035,11 @@
)
try:
# real charset decoding will happen in
RequestHandler.decode_argument()
- uri_arguments = parse_qs_bytes(body, keep_blank_values=True)
+ uri_arguments = parse_qs_bytes(
+ body,
+ keep_blank_values=True,
+ max_num_fields=config.urlencoded.max_arguments,
+ )
except Exception as e:
raise HTTPInputError("Invalid x-www-form-urlencoded body: %s" % e)
from e
for name, values in uri_arguments.items():
@@ -1078,7 +1101,9 @@
final_boundary_index = data.rfind(b"--" + boundary + b"--")
if final_boundary_index == -1:
raise HTTPInputError("Invalid multipart/form-data: no final boundary
found")
- parts = data[:final_boundary_index].split(b"--" + boundary + b"\r\n")
+ parts = data[:final_boundary_index].split(
+ b"--" + boundary + b"\r\n", config.max_parts + 1
+ )
if len(parts) > config.max_parts:
raise HTTPInputError("multipart/form-data has too many parts")
for part in parts:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.5.7/tornado/test/auth_test.py
new/tornado-6.5.8/tornado/test/auth_test.py
--- old/tornado-6.5.7/tornado/test/auth_test.py 2026-06-08 19:18:33.000000000
+0200
+++ new/tornado-6.5.8/tornado/test/auth_test.py 2026-08-07 03:56:56.000000000
+0200
@@ -18,7 +18,8 @@
from tornado.httpclient import HTTPClientError
from tornado.httputil import url_concat
from tornado.log import app_log
-from tornado.testing import AsyncHTTPTestCase, ExpectLog
+from tornado.testing import AsyncHTTPTestCase, ExpectLog,
setup_with_context_manager
+from tornado.test.util import ignore_deprecation
from tornado.web import RequestHandler, Application, HTTPError
try:
@@ -279,12 +280,46 @@
self.write(dict(screen_name="foo", name="Foo"))
+class OpenIDAuthTest(AsyncHTTPTestCase):
+ def setUp(self):
+ setup_with_context_manager(self, ignore_deprecation())
+ return super().setUp()
+
+ def get_app(self):
+ return Application(
+ [
+ ("/openid/client/login", OpenIdClientLoginHandler,
dict(test=self)),
+ ("/openid/server/authenticate",
OpenIdServerAuthenticateHandler),
+ ],
+ http_client=self.http_client,
+ )
+
+ def test_openid_redirect(self):
+ with ignore_deprecation():
+ response = self.fetch("/openid/client/login",
follow_redirects=False)
+ self.assertEqual(response.code, 302)
+ self.assertIn("/openid/server/authenticate?",
response.headers["Location"])
+
+ def test_openid_get_user(self):
+ for i in range(2):
+ with self.subTest(i=i):
+ with ignore_deprecation():
+ response = self.fetch(
+ "/openid/client/login?openid.mode=blah"
+ "&openid.ns.ax=http://openid.net/srv/ax/1.0"
+
"&openid.ax.type.email=http://axschema.org/contact/email"
+ "&[email protected]"
+ )
+ response.rethrow()
+ parsed = json_decode(response.body)
+ self.assertEqual(parsed["email"], "[email protected]")
+
+
class AuthTest(AsyncHTTPTestCase):
def get_app(self):
return Application(
[
# test endpoints
- ("/openid/client/login", OpenIdClientLoginHandler,
dict(test=self)),
(
"/oauth10/client/login",
OAuth1ClientLoginHandler,
@@ -329,7 +364,6 @@
dict(test=self),
),
# simulated servers
- ("/openid/server/authenticate",
OpenIdServerAuthenticateHandler),
("/oauth1/server/request_token",
OAuth1ServerRequestTokenHandler),
("/oauth1/server/access_token",
OAuth1ServerAccessTokenHandler),
("/facebook/server/access_token",
FacebookServerAccessTokenHandler),
@@ -348,24 +382,6 @@
facebook_secret="test_facebook_secret",
)
- def test_openid_redirect(self):
- response = self.fetch("/openid/client/login", follow_redirects=False)
- self.assertEqual(response.code, 302)
- self.assertIn("/openid/server/authenticate?",
response.headers["Location"])
-
- def test_openid_get_user(self):
- for i in range(2):
- with self.subTest(i=i):
- response = self.fetch(
- "/openid/client/login?openid.mode=blah"
- "&openid.ns.ax=http://openid.net/srv/ax/1.0"
- "&openid.ax.type.email=http://axschema.org/contact/email"
- "&[email protected]"
- )
- response.rethrow()
- parsed = json_decode(response.body)
- self.assertEqual(parsed["email"], "[email protected]")
-
def test_oauth10_redirect(self):
response = self.fetch("/oauth10/client/login", follow_redirects=False)
self.assertEqual(response.code, 302)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.5.7/tornado/test/httpclient_test.py
new/tornado-6.5.8/tornado/test/httpclient_test.py
--- old/tornado-6.5.7/tornado/test/httpclient_test.py 2026-06-08
19:18:33.000000000 +0200
+++ new/tornado-6.5.8/tornado/test/httpclient_test.py 2026-08-07
03:56:56.000000000 +0200
@@ -795,7 +795,12 @@
"/redirect?url=%s&status=302" %
self.get_url2("/echo_headers")
)
if url_creds:
- url = url.replace("http://", "http://%s@" % url_creds)
+ # Only add credentials to the outer URL being fetched, not
to the
+ # "url" query parameter (the redirect target), which also
starts
+ # with "http://". Otherwise the redirect's Location header
would
+ # carry its own explicit credentials for the new origin,
which
+ # libcurl legitimately honors instead of stripping.
+ url = url.replace("http://", "http://%s@" % url_creds, 1)
response = self.fetch(**dict(path=url) | kwargs)
response.rethrow()
echoed_headers = json_decode(response.body)
@@ -809,17 +814,27 @@
"/redirect?url=%s&status=302" %
self.get_url("/echo_headers")
)
if url_creds:
- url = url.replace("http://", "http://%s@" % url_creds)
+ url = url.replace("http://", "http://%s@" % url_creds, 1)
response = self.fetch(**dict(path=url) | kwargs)
response.rethrow()
echoed_headers = json_decode(response.body)
# Confirm that non-auth headers are getting through
self.assertIn("User-Agent", echoed_headers)
- # Auth headers are not stripped when the redirect is
same-origin.
- # Each of our tests uses one of these headers, but not both.
- self.assertTrue(
- "Authorization" in echoed_headers or "Cookie" in
echoed_headers
- )
+ if name == "credentials in URL":
+ # Some libcurl versions (known regression as of 8.20/8.21,
+ # still present as of curl's git master) drop credentials
+ # embedded in the URL across a same-origin redirect whose
+ # Location header is an absolute URL, even though they
+ # should be preserved. This isn't a security concern
+ # (nothing is leaked to another origin), so just don't
+ # assert on it either way here.
+ pass
+ else:
+ # Auth headers are not stripped when the redirect is
same-origin.
+ # Each of our tests uses one of these headers, but not
both.
+ self.assertTrue(
+ "Authorization" in echoed_headers or "Cookie" in
echoed_headers
+ )
class RequestProxyTest(unittest.TestCase):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.5.7/tornado/test/httputil_test.py
new/tornado-6.5.8/tornado/test/httputil_test.py
--- old/tornado-6.5.7/tornado/test/httputil_test.py 2026-06-08
19:18:33.000000000 +0200
+++ new/tornado-6.5.8/tornado/test/httputil_test.py 2026-08-07
03:56:56.000000000 +0200
@@ -1,4 +1,5 @@
from tornado.httputil import (
+ parse_body_arguments,
url_concat,
parse_multipart_form_data,
HTTPHeaders,
@@ -95,6 +96,23 @@
self.assertIn(("b", "2"), qsl)
+class UrlEncodedDataTest(unittest.TestCase):
+ def test_urlencoded_data(self):
+ data = b"a=1&b=2&a=3"
+ args, files = form_data_args()
+ parse_body_arguments("application/x-www-form-urlencoded", data, args,
files)
+ self.assertEqual(args["a"], [b"1", b"3"])
+ self.assertEqual(args["b"], [b"2"])
+ self.assertEqual(files, {})
+
+ def test_max_arguments(self):
+ data = b"".join(b"a=1&" for _ in range(1001))
+ args, files = form_data_args()
+ with self.assertRaises(HTTPInputError) as cm:
+ parse_body_arguments("application/x-www-form-urlencoded", data,
args, files)
+ self.assertIn("Max number of fields exceeded", str(cm.exception))
+
+
class MultipartFormDataTest(unittest.TestCase):
def test_file_upload(self):
data = b"""\
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.5.7/tornado/test/web_test.py
new/tornado-6.5.8/tornado/test/web_test.py
--- old/tornado-6.5.7/tornado/test/web_test.py 2026-06-08 19:18:33.000000000
+0200
+++ new/tornado-6.5.8/tornado/test/web_test.py 2026-08-07 03:56:56.000000000
+0200
@@ -329,6 +329,18 @@
"unexpected exception for char %r in domain:
%s\n"
% (char, e)
)
+ try:
+ self.set_cookie("foo", "bar", DoMaIn="example" + char
+ ".com")
+ self.write(
+ "Didn't get expected exception for char %r in
DoMaIn\n"
+ % char
+ )
+ except http.cookies.CookieError as e:
+ if "Invalid cookie attribute DoMaIn" not in str(e):
+ self.write(
+ "unexpected exception for char %r in DoMaIn:
%s\n"
+ % (char, e)
+ )
try:
self.set_cookie("foo", "bar", path="/" + char)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.5.7/tornado/web.py
new/tornado-6.5.8/tornado/web.py
--- old/tornado-6.5.7/tornado/web.py 2026-06-08 19:18:33.000000000 +0200
+++ new/tornado-6.5.8/tornado/web.py 2026-08-07 03:56:56.000000000 +0200
@@ -717,6 +717,12 @@
raise http.cookies.CookieError(
f"Invalid cookie attribute {attr_name}={attr_value!r} for
cookie {name!r}"
)
+ for k, v in kwargs.items():
+ # Also check for disallowed characters in deprecated kwargs.
+ if re.search(r"[\x00-\x20\x3b\x7f]", str(v)):
+ raise http.cookies.CookieError(
+ f"Invalid cookie attribute {k}={v!r} for cookie {name!r}"
+ )
if not hasattr(self, "_new_cookie"):
self._new_cookie = (
http.cookies.SimpleCookie()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.5.7/tornado.egg-info/PKG-INFO
new/tornado-6.5.8/tornado.egg-info/PKG-INFO
--- old/tornado-6.5.7/tornado.egg-info/PKG-INFO 2026-06-08 19:18:41.000000000
+0200
+++ new/tornado-6.5.8/tornado.egg-info/PKG-INFO 2026-08-07 03:57:05.000000000
+0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: tornado
-Version: 6.5.7
+Version: 6.5.8
Summary: Tornado is a Python web framework and asynchronous networking
library, originally developed at FriendFeed.
Home-page: http://www.tornadoweb.org/
Author: Facebook
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.5.7/tornado.egg-info/SOURCES.txt
new/tornado-6.5.8/tornado.egg-info/SOURCES.txt
--- old/tornado-6.5.7/tornado.egg-info/SOURCES.txt 2026-06-08
19:18:41.000000000 +0200
+++ new/tornado-6.5.8/tornado.egg-info/SOURCES.txt 2026-08-07
03:57:05.000000000 +0200
@@ -124,6 +124,7 @@
docs/releases/v6.5.5.rst
docs/releases/v6.5.6.rst
docs/releases/v6.5.7.rst
+docs/releases/v6.5.8.rst
tornado/__init__.py
tornado/__init__.pyi
tornado/_locale_data.py