Skip to content

Commit add2e52

Browse files
committed
Make Serializer.dumps() require a body parameter.
When caching permanent redirects, if `body` is left to `None`, there's an infinite recursion that will lead to the caching to silently fail and not cache anything at all. So instead, make `body` a required parameter, which can be empty (`''`) for cached redirects.
1 parent 9a4c054 commit add2e52

File tree

4 files changed

+15
-26
lines changed

4 files changed

+15
-26
lines changed

cachecontrol/controller.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -309,14 +309,14 @@ def cache_response(self, request, response, body=None, status_codes=None):
309309
if self.cache_etags and "etag" in response_headers:
310310
logger.debug("Caching due to etag")
311311
self.cache.set(
312-
cache_url, self.serializer.dumps(request, response, body=body)
312+
cache_url, self.serializer.dumps(request, response, body)
313313
)
314314

315315
# Add to the cache any permanent redirects. We do this before looking
316316
# that the Date headers.
317317
elif int(response.status) in PERMANENT_REDIRECT_STATUSES:
318318
logger.debug("Caching permanent redirect")
319-
self.cache.set(cache_url, self.serializer.dumps(request, response))
319+
self.cache.set(cache_url, self.serializer.dumps(request, response, b''))
320320

321321
# Add to the cache if the response headers demand it. If there
322322
# is no date header then we can't do anything about expiring
@@ -326,7 +326,7 @@ def cache_response(self, request, response, body=None, status_codes=None):
326326
if "max-age" in cc and cc["max-age"] > 0:
327327
logger.debug("Caching b/c date exists and max-age > 0")
328328
self.cache.set(
329-
cache_url, self.serializer.dumps(request, response, body=body)
329+
cache_url, self.serializer.dumps(request, response, body)
330330
)
331331

332332
# If the request can expire, it means we should cache it
@@ -335,7 +335,7 @@ def cache_response(self, request, response, body=None, status_codes=None):
335335
if response_headers["expires"]:
336336
logger.debug("Caching b/c of expires header")
337337
self.cache.set(
338-
cache_url, self.serializer.dumps(request, response, body=body)
338+
cache_url, self.serializer.dumps(request, response, body)
339339
)
340340

341341
def update_cached_response(self, request, response):
@@ -374,6 +374,7 @@ def update_cached_response(self, request, response):
374374
cached_response.status = 200
375375

376376
# update our cache
377-
self.cache.set(cache_url, self.serializer.dumps(request, cached_response))
377+
body = cached_response.read(decode_content=False)
378+
self.cache.set(cache_url, self.serializer.dumps(request, cached_response, body))
378379

379380
return cached_response

cachecontrol/serialize.py

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,14 @@ def _b64_decode_str(s):
1717
return _b64_decode_bytes(s).decode("utf8")
1818

1919

20+
_default_body_read = object()
21+
22+
2023
class Serializer(object):
2124

22-
def dumps(self, request, response, body=None):
25+
def dumps(self, request, response, body):
2326
response_headers = CaseInsensitiveDict(response.headers)
2427

25-
if body is None:
26-
body = response.read(decode_content=False)
27-
28-
# NOTE: 99% sure this is dead code. I'm only leaving it
29-
# here b/c I don't have a test yet to prove
30-
# it. Basically, before using
31-
# `cachecontrol.filewrapper.CallbackFileWrapper`,
32-
# this made an effort to reset the file handle. The
33-
# `CallbackFileWrapper` short circuits this code by
34-
# setting the body as the content is consumed, the
35-
# result being a `body` argument is *always* passed
36-
# into cache_response, and in turn,
37-
# `Serializer.dump`.
38-
response._fp = io.BytesIO(body)
39-
4028
# NOTE: This is all a bit weird, but it's really important that on
4129
# Python 2.x these objects are unicode and not str, even when
4230
# they contain only ascii. The problem here is that msgpack

tests/test_cache_control.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ def test_no_cache_with_wrong_sized_body(self, cc):
6767
# When the body is the wrong size, then we don't want to cache it
6868
# because it is obviously broken.
6969
resp = self.resp({"cache-control": "max-age=3600", "Content-Length": "5"})
70-
cc.cache_response(self.req(), resp, body=b"0" * 10)
70+
cc.cache_response(self.req(), resp, b"0" * 10)
7171

7272
assert not cc.cache.set.called
7373

@@ -82,7 +82,7 @@ def test_cache_response_cache_max_age(self, cc):
8282
resp = self.resp({"cache-control": "max-age=3600", "date": now})
8383
req = self.req()
8484
cc.cache_response(req, resp)
85-
cc.serializer.dumps.assert_called_with(req, resp, body=None)
85+
cc.serializer.dumps.assert_called_with(req, resp, None)
8686
cc.cache.set.assert_called_with(self.url, ANY)
8787

8888
def test_cache_response_cache_max_age_with_invalid_value_not_cached(self, cc):

tests/test_serialization.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ def test_read_latest_version_streamable(self, url):
8989
original_resp = requests.get(url, stream=True)
9090
req = original_resp.request
9191

92-
resp = self.serializer.loads(req, self.serializer.dumps(req, original_resp.raw))
92+
resp = self.serializer.loads(req, self.serializer.dumps(req, original_resp.raw, original_resp.content))
9393

9494
assert resp.read()
9595

@@ -99,7 +99,7 @@ def test_read_latest_version(self, url):
9999
req = original_resp.request
100100

101101
resp = self.serializer.loads(
102-
req, self.serializer.dumps(req, original_resp.raw, body=data)
102+
req, self.serializer.dumps(req, original_resp.raw, data)
103103
)
104104

105105
assert resp.read() == data
@@ -114,5 +114,5 @@ def test_no_vary_header(self, url):
114114
original_resp.raw.headers["vary"] = "Foo"
115115

116116
assert self.serializer.loads(
117-
req, self.serializer.dumps(req, original_resp.raw, body=data)
117+
req, self.serializer.dumps(req, original_resp.raw, data)
118118
)

0 commit comments

Comments
 (0)