1
0
mirror of https://github.com/kevin1024/vcrpy.git synced 2025-12-10 01:25:34 +00:00

Merge pull request #192 from agriffis/insensitive-headers

Make request.headers always a CaseInsensitiveDict.
This commit is contained in:
Ivan 'Goat' Malison
2015-08-28 14:47:45 -07:00
8 changed files with 99 additions and 53 deletions

View File

@@ -1,19 +1,16 @@
from six import BytesIO, text_type
from six.moves.urllib.parse import urlparse, urlencode, urlunparse
import copy
import json
from .compat import collections
def remove_headers(request, headers_to_remove):
headers = copy.copy(request.headers)
headers_to_remove = [h.lower() for h in headers_to_remove]
keys = [k for k in headers if k.lower() in headers_to_remove]
if keys:
for k in keys:
headers.pop(k)
request.headers = headers
new_headers = request.headers.copy()
for k in headers_to_remove:
if k in new_headers:
del new_headers[k]
request.headers = new_headers
return request
@@ -30,8 +27,7 @@ def remove_query_parameters(request, query_parameters_to_remove):
def remove_post_data_parameters(request, post_data_parameters_to_remove):
if request.method == 'POST' and not isinstance(request.body, BytesIO):
if ('Content-Type' in request.headers and
request.headers['Content-Type'] == 'application/json'):
if request.headers.get('Content-Type') == 'application/json':
json_data = json.loads(request.body.decode('utf-8'))
for k in list(json_data.keys()):
if k in post_data_parameters_to_remove:

View File

@@ -1,6 +1,6 @@
import json
from six.moves import urllib, xmlrpc_client
from .util import CaseInsensitiveDict, read_body
from .util import read_body
import logging
@@ -66,9 +66,8 @@ def _identity(x):
def _get_transformer(request):
headers = CaseInsensitiveDict(request.headers)
for checker, transformer in _checker_transformer_pairs:
if checker(headers): return transformer
if checker(request.headers): return transformer
else:
return _identity

View File

@@ -1,27 +1,12 @@
import warnings
from six import BytesIO, text_type
from six.moves.urllib.parse import urlparse, parse_qsl
from .util import CaseInsensitiveDict
class Request(object):
"""
VCR's representation of a request.
There is a weird quirk in HTTP. You can send the same header twice. For
this reason, headers are represented by a dict, with lists as the values.
However, it appears that HTTPlib is completely incapable of sending the
same header twice. This puts me in a weird position: I want to be able to
accurately represent HTTP headers in cassettes, but I don't want the extra
step of always having to do [0] in the general case, i.e.
request.headers['key'][0]
In addition, some servers sometimes send the same header more than once,
and httplib *can* deal with this situation.
Futhermore, I wanted to keep the request and response cassette format as
similar as possible.
For this reason, in cassettes I keep a dict with lists as keys, but once
deserialized into VCR, I keep them as plain, naked dicts.
VCR's representation of a request.
"""
def __init__(self, method, uri, body, headers):
@@ -32,9 +17,17 @@ class Request(object):
self.body = body.read()
else:
self.body = body
self.headers = {}
for key in headers:
self.add_header(key, headers[key])
self.headers = headers
@property
def headers(self):
return self._headers
@headers.setter
def headers(self, value):
if not isinstance(value, HeadersDict):
value = HeadersDict(value)
self._headers = value
@property
def body(self):
@@ -47,11 +40,10 @@ class Request(object):
self._body = value
def add_header(self, key, value):
# see class docstring for an explanation
if isinstance(value, (tuple, list)):
self.headers[key] = value[0]
else:
self.headers[key] = value
warnings.warn("Request.add_header is deprecated. "
"Please assign to request.headers instead.",
DeprecationWarning)
self.headers[key] = value
@property
def scheme(self):
@@ -105,3 +97,35 @@ class Request(object):
@classmethod
def _from_dict(cls, dct):
return Request(**dct)
class HeadersDict(CaseInsensitiveDict):
"""
There is a weird quirk in HTTP. You can send the same header twice. For
this reason, headers are represented by a dict, with lists as the values.
However, it appears that HTTPlib is completely incapable of sending the
same header twice. This puts me in a weird position: I want to be able to
accurately represent HTTP headers in cassettes, but I don't want the extra
step of always having to do [0] in the general case, i.e.
request.headers['key'][0]
In addition, some servers sometimes send the same header more than once,
and httplib *can* deal with this situation.
Futhermore, I wanted to keep the request and response cassette format as
similar as possible.
For this reason, in cassettes I keep a dict with lists as keys, but once
deserialized into VCR, I keep them as plain, naked dicts.
"""
def __setitem__(self, key, value):
if isinstance(value, (tuple, list)):
value = value[0]
# Preserve the case from the first time this key was set.
old = self._store.get(key.lower())
if old:
key = old[0]
super(HeadersDict, self).__setitem__(key, value)

View File

@@ -188,8 +188,7 @@ class VCRConnection(object):
log.debug('Got {0}'.format(self._vcr_request))
def putheader(self, header, *values):
for value in values:
self._vcr_request.add_header(header, value)
self._vcr_request.headers[header] = values
def send(self, data):
'''

View File

@@ -15,7 +15,7 @@ def vcr_fetch_impl(cassette, real_fetch_impl):
@functools.wraps(real_fetch_impl)
def new_fetch_impl(self, request, callback):
headers = dict(request.headers)
headers = request.headers.copy()
if request.user_agent:
headers.setdefault('User-Agent', request.user_agent)