Repository: kevin1024/vcrpy

Issue:
AttributeError: 'NoneType' object has no attribute 'decode' when 'body' in match_on, fixed with 'raw_body'
When using vcr with the following configuration with 'body', there are errors with loading the JSON response -- it could be due to a blank response or blank payload. When I use 'raw_body' it works perfectly. Here's the stack trace (relevant sections):

```bash
  File "/home/vagrant/venv/local/lib/python2.7/site-packages/requests/sessions.py", line 473, in get
    return self.request('GET', url, **kwargs)
  File "/home/vagrant/venv/local/lib/python2.7/site-packages/requests/sessions.py", line 461, in request
    resp = self.send(prep, **send_kwargs)
  File "/home/vagrant/venv/local/lib/python2.7/site-packages/requests/sessions.py", line 573, in send
    r = adapter.send(request, **kwargs)
  File "/home/vagrant/venv/local/lib/python2.7/site-packages/requests/adapters.py", line 370, in send
    timeout=timeout
  File "/home/vagrant/venv/local/lib/python2.7/site-packages/requests/packages/urllib3/connectionpool.py", line 518, in urlopen
    body=body, headers=headers)
  File "/home/vagrant/venv/local/lib/python2.7/site-packages/requests/packages/urllib3/connectionpool.py", line 353, in _make_request
    httplib_response = conn.getresponse(buffering=True)
  File "/home/vagrant/venv/local/lib/python2.7/site-packages/vcr/stubs/__init__.py", line 219, in getresponse
    if self.cassette.can_play_response_for(self._vcr_request):
  File "/home/vagrant/venv/local/lib/python2.7/site-packages/vcr/cassette.py", line 232, in can_play_response_for
    return request and request in self and \
  File "/home/vagrant/venv/local/lib/python2.7/site-packages/vcr/cassette.py", line 303, in __contains__
    for index, response in self._responses(request):
  File "/home/vagrant/venv/local/lib/python2.7/site-packages/vcr/cassette.py", line 227, in _responses
    if requests_match(request, stored_request, self._match_on):
  File "/home/vagrant/venv/local/lib/python2.7/site-packages/vcr/matchers.py", line 97, in requests_match
    matches = [(m(r1, r2), m) for m in matchers]
  File "/home/vagrant/venv/local/lib/python2.7/site-packages/vcr/matchers.py", line 80, in body
    return transformer(read_body(r1)) == transformer(read_body(r2))
  File "/home/vagrant/venv/local/lib/python2.7/site-packages/vcr/matchers.py", line 52, in _transform_json
    return json.loads(body.decode('utf-8'))
AttributeError: 'NoneType' object has no attribute 'decode'
```

Discussion:

Patch:
diff --git a/vcr/matchers.py b/vcr/matchers.py
index b54ed2f..8fe334e 100644
--- a/vcr/matchers.py
+++ b/vcr/matchers.py
@@ -49,7 +49,8 @@ def _transform_json(body):
     # Request body is always a byte string, but json.loads() wants a text
     # string. RFC 7159 says the default encoding is UTF-8 (although UTF-16
     # and UTF-32 are also allowed: hmmmmm).
-    return json.loads(body.decode('utf-8'))
+    if body:
+        return json.loads(body.decode('utf-8'))
 
 
 _xml_header_checker = _header_checker('text/xml')


Test patch:
diff --git a/tests/integration/test_requests.py b/tests/integration/test_requests.py
index 84a992b..804ab2e 100644
--- a/tests/integration/test_requests.py
+++ b/tests/integration/test_requests.py
@@ -38,6 +38,18 @@ def test_body(tmpdir, httpbin_both):
         assert content == requests.get(url).content
 
 
+def test_get_empty_content_type_json(tmpdir, httpbin_both):
+    '''Ensure GET with application/json content-type and empty request body doesn't crash'''
+    url = httpbin_both + '/status/200'
+    headers = {'Content-Type': 'application/json'}
+
+    with vcr.use_cassette(str(tmpdir.join('get_empty_json.yaml')), match_on=('body',)):
+        status = requests.get(url, headers=headers).status_code
+
+    with vcr.use_cassette(str(tmpdir.join('get_empty_json.yaml')), match_on=('body',)):
+        assert status == requests.get(url, headers=headers).status_code
+
+
 def test_effective_url(tmpdir, httpbin_both):
     '''Ensure that the effective_url is captured'''
     url = httpbin_both.url + '/redirect-to?url=/html'