[placement] ensure that allow headers are native strings

mod-wsgi checks that response header values are what's described
as "native strings". This means whatever `str` is in either
python 2 or 3, but never `unicode`. When they are not mod-wsgi
will 500. For the most part this is taken care of by webob, but in
the case of the 405 handling, the webob response is not being
fully massaged.

mod-wsgi is doing this because it supposed to. Python WSGI server
gateways have different expectations of headers depending on whether
the Python is 2 or 3. See

https://www.python.org/dev/peps/pep-3333/#a-note-on-string-types

In addition to the unit test, the gabbi tests are now using a
version of wsgi-intercept that will raise a TypeError when the
application response headers are not using the correct form. This
check needs to be done in wsgi-intercept rather than the gabbi tests
because both wsgi-intercept and the http client makes requests
transform the headers for their own purposes.

This fix ensures that instead of a 500 the correct 405 response
happens.

Closes-Bug: #1626496
Depends-On: I3b8aabda929fe39b60e645abb6fabb9769554829
Change-Id: Ifa436e11e79adc2e159b4c5e7d3623d9a792b5f7
This commit is contained in:
Chris Dent 2016-09-22 12:58:41 +00:00
parent de82d98333
commit 5fdb9226d2
4 changed files with 24 additions and 3 deletions

View File

@ -107,7 +107,11 @@ def handle_405(environ, start_response):
_methods = util.wsgi_path_item(environ, '_methods')
headers = {}
if _methods:
headers['allow'] = _methods
# Ensure allow header is a python 2 or 3 native string (thus
# not unicode in python 2 but stay a string in python 3)
# In the process done by Routes to save the allowed methods
# to its routing table they become unicode in py2.
headers['allow'] = str(_methods)
raise webob.exc.HTTPMethodNotAllowed(
_('The method specified is not allowed for this resource.'),
headers=headers, json_formatter=util.json_error_formatter)

View File

@ -12,10 +12,15 @@
import os
import wsgi_intercept
from gabbi import driver
from nova.tests.functional.api.openstack.placement import fixtures
# Check that wsgi application response headers are always
# native str.
wsgi_intercept.STRICT_RESPONSE_HEADERS = True
TESTS_DIR = 'gabbits'

View File

@ -92,12 +92,24 @@ class MapperTest(test.NoDBTestCase):
action = self.mapper.match(environ=environ)['action']
self.assertEqual('hello', action)
def test_405(self):
def test_405_methods(self):
environ = _environ(path='/hello', method='POST')
result = self.mapper.match(environ=environ)
self.assertEqual(handler.handle_405, result['action'])
self.assertEqual('GET', result['_methods'])
def test_405_headers(self):
environ = _environ(path='/hello', method='POST')
error = self.assertRaises(webob.exc.HTTPMethodNotAllowed,
handler.dispatch,
environ, start_response,
self.mapper)
allow_header = error.headers['allow']
self.assertEqual('GET', allow_header)
# PEP 3333 requires that headers be whatever the native str
# is in that version of Python. Never unicode.
self.assertEqual(str, type(allow_header))
class PlacementLoggingTest(test.NoDBTestCase):

View File

@ -33,4 +33,4 @@ oslo.vmware>=2.11.0 # Apache-2.0
reno>=1.8.0 # Apache2
# placement functional tests
wsgi-intercept>=0.6.1 # MIT License
wsgi-intercept>=1.4.1 # MIT License