From f3ef966d0c717099d2f4a1697bd661b48c703efd Mon Sep 17 00:00:00 2001 From: Illia Volochii Date: Wed, 7 Jan 2026 18:07:30 +0200 Subject: [PATCH] Merge commit from fork * Stop decoding response content during redirects needlessly * Rename the new query parameter * Add a changelog entry --- dummyserver/app.py | 8 +++++++- src/urllib3/response.py | 6 +++++- test/with_dummyserver/test_connectionpool.py | 19 +++++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/dummyserver/app.py b/dummyserver/app.py index 0eeb93f7..5b82e932 100644 --- a/dummyserver/app.py +++ b/dummyserver/app.py @@ -233,10 +233,16 @@ async def redirect() -> ResponseReturnValue: values = await request.values target = values.get("target", "/") status = values.get("status", "303 See Other") + compressed = values.get("compressed") == "true" status_code = status.split(" ")[0] headers = [("Location", target)] - return await make_response("", status_code, headers) + if compressed: + headers.append(("Content-Encoding", "gzip")) + data = gzip.compress(b"foo") + else: + data = b"" + return await make_response(data, status_code, headers) @hypercorn_app.route("/redirect_after") diff --git a/src/urllib3/response.py b/src/urllib3/response.py index 5632dab3..720fbf26 100644 --- a/src/urllib3/response.py +++ b/src/urllib3/response.py @@ -677,7 +677,11 @@ class HTTPResponse(BaseHTTPResponse): Unread data in the HTTPResponse connection blocks the connection from being released back to the pool. """ try: - self.read() + self.read( + # Do not spend resources decoding the content unless + # decoding has already been initiated. + decode_content=self._has_decoded_content, + ) except (HTTPError, OSError, BaseSSLError, HTTPException): pass diff --git a/test/with_dummyserver/test_connectionpool.py b/test/with_dummyserver/test_connectionpool.py index ce165e24..8d6107ae 100644 --- a/test/with_dummyserver/test_connectionpool.py +++ b/test/with_dummyserver/test_connectionpool.py @@ -508,6 +508,25 @@ class TestConnectionPool(HypercornDummyServerTestCase): assert r.status == 200 assert r.data == b"Dummy server!" + @mock.patch("urllib3.response.GzipDecoder.decompress") + def test_no_decoding_with_redirect_when_preload_disabled( + self, gzip_decompress: mock.MagicMock + ) -> None: + """ + Test that urllib3 does not attempt to decode a gzipped redirect + response when `preload_content` is set to `False`. + """ + with HTTPConnectionPool(self.host, self.port) as pool: + # Three requests are expected: two redirects and one final / 200 OK. + response = pool.request( + "GET", + "/redirect", + fields={"target": "/redirect?compressed=true", "compressed": "true"}, + preload_content=False, + ) + assert response.status == 200 + gzip_decompress.assert_not_called() + def test_303_redirect_makes_request_lose_body(self) -> None: with HTTPConnectionPool(self.host, self.port) as pool: response = pool.request( -- 2.52.0