Hello community,

here is the log from the commit of package python-gunicorn for openSUSE:Factory 
checked in at 2020-04-04 12:19:47
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-gunicorn (Old)
 and      /work/SRC/openSUSE:Factory/.python-gunicorn.new.3248 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-gunicorn"

Sat Apr  4 12:19:47 2020 rev:17 rq:790071 version:19.10.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-gunicorn/python-gunicorn.changes  
2019-07-30 13:04:08.590405200 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-gunicorn.new.3248/python-gunicorn.changes    
    2020-04-04 12:19:51.451646457 +0200
@@ -1,0 +2,18 @@
+Tue Mar 31 09:59:42 UTC 2020 - Ondřej Súkup <[email protected]>
+
+- update to 19.10.0
+- last with py2 support
+ * unblock select loop during reload of a sync worker
+ * security fix: http desync attack
+ * handle `wsgi.input_terminated`
+ * added support for str and bytes in unix  socket addresses
+ * fixed `max_requests` setting
+ * headers values are now encoded as LATN1, not ASCII
+ * fixed `InotifyReloadeder`:  handle `module.__file__` is None
+ * fixed compatibility with tornado 6
+ * fixed root logging
+ * Prevent removalof unix sockets from `reuse_port`
+ * Clear tornado ioloop before os.fork
+ * Miscellaneous fixes and improvement for linting using Pylints
+
+-------------------------------------------------------------------

Old:
----
  gunicorn-19.9.0.tar.gz

New:
----
  gunicorn-19.10.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-gunicorn.spec ++++++
--- /var/tmp/diff_new_pack.Foqjmt/_old  2020-04-04 12:19:52.955647750 +0200
+++ /var/tmp/diff_new_pack.Foqjmt/_new  2020-04-04 12:19:52.959647753 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-gunicorn
 #
-# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2020 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-gunicorn
-Version:        19.9.0
+Version:        19.10.0
 Release:        0
 Summary:        WSGI HTTP Server for UNIX
 License:        MIT
@@ -73,7 +73,7 @@
 %python_expand %fdupes %{buildroot}%{$python_sitelib}
 
 %check
-%python_exec setup.py test
+%pytest
 
 %post
 %python_install_alternative gunicorn

++++++ gunicorn-19.9.0.tar.gz -> gunicorn-19.10.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/PKG-INFO 
new/gunicorn-19.10.0/PKG-INFO
--- old/gunicorn-19.9.0/PKG-INFO        2018-07-03 22:11:42.000000000 +0200
+++ new/gunicorn-19.10.0/PKG-INFO       2019-11-23 10:51:47.701091800 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: gunicorn
-Version: 19.9.0
+Version: 19.10.0
 Summary: WSGI HTTP Server for UNIX
 Home-page: http://gunicorn.org
 Author: Benoit Chesneau
@@ -88,6 +88,7 @@
 Classifier: Programming Language :: Python :: 3.4
 Classifier: Programming Language :: Python :: 3.5
 Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
 Classifier: Topic :: Internet
 Classifier: Topic :: Utilities
 Classifier: Topic :: Software Development :: Libraries :: Python Modules
@@ -96,7 +97,7 @@
 Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Server
 Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
 Requires-Python: >=2.6, !=3.0.*, !=3.1.*
-Provides-Extra: tornado
 Provides-Extra: gevent
 Provides-Extra: eventlet
+Provides-Extra: tornado
 Provides-Extra: gthread
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/THANKS new/gunicorn-19.10.0/THANKS
--- old/gunicorn-19.9.0/THANKS  2018-06-29 20:06:23.000000000 +0200
+++ new/gunicorn-19.10.0/THANKS 2019-11-23 10:49:49.000000000 +0100
@@ -173,3 +173,4 @@
 Xie Shi <[email protected]>
 Yue Du <[email protected]>
 zakdances <[email protected]>
+Emile Fugulin <[email protected]>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/docs/site/index.html 
new/gunicorn-19.10.0/docs/site/index.html
--- old/gunicorn-19.9.0/docs/site/index.html    2018-07-03 22:08:39.000000000 
+0200
+++ new/gunicorn-19.10.0/docs/site/index.html   2019-11-23 10:49:49.000000000 
+0100
@@ -16,7 +16,7 @@
     <div class="logo-div">
       <div class="latest">
         Latest version: <strong><a
-            href="http://docs.gunicorn.org/en/stable";>19.9.0</a></strong>
+            href="https://docs.gunicorn.org/en/stable/";>19.9.0</a></strong>
       </div>
 
       <div class="logo"><img src="images/logo.jpg" ></div>
@@ -179,7 +179,7 @@
     </div>
   </div>
 
-  <script 
src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js";></script>
+  <script 
src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js";></script>
   <script src="js/main.js"></script>
 </body>
 </html>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/docs/source/settings.rst 
new/gunicorn-19.10.0/docs/source/settings.rst
--- old/gunicorn-19.9.0/docs/source/settings.rst        2018-07-03 
22:08:22.000000000 +0200
+++ new/gunicorn-19.10.0/docs/source/settings.rst       2019-11-23 
10:49:50.000000000 +0100
@@ -829,7 +829,7 @@
 ~~~~~
 
 * ``--chdir``
