From d258498ddf3d314d74f042c441deb0a43c8fe618 Mon Sep 17 00:00:00 2001 From: Andrew Dang Date: Tue, 7 Jul 2026 16:58:53 -0500 Subject: [PATCH] Fix 503 request flags in unservicable connections Pass the server proxy and strict mode settings into HTTP request parsing from HTTPConnection.communicate. This preserves the configured request handling flags for accepted connections and covers the constructor arguments with a focused regression test. --- cheroot/server.py | 7 ++- cheroot/test/test_server.py | 54 ++++++++++++++++++++++- docs/changelog-fragments.d/831.bugfix.rst | 1 + 3 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 docs/changelog-fragments.d/831.bugfix.rst diff --git a/cheroot/server.py b/cheroot/server.py index 284cf17c72..418a86b7a4 100644 --- a/cheroot/server.py +++ b/cheroot/server.py @@ -1306,7 +1306,12 @@ def communicate(self): # noqa: C901 # FIXME """ request_seen = False try: - req = self.RequestHandlerClass(self.server, self) + req = self.RequestHandlerClass( + self.server, + self, + proxy_mode=self.server.proxy_mode, + strict_mode=self.server.strict_mode, + ) req.parse_request() if self.server.stats['Enabled']: self.requests_seen += 1 diff --git a/cheroot/test/test_server.py b/cheroot/test/test_server.py index ae6e390a44..b434d88495 100644 --- a/cheroot/test/test_server.py +++ b/cheroot/test/test_server.py @@ -20,7 +20,7 @@ from pypytools.gc.custom import DefaultGc from .._compat import IS_LINUX, IS_MACOS, IS_WINDOWS, SYS_PLATFORM, bton, ntob -from ..server import IS_UID_GID_RESOLVABLE, Gateway, HTTPServer +from ..server import IS_UID_GID_RESOLVABLE, Gateway, HTTPConnection, HTTPServer from ..testing import ( ANY_INTERFACE_IPV4, ANY_INTERFACE_IPV6, @@ -127,6 +127,58 @@ def test_stop_interrupts_serve(): assert not serve_thread.is_alive() +def test_communicate_uses_server_proxy_and_strict_mode(): + """Check that parsed requests inherit proxy/strict mode from the server.""" + httpserver = HTTPServer( + bind_addr=(ANY_INTERFACE_IPV4, EPHEMERAL_PORT), + gateway=Gateway, + ) + request_init_args = [] + + class CapturingHTTPRequest: + """Capture request constructor args used during communication.""" + + def __init__( + self, + server, + conn, + proxy_mode=False, + strict_mode=True, + ): + request_init_args.append( + { + 'server': server, + 'conn': conn, + 'proxy_mode': proxy_mode, + 'strict_mode': strict_mode, + }, + ) + self.ready = False + + def parse_request(self): + return None + + conn = HTTPConnection( + httpserver, + types.SimpleNamespace(), + makefile=lambda _sock, _mode, _bufsize: types.SimpleNamespace(), + ) + conn.RequestHandlerClass = CapturingHTTPRequest + httpserver.proxy_mode = True + httpserver.strict_mode = False + + assert conn.communicate() is False + + assert request_init_args == [ + { + 'server': httpserver, + 'conn': conn, + 'proxy_mode': True, + 'strict_mode': False, + }, + ] + + @pytest.mark.parametrize( 'exc_cls', ( diff --git a/docs/changelog-fragments.d/831.bugfix.rst b/docs/changelog-fragments.d/831.bugfix.rst new file mode 100644 index 0000000000..b44465d026 --- /dev/null +++ b/docs/changelog-fragments.d/831.bugfix.rst @@ -0,0 +1 @@ +Preserved server proxy and strict mode settings when parsing requests on accepted connections.