From cd6cf6e05354a9817830a72913fc62b0c330bd62 Mon Sep 17 00:00:00 2001 From: ANTO JEROME A Date: Tue, 3 Nov 2026 18:57:27 +0530 Subject: [PATCH 1/3] Preserve cached response status during 304 revalidation --- cachecontrol/controller.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/cachecontrol/controller.py b/cachecontrol/controller.py index b8c75ea8..13bde9e6 100644 --- a/cachecontrol/controller.py +++ b/cachecontrol/controller.py @@ -508,9 +508,6 @@ def update_cached_response( } ) - # we want a 200 b/c we have content via the cache - cached_response.status = 200 - # update our cache self._cache_set(cache_url, request, cached_response) From af352da1b40931712b034483567e1a4b6ab92757 Mon Sep 17 00:00:00 2001 From: ANTO JEROME A Date: Tue, 3 Nov 2026 18:58:29 +0530 Subject: [PATCH 2/3] Test status preservation across cache backends and cacheable responses Refactor tests to parameterize status codes for cached response updates. --- tests/test_cache_control.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/tests/test_cache_control.py b/tests/test_cache_control.py index a31c5e9d..1a7b8f5d 100644 --- a/tests/test_cache_control.py +++ b/tests/test_cache_control.py @@ -234,7 +234,10 @@ def test_update_cached_response_no_local_cache(self): result = cc.update_cached_response(req, resp) assert result is resp - def test_update_cached_response_with_valid_headers_separate_body(self, tmp_path): + @pytest.mark.parametrize("status", [200, 203, 300, 301, 308]) + def test_update_cached_response_with_valid_headers_separate_body( + self, tmp_path, status + ): """ If the local cache has the given URL ``update_cached_response()`` will: @@ -244,9 +247,10 @@ def test_update_cached_response_with_valid_headers_separate_body(self, tmp_path) This is the version for a cache that stores a separate body. """ cache = SeparateBodyFileCache(os.fsdecode(tmp_path)) - self.update_cached_response_with_valid_headers_test(cache) + self.update_cached_response_with_valid_headers_test(cache, status) - def test_update_cached_response_with_valid_headers(self): + @pytest.mark.parametrize("status", [200, 203, 300, 301, 308]) + def test_update_cached_response_with_valid_headers(self, status): """ If the local cache has the given URL ``update_cached_response()`` will: @@ -256,9 +260,9 @@ def test_update_cached_response_with_valid_headers(self): This is the version for non-separate body. """ cache = DictCache({}) - self.update_cached_response_with_valid_headers_test(cache) + self.update_cached_response_with_valid_headers_test(cache, status) - def update_cached_response_with_valid_headers_test(self, cache): + def update_cached_response_with_valid_headers_test(self, cache, status): """ If the local cache has the given URL ``update_cached_response()`` will: @@ -273,7 +277,7 @@ def update_cached_response_with_valid_headers_test(self, cache): url = "http://localhost:123/x" req = DummyRequest(url=url, headers={}) cached_resp = DummyResponse( - status=200, + status=status, headers={ "ETag": etag, "x-value:": "a", @@ -307,6 +311,7 @@ def update_cached_response_with_valid_headers_test(self, cache): result2 = cc.cached_request(req) for r in [result, result2]: + assert r.status == status assert r.headers["ETag"] == etag assert r.headers["x-value"] == "b" assert r.headers["Content-Length"] == "100" From 99a60aef92f0d2e7905e369b35e61576019f2e4f Mon Sep 17 00:00:00 2001 From: ANTO JEROME A Date: Tue, 3 Nov 2026 18:59:07 +0530 Subject: [PATCH 3/3] Cover ETag revalidation of permanent redirects through the adapter Added a test for revalidated redirects with status codes 301 and 308, ensuring proper caching behavior. --- tests/test_redirects.py | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/test_redirects.py b/tests/test_redirects.py index 9d6932b2..6db0aeaf 100644 --- a/tests/test_redirects.py +++ b/tests/test_redirects.py @@ -6,9 +6,14 @@ Test for supporting redirect caches as needed. """ +from unittest.mock import patch + +import pytest import requests +from urllib3 import HTTPResponse from cachecontrol import CacheControl +from cachecontrol.adapter import CacheControlAdapter class TestPermanentRedirects: @@ -53,3 +58,36 @@ def test_bust_cache_on_redirect(self, url): ) assert not resp.from_cache + + +@pytest.mark.parametrize("status", [301, 308]) +def test_revalidated_redirect_keeps_status(status): + session = CacheControl(requests.Session()) + url = "https://example.test/old" + headers = { + "ETag": '"redirect"', + "Location": "/new", + "Date": "Tue, 03 Nov 2026 12:00:00 GMT", + "Cache-Control": "max-age=0", + } + adapter = session.get_adapter(url) + adapter.controller.cache_response( + requests.Request("GET", url).prepare(), + HTTPResponse(status=status, headers=headers, body=b""), + body=b"", + ) + + def revalidate(self, request, *args, **kwargs): + assert request.headers["If-None-Match"] == '"redirect"' + return CacheControlAdapter.build_response( + self, request, HTTPResponse(status=304, headers=headers, body=b"") + ) + + with patch("requests.adapters.HTTPAdapter.send", revalidate): + response = session.get(url, allow_redirects=False) + + assert response.from_cache + assert response.status_code == status + assert response.is_redirect + assert response.headers["Location"] == "/new" + assert response.content == b""