-* ``/Users/randall/src/gunicorn/docs/source``
+* ``/usr/src/app``
 
 Chdir to specified directory before apps loading.
 
@@ -1235,7 +1235,7 @@
 
 The maximum number of requests a worker will process before restarting.
 
-Any value greater than zero will limit the number of requests a work
+Any value greater than zero will limit the number of requests a worker
 will process before automatically restarting. This is a simple method
 to help limit the damage of memory leaks.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/examples/echo.py 
new/gunicorn-19.10.0/examples/echo.py
--- old/gunicorn-19.9.0/examples/echo.py        2018-04-30 20:14:25.000000000 
+0200
+++ new/gunicorn-19.10.0/examples/echo.py       2019-11-23 10:49:50.000000000 
+0100
@@ -24,8 +24,7 @@
     response_headers = [
         ('Content-type', 'text/plain'),
         ('Content-Length', str(len(data))),
-        ('X-Gunicorn-Version', __version__),
-        ("Test", "test тест"),
+        ('X-Gunicorn-Version', __version__)
     ]
     start_response(status, response_headers)
     return iter([data])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/examples/log_app.py 
new/gunicorn-19.10.0/examples/log_app.py
--- old/gunicorn-19.9.0/examples/log_app.py     2017-06-29 22:27:41.000000000 
+0200
+++ new/gunicorn-19.10.0/examples/log_app.py    2019-11-19 22:58:55.000000000 
+0100
@@ -13,4 +13,4 @@
     log.info("Hello Info!")
     log.warn("Hello Warn!")
     log.error("Hello Error!")
-    return ["Hello World!\n"]
+    return [b"Hello World!\n"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/examples/readline.py 
new/gunicorn-19.10.0/examples/readline.py
--- old/gunicorn-19.9.0/examples/readline.py    2017-09-18 03:14:58.000000000 
+0200
+++ new/gunicorn-19.10.0/examples/readline.py   1970-01-01 01:00:00.000000000 
+0100
@@ -1,45 +0,0 @@
-# -*- coding: utf-8 -
-#
-# This file is part of gunicorn released under the MIT license.
-# See the NOTICE for more information.
-#
-# Simple example of readline, reading from a stream then echoing the response
-#
-# Usage:
-#
-# Launch a server with the app in a terminal
-#
-#     $ gunicorn -w3 readline:app
-#
-# Then in another terminal launch the following command:
-#
-#     $ curl -XPOST -d'test\r\ntest2\r\n' -H"Transfer-Encoding: Chunked" 
http://localhost:8000
-
-
-
-from gunicorn import __version__
-
-
-def app(environ, start_response):
-    """Simplest possible application object"""
-    status = '200 OK'
-
-    response_headers = [
-        ('Content-type', 'text/plain'),
-        ('Transfer-Encoding', "chunked"),
-        ('X-Gunicorn-Version', __version__),
-        #("Test", "test тест"),
-    ]
-    start_response(status, response_headers)
-
-    body = environ['wsgi.input']
-
-    lines = []
-    while True:
-        line = body.readline()
-        if line == b"":
-            break
-        print(line)
-        lines.append(line)
-
-    return iter(lines)
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/examples/readline_app.py 
new/gunicorn-19.10.0/examples/readline_app.py
--- old/gunicorn-19.9.0/examples/readline_app.py        1970-01-01 
01:00:00.000000000 +0100
+++ new/gunicorn-19.10.0/examples/readline_app.py       2019-11-19 
22:58:55.000000000 +0100
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -
+#
+# This file is part of gunicorn released under the MIT license.
+# See the NOTICE for more information.
+#
+# Simple example of readline, reading from a stream then echoing the response
+#
+# Usage:
+#
+# Launch a server with the app in a terminal
+#
+#     $ gunicorn -w3 readline_app:app
+#
+# Then in another terminal launch the following command:
+#
+#     $ curl -XPOST -d'test\r\ntest2\r\n' -H"Transfer-Encoding: Chunked" 
http://localhost:8000
+
+
+
+from gunicorn import __version__
+
+
+def app(environ, start_response):
+    """Simplest possible application object"""
+    status = '200 OK'
+
+    response_headers = [
+        ('Content-type', 'text/plain'),
+        ('Transfer-Encoding', "chunked"),
+        ('X-Gunicorn-Version', __version__)
+    ]
+    start_response(status, response_headers)
+
+    body = environ['wsgi.input']
+
+    lines = []
+    while True:
+        line = body.readline()
+        if line == b"":
+            break
+        print(line)
+        lines.append(line)
+
+    return iter(lines)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/examples/test.py 
new/gunicorn-19.10.0/examples/test.py
--- old/gunicorn-19.9.0/examples/test.py        2017-09-18 03:14:58.000000000 
+0200
+++ new/gunicorn-19.10.0/examples/test.py       2019-11-22 14:10:19.000000000 
+0100
@@ -21,7 +21,7 @@
         ('Content-type', 'text/plain'),
         ('Content-Length', str(len(data))),
         ('X-Gunicorn-Version', __version__),
-        #("Test", "test тест"),
+        ('Foo', 'B\u00e5r'),  # Foo: Bår
     ]
     start_response(status, response_headers)
     return iter([data])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/gunicorn/__init__.py 
