Skip to content

Commit

Permalink
Check if CORS is enabled on a request only once
Browse files Browse the repository at this point in the history
Fixes #91. Checking if CORS should be enabled for a request is potentially expensive via the regexes and now the signal. To avoid incurring that cost now we cache the result on the request rather than recompute it at each step in the middleware.
  • Loading branch information
Adam Chainz committed Oct 19, 2016
1 parent 81ace20 commit 151c8b1
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 15 deletions.
28 changes: 13 additions & 15 deletions corsheaders/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@

try:
from django.utils.deprecation import MiddlewareMixin
except ImportError:
except ImportError: # pragma: no cover
# Not required for Django <= 1.9, see:
# https://docs.djangoproject.com/en/1.10/topics/http/middleware/#upgrading-pre-django-1-10-style-middleware
MiddlewareMixin = object
MiddlewareMixin = object # pragma: no cover

ACCESS_CONTROL_ALLOW_ORIGIN = 'Access-Control-Allow-Origin'
ACCESS_CONTROL_EXPOSE_HEADERS = 'Access-Control-Expose-Headers'
Expand Down Expand Up @@ -78,24 +78,22 @@ def process_request(self, request):
view/exception middleware along with the requested view;
it will call any response middlewares
"""
if self.is_enabled(request) and conf.CORS_REPLACE_HTTPS_REFERER:
self._https_referer_replace(request)

if (
self.is_enabled(request) and
request.method == 'OPTIONS' and
"HTTP_ACCESS_CONTROL_REQUEST_METHOD" in request.META
):
response = http.HttpResponse()
return response
request._cors_enabled = self.is_enabled(request)
if self.is_enabled(request):
if conf.CORS_REPLACE_HTTPS_REFERER:
self._https_referer_replace(request)

return None
if (
request.method == 'OPTIONS' and
"HTTP_ACCESS_CONTROL_REQUEST_METHOD" in request.META
):
return http.HttpResponse()

def process_view(self, request, callback, callback_args, callback_kwargs):
"""
Do the referer replacement here as well
"""
if self.is_enabled(request) and conf.CORS_REPLACE_HTTPS_REFERER:
if request._cors_enabled and conf.CORS_REPLACE_HTTPS_REFERER:
self._https_referer_replace(request)
return None

Expand All @@ -104,7 +102,7 @@ def process_response(self, request, response):
Add the respective CORS headers
"""
origin = request.META.get('HTTP_ORIGIN')
if self.is_enabled(request) and origin:
if request._cors_enabled and origin:
# todo: check hostname from db instead
url = urlparse(origin)

Expand Down
17 changes: 17 additions & 0 deletions tests/test_middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,3 +373,20 @@ def allow_api_to_all(sender, request, **kwargs):
)
assert resp.status_code == 200
assert resp[ACCESS_CONTROL_ALLOW_ORIGIN] == 'http://example.org'

@override_settings(CORS_ORIGIN_WHITELIST=['example.com'])
def test_signal_called_once_during_normal_flow(self):

def allow_all(sender, request, **kwargs):
allow_all.calls += 1
return True
allow_all.calls = 0

check_request_enabled.connect(allow_all)

resp = self.client.get(
'/test-view/',
HTTP_ORIGIN='http://example.org',
)

assert allow_all.calls == 1

0 comments on commit 151c8b1

Please sign in to comment.