From b5c27f99d1c293c1468a2b670c36cf49f89c5e79 Mon Sep 17 00:00:00 2001 From: Nick DiRienzo Date: Mon, 20 Jun 2016 16:57:40 -0700 Subject: [PATCH 1/7] Move deepcopy higher to not mutate original headers --- vcr/filters.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vcr/filters.py b/vcr/filters.py index db6c130..f5f9175 100644 --- a/vcr/filters.py +++ b/vcr/filters.py @@ -146,9 +146,9 @@ def decode_response(response): else: # encoding == 'deflate' return zlib.decompress(body) + 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']: From 60145983bf33ca45367c7049137ae5fb85fe70a2 Mon Sep 17 00:00:00 2001 From: Nick DiRienzo Date: Mon, 20 Jun 2016 23:23:31 -0700 Subject: [PATCH 2/7] Added regression test --- tests/integration/test_stubs.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/integration/test_stubs.py b/tests/integration/test_stubs.py index aa40004..79c6c35 100644 --- a/tests/integration/test_stubs.py +++ b/tests/integration/test_stubs.py @@ -1,5 +1,8 @@ import vcr import six.moves.http_client as httplib +from six.moves.urllib.request import urlopen, Request + +from assertions import assert_is_json def _headers_are_case_insensitive(host, port): @@ -44,3 +47,28 @@ 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')) + url = httpbin.url + '/gzip' + request = Request(url) + outside = urlopen(request) + + with vcr.use_cassette(testfile, decode_compressed_response=True): + inside = urlopen(request) + + # Assert that we do not modify the original response while appending + # to the casssette. + assert 'gzip' == inside.headers['content-encoding'] + + # They should be the same response. + assert inside.headers.items() == outside.headers.items() + assert inside.read() == outside.read() + + # Even though the above are raw bytes, the JSON data should have be decoded + # and saved to the cassette. + with vcr.use_cassette(testfile) as cass: + inside2 = urlopen(request) + assert 'content-encoding' not in inside2.headers + assert_is_json(inside2.read()) From 2f4c803678e1ba89534723aa30ad502fd1162f5b Mon Sep 17 00:00:00 2001 From: Nick DiRienzo Date: Mon, 20 Jun 2016 23:36:51 -0700 Subject: [PATCH 3/7] Added a note on the deepcopy --- vcr/filters.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vcr/filters.py b/vcr/filters.py index f5f9175..d1a3037 100644 --- a/vcr/filters.py +++ b/vcr/filters.py @@ -146,6 +146,8 @@ def decode_response(response): else: # encoding == 'deflate' return zlib.decompress(body) + # Deepcopy here in case headers contain lists and other objects that could + # be mutated by a shallow copy. response = copy.deepcopy(response) headers = CaseInsensitiveDict(response['headers']) if is_compressed(headers): From c3298c25a30a447830a4b7c717fb7b243b7854d7 Mon Sep 17 00:00:00 2001 From: Nick DiRienzo Date: Mon, 20 Jun 2016 23:43:47 -0700 Subject: [PATCH 4/7] Updated comments --- tests/integration/test_stubs.py | 4 ++-- vcr/filters.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/integration/test_stubs.py b/tests/integration/test_stubs.py index 79c6c35..92ce0f2 100644 --- a/tests/integration/test_stubs.py +++ b/tests/integration/test_stubs.py @@ -66,8 +66,8 @@ def test_original_decoded_response_is_not_modified(tmpdir, httpbin): assert inside.headers.items() == outside.headers.items() assert inside.read() == outside.read() - # Even though the above are raw bytes, the JSON data should have be decoded - # and saved to the cassette. + # Even though the above are raw bytes, the JSON data should have been + # decoded and saved to the cassette. with vcr.use_cassette(testfile) as cass: inside2 = urlopen(request) assert 'content-encoding' not in inside2.headers diff --git a/vcr/filters.py b/vcr/filters.py index d1a3037..bd7e6c6 100644 --- a/vcr/filters.py +++ b/vcr/filters.py @@ -146,8 +146,8 @@ def decode_response(response): else: # encoding == 'deflate' return zlib.decompress(body) - # Deepcopy here in case headers contain lists and other objects that could - # be mutated by a shallow copy. + # 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): From 787c6bdb772e06b66660aec02704018c4412e40f Mon Sep 17 00:00:00 2001 From: Nick DiRienzo Date: Tue, 21 Jun 2016 06:54:05 -0700 Subject: [PATCH 5/7] Fix flake8 issue --- tests/integration/test_stubs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/test_stubs.py b/tests/integration/test_stubs.py index 92ce0f2..b72aa63 100644 --- a/tests/integration/test_stubs.py +++ b/tests/integration/test_stubs.py @@ -68,7 +68,7 @@ def test_original_decoded_response_is_not_modified(tmpdir, httpbin): # Even though the above are raw bytes, the JSON data should have been # decoded and saved to the cassette. - with vcr.use_cassette(testfile) as cass: + with vcr.use_cassette(testfile): inside2 = urlopen(request) assert 'content-encoding' not in inside2.headers assert_is_json(inside2.read()) From 9a8067d8e7ad5e9a3e852c65a569f16335a2c80f Mon Sep 17 00:00:00 2001 From: Nick DiRienzo Date: Tue, 21 Jun 2016 07:00:53 -0700 Subject: [PATCH 6/7] Renamed inside2 to inside --- tests/integration/test_stubs.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/integration/test_stubs.py b/tests/integration/test_stubs.py index b72aa63..b4cdd53 100644 --- a/tests/integration/test_stubs.py +++ b/tests/integration/test_stubs.py @@ -69,6 +69,6 @@ def test_original_decoded_response_is_not_modified(tmpdir, httpbin): # Even though the above are raw bytes, the JSON data should have been # decoded and saved to the cassette. with vcr.use_cassette(testfile): - inside2 = urlopen(request) - assert 'content-encoding' not in inside2.headers - assert_is_json(inside2.read()) + inside = urlopen(request) + assert 'content-encoding' not in inside.headers + assert_is_json(inside.read()) From c88c738df9af396f9d9b43b91a9ddc4f5b693b3a Mon Sep 17 00:00:00 2001 From: Nick DiRienzo Date: Tue, 21 Jun 2016 07:14:51 -0700 Subject: [PATCH 7/7] Removed requests usage from test --- tests/integration/test_stubs.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/tests/integration/test_stubs.py b/tests/integration/test_stubs.py index b4cdd53..745d64b 100644 --- a/tests/integration/test_stubs.py +++ b/tests/integration/test_stubs.py @@ -1,6 +1,5 @@ import vcr import six.moves.http_client as httplib -from six.moves.urllib.request import urlopen, Request from assertions import assert_is_json @@ -51,24 +50,31 @@ def test_multiple_headers(tmpdir, httpbin): def test_original_decoded_response_is_not_modified(tmpdir, httpbin): testfile = str(tmpdir.join('decoded_response.yml')) - url = httpbin.url + '/gzip' - request = Request(url) - outside = urlopen(request) + 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): - inside = urlopen(request) + 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 be the same response. - assert inside.headers.items() == outside.headers.items() + # 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): - inside = urlopen(request) + conn = httplib.HTTPConnection(host, port) + conn.request('GET', '/gzip') + inside = conn.getresponse() + assert 'content-encoding' not in inside.headers assert_is_json(inside.read())