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 2024-08-02 17:26:09
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-tornado6 (Old)
and /work/SRC/openSUSE:Factory/.python-tornado6.new.7232 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-tornado6"
Fri Aug 2 17:26:09 2024 rev:18 rq:1190823 version:6.4.1
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-tornado6/python-tornado6.changes
2024-05-20 18:09:31.917764967 +0200
+++
/work/SRC/openSUSE:Factory/.python-tornado6.new.7232/python-tornado6.changes
2024-08-02 17:26:25.355041172 +0200
@@ -1,0 +2,34 @@
+Wed Jul 31 09:32:23 UTC 2024 - Dominique Leuenberger <[email protected]>
+
+- Update to version 6.4.1:
+ + Security Improvements:
+ - Parsing of the ``Transfer-Encoding`` header is now stricter.
+ Unexpected transfer-encoding values were previously ignored
+ and treated as the HTTP/1.0 default of read-until-close. This
+ can lead to framing issues with certain proxies. We now treat
+ any unexpected value as an error.
+ - Handling of whitespace in headers now matches the RFC more
+ closely. Only space and tab characters are treated as
+ whitespace and stripped from the beginning and end of header
+ values. Other unicode whitespace characters are now left
+ alone. This could also lead to framing issues with certain
+ proxies.
+ - `tornado.curl_httpclient` now prohibits carriage return and
+ linefeed headers in HTTP headers (matching the behavior of
+ `simple_httpclient`). These characters could be used for
+ header injection or request smuggling if untrusted data were
+ used in headers.
+ + General Changes:
+ - `tornado.iostream`: `SLIOStream` now understands changes to
+ error codes from OpenSSL 3.2. The main result of this change
+ is to reduce the noise in the logs for certain errors.
+ - `tornado.simple_httpclient`: `simple_httpclient` now
+ prohibits carriage return characters in HTTP headers. It had
+ previously prohibited only linefeed characters.
+ - `tornado.testing`: `.AsyncTestCase` subclasses can now be
+ instantiated without being associated with a test method.
+ Improves compatibility with test discovery in Pytest 8.2.
+- Drop support-pytest-8.2.patch: fixed upstream.
+- Drop openssl-3.2.patch: fixed upstream.
+
+-------------------------------------------------------------------
Old:
----
openssl-3.2.patch
support-pytest-8.2.patch
tornado-6.4.tar.gz
New:
----
tornado-6.4.1.tar.gz
BETA DEBUG BEGIN:
Old:- Drop support-pytest-8.2.patch: fixed upstream.
- Drop openssl-3.2.patch: fixed upstream.
Old: Improves compatibility with test discovery in Pytest 8.2.
- Drop support-pytest-8.2.patch: fixed upstream.
- Drop openssl-3.2.patch: fixed upstream.
BETA DEBUG END:
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-tornado6.spec ++++++
--- /var/tmp/diff_new_pack.0016rw/_old 2024-08-02 17:26:26.919105667 +0200
+++ /var/tmp/diff_new_pack.0016rw/_new 2024-08-02 17:26:26.919105667 +0200
@@ -19,7 +19,7 @@
%{?sle15_python_module_pythons}
%define skip_python2 1
Name: python-tornado6
-Version: 6.4
+Version: 6.4.1
Release: 0
Summary: Open source version of scalable, non-blocking web server that
power FriendFeed
License: Apache-2.0
@@ -28,10 +28,6 @@
Source99: python-tornado6-rpmlintrc
# PATCH-FIX-OPENSUSE ignore-resourcewarning-doctests.patch -- ignore resource
warnings on OBS
Patch0: ignore-resourcewarning-doctests.patch
-# PATCH-FIX-OPENSUSE openssl-3.2.patch gh#tornadoweb/tornado#3355
-Patch1: openssl-3.2.patch
-# PATCH-FIX-UPSTREAM gh#tornadoweb/tornado#3374
-Patch2: support-pytest-8.2.patch
BuildRequires: %{python_module base >= 3.8}
BuildRequires: %{python_module devel}
BuildRequires: %{python_module pip}
++++++ tornado-6.4.tar.gz -> tornado-6.4.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.4/PKG-INFO new/tornado-6.4.1/PKG-INFO
--- old/tornado-6.4/PKG-INFO 2023-11-29 04:20:19.857731000 +0100
+++ new/tornado-6.4.1/PKG-INFO 2024-06-06 20:12:53.604281000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: tornado
-Version: 6.4
+Version: 6.4.1
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.4/docs/releases/v6.4.1.rst
new/tornado-6.4.1/docs/releases/v6.4.1.rst
--- old/tornado-6.4/docs/releases/v6.4.1.rst 1970-01-01 01:00:00.000000000
+0100
+++ new/tornado-6.4.1/docs/releases/v6.4.1.rst 2024-06-06 20:12:50.000000000
+0200
@@ -0,0 +1,41 @@
+What's new in Tornado 6.4.1
+===========================
+
+Jun 6, 2024
+-----------
+
+Security Improvements
+~~~~~~~~~~~~~~~~~~~~~
+
+- Parsing of the ``Transfer-Encoding`` header is now stricter. Unexpected
transfer-encoding values
+ were previously ignored and treated as the HTTP/1.0 default of
read-until-close. This can lead to
+ framing issues with certain proxies. We now treat any unexpected value as an
error.
+- Handling of whitespace in headers now matches the RFC more closely. Only
space and tab characters
+ are treated as whitespace and stripped from the beginning and end of header
values. Other unicode
+ whitespace characters are now left alone. This could also lead to framing
issues with certain
+ proxies.
+- ``tornado.curl_httpclient`` now prohibits carriage return and linefeed
headers in HTTP headers
+ (matching the behavior of ``simple_httpclient``). These characters could be
used for header
+ injection or request smuggling if untrusted data were used in headers.
+
+General Changes
+~~~~~~~~~~~~~~~
+
+`tornado.iostream`
+~~~~~~~~~~~~~~~~~~
+
+- `.SSLIOStream` now understands changes to error codes from OpenSSL 3.2. The
main result of this
+ change is to reduce the noise in the logs for certain errors.
+
+``tornado.simple_httpclient``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- ``simple_httpclient`` now prohibits carriage return characters in HTTP
headers. It had previously
+ prohibited only linefeed characters.
+
+`tornado.testing`
+~~~~~~~~~~~~~~~~~
+
+- `.AsyncTestCase` subclasses can now be instantiated without being associated
with a test
+ method. This improves compatibility with test discovery in Pytest 8.2.
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.4/docs/releases.rst
new/tornado-6.4.1/docs/releases.rst
--- old/tornado-6.4/docs/releases.rst 2023-11-29 04:20:18.000000000 +0100
+++ new/tornado-6.4.1/docs/releases.rst 2024-06-06 20:12:50.000000000 +0200
@@ -4,6 +4,7 @@
.. toctree::
:maxdepth: 2
+ releases/v6.4.1
releases/v6.4.0
releases/v6.3.3
releases/v6.3.2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.4/requirements.txt
new/tornado-6.4.1/requirements.txt
--- old/tornado-6.4/requirements.txt 2023-11-29 04:20:18.000000000 +0100
+++ new/tornado-6.4.1/requirements.txt 2024-06-06 20:12:50.000000000 +0200
@@ -8,7 +8,7 @@
# via sphinx
babel==2.11.0
# via sphinx
-black==22.12.0
+black==24.4.2
# via -r requirements.in
build==0.10.0
# via pip-tools
@@ -38,11 +38,11 @@
# virtualenv
flake8==6.0.0
# via -r requirements.in
-idna==3.4
+idna==3.7
# via requests
imagesize==1.4.1
# via sphinx
-jinja2==3.1.2
+jinja2==3.1.4
# via sphinx
markupsafe==2.1.2
# via jinja2
@@ -56,6 +56,7 @@
# mypy
packaging==23.1
# via
+ # black
# build
# pyproject-api
# sphinx
@@ -83,7 +84,7 @@
# via build
pytz==2022.7.1
# via babel
-requests==2.31.0
+requests==2.32.2
# via sphinx
snowballstemmer==2.2.0
# via sphinx
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.4/tornado/__init__.py
new/tornado-6.4.1/tornado/__init__.py
--- old/tornado-6.4/tornado/__init__.py 2023-11-29 04:20:18.000000000 +0100
+++ new/tornado-6.4.1/tornado/__init__.py 2024-06-06 20:12:50.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.4"
-version_info = (6, 4, 0, 0)
+version = "6.4.1"
+version_info = (6, 4, 0, 1)
import importlib
import typing
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.4/tornado/concurrent.py
new/tornado-6.4.1/tornado/concurrent.py
--- old/tornado-6.4/tornado/concurrent.py 2023-11-29 04:20:18.000000000
+0100
+++ new/tornado-6.4.1/tornado/concurrent.py 2024-06-06 20:12:50.000000000
+0200
@@ -118,6 +118,7 @@
The ``callback`` argument was removed.
"""
+
# Fully type-checking decorators is tricky, and this one is
# discouraged anyway so it doesn't have all the generic magic.
def run_on_executor_decorator(fn: Callable) -> Callable[..., Future]:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.4/tornado/curl_httpclient.py
new/tornado-6.4.1/tornado/curl_httpclient.py
--- old/tornado-6.4/tornado/curl_httpclient.py 2023-11-29 04:20:18.000000000
+0100
+++ new/tornado-6.4.1/tornado/curl_httpclient.py 2024-06-06
20:12:50.000000000 +0200
@@ -19,6 +19,7 @@
import functools
import logging
import pycurl
+import re
import threading
import time
from io import BytesIO
@@ -44,6 +45,8 @@
curl_log = logging.getLogger("tornado.curl_httpclient")
+CR_OR_LF_RE = re.compile(b"\r|\n")
+
class CurlAsyncHTTPClient(AsyncHTTPClient):
def initialize( # type: ignore
@@ -347,14 +350,15 @@
if "Pragma" not in request.headers:
request.headers["Pragma"] = ""
- curl.setopt(
- pycurl.HTTPHEADER,
- [
- b"%s: %s"
- % (native_str(k).encode("ASCII"),
native_str(v).encode("ISO8859-1"))
- for k, v in request.headers.get_all()
- ],
- )
+ encoded_headers = [
+ b"%s: %s"
+ % (native_str(k).encode("ASCII"),
native_str(v).encode("ISO8859-1"))
+ for k, v in request.headers.get_all()
+ ]
+ for line in encoded_headers:
+ if CR_OR_LF_RE.search(line):
+ raise ValueError("Illegal characters in header (CR or LF): %r"
% line)
+ curl.setopt(pycurl.HTTPHEADER, encoded_headers)
curl.setopt(
pycurl.HEADERFUNCTION,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.4/tornado/gen.py
new/tornado-6.4.1/tornado/gen.py
--- old/tornado-6.4/tornado/gen.py 2023-11-29 04:20:18.000000000 +0100
+++ new/tornado-6.4.1/tornado/gen.py 2024-06-06 20:12:50.000000000 +0200
@@ -66,6 +66,7 @@
via ``singledispatch``.
"""
+
import asyncio
import builtins
import collections
@@ -165,13 +166,11 @@
@overload
def coroutine(
func: Callable[..., "Generator[Any, Any, _T]"]
-) -> Callable[..., "Future[_T]"]:
- ...
+) -> Callable[..., "Future[_T]"]: ...
@overload
-def coroutine(func: Callable[..., _T]) -> Callable[..., "Future[_T]"]:
- ...
+def coroutine(func: Callable[..., _T]) -> Callable[..., "Future[_T]"]: ...
def coroutine(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.4/tornado/http1connection.py
new/tornado-6.4.1/tornado/http1connection.py
--- old/tornado-6.4/tornado/http1connection.py 2023-11-29 04:20:18.000000000
+0100
+++ new/tornado-6.4.1/tornado/http1connection.py 2024-06-06
20:12:50.000000000 +0200
@@ -38,6 +38,8 @@
from typing import cast, Optional, Type, Awaitable, Callable, Union, Tuple
+CR_OR_LF_RE = re.compile(b"\r|\n")
+
class _QuietException(Exception):
def __init__(self) -> None:
@@ -389,14 +391,11 @@
self._request_start_line = start_line
lines.append(utf8("%s %s HTTP/1.1" % (start_line[0],
start_line[1])))
# Client requests with a non-empty body must have either a
- # Content-Length or a Transfer-Encoding.
+ # Content-Length or a Transfer-Encoding. If Content-Length is not
+ # present we'll add our Transfer-Encoding below.
self._chunking_output = (
start_line.method in ("POST", "PUT", "PATCH")
and "Content-Length" not in headers
- and (
- "Transfer-Encoding" not in headers
- or headers["Transfer-Encoding"] == "chunked"
- )
)
else:
assert isinstance(start_line, httputil.ResponseStartLine)
@@ -418,9 +417,6 @@
and (start_line.code < 100 or start_line.code >= 200)
# No need to chunk the output if a Content-Length is specified.
and "Content-Length" not in headers
- # Applications are discouraged from touching Transfer-Encoding,
- # but if they do, leave it alone.
- and "Transfer-Encoding" not in headers
)
# If connection to a 1.1 client will be closed, inform client
if (
@@ -453,8 +449,8 @@
)
lines.extend(line.encode("latin1") for line in header_lines)
for line in lines:
- if b"\n" in line:
- raise ValueError("Newline in header: " + repr(line))
+ if CR_OR_LF_RE.search(line):
+ raise ValueError("Illegal characters (CR or LF) in header: %r"
% line)
future = None
if self.stream.closed():
future = self._write_future = Future()
@@ -560,7 +556,7 @@
return connection_header != "close"
elif (
"Content-Length" in headers
- or headers.get("Transfer-Encoding", "").lower() == "chunked"
+ or is_transfer_encoding_chunked(headers)
or getattr(start_line, "method", None) in ("HEAD", "GET")
):
# start_line may be a request or response start line; only
@@ -598,13 +594,6 @@
delegate: httputil.HTTPMessageDelegate,
) -> Optional[Awaitable[None]]:
if "Content-Length" in headers:
- if "Transfer-Encoding" in headers:
- # Response cannot contain both Content-Length and
- # Transfer-Encoding headers.
- # http://tools.ietf.org/html/rfc7230#section-3.3.3
- raise httputil.HTTPInputError(
- "Response with both Transfer-Encoding and Content-Length"
- )
if "," in headers["Content-Length"]:
# Proxies sometimes cause Content-Length headers to get
# duplicated. If all the values are identical then we can
@@ -631,20 +620,22 @@
else:
content_length = None
+ is_chunked = is_transfer_encoding_chunked(headers)
+
if code == 204:
# This response code is not allowed to have a non-empty body,
# and has an implicit length of zero instead of read-until-close.
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.3
- if "Transfer-Encoding" in headers or content_length not in (None,
0):
+ if is_chunked or content_length not in (None, 0):
raise httputil.HTTPInputError(
"Response with code %d should not have body" % code
)
content_length = 0
+ if is_chunked:
+ return self._read_chunked_body(delegate)
if content_length is not None:
return self._read_fixed_body(content_length, delegate)
- if headers.get("Transfer-Encoding", "").lower() == "chunked":
- return self._read_chunked_body(delegate)
if self.is_client:
return self._read_body_until_close(delegate)
return None
@@ -863,3 +854,33 @@
if HEXDIGITS.fullmatch(s) is None:
raise ValueError("not a hexadecimal integer: %r" % s)
return int(s, 16)
+
+
+def is_transfer_encoding_chunked(headers: httputil.HTTPHeaders) -> bool:
+ """Returns true if the headers specify Transfer-Encoding: chunked.
+
+ Raise httputil.HTTPInputError if any other transfer encoding is used.
+ """
+ # Note that transfer-encoding is an area in which postel's law can lead
+ # us astray. If a proxy and a backend server are liberal in what they
accept,
+ # but accept slightly different things, this can lead to mismatched framing
+ # and request smuggling issues. Therefore we are as strict as possible here
+ # (even technically going beyond the requirements of the RFCs: a value of
+ # ",chunked" is legal but doesn't appear in practice for legitimate
traffic)
+ if "Transfer-Encoding" not in headers:
+ return False
+ if "Content-Length" in headers:
+ # Message cannot contain both Content-Length and
+ # Transfer-Encoding headers.
+ # http://tools.ietf.org/html/rfc7230#section-3.3.3
+ raise httputil.HTTPInputError(
+ "Message with both Transfer-Encoding and Content-Length"
+ )
+ if headers["Transfer-Encoding"].lower() == "chunked":
+ return True
+ # We do not support any transfer-encodings other than chunked, and we do
not
+ # expect to add any support because the concept of transfer-encoding has
+ # been removed in HTTP/2.
+ raise httputil.HTTPInputError(
+ "Unsupported Transfer-Encoding %s" % headers["Transfer-Encoding"]
+ )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.4/tornado/httputil.py
new/tornado-6.4.1/tornado/httputil.py
--- old/tornado-6.4/tornado/httputil.py 2023-11-29 04:20:18.000000000 +0100
+++ new/tornado-6.4.1/tornado/httputil.py 2024-06-06 20:12:50.000000000
+0200
@@ -62,6 +62,9 @@
from asyncio import Future # noqa: F401
import unittest # noqa: F401
+# To be used with str.strip() and related methods.
+HTTP_WHITESPACE = " \t"
+
@lru_cache(1000)
def _normalize_header(name: str) -> str:
@@ -171,7 +174,7 @@
# continuation of a multi-line header
if self._last_key is None:
raise HTTPInputError("first header line cannot start with
whitespace")
- new_part = " " + line.lstrip()
+ new_part = " " + line.lstrip(HTTP_WHITESPACE)
self._as_list[self._last_key][-1] += new_part
self._dict[self._last_key] += new_part
else:
@@ -179,7 +182,7 @@
name, value = line.split(":", 1)
except ValueError:
raise HTTPInputError("no colon in header line")
- self.add(name, value.strip())
+ self.add(name, value.strip(HTTP_WHITESPACE))
@classmethod
def parse(cls, headers: str) -> "HTTPHeaders":
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.4/tornado/iostream.py
new/tornado-6.4.1/tornado/iostream.py
--- old/tornado-6.4/tornado/iostream.py 2023-11-29 04:20:18.000000000 +0100
+++ new/tornado-6.4.1/tornado/iostream.py 2024-06-06 20:12:50.000000000
+0200
@@ -1374,7 +1374,7 @@
return
elif err.args[0] in (ssl.SSL_ERROR_EOF, ssl.SSL_ERROR_ZERO_RETURN):
return self.close(exc_info=err)
- elif err.args[0] == ssl.SSL_ERROR_SSL:
+ elif err.args[0] in (ssl.SSL_ERROR_SSL, ssl.SSL_ERROR_SYSCALL):
try:
peer = self.socket.getpeername()
except Exception:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.4/tornado/simple_httpclient.py
new/tornado-6.4.1/tornado/simple_httpclient.py
--- old/tornado-6.4/tornado/simple_httpclient.py 2023-11-29
04:20:18.000000000 +0100
+++ new/tornado-6.4.1/tornado/simple_httpclient.py 2024-06-06
20:12:50.000000000 +0200
@@ -429,9 +429,9 @@
self.request.method == "POST"
and "Content-Type" not in self.request.headers
):
- self.request.headers[
- "Content-Type"
- ] = "application/x-www-form-urlencoded"
+ self.request.headers["Content-Type"] = (
+ "application/x-www-form-urlencoded"
+ )
if self.request.decompress_response:
self.request.headers["Accept-Encoding"] = "gzip"
req_path = (self.parsed.path or "/") + (
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.4/tornado/test/__main__.py
new/tornado-6.4.1/tornado/test/__main__.py
--- old/tornado-6.4/tornado/test/__main__.py 2023-11-29 04:20:18.000000000
+0100
+++ new/tornado-6.4.1/tornado/test/__main__.py 2024-06-06 20:12:50.000000000
+0200
@@ -2,6 +2,7 @@
This only works in python 2.7+.
"""
+
from tornado.test.runtests import all, main
# tornado.testing.main autodiscovery relies on 'all' being present in
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.4/tornado/test/escape_test.py
new/tornado-6.4.1/tornado/test/escape_test.py
--- old/tornado-6.4/tornado/test/escape_test.py 2023-11-29 04:20:18.000000000
+0100
+++ new/tornado-6.4.1/tornado/test/escape_test.py 2024-06-06
20:12:50.000000000 +0200
@@ -194,9 +194,11 @@
(
"www.external-link.com and www.internal-link.com/blogs extra",
{
- "extra_params": lambda href: 'class="internal"'
- if href.startswith("http://www.internal-link.com")
- else 'rel="nofollow" class="external"'
+ "extra_params": lambda href: (
+ 'class="internal"'
+ if href.startswith("http://www.internal-link.com")
+ else 'rel="nofollow" class="external"'
+ )
},
'<a href="http://www.external-link.com" rel="nofollow"
class="external">www.external-link.com</a>' # noqa: E501
' and <a href="http://www.internal-link.com/blogs"
class="internal">www.internal-link.com/blogs</a> extra', # noqa: E501
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.4/tornado/test/httpclient_test.py
new/tornado-6.4.1/tornado/test/httpclient_test.py
--- old/tornado-6.4/tornado/test/httpclient_test.py 2023-11-29
04:20:18.000000000 +0100
+++ new/tornado-6.4.1/tornado/test/httpclient_test.py 2024-06-06
20:12:50.000000000 +0200
@@ -725,6 +725,22 @@
if el.logged_stack:
break
+ def test_header_crlf(self):
+ # Ensure that the client doesn't allow CRLF injection in headers. RFC
9112 section 2.2
+ # prohibits a bare CR specifically and "a recipient MAY recognize a
single LF as a line
+ # terminator" so we check each character separately as well as the
(redundant) CRLF pair.
+ for header, name in [
+ ("foo\rbar:", "cr"),
+ ("foo\nbar:", "lf"),
+ ("foo\r\nbar:", "crlf"),
+ ]:
+ with self.subTest(name=name, position="value"):
+ with self.assertRaises(ValueError):
+ self.fetch("/hello", headers={"foo": header})
+ with self.subTest(name=name, position="key"):
+ with self.assertRaises(ValueError):
+ self.fetch("/hello", headers={header: "foo"})
+
class RequestProxyTest(unittest.TestCase):
def test_request_set(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.4/tornado/test/httpserver_test.py
new/tornado-6.4.1/tornado/test/httpserver_test.py
--- old/tornado-6.4/tornado/test/httpserver_test.py 2023-11-29
04:20:18.000000000 +0100
+++ new/tornado-6.4.1/tornado/test/httpserver_test.py 2024-06-06
20:12:50.000000000 +0200
@@ -581,6 +581,76 @@
)
self.assertEqual(400, start_line.code)
+ def test_chunked_request_body_duplicate_header(self):
+ # Repeated Transfer-Encoding headers should be an error (and not
confuse
+ # the chunked-encoding detection to mess up framing).
+ self.stream.write(
+ b"""\
+POST /echo HTTP/1.1
+Transfer-Encoding: chunked
+Transfer-encoding: chunked
+
+2
+ok
+0
+
+"""
+ )
+ with ExpectLog(
+ gen_log,
+ ".*Unsupported Transfer-Encoding chunked,chunked",
+ level=logging.INFO,
+ ):
+ start_line, headers, response = self.io_loop.run_sync(
+ lambda: read_stream_body(self.stream)
+ )
+ self.assertEqual(400, start_line.code)
+
+ def test_chunked_request_body_unsupported_transfer_encoding(self):
+ # We don't support transfer-encodings other than chunked.
+ self.stream.write(
+ b"""\
+POST /echo HTTP/1.1
+Transfer-Encoding: gzip, chunked
+
+2
+ok
+0
+
+"""
+ )
+ with ExpectLog(
+ gen_log, ".*Unsupported Transfer-Encoding gzip, chunked",
level=logging.INFO
+ ):
+ start_line, headers, response = self.io_loop.run_sync(
+ lambda: read_stream_body(self.stream)
+ )
+ self.assertEqual(400, start_line.code)
+
+ def test_chunked_request_body_transfer_encoding_and_content_length(self):
+ # Transfer-encoding and content-length are mutually exclusive
+ self.stream.write(
+ b"""\
+POST /echo HTTP/1.1
+Transfer-Encoding: chunked
+Content-Length: 2
+
+2
+ok
+0
+
+"""
+ )
+ with ExpectLog(
+ gen_log,
+ ".*Message with both Transfer-Encoding and Content-Length",
+ level=logging.INFO,
+ ):
+ start_line, headers, response = self.io_loop.run_sync(
+ lambda: read_stream_body(self.stream)
+ )
+ self.assertEqual(400, start_line.code)
+
@gen_test
def test_invalid_content_length(self):
# HTTP only allows decimal digits in content-length. Make sure we don't
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.4/tornado/test/httputil_test.py
new/tornado-6.4.1/tornado/test/httputil_test.py
--- old/tornado-6.4/tornado/test/httputil_test.py 2023-11-29
04:20:18.000000000 +0100
+++ new/tornado-6.4.1/tornado/test/httputil_test.py 2024-06-06
20:12:50.000000000 +0200
@@ -334,6 +334,25 @@
gen_log.warning("failed while trying %r in %s", newline,
encoding)
raise
+ def test_unicode_whitespace(self):
+ # Only tabs and spaces are to be stripped according to the HTTP
standard.
+ # Other unicode whitespace is to be left as-is. In the context of
headers,
+ # this specifically means the whitespace characters falling within the
+ # latin1 charset.
+ whitespace = [
+ (" ", True), # SPACE
+ ("\t", True), # TAB
+ ("\u00a0", False), # NON-BREAKING SPACE
+ ("\u0085", False), # NEXT LINE
+ ]
+ for c, stripped in whitespace:
+ headers = HTTPHeaders.parse("Transfer-Encoding: %schunked" % c)
+ if stripped:
+ expected = [("Transfer-Encoding", "chunked")]
+ else:
+ expected = [("Transfer-Encoding", "%schunked" % c)]
+ self.assertEqual(expected, list(headers.get_all()))
+
def test_optional_cr(self):
# Both CRLF and LF should be accepted as separators. CR should not be
# part of the data when followed by LF, but it is a normal char
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.4/tornado/test/ioloop_test.py
new/tornado-6.4.1/tornado/test/ioloop_test.py
--- old/tornado-6.4/tornado/test/ioloop_test.py 2023-11-29 04:20:18.000000000
+0100
+++ new/tornado-6.4.1/tornado/test/ioloop_test.py 2024-06-06
20:12:50.000000000 +0200
@@ -261,6 +261,7 @@
the object should be closed (by IOLoop.close(all_fds=True),
not just the fd.
"""
+
# Use a socket since they are supported by IOLoop on all platforms.
# Unfortunately, sockets don't support the .closed attribute for
# inspecting their close status, so we must use a wrapper.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.4/tornado/test/simple_httpclient_test.py
new/tornado-6.4.1/tornado/test/simple_httpclient_test.py
--- old/tornado-6.4/tornado/test/simple_httpclient_test.py 2023-11-29
04:20:18.000000000 +0100
+++ new/tornado-6.4.1/tornado/test/simple_httpclient_test.py 2024-06-06
20:12:50.000000000 +0200
@@ -828,7 +828,7 @@
with ExpectLog(
gen_log,
(
- "Malformed HTTP message from None: Response "
+ "Malformed HTTP message from None: Message "
"with both Transfer-Encoding and Content-Length"
),
level=logging.INFO,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.4/tornado/test/testing_test.py
new/tornado-6.4.1/tornado/test/testing_test.py
--- old/tornado-6.4/tornado/test/testing_test.py 2023-11-29
04:20:18.000000000 +0100
+++ new/tornado-6.4.1/tornado/test/testing_test.py 2024-06-06
20:12:50.000000000 +0200
@@ -5,7 +5,6 @@
from tornado.web import Application
import asyncio
import contextlib
-import inspect
import gc
import os
import platform
@@ -118,7 +117,11 @@
super().tearDown()
-class AsyncTestCaseWrapperTest(unittest.TestCase):
+class AsyncTestCaseReturnAssertionsTest(unittest.TestCase):
+ # These tests verify that tests that return non-None values (without being
decorated with
+ # @gen_test) raise errors instead of incorrectly succeeding. These tests
should be removed or
+ # updated when the _callTestMethod method is removed from AsyncTestCase
(the same checks will
+ # still happen, but they'll be performed in the stdlib as
DeprecationWarnings)
def test_undecorated_generator(self):
class Test(AsyncTestCase):
def test_gen(self):
@@ -135,7 +138,10 @@
"pypy destructor warnings cannot be silenced",
)
@unittest.skipIf(
- sys.version_info >= (3, 12), "py312 has its own check for test case
returns"
+ # This check actually exists in 3.11 but it changed in 3.12 in a way
that breaks
+ # this test.
+ sys.version_info >= (3, 12),
+ "py312 has its own check for test case returns",
)
def test_undecorated_coroutine(self):
class Test(AsyncTestCase):
@@ -176,17 +182,6 @@
self.assertEqual(len(result.errors), 1)
self.assertIn("Return value from test method ignored",
result.errors[0][1])
- def test_unwrap(self):
- class Test(AsyncTestCase):
- def test_foo(self):
- pass
-
- test = Test("test_foo")
- self.assertIs(
- inspect.unwrap(test.test_foo),
- test.test_foo.orig_method, # type: ignore[attr-defined]
- )
-
class SetUpTearDownTest(unittest.TestCase):
def test_set_up_tear_down(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.4/tornado/testing.py
new/tornado-6.4.1/tornado/testing.py
--- old/tornado-6.4/tornado/testing.py 2023-11-29 04:20:18.000000000 +0100
+++ new/tornado-6.4.1/tornado/testing.py 2024-06-06 20:12:50.000000000
+0200
@@ -84,39 +84,6 @@
return 5
-class _TestMethodWrapper(object):
- """Wraps a test method to raise an error if it returns a value.
-
- This is mainly used to detect undecorated generators (if a test
- method yields it must use a decorator to consume the generator),
- but will also detect other kinds of return values (these are not
- necessarily errors, but we alert anyway since there is no good
- reason to return a value from a test).
- """
-
- def __init__(self, orig_method: Callable) -> None:
- self.orig_method = orig_method
- self.__wrapped__ = orig_method
-
- def __call__(self, *args: Any, **kwargs: Any) -> None:
- result = self.orig_method(*args, **kwargs)
- if isinstance(result, Generator) or inspect.iscoroutine(result):
- raise TypeError(
- "Generator and coroutine test methods should be"
- " decorated with tornado.testing.gen_test"
- )
- elif result is not None:
- raise ValueError("Return value from test method ignored: %r" %
result)
-
- def __getattr__(self, name: str) -> Any:
- """Proxy all unknown attributes to the original method.
-
- This is important for some of the decorators in the `unittest`
- module, such as `unittest.skipIf`.
- """
- return getattr(self.orig_method, name)
-
-
class AsyncTestCase(unittest.TestCase):
"""`~unittest.TestCase` subclass for testing `.IOLoop`-based
asynchronous code.
@@ -173,12 +140,6 @@
self.__stop_args = None # type: Any
self.__timeout = None # type: Optional[object]
- # It's easy to forget the @gen_test decorator, but if you do
- # the test will silently be ignored because nothing will consume
- # the generator. Replace the test method with a wrapper that will
- # make sure it's not an undecorated generator.
- setattr(self, methodName, _TestMethodWrapper(getattr(self,
methodName)))
-
# Not used in this class itself, but used by @gen_test
self._test_generator = None # type: Optional[Union[Generator,
Coroutine]]
@@ -289,6 +250,30 @@
self.__rethrow()
return ret
+ def _callTestMethod(self, method: Callable) -> None:
+ """Run the given test method, raising an error if it returns non-None.
+
+ Failure to decorate asynchronous test methods with ``@gen_test`` can
lead to tests
+ incorrectly passing.
+
+ Remove this override when Python 3.10 support is dropped. This check
(in the form of a
+ DeprecationWarning) became a part of the standard library in 3.11.
+
+ Note that ``_callTestMethod`` is not documented as a public interface.
However, it is
+ present in all supported versions of Python (3.8+), and if it goes
away in the future that's
+ OK because we can just remove this override as noted above.
+ """
+ # Calling super()._callTestMethod would hide the return value, even in
python 3.8-3.10
+ # where the check isn't being done for us.
+ result = method()
+ if isinstance(result, Generator) or inspect.iscoroutine(result):
+ raise TypeError(
+ "Generator and coroutine test methods should be"
+ " decorated with tornado.testing.gen_test"
+ )
+ elif result is not None:
+ raise ValueError("Return value from test method ignored: %r" %
result)
+
def stop(self, _arg: Any = None, **kwargs: Any) -> None:
"""Stops the `.IOLoop`, causing one pending (or future) call to
`wait()`
to return.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.4/tornado/websocket.py
new/tornado-6.4.1/tornado/websocket.py
--- old/tornado-6.4/tornado/websocket.py 2023-11-29 04:20:18.000000000
+0100
+++ new/tornado-6.4.1/tornado/websocket.py 2024-06-06 20:12:50.000000000
+0200
@@ -1392,9 +1392,9 @@
# from the server).
# TODO: set server parameters for deflate extension
# if requested in self.compression_options.
- request.headers[
- "Sec-WebSocket-Extensions"
- ] = "permessage-deflate; client_max_window_bits"
+ request.headers["Sec-WebSocket-Extensions"] = (
+ "permessage-deflate; client_max_window_bits"
+ )
# Websocket connection is currently unable to follow redirects
request.follow_redirects = False
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/tornado-6.4/tornado.egg-info/PKG-INFO
new/tornado-6.4.1/tornado.egg-info/PKG-INFO
--- old/tornado-6.4/tornado.egg-info/PKG-INFO 2023-11-29 04:20:19.000000000
+0100
+++ new/tornado-6.4.1/tornado.egg-info/PKG-INFO 2024-06-06 20:12:53.000000000
+0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: tornado
-Version: 6.4
+Version: 6.4.1
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.4/tornado.egg-info/SOURCES.txt
new/tornado-6.4.1/tornado.egg-info/SOURCES.txt
--- old/tornado-6.4/tornado.egg-info/SOURCES.txt 2023-11-29
04:20:19.000000000 +0100
+++ new/tornado-6.4.1/tornado.egg-info/SOURCES.txt 2024-06-06
20:12:53.000000000 +0200
@@ -114,6 +114,7 @@
docs/releases/v6.3.2.rst
docs/releases/v6.3.3.rst
docs/releases/v6.4.0.rst
+docs/releases/v6.4.1.rst
tornado/__init__.py
tornado/_locale_data.py
tornado/auth.py