new/gunicorn-19.10.0/gunicorn/__init__.py
--- old/gunicorn-19.9.0/gunicorn/__init__.py    2018-07-03 22:08:44.000000000 
+0200
+++ new/gunicorn-19.10.0/gunicorn/__init__.py   2019-11-23 10:50:53.000000000 
+0100
@@ -3,6 +3,6 @@
 # This file is part of gunicorn released under the MIT license.
 # See the NOTICE for more information.
 
-version_info = (19, 9, 0)
+version_info = (19, 10, 0)
 __version__ = ".".join([str(v) for v in version_info])
 SERVER_SOFTWARE = "gunicorn/%s" % __version__
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/gunicorn/app/wsgiapp.py 
new/gunicorn-19.10.0/gunicorn/app/wsgiapp.py
--- old/gunicorn-19.9.0/gunicorn/app/wsgiapp.py 2018-06-29 20:06:20.000000000 
+0200
+++ new/gunicorn-19.10.0/gunicorn/app/wsgiapp.py        2019-11-23 
10:49:50.000000000 +0100
@@ -30,7 +30,7 @@
             from .pasterapp import paste_config
             return paste_config(self.cfg, self.cfgurl, self.relpath)
 
-        if len(args) < 1:
+        if not args:
             parser.error("No application module specified.")
 
         self.cfg.set("default_proc_name", args[0])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/gunicorn/arbiter.py 
new/gunicorn-19.10.0/gunicorn/arbiter.py
--- old/gunicorn-19.9.0/gunicorn/arbiter.py     2018-01-22 20:16:44.000000000 
+0100
+++ new/gunicorn-19.10.0/gunicorn/arbiter.py    2019-11-23 10:49:50.000000000 
+0100
@@ -377,8 +377,11 @@
         :attr graceful: boolean, If True (the default) workers will be
         killed gracefully  (ie. trying to wait for the current connection)
         """
-
-        unlink = self.reexec_pid == self.master_pid == 0 and not self.systemd
+        unlink = (
+            self.reexec_pid == self.master_pid == 0
+            and not self.systemd
+            and not self.cfg.reuse_port
+        )
         sock.close_sockets(self.LISTENERS, unlink)
 
         self.LISTENERS = []
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/gunicorn/config.py 
new/gunicorn-19.10.0/gunicorn/config.py
--- old/gunicorn-19.9.0/gunicorn/config.py      2018-05-26 20:25:25.000000000 
+0200
+++ new/gunicorn-19.10.0/gunicorn/config.py     2019-11-23 10:49:50.000000000 
+0100
@@ -611,7 +611,7 @@
         A string referring to one of the following bundled classes:
 
         * ``sync``
-        * ``eventlet`` - Requires eventlet >= 0.9.7 (or install it via 
+        * ``eventlet`` - Requires eventlet >= 0.24.1 (or install it via 
           ``pip install gunicorn[eventlet]``)
         * ``gevent``   - Requires gevent >= 0.13 (or install it via 
           ``pip install gunicorn[gevent]``)
@@ -686,7 +686,7 @@
     desc = """\
         The maximum number of requests a worker will process before restarting.
 
-        Any value greater than zero will limit the number of requests a work
+        Any value greater than zero will limit the number of requests a worker
         will process before automatically restarting. This is a simple method
         to help limit the damage of memory leaks.
 
