summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulien Danjou <julien@danjou.info>2016-03-09 13:55:12 +0100
committerJulien Danjou <julien@danjou.info>2016-03-14 15:51:18 +0100
commit3988776dba4789360d3ea6bddf4eaeb33eb35d7c (patch)
treed38e003313931182147cd7ae27a8f27c8d3fd39b
parent6a897ab40c468748e9cce40debf73fbdf4d2d5ee (diff)
downloadoslo-middleware-3988776dba4789360d3ea6bddf4eaeb33eb35d7c.tar.gz
cors: prevent WebOb setting a default Content-Type
This related to https://github.com/Pylons/webob/issues/205 upstream. Change-Id: I18eb78d4206c20efc934fe8709881c2bd6972983
-rw-r--r--oslo_middleware/cors.py7
-rw-r--r--oslo_middleware/tests/test_cors.py46
2 files changed, 38 insertions, 15 deletions
diff --git a/oslo_middleware/cors.py b/oslo_middleware/cors.py
index 4fb8101..2e53741 100644
--- a/oslo_middleware/cors.py
+++ b/oslo_middleware/cors.py
@@ -65,6 +65,11 @@ class InvalidOriginError(Exception):
'CORS request from origin \'%s\' not permitted.' % origin)
+class _NoContentTypeResponse(webob.response.Response):
+
+ default_content_type = None # prevents webob assigning content type
+
+
class CORS(base.ConfigurableMiddleware):
"""CORS Middleware.
@@ -287,7 +292,7 @@ class CORS(base.ConfigurableMiddleware):
# underlying middleware's response content needs to be persisted.
# Otherwise, create a new response.
if 200 > response.status_code or response.status_code >= 300:
- response = webob.response.Response(status=webob.exc.HTTPOk.code)
+ response = _NoContentTypeResponse(status=webob.exc.HTTPOk.code)
# Does the request have an origin header? (Section 6.2.1)
if 'Origin' not in request.headers:
diff --git a/oslo_middleware/tests/test_cors.py b/oslo_middleware/tests/test_cors.py
index c94b416..e07a85b 100644
--- a/oslo_middleware/tests/test_cors.py
+++ b/oslo_middleware/tests/test_cors.py
@@ -70,7 +70,8 @@ class CORSTestBase(test_base.BaseTestCase):
allow_headers=None,
allow_credentials=None,
expose_headers=None,
- vary='Origin'):
+ vary='Origin',
+ has_content_type=False):
"""Test helper for CORS response headers.
Assert all the headers in a given response. By default, we assume
@@ -110,6 +111,10 @@ class CORSTestBase(test_base.BaseTestCase):
'Access-Control-Expose-Headers',
expose_headers)
+ # Assert no Content-Type added.
+ if not has_content_type:
+ self.assertHeader(response, 'Content-Type')
+
# If we're expecting an origin response, also assert that the
# Vary: Origin header is set, since this implementation of the CORS
# specification permits multiple origin domains.
@@ -344,7 +349,8 @@ class CORSRegularRequestTest(CORSTestBase):
allow_methods=None,
allow_headers=None,
allow_credentials=None,
- expose_headers=None)
+ expose_headers=None,
+ has_content_type=True)
def test_origin_headers(self):
"""CORS Specification Section 6.1.2
@@ -367,7 +373,8 @@ class CORSRegularRequestTest(CORSTestBase):
allow_methods=None,
allow_headers=None,
allow_credentials=None,
- expose_headers=None)
+ expose_headers=None,
+ has_content_type=True)
# Test origin header not present in configuration.
for method in self.methods:
@@ -382,7 +389,8 @@ class CORSRegularRequestTest(CORSTestBase):
allow_methods=None,
allow_headers=None,
allow_credentials=None,
- expose_headers=None)
+ expose_headers=None,
+ has_content_type=True)
# Test valid, but case-mismatched origin header.
for method in self.methods:
@@ -397,7 +405,8 @@ class CORSRegularRequestTest(CORSTestBase):
allow_methods=None,
allow_headers=None,
allow_credentials=None,
- expose_headers=None)
+ expose_headers=None,
+ has_content_type=True)
# Test valid header from list of duplicates.
for method in self.methods:
@@ -412,7 +421,8 @@ class CORSRegularRequestTest(CORSTestBase):
allow_methods=None,
allow_headers=None,
allow_credentials=None,
- expose_headers=None)
+ expose_headers=None,
+ has_content_type=True)
def test_supports_credentials(self):
"""CORS Specification Section 6.1.3
@@ -440,7 +450,8 @@ class CORSRegularRequestTest(CORSTestBase):
allow_methods=None,
allow_headers=None,
allow_credentials=None,
- expose_headers=None)
+ expose_headers=None,
+ has_content_type=True)
# Test valid origin header with credentials
for method in self.methods:
@@ -455,7 +466,8 @@ class CORSRegularRequestTest(CORSTestBase):
allow_methods=None,
allow_headers=None,
allow_credentials="true",
- expose_headers=None)
+ expose_headers=None,
+ has_content_type=True)
def test_expose_headers(self):
"""CORS Specification Section 6.1.4
@@ -476,7 +488,8 @@ class CORSRegularRequestTest(CORSTestBase):
allow_methods=None,
allow_headers=None,
allow_credentials=None,
- expose_headers='X-Header-1,X-Header-2')
+ expose_headers='X-Header-1,X-Header-2',
+ has_content_type=True)
def test_application_options_response(self):
"""Assert that an application provided OPTIONS response is honored.
@@ -523,7 +536,8 @@ class CORSRegularRequestTest(CORSTestBase):
allow_headers=None,
allow_credentials=None,
expose_headers=None,
- vary='Custom-Vary,Origin')
+ vary='Custom-Vary,Origin',
+ has_content_type=True)
class CORSPreflightRequestTest(CORSTestBase):
@@ -1058,7 +1072,8 @@ class CORSPreflightRequestTest(CORSTestBase):
allow_methods='GET',
allow_headers=None,
allow_credentials=None,
- expose_headers=None)
+ expose_headers=None,
+ has_content_type=True)
class CORSTestWildcard(CORSTestBase):
@@ -1139,7 +1154,8 @@ class CORSTestWildcard(CORSTestBase):
max_age=None,
allow_headers='',
allow_credentials='true',
- expose_headers=None)
+ expose_headers=None,
+ has_content_type=True)
# Test invalid domain
request = webob.Request.blank('/')
@@ -1154,7 +1170,8 @@ class CORSTestWildcard(CORSTestBase):
allow_methods='GET',
allow_headers='',
allow_credentials='true',
- expose_headers=None)
+ expose_headers=None,
+ has_content_type=True)
class CORSTestLatentProperties(CORSTestBase):
@@ -1253,7 +1270,8 @@ class CORSTestLatentProperties(CORSTestBase):
allow_headers=None,
allow_credentials='true',
expose_headers='X-Configured,'
- 'X-Server-Generated-Response')
+ 'X-Server-Generated-Response',
+ has_content_type=True)
def test_invalid_latent_expose_headers(self):
"""Assert that passing a non-list is caught in expose headers."""