Fix the incompatible issue in response header

Some changes were made to fix fernet padding for python3 [1],
fernet payload is decoded to str after encryption when
creating a fernet token. But it will be unicode string on
python27 and this is not compatible with `mod_wsgi`.

`mod_wsgi` needs the value in the response headers is binary(str)
type on python2, and unicode(str) type on python3. This patch
does this translation accordingly to make keystone works with
`mod_wsgi`.

[1] https://review.openstack.org/#/c/231711/
Closes-Bug: #1528981

Change-Id: I0217ac10d20c51a9c17bed566f326eb6db6ed949
This commit is contained in:
Dave Chen 2015-12-24 15:10:47 +08:00
parent a422291b03
commit 5b445469b6
2 changed files with 42 additions and 0 deletions

View File

@ -743,6 +743,36 @@ def render_response(body=None, status=None, headers=None, method=None):
headers.append(('Content-Type', 'application/json'))
status = status or (200, 'OK')
# NOTE(davechen): `mod_wsgi` follows the standards from pep-3333 and
# requires the value in response header to be binary type(str) on python2,
# unicode based string(str) on python3, or else keystone will not work
# under apache with `mod_wsgi`.
# keystone needs to check the data type of each header and convert the
# type if needed.
# see bug:
# https://bugs.launchpad.net/keystone/+bug/1528981
# see pep-3333:
# https://www.python.org/dev/peps/pep-3333/#a-note-on-string-types
# see source from mod_wsgi:
# https://github.com/GrahamDumpleton/mod_wsgi(methods:
# wsgi_convert_headers_to_bytes(...), wsgi_convert_string_to_bytes(...)
# and wsgi_validate_header_value(...)).
def _convert_to_str(headers):
str_headers = []
for header in headers:
str_header = []
for value in header:
if not isinstance(value, str):
str_header.append(str(value))
else:
str_header.append(value)
# convert the list to the immutable tuple to build the headers.
# header's key/value will be guaranteed to be str type.
str_headers.append(tuple(str_header))
return str_headers
headers = _convert_to_str(headers)
resp = webob.Response(body=body,
status='%s %s' % status,
headerlist=headers)

View File

@ -170,6 +170,18 @@ class ApplicationTest(BaseWSGITest):
self.assertEqual('Some-Value', resp.headers.get('Custom-Header'))
self.assertEqual('X-Auth-Token', resp.headers.get('Vary'))
def test_render_response_non_str_headers_converted(self):
resp = wsgi.render_response(
headers=[('Byte-Header', 'Byte-Value'),
(u'Unicode-Header', u'Unicode-Value')])
# assert that all headers are identified.
self.assertThat(resp.headers, matchers.HasLength(4))
self.assertEqual('Unicode-Value', resp.headers.get('Unicode-Header'))
# assert that unicode value is converted, the expected type is str
# on both python2 and python3.
self.assertEqual(str,
type(resp.headers.get('Unicode-Header')))
def test_render_response_no_body(self):
resp = wsgi.render_response()
self.assertEqual('204 No Content', resp.status)