@@ -1948,3 +1948,20 @@
 
         .. versionadded:: 19.7
         """
+
+
+class StripHeaderSpaces(Setting):
+    name = "strip_header_spaces"
+    section = "Server Mechanics"
+    cli = ["--strip-header-spaces"]
+    validator = validate_bool
+    action = "store_true"
+    default = False
+    desc = """\
+        Strip spaces present between the header name and the the ``:``.
+        
+        This is known to induce vulnerabilities and is not compliant with the 
HTTP/1.1 standard.
+        See 
https://portswigger.net/research/http-desync-attacks-request-smuggling-reborn.
+        
+        Use with care and only if necessary.
+        """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/gunicorn/glogging.py 
new/gunicorn-19.10.0/gunicorn/glogging.py
--- old/gunicorn-19.9.0/gunicorn/glogging.py    2018-05-26 20:25:25.000000000 
+0200
+++ new/gunicorn-19.10.0/gunicorn/glogging.py   2019-11-23 10:49:50.000000000 
+0100
@@ -54,8 +54,8 @@
         version=1,
         disable_existing_loggers=False,
 
+        root={"level": "INFO", "handlers": ["console"]},
         loggers={
-            "root": {"level": "INFO", "handlers": ["console"]},
             "gunicorn.error": {
                 "level": "INFO",
                 "handlers": ["error_console"],
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/gunicorn/http/message.py 
new/gunicorn-19.10.0/gunicorn/http/message.py
--- old/gunicorn-19.9.0/gunicorn/http/message.py        2018-04-30 
20:34:58.000000000 +0200
+++ new/gunicorn-19.10.0/gunicorn/http/message.py       2019-11-23 
10:49:50.000000000 +0100
@@ -15,7 +15,7 @@
     LimitRequestLine, LimitRequestHeaders)
 from gunicorn.http.errors import InvalidProxyLine, ForbiddenProxyRequest
 from gunicorn.http.errors import InvalidSchemeHeaders
-from gunicorn.six import BytesIO, string_types
+from gunicorn.six import BytesIO
 from gunicorn.util import split_request_uri
 
 MAX_REQUEST_LINE = 8190
@@ -72,11 +72,11 @@
             secure_scheme_headers = cfg.secure_scheme_headers
         elif isinstance(self.unreader, SocketUnreader):
             remote_addr = self.unreader.sock.getpeername()
-            if isinstance(remote_addr, tuple):
+            if self.unreader.sock.family in (socket.AF_INET, socket.AF_INET6):
                 remote_host = remote_addr[0]
                 if remote_host in cfg.forwarded_allow_ips:
                     secure_scheme_headers = cfg.secure_scheme_headers
-            elif isinstance(remote_addr, string_types):
+            elif self.unreader.sock.family == socket.AF_UNIX:
                 secure_scheme_headers = cfg.secure_scheme_headers
 
         # Parse headers into key/value pairs paying attention
@@ -91,7 +91,10 @@
             if curr.find(":") < 0:
                 raise InvalidHeader(curr.strip())
             name, value = curr.split(":", 1)
-            name = name.rstrip(" \t").upper()
+            if self.cfg.strip_header_spaces:
+                name = name.rstrip(" \t").upper()
+            else:
+                name = name.upper()
             if HEADER_RE.search(name):
                 raise InvalidHeaderName(name)
 
@@ -129,9 +132,12 @@
         content_length = None
         for (name, value) in self.headers:
             if name == "CONTENT-LENGTH":
+                if content_length is not None:
+                    raise InvalidHeader("CONTENT-LENGTH", req=self)
                 content_length = value
             elif name == "TRANSFER-ENCODING":
-                chunked = value.lower() == "chunked"
+                if value.lower() == "chunked":
+                    chunked = True
             elif name == "SEC-WEBSOCKET-KEY1":
                 content_length = 8
 
@@ -243,7 +249,7 @@
                 if idx > limit > 0:
                     raise LimitRequestLine(idx, limit)
                 break
-            elif len(data) - 2 > limit > 0:
+            if len(data) - 2 > limit > 0:
                 raise LimitRequestLine(len(data), limit)
             self.get_data(unreader, buf)
             data = buf.getvalue()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/gunicorn/http/wsgi.py 
new/gunicorn-19.10.0/gunicorn/http/wsgi.py
--- old/gunicorn-19.9.0/gunicorn/http/wsgi.py   2018-05-26 20:25:25.000000000 
+0200
+++ new/gunicorn-19.10.0/gunicorn/http/wsgi.py  2019-11-23 10:49:50.000000000 
+0100
@@ -84,6 +84,7 @@
         "wsgi.multiprocess": (cfg.workers > 1),
         "wsgi.run_once": False,
         "wsgi.file_wrapper": FileWrapper,
+        "wsgi.input_terminated": True,
         "SERVER_SOFTWARE": SERVER_SOFTWARE,
     }
 
@@ -141,6 +142,7 @@
             continue
         elif hdr_name == "CONTENT-LENGTH":
             environ['CONTENT_LENGTH'] = hdr_value
+            environ['wsgi.input_terminated'] = False
             continue
 
         key = 'HTTP_' + hdr_name.replace('-', '_')
@@ -326,7 +328,7 @@
         tosend.extend(["%s: %s\r\n" % (k, v) for k, v in self.headers])
 
         header_str = "%s\r\n" % "".join(tosend)
-        util.write(self.sock, util.to_bytestring(header_str, "ascii"))
+        util.write(self.sock, util.to_bytestring(header_str, "latin-1"))
         self.headers_sent = True
 
     def write(self, arg):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/gunicorn/reloader.py 
new/gunicorn-19.10.0/gunicorn/reloader.py
--- old/gunicorn-19.9.0/gunicorn/reloader.py    2018-06-17 22:17:58.000000000 
+0200
+++ new/gunicorn-19.10.0/gunicorn/reloader.py   2019-11-23 10:49:50.000000000 
+0100
@@ -2,6 +2,7 @@
 #
 # This file is part of gunicorn released under the MIT license.
 # See the NOTICE for more information.
+# pylint: disable=no-else-continue
 
 import os
 import os.path
@@ -96,7 +97,7 @@
             fnames = [
                 os.path.dirname(COMPILED_EXT_RE.sub('py', module.__file__))
                 for module in tuple(sys.modules.values())
-                if hasattr(module, '__file__')
+                if getattr(module, '__file__', None)
             ]
 
             return set(fnames)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/gunicorn/sock.py 
new/gunicorn-19.10.0/gunicorn/sock.py
--- old/gunicorn-19.9.0/gunicorn/sock.py        2018-01-22 20:16:44.000000000 
+0100
+++ new/gunicorn-19.10.0/gunicorn/sock.py       2019-11-23 10:49:50.000000000 
+0100
@@ -11,7 +11,7 @@
 import time
 
 from gunicorn import util
-from gunicorn.six import string_types
+from gunicorn.six import string_types, binary_type
 
 
 class BaseSocket(object):
@@ -133,7 +133,7 @@
             sock_type = TCP6Socket
         else:
             sock_type = TCPSocket
-    elif isinstance(addr, string_types):
+    elif isinstance(addr, (string_types, binary_type)):
         sock_type = UnixSocket
     else:
         raise TypeError("Unable to create socket from: %r" % addr)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/gunicorn/util.py 
new/gunicorn-19.10.0/gunicorn/util.py
--- old/gunicorn-19.9.0/gunicorn/util.py        2018-04-28 04:13:16.000000000 
+0200
+++ new/gunicorn-19.10.0/gunicorn/util.py       2019-11-23 10:49:50.000000000 
+0100
@@ -51,7 +51,7 @@
         setproctitle("gunicorn: %s" % title)
 except ImportError:
     def _setproctitle(title):
-        return
+        pass
 
 
 try:
@@ -342,7 +342,7 @@
 def import_app(module):
     parts = module.split(":", 1)
     if len(parts) == 1:
-        module, obj = module, "application"
+        obj = "application"
     else:
         module, obj = parts[0], parts[1]
 
@@ -352,8 +352,7 @@
         if module.endswith(".py") and os.path.exists(module):
             msg = "Failed to find application, did you mean '%s:%s'?"
             raise ImportError(msg % (module.rsplit(".", 1)[0], obj))
-        else:
-            raise
+        raise
 
     mod = sys.modules[module]
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/gunicorn/workers/base.py 
new/gunicorn-19.10.0/gunicorn/workers/base.py
--- old/gunicorn-19.9.0/gunicorn/workers/base.py        2018-06-17 
22:17:58.000000000 +0200
+++ new/gunicorn-19.10.0/gunicorn/workers/base.py       2019-11-23 
10:49:50.000000000 +0100
@@ -18,7 +18,7 @@
 from gunicorn.reloader import reloader_engines
 from gunicorn.http.errors import (
     InvalidHeader, InvalidHeaderName, InvalidRequestLine, InvalidRequestMethod,
-    InvalidHTTPVersion, LimitRequestLine, LimitRequestHeaders,
+    InvalidHTTPVersion, LimitRequestLine, LimitRequestHeaders
 )
 from gunicorn.http.errors import InvalidProxyLine, ForbiddenProxyRequest
 from gunicorn.http.errors import InvalidSchemeHeaders
@@ -51,8 +51,13 @@
         self.reloader = None
 
         self.nr = 0
-        jitter = randint(0, cfg.max_requests_jitter)
-        self.max_requests = cfg.max_requests + jitter or MAXSIZE
+
+        if cfg.max_requests > 0:
+            jitter = randint(0, cfg.max_requests_jitter)
+            self.max_requests = cfg.max_requests + jitter
+        else:
+            self.max_requests = MAXSIZE
+
         self.alive = True
         self.log = log
         self.tmp = WorkerTmp(cfg)
@@ -117,6 +122,7 @@
             def changed(fname):
                 self.log.info("Worker reloading: %s modified", fname)
                 self.alive = False
+                os.write(self.PIPE[1], b"1")
                 self.cfg.worker_int(self)
                 time.sleep(0.1)
                 sys.exit(0)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/gunicorn/workers/geventlet.py 
new/gunicorn-19.10.0/gunicorn/workers/geventlet.py
--- old/gunicorn-19.9.0/gunicorn/workers/geventlet.py   2018-06-29 
20:06:23.000000000 +0200
+++ new/gunicorn-19.10.0/gunicorn/workers/geventlet.py  2019-11-23 
10:49:50.000000000 +0100
@@ -10,12 +10,11 @@
 try:
     import eventlet
 except ImportError:
-    raise RuntimeError("You need eventlet installed to use this worker.")
+    raise RuntimeError("eventlet worker requires eventlet 0.24.1 or higher")
 
 # validate the eventlet version
-if eventlet.version_info < (0, 9, 7):
-    raise RuntimeError("You need eventlet >= 0.9.7")
-
+if eventlet.version_info < (0, 24, 1):
+    raise RuntimeError("eventlet worker requires eventlet 0.24.1 or higher")
 
 from eventlet import hubs, greenthread
 from eventlet.greenio import GreenSocket
@@ -95,12 +94,11 @@
     def is_already_handled(self, respiter):
         if respiter == EVENTLET_ALREADY_HANDLED:
             raise StopIteration()
-        else:
-            return super(EventletWorker, self).is_already_handled(respiter)
+        return super(EventletWorker, self).is_already_handled(respiter)
 
     def init_process(self):
-        super(EventletWorker, self).init_process()
         self.patch()
+        super(EventletWorker, self).init_process()
 
     def handle_quit(self, sig, frame):
         eventlet.spawn(super(EventletWorker, self).handle_quit, sig, frame)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/gunicorn/workers/gthread.py 
new/gunicorn-19.10.0/gunicorn/workers/gthread.py
--- old/gunicorn-19.9.0/gunicorn/workers/gthread.py     2018-04-28 
04:13:16.000000000 +0200
+++ new/gunicorn-19.10.0/gunicorn/workers/gthread.py    2019-11-23 
10:49:50.000000000 +0100
@@ -9,6 +9,7 @@
 # keepalive connections are put back in the loop waiting for an event.
 # If no event happen after the keep alive timeout, the connectoin is
 # closed.
+# pylint: disable=no-else-break
 
 from collections import deque
 from datetime import datetime
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/gunicorn/workers/gtornado.py 
new/gunicorn-19.10.0/gunicorn/workers/gtornado.py
--- old/gunicorn-19.9.0/gunicorn/workers/gtornado.py    2018-04-28 
04:13:16.000000000 +0200
+++ new/gunicorn-19.10.0/gunicorn/workers/gtornado.py   2019-11-23 
10:49:50.000000000 +0100
@@ -69,6 +69,14 @@
                 if not self.ioloop._callbacks:
                     self.ioloop.stop()
 
+    def init_process(self):
+        # IOLoop cannot survive a fork or be shared across processes
+        # in any way. When multiple processes are being used, each process
+        # should create its own IOLoop. We should clear current IOLoop
+        # if exists before os.fork.
+        IOLoop.clear_current()
+        super(TornadoWorker, self).init_process()
+
     def run(self):
         self.ioloop = IOLoop.instance()
         self.alive = True
@@ -84,9 +92,11 @@
         # instance of tornado.web.Application or is an
         # instance of tornado.wsgi.WSGIApplication
         app = self.wsgi
-        if not isinstance(app, tornado.web.Application) or \
-           isinstance(app, tornado.wsgi.WSGIApplication):
-            app = WSGIContainer(app)
+
+        if tornado.version_info[0] < 6:
+            if not isinstance(app, tornado.web.Application) or \
+            isinstance(app, tornado.wsgi.WSGIApplication):
+                app = WSGIContainer(app)
 
         # Monkey-patching HTTPConnection.finish to count the
         # number of requests being handled by Tornado. This
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/gunicorn.egg-info/PKG-INFO 
new/gunicorn-19.10.0/gunicorn.egg-info/PKG-INFO
--- old/gunicorn-19.9.0/gunicorn.egg-info/PKG-INFO      2018-07-03 
22:11:41.000000000 +0200
+++ new/gunicorn-19.10.0/gunicorn.egg-info/PKG-INFO     2019-11-23 
10:51:47.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: gunicorn
-Version: 19.9.0
+Version: 19.10.0
 Summary: WSGI HTTP Server for UNIX
 Home-page: http://gunicorn.org
 Author: Benoit Chesneau
@@ -88,6 +88,7 @@
 Classifier: Programming Language :: Python :: 3.4
 Classifier: Programming Language :: Python :: 3.5
 Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
 Classifier: Topic :: Internet
 Classifier: Topic :: Utilities
 Classifier: Topic :: Software Development :: Libraries :: Python Modules
@@ -96,7 +97,7 @@
 Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Server
 Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
 Requires-Python: >=2.6, !=3.0.*, !=3.1.*
-Provides-Extra: tornado
 Provides-Extra: gevent
 Provides-Extra: eventlet
+Provides-Extra: tornado
 Provides-Extra: gthread
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/gunicorn.egg-info/SOURCES.txt 
new/gunicorn-19.10.0/gunicorn.egg-info/SOURCES.txt
--- old/gunicorn-19.9.0/gunicorn.egg-info/SOURCES.txt   2018-07-03 
22:11:41.000000000 +0200
+++ new/gunicorn-19.10.0/gunicorn.egg-info/SOURCES.txt  2019-11-23 
10:51:47.000000000 +0100
@@ -92,7 +92,7 @@
 examples/multidomainapp.py
 examples/nginx.conf
 examples/read_django_settings.py
-examples/readline.py
+examples/readline_app.py
 examples/sendfile.py
 examples/server.crt
 examples/server.key
@@ -232,6 +232,10 @@
 tests/requests/invalid/018.py
 tests/requests/invalid/019.http
 tests/requests/invalid/019.py
+tests/requests/invalid/020.http
+tests/requests/invalid/020.py
+tests/requests/invalid/021.http
+tests/requests/invalid/021.py
 tests/requests/invalid/pp_01.http
 tests/requests/invalid/pp_01.py
 tests/requests/invalid/pp_02.http
@@ -290,6 +294,12 @@
 tests/requests/valid/026.py
 tests/requests/valid/027.http
 tests/requests/valid/027.py
+tests/requests/valid/028.http
+tests/requests/valid/028.py
+tests/requests/valid/029.http
+tests/requests/valid/029.py
+tests/requests/valid/030.http
+tests/requests/valid/030.py
 tests/requests/valid/099.http
 tests/requests/valid/099.py
 tests/requests/valid/100.http
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/setup.py 
new/gunicorn-19.10.0/setup.py
--- old/gunicorn-19.9.0/setup.py        2018-04-28 04:13:16.000000000 +0200
+++ new/gunicorn-19.10.0/setup.py       2019-11-23 10:49:50.000000000 +0100
@@ -29,6 +29,7 @@
     'Programming Language :: Python :: 3.4',
     'Programming Language :: Python :: 3.5',
     'Programming Language :: Python :: 3.6',
+    'Programming Language :: Python :: 3.7',
     'Topic :: Internet',
     'Topic :: Utilities',
     'Topic :: Software Development :: Libraries :: Python Modules',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/tests/requests/invalid/020.http 
new/gunicorn-19.10.0/tests/requests/invalid/020.http
--- old/gunicorn-19.9.0/tests/requests/invalid/020.http 1970-01-01 
01:00:00.000000000 +0100
+++ new/gunicorn-19.10.0/tests/requests/invalid/020.http        2019-11-20 
21:51:41.000000000 +0100
@@ -0,0 +1,4 @@
+GET /stuff/here?foo=bar HTTP/1.1\r\n
+Content-Length : 3\r\n
+\r\n
+xyz
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/tests/requests/invalid/020.py 
new/gunicorn-19.10.0/tests/requests/invalid/020.py
--- old/gunicorn-19.9.0/tests/requests/invalid/020.py   1970-01-01 
01:00:00.000000000 +0100
+++ new/gunicorn-19.10.0/tests/requests/invalid/020.py  2019-11-20 
21:51:41.000000000 +0100
@@ -0,0 +1,5 @@
+from gunicorn.config import Config
+from gunicorn.http.errors import InvalidHeaderName
+
+cfg = Config()
+request = InvalidHeaderName
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/tests/requests/invalid/021.http 
new/gunicorn-19.10.0/tests/requests/invalid/021.http
--- old/gunicorn-19.9.0/tests/requests/invalid/021.http 1970-01-01 
01:00:00.000000000 +0100
+++ new/gunicorn-19.10.0/tests/requests/invalid/021.http        2019-11-20 
21:52:43.000000000 +0100
@@ -0,0 +1,5 @@
+GET /stuff/here?foo=bar HTTP/1.1\r\n
+Content-Length: 3\r\n
+Content-Length: 2\r\n
+\r\n
+xyz
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/tests/requests/invalid/021.py 
new/gunicorn-19.10.0/tests/requests/invalid/021.py
--- old/gunicorn-19.9.0/tests/requests/invalid/021.py   1970-01-01 
01:00:00.000000000 +0100
+++ new/gunicorn-19.10.0/tests/requests/invalid/021.py  2019-11-20 
21:52:43.000000000 +0100
@@ -0,0 +1,5 @@
+from gunicorn.config import Config
+from gunicorn.http.errors import InvalidHeader
+
+cfg = Config()
+request = InvalidHeader
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/tests/requests/valid/028.http 
new/gunicorn-19.10.0/tests/requests/valid/028.http
--- old/gunicorn-19.9.0/tests/requests/valid/028.http   1970-01-01 
01:00:00.000000000 +0100
+++ new/gunicorn-19.10.0/tests/requests/valid/028.http  2019-11-20 
21:51:41.000000000 +0100
@@ -0,0 +1,4 @@
+GET /stuff/here?foo=bar HTTP/1.1\r\n
+Content-Length : 3\r\n
+\r\n
+xyz
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/tests/requests/valid/028.py 
new/gunicorn-19.10.0/tests/requests/valid/028.py
--- old/gunicorn-19.9.0/tests/requests/valid/028.py     1970-01-01 
01:00:00.000000000 +0100
+++ new/gunicorn-19.10.0/tests/requests/valid/028.py    2019-11-20 
21:51:41.000000000 +0100
@@ -0,0 +1,14 @@
+from gunicorn.config import Config
+
+cfg = Config()
+cfg.set("strip_header_spaces", True)
+
+request = {
+    "method": "GET",
+    "uri": uri("/stuff/here?foo=bar"),
+    "version": (1, 1),
+    "headers": [
+        ("CONTENT-LENGTH", "3"),
+    ],
+    "body": b"xyz"
+}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/tests/requests/valid/029.http 
new/gunicorn-19.10.0/tests/requests/valid/029.http
--- old/gunicorn-19.9.0/tests/requests/valid/029.http   1970-01-01 
01:00:00.000000000 +0100
+++ new/gunicorn-19.10.0/tests/requests/valid/029.http  2019-11-20 
21:52:43.000000000 +0100
@@ -0,0 +1,7 @@
+GET /stuff/here?foo=bar HTTP/1.1\r\n
+Transfer-Encoding: chunked\r\n
+Transfer-Encoding: identity\r\n
+\r\n
+5\r\n
+hello\r\n
+000\r\n
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/tests/requests/valid/029.py 
new/gunicorn-19.10.0/tests/requests/valid/029.py
--- old/gunicorn-19.9.0/tests/requests/valid/029.py     1970-01-01 
01:00:00.000000000 +0100
+++ new/gunicorn-19.10.0/tests/requests/valid/029.py    2019-11-20 
21:52:43.000000000 +0100
@@ -0,0 +1,14 @@
+from gunicorn.config import Config
+
+cfg = Config()
+
+request = {
+    "method": "GET",
+    "uri": uri("/stuff/here?foo=bar"),
+    "version": (1, 1),
+    "headers": [
+        ('TRANSFER-ENCODING', 'chunked'),
+        ('TRANSFER-ENCODING', 'identity')
+    ],
+    "body": b"hello"
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/tests/requests/valid/030.http 
new/gunicorn-19.10.0/tests/requests/valid/030.http
--- old/gunicorn-19.9.0/tests/requests/valid/030.http   1970-01-01 
01:00:00.000000000 +0100
+++ new/gunicorn-19.10.0/tests/requests/valid/030.http  2019-11-20 
21:52:43.000000000 +0100
@@ -0,0 +1,7 @@
+GET /stuff/here?foo=bar HTTP/1.1\r\n
+Transfer-Encoding: identity\r\n
+Transfer-Encoding: chunked\r\n
+\r\n
+5\r\n
+hello\r\n
+000\r\n
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/tests/requests/valid/030.py 
new/gunicorn-19.10.0/tests/requests/valid/030.py
--- old/gunicorn-19.9.0/tests/requests/valid/030.py     1970-01-01 
01:00:00.000000000 +0100
+++ new/gunicorn-19.10.0/tests/requests/valid/030.py    2019-11-20 
21:52:43.000000000 +0100
@@ -0,0 +1,14 @@
+from gunicorn.config import Config
+
+cfg = Config()
+
+request = {
+    "method": "GET",
+    "uri": uri("/stuff/here?foo=bar"),
+    "version": (1, 1),
+    "headers": [
+        ('TRANSFER-ENCODING', 'identity'),
+        ('TRANSFER-ENCODING', 'chunked')
+    ],
+    "body": b"hello"
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/tests/test_arbiter.py 
new/gunicorn-19.10.0/tests/test_arbiter.py
--- old/gunicorn-19.9.0/tests/test_arbiter.py   2017-09-18 03:14:58.000000000 
+0200
+++ new/gunicorn-19.10.0/tests/test_arbiter.py  2019-11-23 10:49:50.000000000 
+0100
@@ -12,6 +12,7 @@
 
 import gunicorn.app.base
 import gunicorn.arbiter
+from gunicorn.config import ReusePort
 
 
 class DummyApplication(gunicorn.app.base.BaseApplication):
@@ -63,6 +64,15 @@
     arbiter.stop()
     close_sockets.assert_called_with([], False)
 
+
[email protected]('gunicorn.sock.close_sockets')
+def test_arbiter_stop_does_not_unlink_when_using_reuse_port(close_sockets):
+    arbiter = gunicorn.arbiter.Arbiter(DummyApplication())
+    arbiter.cfg.settings['reuse_port'] = ReusePort()
+    arbiter.cfg.settings['reuse_port'].set(True)
+    arbiter.stop()
+    close_sockets.assert_called_with([], False)
+
 
 @mock.patch('os.getpid')
 @mock.patch('os.fork')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/tests/test_http.py 
new/gunicorn-19.10.0/tests/test_http.py
--- old/gunicorn-19.9.0/tests/test_http.py      2018-01-22 20:16:44.000000000 
+0100
+++ new/gunicorn-19.10.0/tests/test_http.py     2019-11-23 10:49:50.000000000 
+0100
@@ -81,8 +81,13 @@
     mocked_request = mock.MagicMock()
     response = Response(mocked_request, mocked_socket, None)
 
-    # set umlaut header
+    # set umlaut header value - latin-1 is OK
     response.headers.append(('foo', u'häder'))
+    response.send_headers()
+
+    # set a-breve header value - unicode, non-latin-1 fails
+    response = Response(mocked_request, mocked_socket, None)
+    response.headers.append(('apple', u'măr'))
     with pytest.raises(UnicodeEncodeError):
         response.send_headers()
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gunicorn-19.9.0/tests/test_sock.py 
new/gunicorn-19.10.0/tests/test_sock.py
--- old/gunicorn-19.9.0/tests/test_sock.py      2017-09-18 03:14:58.000000000 
+0200
+++ new/gunicorn-19.10.0/tests/test_sock.py     2019-11-23 10:49:50.000000000 
+0100
@@ -11,6 +11,27 @@
 from gunicorn import sock
 
 
[email protected]('os.stat')
+def test_create_sockets_unix_bytes(stat):
+    conf = mock.Mock(address=[b'127.0.0.1:8000'])
+    log = mock.Mock()
+    with mock.patch.object(sock.UnixSocket, '__init__', lambda *args: None):
+        listeners = sock.create_sockets(conf, log)
+        assert len(listeners) == 1
+        print(type(listeners[0]))
+        assert isinstance(listeners[0], sock.UnixSocket)
+
+
[email protected]('os.stat')
+def test_create_sockets_unix_strings(stat):
+    conf = mock.Mock(address=['127.0.0.1:8000'])
+    log = mock.Mock()
+    with mock.patch.object(sock.UnixSocket, '__init__', lambda *args: None):
+        listeners = sock.create_sockets(conf, log)
+        assert len(listeners) == 1
+        assert isinstance(listeners[0], sock.UnixSocket)
+
+
 def test_socket_close():
     listener1 = mock.Mock()
     listener1.getsockname.return_value = ('127.0.0.1', '80')


Reply via email to