summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Krotscheck <krotscheck@gmail.com>2016-03-09 07:27:39 -0800
committerMichael Krotscheck <krotscheck@gmail.com>2016-03-09 07:27:39 -0800
commit6a897ab40c468748e9cce40debf73fbdf4d2d5ee (patch)
tree09c849f3267c0d006ccfd41449420e7fc8b31744
parent83b79fd527e9e7dd694e8067a3be8403414ac223 (diff)
downloadoslo-middleware-6a897ab40c468748e9cce40debf73fbdf4d2d5ee.tar.gz
CORS Middleware now honors upstream Vary header
If an upstream middleware or server returns a 'Vary' header, the CORS middleware will honor that header and append its own, rather than overwriting it. https://tools.ietf.org/html/rfc7231#section-7.1.4 Change-Id: I422cf1723dca7e1ecf0ce863b389f125d4f813bb
-rw-r--r--oslo_middleware/cors.py5
-rw-r--r--oslo_middleware/tests/test_cors.py35
2 files changed, 37 insertions, 3 deletions
diff --git a/oslo_middleware/cors.py b/oslo_middleware/cors.py
index 7fbe2d2..4fb8101 100644
--- a/oslo_middleware/cors.py
+++ b/oslo_middleware/cors.py
@@ -391,7 +391,10 @@ class CORS(base.ConfigurableMiddleware):
return
# Set the default origin permission headers. (Sections 6.1.3 & 6.4)
- response.headers['Vary'] = 'Origin'
+ if 'Vary' in response.headers:
+ response.headers['Vary'] += ',Origin'
+ else:
+ response.headers['Vary'] = 'Origin'
response.headers['Access-Control-Allow-Origin'] = origin
# Does this CORS configuration permit credentials? (Section 6.1.3)
diff --git a/oslo_middleware/tests/test_cors.py b/oslo_middleware/tests/test_cors.py
index 1d7d3ab..c94b416 100644
--- a/oslo_middleware/tests/test_cors.py
+++ b/oslo_middleware/tests/test_cors.py
@@ -31,6 +31,12 @@ def test_application(req):
response.headers['X-Server-Generated-Response'] = '1'
return response
+ if req.path_info == '/server_cors_vary':
+ # Mirror back the origin in the request.
+ response = webob.Response(status=200)
+ response.headers['Vary'] = 'Custom-Vary'
+ return response
+
if req.path_info == '/server_no_cors':
# Send a response with no CORS headers.
response = webob.Response(status=200)
@@ -63,7 +69,8 @@ class CORSTestBase(test_base.BaseTestCase):
allow_methods=None,
allow_headers=None,
allow_credentials=None,
- expose_headers=None):
+ expose_headers=None,
+ vary='Origin'):
"""Test helper for CORS response headers.
Assert all the headers in a given response. By default, we assume
@@ -107,7 +114,7 @@ class CORSTestBase(test_base.BaseTestCase):
# Vary: Origin header is set, since this implementation of the CORS
# specification permits multiple origin domains.
if allow_origin:
- self.assertHeader(response, 'Vary', 'Origin')
+ self.assertHeader(response, 'Vary', vary)
def assertHeader(self, response, header, value=None):
if value:
@@ -494,6 +501,30 @@ class CORSRegularRequestTest(CORSTestBase):
self.assertEqual(response.headers['X-Server-Generated-Response'],
'1')
+ def test_application_vary_respected(self):
+ """Assert that an application's provided Vary header is persisted.
+
+ If the underlying application, via middleware or other, provides a
+ Vary header, its response should be honored.
+ """
+
+ request = webob.Request.blank('/server_cors_vary')
+ request.method = "GET"
+ request.headers['Origin'] = 'http://valid.example.com'
+ request.headers['Access-Control-Request-Method'] = 'GET'
+
+ response = request.get_response(self.application)
+
+ self.assertCORSResponse(response,
+ status='200 OK',
+ allow_origin='http://valid.example.com',
+ max_age=None,
+ allow_methods=None,
+ allow_headers=None,
+ allow_credentials=None,
+ expose_headers=None,
+ vary='Custom-Vary,Origin')
+
class CORSPreflightRequestTest(CORSTestBase):
"""CORS Specification Section 6.2