Make gate keeper to save relative location header path

Why we need this:
  Some middlewares want to keep HTTP Location header as relative path
  (e.g. using Load balancer in front of proxy).

What is the problem in current Swift:
  Current Swift already has the flag to keep it as relative when returning
  the reponse using swift.common.swob.Response. However, auth_token middleware,
  that is from keystonemiddleware, unfortunately can change the relative path
  to absolute because of using webob instead of swob.

What this patch is doing:
  Make gate_keeper able to re-transform the location header from absolute path
  to relative path if 'swift.leave_relative_location' is explicitely set because
  gate_keeper should be the most left side middleware except catch_errors middleware
  in the pipeline.

Change-Id: Ic634c3f1b1e26635206d5a54df8b15354e8df163
This commit is contained in:
Kota Tsuyuzaki 2017-09-16 04:58:31 +09:00
parent d2e32b39e8
commit d6fcf74594
2 changed files with 52 additions and 0 deletions

View File

@ -36,6 +36,7 @@ from swift.common.utils import get_logger, config_true_value
from swift.common.request_helpers import (
remove_items, get_sys_meta_prefix, OBJECT_TRANSIENT_SYSMETA_PREFIX
)
from six.moves.urllib.parse import urlsplit
import re
#: A list of python regular expressions that will be used to
@ -89,9 +90,29 @@ class GatekeeperMiddleware(object):
[('X-Timestamp', ts)])
def gatekeeper_response(status, response_headers, exc_info=None):
def fixed_response_headers():
def relative_path(value):
parsed = urlsplit(v)
new_path = parsed.path
if parsed.query:
new_path += ('?%s' % parsed.query)
if parsed.fragment:
new_path += ('#%s' % parsed.fragment)
return new_path
if not env.get('swift.leave_relative_location'):
return response_headers
else:
return [
(k, v) if k.lower() != 'location' else
(k, relative_path(v)) for (k, v) in response_headers
]
response_headers = fixed_response_headers()
removed = filter(
lambda h: self.outbound_condition(h[0]),
response_headers)
if removed:
self.logger.debug('removed response headers: %s' % removed)
new_headers = filter(

View File

@ -215,5 +215,36 @@ class TestGatekeeper(unittest.TestCase):
for app_hdrs in ({}, self.forbidden_headers_out):
self._test_duplicate_headers_not_removed(method, app_hdrs)
def _test_location_header(self, location_path):
headers = {'Location': location_path}
req = Request.blank(
'/v/a/c', environ={'REQUEST_METHOD': 'GET',
'swift.leave_relative_location': True})
class SelfishApp(FakeApp):
def __call__(self, env, start_response):
self.req = Request(env)
resp = Response(request=self.req, body='FAKE APP',
headers=self.headers)
# like webob, middlewares in the pipeline may rewrite
# location header from relative to absolute
resp.location = resp.absolute_location()
return resp(env, start_response)
selfish_app = SelfishApp(headers=headers)
app = self.get_app(selfish_app, {})
resp = req.get_response(app)
self.assertEqual('200 OK', resp.status)
self.assertIn('Location', resp.headers)
self.assertEqual(resp.headers['Location'], location_path)
def test_location_header_fixed(self):
self._test_location_header('/v/a/c/o2')
self._test_location_header('/v/a/c/o2?query=path&query2=doit')
self._test_location_header('/v/a/c/o2?query=path#test')
self._test_location_header('/v/a/c/o2;whatisparam?query=path#test')
if __name__ == '__main__':
unittest.main()