diff --git a/tests/integration/test_stubs.py b/tests/integration/test_stubs.py index aa40004..745d64b 100644 --- a/tests/integration/test_stubs.py +++ b/tests/integration/test_stubs.py @@ -1,6 +1,8 @@ import vcr import six.moves.http_client as httplib +from assertions import assert_is_json + def _headers_are_case_insensitive(host, port): conn = httplib.HTTPConnection(host, port) @@ -44,3 +46,35 @@ def test_multiple_headers(tmpdir, httpbin): inside = _multiple_header_value(httpbin) assert outside == inside + + +def test_original_decoded_response_is_not_modified(tmpdir, httpbin): + testfile = str(tmpdir.join('decoded_response.yml')) + host, port = httpbin.host, httpbin.port + + conn = httplib.HTTPConnection(host, port) + conn.request('GET', '/gzip') + outside = conn.getresponse() + + with vcr.use_cassette(testfile, decode_compressed_response=True): + conn = httplib.HTTPConnection(host, port) + conn.request('GET', '/gzip') + inside = conn.getresponse() + + # Assert that we do not modify the original response while appending + # to the casssette. + assert 'gzip' == inside.headers['content-encoding'] + + # They should effectively be the same response. + assert inside.headers.items() == outside.getheaders() + assert inside.read() == outside.read() + + # Even though the above are raw bytes, the JSON data should have been + # decoded and saved to the cassette. + with vcr.use_cassette(testfile): + conn = httplib.HTTPConnection(host, port) + conn.request('GET', '/gzip') + inside = conn.getresponse() + + assert 'content-encoding' not in inside.headers + assert_is_json(inside.read()) diff --git a/vcr/filters.py b/vcr/filters.py index db6c130..bd7e6c6 100644 --- a/vcr/filters.py +++ b/vcr/filters.py @@ -146,9 +146,11 @@ def decode_response(response): else: # encoding == 'deflate' return zlib.decompress(body) + # Deepcopy here in case `headers` contain objects that could + # be mutated by a shallow copy and corrupt the real response. + response = copy.deepcopy(response) headers = CaseInsensitiveDict(response['headers']) if is_compressed(headers): - response = copy.deepcopy(response) encoding = headers['content-encoding'][0] headers['content-encoding'].remove(encoding) if not headers['content-encoding']: