[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1111653: bookworm-pu: package waitress/2.1.2-2+deb12u1



Package: release.debian.org
Severity: normal
Tags: bookworm
X-Debbugs-Cc: waitress@packages.debian.org, security@debian.org
Control: affects -1 + src:waitress
User: release.debian.org@packages.debian.org
Usertags: pu

  * CVE-2024-49768: race condition in HTTP pipelining
    (Closes: #1086467)
  * CVE-2024-49769: DoS due to resource exhaustion
    (Closes: #1086468)
diffstat for waitress-2.1.2 waitress-2.1.2

 changelog                                                               |   10 
 patches/0001-Fix-a-race-condition-on-recv_bytes-boundary-when-req.patch |   58 +++
 patches/0002-Make-DummySock-look-more-like-an-actual-socket.patch       |  161 ++++++++++
 patches/0003-Add-a-new-test-to-validate-the-lookahead-race-condit.patch |   89 +++++
 patches/0004-Remove-test-for-getpeername.patch                          |   34 ++
 patches/0005-When-closing-the-socket-set-it-to-None.patch               |   40 ++
 patches/0006-Don-t-exit-handle_write-early-even-if-socket-is-not-.patch |   32 +
 patches/0007-Assume-socket-is-not-connected-when-passed-to-wasync.patch |   51 +++
 patches/0008-HTTPChannel-is-always-created-from-accept-explicitly.patch |   27 +
 patches/series                                                          |    8 
 10 files changed, 510 insertions(+)

diff -Nru waitress-2.1.2/debian/changelog waitress-2.1.2/debian/changelog
--- waitress-2.1.2/debian/changelog	2022-11-14 18:15:51.000000000 +0200
+++ waitress-2.1.2/debian/changelog	2025-08-20 18:31:13.000000000 +0300
@@ -1,3 +1,13 @@
+waitress (2.1.2-2+deb12u1) bookworm; urgency=medium
+
+  * Non-maintainer upload.
+  * CVE-2024-49768: race condition in HTTP pipelining
+    (Closes: #1086467)
+  * CVE-2024-49769: DoS due to resource exhaustion
+    (Closes: #1086468)
+
+ -- Adrian Bunk <bunk@debian.org>  Wed, 20 Aug 2025 18:31:13 +0300
+
 waitress (2.1.2-2) unstable; urgency=medium
 
   * Team Upload.
diff -Nru waitress-2.1.2/debian/patches/0001-Fix-a-race-condition-on-recv_bytes-boundary-when-req.patch waitress-2.1.2/debian/patches/0001-Fix-a-race-condition-on-recv_bytes-boundary-when-req.patch
--- waitress-2.1.2/debian/patches/0001-Fix-a-race-condition-on-recv_bytes-boundary-when-req.patch	1970-01-01 02:00:00.000000000 +0200
+++ waitress-2.1.2/debian/patches/0001-Fix-a-race-condition-on-recv_bytes-boundary-when-req.patch	2025-08-20 18:30:00.000000000 +0300
@@ -0,0 +1,58 @@
+From f53910e5463bcd52a0b39c1e7a1759b6ac17dbdf Mon Sep 17 00:00:00 2001
+From: Delta Regeer <bertjw@regeer.org>
+Date: Sat, 26 Oct 2024 22:13:08 -0600
+Subject: Fix a race condition on recv_bytes boundary when request is invalid
+
+A remote client may send a request that is exactly recv_bytes long,
+followed by a secondary request using HTTP pipelining.
+
+When request lookahead is disabled (default) we won't read any more
+requests, and when the first request fails due to a parsing error, we
+simply close the connection.
+
+However when request lookahead is enabled, it is possible to process and
+receive the first request, start sending the error message back to the
+client while we read the next request and queue it. This will allow the
+secondar request to be serviced by the worker thread while the
+connection should be closed.
+
+The fix here checks if we should not have read the data in the first
+place (because the conection is going to be torn down) while we hold the
+`requests_lock` which means the service thread can't be in the middle of
+flipping the `close_when_flushed` flag.
+---
+ src/waitress/channel.py | 11 ++++++++++-
+ 1 file changed, 10 insertions(+), 1 deletion(-)
+
+diff --git a/src/waitress/channel.py b/src/waitress/channel.py
+index eb59dd3..756adce 100644
+--- a/src/waitress/channel.py
++++ b/src/waitress/channel.py
+@@ -147,7 +147,7 @@ class HTTPChannel(wasyncore.dispatcher):
+         # 1. We're not already about to close the connection.
+         # 2. We're not waiting to flush remaining data before closing the
+         #    connection
+-        # 3. There are not too many tasks already queued
++        # 3. There are not too many tasks already queued (if lookahead is enabled)
+         # 4. There's no data in the output buffer that needs to be sent
+         #    before we potentially create a new task.
+ 
+@@ -203,6 +203,15 @@ class HTTPChannel(wasyncore.dispatcher):
+             return False
+ 
+         with self.requests_lock:
++            # Don't bother processing anymore data if this connection is about
++            # to close. This may happen if readable() returned True, on the
++            # main thread before the service thread set the close_when_flushed
++            # flag, and we read data but our service thread is attempting to
++            # shut down the connection due to an error. We want to make sure we
++            # do this while holding the request_lock so that we can't race
++            if self.will_close or self.close_when_flushed:
++                return False
++
+             while data:
+                 if self.request is None:
+                     self.request = self.parser_class(self.adj)
+-- 
+2.30.2
+
diff -Nru waitress-2.1.2/debian/patches/0002-Make-DummySock-look-more-like-an-actual-socket.patch waitress-2.1.2/debian/patches/0002-Make-DummySock-look-more-like-an-actual-socket.patch
--- waitress-2.1.2/debian/patches/0002-Make-DummySock-look-more-like-an-actual-socket.patch	1970-01-01 02:00:00.000000000 +0200
+++ waitress-2.1.2/debian/patches/0002-Make-DummySock-look-more-like-an-actual-socket.patch	2025-08-20 18:30:00.000000000 +0300
@@ -0,0 +1,161 @@
+From 264eb0ddeea74175d9e5e53028202500bd8cb6ad Mon Sep 17 00:00:00 2001
+From: Delta Regeer <bertjw@regeer.org>
+Date: Sat, 26 Oct 2024 22:10:36 -0600
+Subject: Make DummySock() look more like an actual socket
+
+This forces DummySock() to look like a properly connected socket where
+there is a buffer that is read from by the remote, and a buffer that is
+written to by the remote.
+
+The local side does the opposite, this way data written by the local
+side can be read by the remote without operating on the same buffer.
+---
+ tests/test_channel.py | 57 +++++++++++++++++++++++++++++++++----------
+ 1 file changed, 44 insertions(+), 13 deletions(-)
+
+diff --git a/tests/test_channel.py b/tests/test_channel.py
+index 8467ae7..7d677e9 100644
+--- a/tests/test_channel.py
++++ b/tests/test_channel.py
+@@ -18,7 +18,7 @@ class TestHTTPChannel(unittest.TestCase):
+         map = {}
+         inst = self._makeOne(sock, "127.0.0.1", adj, map=map)
+         inst.outbuf_lock = DummyLock()
+-        return inst, sock, map
++        return inst, sock.local(), map
+ 
+     def test_ctor(self):
+         inst, _, map = self._makeOneWithMap()
+@@ -218,7 +218,7 @@ class TestHTTPChannel(unittest.TestCase):
+         def send(_):
+             return 0
+ 
+-        sock.send = send
++        sock.remote.send = send
+ 
+         wrote = inst.write_soon(b"a")
+         self.assertEqual(wrote, 1)
+@@ -236,7 +236,7 @@ class TestHTTPChannel(unittest.TestCase):
+         def send(_):
+             return 0
+ 
+-        sock.send = send
++        sock.remote.send = send
+ 
+         outbufs = inst.outbufs
+         wrote = inst.write_soon(wrapper)
+@@ -270,7 +270,7 @@ class TestHTTPChannel(unittest.TestCase):
+         def send(_):
+             return 0
+ 
+-        sock.send = send
++        sock.remote.send = send
+ 
+         inst.adj.outbuf_high_watermark = 3
+         inst.current_outbuf_count = 4
+@@ -286,7 +286,7 @@ class TestHTTPChannel(unittest.TestCase):
+         def send(_):
+             return 0
+ 
+-        sock.send = send
++        sock.remote.send = send
+ 
+         inst.adj.outbuf_high_watermark = 3
+         inst.total_outbufs_len = 4
+@@ -315,7 +315,7 @@ class TestHTTPChannel(unittest.TestCase):
+             inst.connected = False
+             raise Exception()
+ 
+-        sock.send = send
++        sock.remote.send = send
+ 
+         inst.adj.outbuf_high_watermark = 3
+         inst.total_outbufs_len = 4
+@@ -345,7 +345,7 @@ class TestHTTPChannel(unittest.TestCase):
+             inst.connected = False
+             raise Exception()
+ 
+-        sock.send = send
++        sock.remote.send = send
+ 
+         wrote = inst.write_soon(b"xyz")
+         self.assertEqual(wrote, 3)
+@@ -376,7 +376,7 @@ class TestHTTPChannel(unittest.TestCase):
+         inst.total_outbufs_len = len(inst.outbufs[0])
+         inst.adj.send_bytes = 1
+         inst.adj.outbuf_high_watermark = 2
+-        sock.send = lambda x, do_close=True: False
++        sock.remote.send = lambda x, do_close=True: False
+         inst.will_close = False
+         inst.last_activity = 0
+         result = inst.handle_write()
+@@ -400,7 +400,7 @@ class TestHTTPChannel(unittest.TestCase):
+ 
+     def test__flush_some_full_outbuf_socket_returns_zero(self):
+         inst, sock, map = self._makeOneWithMap()
+-        sock.send = lambda x: False
++        sock.remote.send = lambda x: False
+         inst.outbufs[0].append(b"abc")
+         inst.total_outbufs_len = sum(len(x) for x in inst.outbufs)
+         result = inst._flush_some()
+@@ -907,7 +907,8 @@ class DummySock:
+     closed = False
+ 
+     def __init__(self):
+-        self.sent = b""
++        self.local_sent = b""
++        self.remote_sent = b""
+ 
+     def setblocking(self, *arg):
+         self.blocking = True
+@@ -925,14 +926,44 @@ class DummySock:
+         self.closed = True
+ 
+     def send(self, data):
+-        self.sent += data
++        self.remote_sent += data
+         return len(data)
+ 
+     def recv(self, buffer_size):
+-        result = self.sent[:buffer_size]
+-        self.sent = self.sent[buffer_size:]
++        result = self.local_sent[:buffer_size]
++        self.local_sent = self.local_sent[buffer_size:]
+         return result
+ 
++    def local(self):
++        outer = self
++
++        class LocalDummySock:
++            def send(self, data):
++                outer.local_sent += data
++                return len(data)
++
++            def recv(self, buffer_size):
++                result = outer.remote_sent[:buffer_size]
++                outer.remote_sent = outer.remote_sent[buffer_size:]
++                return result
++
++            def close(self):
++                outer.closed = True
++
++            @property
++            def sent(self):
++                return outer.remote_sent
++
++            @property
++            def closed(self):
++                return outer.closed
++
++            @property
++            def remote(self):
++                return outer
++
++        return LocalDummySock()
++
+ 
+ class DummyLock:
+     notified = False
+-- 
+2.30.2
+
diff -Nru waitress-2.1.2/debian/patches/0003-Add-a-new-test-to-validate-the-lookahead-race-condit.patch waitress-2.1.2/debian/patches/0003-Add-a-new-test-to-validate-the-lookahead-race-condit.patch
--- waitress-2.1.2/debian/patches/0003-Add-a-new-test-to-validate-the-lookahead-race-condit.patch	1970-01-01 02:00:00.000000000 +0200
+++ waitress-2.1.2/debian/patches/0003-Add-a-new-test-to-validate-the-lookahead-race-condit.patch	2025-08-20 18:30:00.000000000 +0300
@@ -0,0 +1,89 @@
+From 72176921186f2fca1318321785c0328d4ba5d805 Mon Sep 17 00:00:00 2001
+From: Delta Regeer <bertjw@regeer.org>
+Date: Sat, 26 Oct 2024 22:12:14 -0600
+Subject: Add a new test to validate the lookahead race condition
+
+---
+ tests/test_channel.py | 55 ++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 54 insertions(+), 1 deletion(-)
+
+diff --git a/tests/test_channel.py b/tests/test_channel.py
+index 7d677e9..d798091 100644
+--- a/tests/test_channel.py
++++ b/tests/test_channel.py
+@@ -805,11 +805,12 @@ class TestHTTPChannelLookahead(TestHTTPChannel):
+         )
+         return [body]
+ 
+-    def _make_app_with_lookahead(self):
++    def _make_app_with_lookahead(self, recv_bytes=8192):
+         """
+         Setup a channel with lookahead and store it and the socket in self
+         """
+         adj = DummyAdjustments()
++        adj.recv_bytes = recv_bytes
+         adj.channel_request_lookahead = 5
+         channel, sock, map = self._makeOneWithMap(adj=adj)
+         channel.server.application = self.app_check_disconnect
+@@ -901,6 +902,58 @@ class TestHTTPChannelLookahead(TestHTTPChannel):
+         self.assertEqual(data.split("\r\n")[-1], "finished")
+         self.assertEqual(self.request_body, b"x")
+ 
++    def test_lookahead_bad_request_drop_extra_data(self):
++        """
++        Send two requests, the first one being bad, split on the recv_bytes
++        limit, then emulate a race that could happen whereby we read data from
++        the socket while the service thread is cleaning up due to an error
++        processing the request.
++        """
++
++        invalid_request = [
++            "GET / HTTP/1.1",
++            "Host: localhost:8080",
++            "Content-length: -1",
++            "",
++        ]
++
++        invalid_request_len = len("".join([x + "\r\n" for x in invalid_request]))
++
++        second_request = [
++            "POST / HTTP/1.1",
++            "Host: localhost:8080",
++            "Content-Length: 1",
++            "",
++            "x",
++        ]
++
++        full_request = invalid_request + second_request
++
++        self._make_app_with_lookahead(recv_bytes=invalid_request_len)
++        self._send(*full_request)
++        self.channel.handle_read()
++        self.assertEqual(len(self.channel.requests), 1)
++        self.channel.server.tasks[0].service()
++        self.assertTrue(self.channel.close_when_flushed)
++        # Read all of the next request
++        self.channel.handle_read()
++        self.channel.handle_read()
++        # Validate that there is no more data to be read
++        self.assertEqual(self.sock.remote.local_sent, b"")
++        # Validate that we dropped the data from the second read, and did not
++        # create a new request
++        self.assertEqual(len(self.channel.requests), 0)
++        data = self.sock.recv(256).decode("ascii")
++        self.assertFalse(self.channel.readable())
++        self.assertTrue(self.channel.writable())
++
++        # Handle the write, which will close the socket
++        self.channel.handle_write()
++        self.assertTrue(self.sock.closed)
++
++        data = self.sock.recv(256)
++        self.assertEqual(len(data), 0)
++
+ 
+ class DummySock:
+     blocking = False
+-- 
+2.30.2
+
diff -Nru waitress-2.1.2/debian/patches/0004-Remove-test-for-getpeername.patch waitress-2.1.2/debian/patches/0004-Remove-test-for-getpeername.patch
--- waitress-2.1.2/debian/patches/0004-Remove-test-for-getpeername.patch	1970-01-01 02:00:00.000000000 +0200
+++ waitress-2.1.2/debian/patches/0004-Remove-test-for-getpeername.patch	2025-08-20 18:30:00.000000000 +0300
@@ -0,0 +1,34 @@
+From 8ef9217ae753cbce02c6553c389299f6c82352b2 Mon Sep 17 00:00:00 2001
+From: Delta Regeer <bertjw@regeer.org>
+Date: Sun, 3 Mar 2024 16:23:33 -0700
+Subject: Remove test for getpeername()
+
+---
+ tests/test_wasyncore.py | 11 -----------
+ 1 file changed, 11 deletions(-)
+
+diff --git a/tests/test_wasyncore.py b/tests/test_wasyncore.py
+index e833c7e..5f38bd9 100644
+--- a/tests/test_wasyncore.py
++++ b/tests/test_wasyncore.py
+@@ -1451,17 +1451,6 @@ class Test_dispatcher(unittest.TestCase):
+ 
+         return dispatcher(sock=sock, map=map)
+ 
+-    def test_unexpected_getpeername_exc(self):
+-        sock = dummysocket()
+-
+-        def getpeername():
+-            raise OSError(errno.EBADF)
+-
+-        map = {}
+-        sock.getpeername = getpeername
+-        self.assertRaises(socket.error, self._makeOne, sock=sock, map=map)
+-        self.assertEqual(map, {})
+-
+     def test___repr__accepting(self):
+         sock = dummysocket()
+         map = {}
+-- 
+2.30.2
+
diff -Nru waitress-2.1.2/debian/patches/0005-When-closing-the-socket-set-it-to-None.patch waitress-2.1.2/debian/patches/0005-When-closing-the-socket-set-it-to-None.patch
--- waitress-2.1.2/debian/patches/0005-When-closing-the-socket-set-it-to-None.patch	1970-01-01 02:00:00.000000000 +0200
+++ waitress-2.1.2/debian/patches/0005-When-closing-the-socket-set-it-to-None.patch	2025-08-20 18:30:00.000000000 +0300
@@ -0,0 +1,40 @@
+From 4adc02c27a1c8457aacf1d8f058ae8879655bf58 Mon Sep 17 00:00:00 2001
+From: Delta Regeer <bertjw@regeer.org>
+Date: Sun, 3 Mar 2024 16:37:12 -0700
+Subject: When closing the socket, set it to None
+
+This avoids calling close() twice on the same socket if self.close() or
+self.handle_close() is called multiple times
+---
+ src/waitress/wasyncore.py | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/src/waitress/wasyncore.py b/src/waitress/wasyncore.py
+index b3459e0..116c226 100644
+--- a/src/waitress/wasyncore.py
++++ b/src/waitress/wasyncore.py
+@@ -470,6 +470,8 @@ class dispatcher:
+                 if why.args[0] not in (ENOTCONN, EBADF):
+                     raise
+ 
++            self.socket = None
++
+     # log and log_info may be overridden to provide more sophisticated
+     # logging and warning methods. In general, log is for 'hit' logging
+     # and 'log_info' is for informational, warning and error logging.
+@@ -520,7 +522,11 @@ class dispatcher:
+         # handle_expt_event() is called if there might be an error on the
+         # socket, or if there is OOB data
+         # check for the error condition first
+-        err = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
++        err = (
++            self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
++            if self.socket is not None
++            else 1
++        )
+         if err != 0:
+             # we can get here when select.select() says that there is an
+             # exceptional condition on the socket
+-- 
+2.30.2
+
diff -Nru waitress-2.1.2/debian/patches/0006-Don-t-exit-handle_write-early-even-if-socket-is-not-.patch waitress-2.1.2/debian/patches/0006-Don-t-exit-handle_write-early-even-if-socket-is-not-.patch
--- waitress-2.1.2/debian/patches/0006-Don-t-exit-handle_write-early-even-if-socket-is-not-.patch	1970-01-01 02:00:00.000000000 +0200
+++ waitress-2.1.2/debian/patches/0006-Don-t-exit-handle_write-early-even-if-socket-is-not-.patch	2025-08-20 18:30:00.000000000 +0300
@@ -0,0 +1,32 @@
+From 3bac1b72c973ed722d29dd58a7bdfba565f1a9b0 Mon Sep 17 00:00:00 2001
+From: Delta Regeer <bertjw@regeer.org>
+Date: Sun, 3 Mar 2024 16:26:22 -0700
+Subject: Don't exit handle_write early -- even if socket is not connected
+
+Calling handle_close() multiple times does not hurt anything, and is
+safe.
+---
+ src/waitress/channel.py | 6 ------
+ 1 file changed, 6 deletions(-)
+
+diff --git a/src/waitress/channel.py b/src/waitress/channel.py
+index 756adce..427c2a7 100644
+--- a/src/waitress/channel.py
++++ b/src/waitress/channel.py
+@@ -92,13 +92,7 @@ class HTTPChannel(wasyncore.dispatcher):
+         # Precondition: there's data in the out buffer to be sent, or
+         # there's a pending will_close request
+ 
+-        if not self.connected:
+-            # we dont want to close the channel twice
+-
+-            return
+-
+         # try to flush any pending output
+-
+         if not self.requests:
+             # 1. There are no running tasks, so we don't need to try to lock
+             #    the outbuf before sending
+-- 
+2.30.2
+
diff -Nru waitress-2.1.2/debian/patches/0007-Assume-socket-is-not-connected-when-passed-to-wasync.patch waitress-2.1.2/debian/patches/0007-Assume-socket-is-not-connected-when-passed-to-wasync.patch
--- waitress-2.1.2/debian/patches/0007-Assume-socket-is-not-connected-when-passed-to-wasync.patch	1970-01-01 02:00:00.000000000 +0200
+++ waitress-2.1.2/debian/patches/0007-Assume-socket-is-not-connected-when-passed-to-wasync.patch	2025-08-20 18:30:00.000000000 +0300
@@ -0,0 +1,51 @@
+From a2cfaab2c980d8e7fd45742dfd3edbcc3b584d5d Mon Sep 17 00:00:00 2001
+From: Delta Regeer <bertjw@regeer.org>
+Date: Sun, 3 Mar 2024 16:16:48 -0700
+Subject: Assume socket is not connected when passed to wasyncore.dispatcher
+
+No longer call getpeername() on the remote socket either, as it is not
+necessary for any of the places where waitress requires that self.addr
+in a subclass of the dispatcher needs it.
+
+This removes a race condition when setting up a HTTPChannel where we
+accepted the socket, and know the remote address, yet call getpeername()
+again which would have the unintended side effect of potentially setting
+self.connected to False because the remote has already shut down part of
+the socket.
+
+This issue was uncovered in #418, where the server would go into a hard
+loop because self.connected was used in various parts of the code base.
+---
+ src/waitress/wasyncore.py | 16 ----------------
+ 1 file changed, 16 deletions(-)
+
+diff --git a/src/waitress/wasyncore.py b/src/waitress/wasyncore.py
+index 116c226..10b0ec9 100644
+--- a/src/waitress/wasyncore.py
++++ b/src/waitress/wasyncore.py
+@@ -298,22 +298,6 @@ class dispatcher:
+             # get a socket from a blocking source.
+             sock.setblocking(0)
+             self.set_socket(sock, map)
+-            self.connected = True
+-            # The constructor no longer requires that the socket
+-            # passed be connected.
+-            try:
+-                self.addr = sock.getpeername()
+-            except OSError as err:
+-                if err.args[0] in (ENOTCONN, EINVAL):
+-                    # To handle the case where we got an unconnected
+-                    # socket.
+-                    self.connected = False
+-                else:
+-                    # The socket is broken in some unknown way, alert
+-                    # the user and remove it from the map (to prevent
+-                    # polling of broken sockets).
+-                    self.del_channel(map)
+-                    raise
+         else:
+             self.socket = None
+ 
+-- 
+2.30.2
+
diff -Nru waitress-2.1.2/debian/patches/0008-HTTPChannel-is-always-created-from-accept-explicitly.patch waitress-2.1.2/debian/patches/0008-HTTPChannel-is-always-created-from-accept-explicitly.patch
--- waitress-2.1.2/debian/patches/0008-HTTPChannel-is-always-created-from-accept-explicitly.patch	1970-01-01 02:00:00.000000000 +0200
+++ waitress-2.1.2/debian/patches/0008-HTTPChannel-is-always-created-from-accept-explicitly.patch	2025-08-20 18:30:00.000000000 +0300
@@ -0,0 +1,27 @@
+From daa92aee796abcf54a46eddd5535fca231c5ce92 Mon Sep 17 00:00:00 2001
+From: Delta Regeer <bertjw@regeer.org>
+Date: Sun, 3 Mar 2024 16:15:51 -0700
+Subject: HTTPChannel is always created from accept, explicitly set
+ self.connected to True
+
+---
+ src/waitress/channel.py | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/src/waitress/channel.py b/src/waitress/channel.py
+index 427c2a7..f4d9677 100644
+--- a/src/waitress/channel.py
++++ b/src/waitress/channel.py
+@@ -67,8 +67,7 @@ class HTTPChannel(wasyncore.dispatcher):
+         self.outbuf_lock = threading.Condition()
+ 
+         wasyncore.dispatcher.__init__(self, sock, map=map)
+-
+-        # Don't let wasyncore.dispatcher throttle self.addr on us.
++        self.connected = True
+         self.addr = addr
+         self.requests = []
+ 
+-- 
+2.30.2
+
diff -Nru waitress-2.1.2/debian/patches/series waitress-2.1.2/debian/patches/series
--- waitress-2.1.2/debian/patches/series	2022-11-14 18:08:02.000000000 +0200
+++ waitress-2.1.2/debian/patches/series	2025-08-20 18:31:13.000000000 +0300
@@ -1,2 +1,10 @@
 docs-Don-t-try-to-detect-the-version-don-t-use-Pylons-the.patch
 docs-Use-internal-ressources-for-intersphinx.patch
+0001-Fix-a-race-condition-on-recv_bytes-boundary-when-req.patch
+0002-Make-DummySock-look-more-like-an-actual-socket.patch
+0003-Add-a-new-test-to-validate-the-lookahead-race-condit.patch
+0004-Remove-test-for-getpeername.patch
+0005-When-closing-the-socket-set-it-to-None.patch
+0006-Don-t-exit-handle_write-early-even-if-socket-is-not-.patch
+0007-Assume-socket-is-not-connected-when-passed-to-wasync.patch
+0008-HTTPChannel-is-always-created-from-accept-explicitly.patch

Reply to: