Fix logging of encoded headers

A change introduced in 3.5.0 sorts headers, but runs into a problem
when the headers are bytes, such as the headers provided by the
python-glanceclient.

requests expects headers to be str type in both python2 and python3.
This means in python2 we need to encode unicode objects as ASCII (the
encoding that should be used for HTTP headers) and in python3 we need to
decode bytes as ASCII into str.

Change-Id: Ib81497c3a873616c22ba68256c596a6fb113e11e
Closes-bug: #1766235
This commit is contained in:
Brian Rosmaita 2018-05-14 16:19:46 -04:00 committed by Monty Taylor
parent 0bebdaf0f9
commit 35de6ebe93
No known key found for this signature in database
GPG Key ID: 7BAE94BC7141A594
3 changed files with 38 additions and 1 deletions

View File

@ -79,6 +79,26 @@ def _mv_legacy_headers_for_service(mv_service_type):
return headers
def _sanitize_headers(headers):
"""Ensure headers are strings and not bytes."""
str_dict = {}
for k, v in headers.items():
if six.PY3:
# requests expects headers to be str type in python3, which means
# if we get a bytes we need to decode it into a str
k = k.decode('ASCII') if isinstance(k, six.binary_type) else k
if v is not None:
v = v.decode('ASCII') if isinstance(v, six.binary_type) else v
else:
# requests expects headers to be str type in python2, which means
# if we get a unicode we need to encode it to ASCII into a str
k = k.encode('ASCII') if isinstance(k, six.text_type) else k
if v is not None:
v = v.encode('ASCII') if isinstance(v, six.text_type) else v
str_dict[k] = v
return str_dict
class _JSONEncoder(json.JSONEncoder):
def default(self, o):
@ -711,6 +731,10 @@ class Session(object):
for k, v in self.additional_headers.items():
headers.setdefault(k, v)
# Bug #1766235: some headers may be bytes
headers = _sanitize_headers(headers)
kwargs['headers'] = headers
kwargs.setdefault('verify', self.verify)
if requests_auth:

View File

@ -17,6 +17,7 @@ import sys
import uuid
import mock
from oslo_utils import encodeutils
import requests
import requests.auth
import six
@ -987,7 +988,12 @@ class SessionAuthTests(utils.TestCase):
'X-OpenStack-Request-ID': request_id,
})
resp = sess.get(self.TEST_URL)
resp = sess.get(
self.TEST_URL,
headers={
encodeutils.safe_encode('x-bytes-header'):
encodeutils.safe_encode('bytes-value')
})
self.assertEqual(response, resp.json())
@ -998,6 +1004,7 @@ class SessionAuthTests(utils.TestCase):
self.assertIn('curl -g -i -X GET {url}'.format(url=self.TEST_URL),
request_output)
self.assertIn('-H "x-bytes-header: bytes-value"', request_output)
self.assertEqual('[200] Content-Type: application/json '
'X-OpenStack-Request-ID: '
'{id}'.format(id=request_id), response_output)

View File

@ -0,0 +1,6 @@
---
fixes:
- |
[`bug 1766235 <https://bugs.launchpad.net/keystoneauth/+bug/1766235>`_]
Fixed an issue where passing headers in as bytes rather than strings
would cause a sorting issue.