Add additional_headers to session and adapter

Allow clients and services to set additional_headers that will be sent
with all requests made by the session.

Change-Id: Idbd2e5159de5790c7db65c806b964f220bb6628e
This commit is contained in:
Jamie Lennox 2016-07-13 14:37:30 +10:00
parent 6b7db34f68
commit 1045a147dd
4 changed files with 79 additions and 2 deletions

View File

@ -45,13 +45,18 @@ class Adapter(object):
:type logger: logging.Logger
:param dict allow: Extra filters to pass when discovering API versions.
(optional)
:param dict additional_headers: Additional headers that should be attached
to every request passing through the
adapter. Headers of the same name specified
per request will take priority.
"""
@positional()
def __init__(self, session, service_type=None, service_name=None,
interface=None, region_name=None, endpoint_override=None,
version=None, auth=None, user_agent=None,
connect_retries=None, logger=None, allow={}):
connect_retries=None, logger=None, allow={},
additional_headers=None):
# NOTE(jamielennox): when adding new parameters to adapter please also
# add them to the adapter call in httpclient.HTTPClient.__init__ as
# well as to load_adapter_from_argparse below if the argument is
@ -69,6 +74,7 @@ class Adapter(object):
self.connect_retries = connect_retries
self.logger = logger
self.allow = allow
self.additional_headers = additional_headers or {}
def _set_endpoint_filter_kwargs(self, kwargs):
if self.service_type:
@ -100,6 +106,9 @@ class Adapter(object):
if self.allow:
kwargs.setdefault('allow', self.allow)
for k, v in self.additional_headers.items():
kwargs.setdefault('headers', {}).setdefault(k, v)
return self.session.request(url, method, **kwargs)
def get_token(self, auth=None):

View File

@ -200,6 +200,10 @@ class Session(object):
can be followed by a request. Either an integer
for a specific count or True/False for
forever/never. (optional, default to 30)
:param dict additional_headers: Additional headers that should be attached
to every request passing through the
session. Headers of the same name specified
per request will take priority.
"""
user_agent = None
@ -211,7 +215,7 @@ class Session(object):
@positional(2)
def __init__(self, auth=None, session=None, original_ip=None, verify=True,
cert=None, timeout=None, user_agent=None,
redirect=_DEFAULT_REDIRECT_LIMIT):
redirect=_DEFAULT_REDIRECT_LIMIT, additional_headers=None):
self.auth = auth
self.session = _construct_session(session)
@ -220,6 +224,7 @@ class Session(object):
self.cert = cert
self.timeout = None
self.redirect = redirect
self.additional_headers = additional_headers or {}
if timeout is not None:
self.timeout = float(timeout)
@ -501,6 +506,9 @@ class Session(object):
headers['Content-Type'] = 'application/json'
kwargs['data'] = self._json.encode(json)
for k, v in self.additional_headers.items():
headers.setdefault(k, v)
kwargs.setdefault('verify', self.verify)
if requests_auth:

View File

@ -930,6 +930,56 @@ class AdapterTest(utils.TestCase):
self.TEST_URL,
'GET')
def test_additional_headers(self):
session_key = uuid.uuid4().hex
session_val = uuid.uuid4().hex
adapter_key = uuid.uuid4().hex
adapter_val = uuid.uuid4().hex
request_key = uuid.uuid4().hex
request_val = uuid.uuid4().hex
text = uuid.uuid4().hex
url = 'http://keystone.test.com'
self.requests_mock.get(url, text=text)
sess = client_session.Session(
additional_headers={session_key: session_val})
adap = adapter.Adapter(session=sess,
additional_headers={adapter_key: adapter_val})
resp = adap.get(url, headers={request_key: request_val})
request = self.requests_mock.last_request
self.assertEqual(resp.text, text)
self.assertEqual(session_val, request.headers[session_key])
self.assertEqual(adapter_val, request.headers[adapter_key])
self.assertEqual(request_val, request.headers[request_key])
def test_additional_headers_overrides(self):
header = uuid.uuid4().hex
session_val = uuid.uuid4().hex
adapter_val = uuid.uuid4().hex
request_val = uuid.uuid4().hex
url = 'http://keystone.test.com'
self.requests_mock.get(url)
sess = client_session.Session(additional_headers={header: session_val})
adap = adapter.Adapter(session=sess)
adap.get(url)
self.assertEqual(session_val,
self.requests_mock.last_request.headers[header])
adap.additional_headers[header] = adapter_val
adap.get(url)
self.assertEqual(adapter_val,
self.requests_mock.last_request.headers[header])
adap.get(url, headers={header: request_val})
self.assertEqual(request_val,
self.requests_mock.last_request.headers[header])
class TCPKeepAliveAdapterTest(utils.TestCase):

View File

@ -0,0 +1,10 @@
---
prelude: >
Allow specifying additional_headers to the session and the adapter to add
headers to all requests that pass through these objects.
features:
- Add the ability to provide additional_headers to the session and adapter
object. This will allow clients particularly to provide additional ways to
identify their requests. It will also hopefully provide an intermediate way
to handle setting microversions until we support them directly with
keystoneauth.