Skip to content

Commit 69cf5bc

Browse files
authored
Merge pull request #146 from dstufft/fix-shared-cache
Correctly handle cached shared between Py2 and Py3
2 parents 6abf016 + d1dd9dc commit 69cf5bc

File tree

3 files changed

+54
-30
lines changed

3 files changed

+54
-30
lines changed

cachecontrol/compat.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@
2424

2525
# Replicate some six behaviour
2626
try:
27-
text_type = (unicode,)
27+
text_type = unicode
2828
except NameError:
29-
text_type = (str,)
29+
text_type = str

cachecontrol/serialize.py

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import msgpack
77
from requests.structures import CaseInsensitiveDict
88

9-
from .compat import HTTPResponse, pickle
9+
from .compat import HTTPResponse, pickle, text_type
1010

1111

1212
def _b64_decode_bytes(b):
@@ -37,27 +37,40 @@ def dumps(self, request, response, body=None):
3737
# `Serializer.dump`.
3838
response._fp = io.BytesIO(body)
3939

40+
# NOTE: This is all a bit weird, but it's really important that on
41+
# Python 2.x these objects are unicode and not str, even when
42+
# they contain only ascii. The problem here is that msgpack
43+
# understands the difference between unicode and bytes and we
44+
# have it set to differentiate between them, however Python 2
45+
# doesn't know the difference. Forcing these to unicode will be
46+
# enough to have msgpack know the difference.
4047
data = {
41-
"response": {
42-
"body": body,
43-
"headers": dict(response.headers),
44-
"status": response.status,
45-
"version": response.version,
46-
"reason": response.reason,
47-
"strict": response.strict,
48-
"decode_content": response.decode_content,
48+
u"response": {
49+
u"body": body,
50+
u"headers": dict(
51+
(text_type(k), text_type(v))
52+
for k, v in response.headers.items()
53+
),
54+
u"status": response.status,
55+
u"version": response.version,
56+
u"reason": text_type(response.reason),
57+
u"strict": response.strict,
58+
u"decode_content": response.decode_content,
4959
},
5060
}
5161

5262
# Construct our vary headers
53-
data["vary"] = {}
54-
if "vary" in response_headers:
55-
varied_headers = response_headers['vary'].split(',')
63+
data[u"vary"] = {}
64+
if u"vary" in response_headers:
65+
varied_headers = response_headers[u'vary'].split(',')
5666
for header in varied_headers:
5767
header = header.strip()
58-
data["vary"][header] = request.headers.get(header, None)
68+
header_value = request.headers.get(header, None)
69+
if header_value is not None:
70+
header_value = text_type(header_value)
71+
data[u"vary"][header] = header_value
5972

60-
return b",".join([b"cc=3", msgpack.dumps(data, use_bin_type=True)])
73+
return b",".join([b"cc=4", msgpack.dumps(data, use_bin_type=True)])
6174

6275
def loads(self, request, data):
6376
# Short circuit if we've been given an empty set of data
@@ -167,6 +180,12 @@ def _loads_v2(self, request, data):
167180
return self.prepare_response(request, cached)
168181

169182
def _loads_v3(self, request, data):
183+
# Due to Python 2 encoding issues, it's impossible to know for sure
184+
# exactly how to load v3 entries, thus we'll treat these as a miss so
185+
# that they get rewritten out as v4 entries.
186+
return
187+
188+
def _loads_v4(self, request, data):
170189
try:
171190
cached = msgpack.loads(data, encoding='utf-8')
172191
except ValueError:

tests/test_serialization.py

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,20 @@ class TestSerializer(object):
1212
def setup(self):
1313
self.serializer = Serializer()
1414
self.response_data = {
15-
'response': {
15+
u'response': {
1616
# Encode the body as bytes b/c it will eventually be
1717
# converted back into a BytesIO object.
18-
'body': 'Hello World'.encode('utf-8'),
19-
'headers': {
20-
'Content-Type': 'text/plain',
21-
'Expires': '87654',
22-
'Cache-Control': 'public',
18+
u'body': 'Hello World'.encode('utf-8'),
19+
u'headers': {
20+
u'Content-Type': u'text/plain',
21+
u'Expires': u'87654',
22+
u'Cache-Control': u'public',
2323
},
24-
'status': 200,
25-
'version': '2',
26-
'reason': '',
27-
'strict': '',
28-
'decode_content': True,
24+
u'status': 200,
25+
u'version': 11,
26+
u'reason': u'',
27+
u'strict': True,
28+
u'decode_content': True,
2929
},
3030
}
3131

@@ -48,9 +48,15 @@ def test_read_version_v2(self):
4848
# We have to decode our urllib3 data back into a unicode string.
4949
assert resp.data == 'Hello World'.encode('utf-8')
5050

51-
def test_read_version_v3(self):
51+
def test_load_by_version_v3(self):
52+
data = b'cc=3,somedata'
5253
req = Mock()
53-
resp = self.serializer._loads_v3(req, msgpack.dumps(self.response_data))
54+
resp = self.serializer.loads(req, data)
55+
assert resp is None
56+
57+
def test_read_version_v4(self):
58+
req = Mock()
59+
resp = self.serializer._loads_v4(req, msgpack.dumps(self.response_data))
5460
# We have to decode our urllib3 data back into a unicode string.
5561
assert resp.data == 'Hello World'.encode('utf-8')
5662

@@ -120,4 +126,3 @@ def test_no_vary_header(self, url):
120126
body=data
121127
)
122128
)
123-

0 commit comments

Comments
 (0)