/usr/lib/python2.7/dist-packages/corsheaders/middleware.py is in python-django-cors-headers 2.1.0+github-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | import re
from django import http
from django.apps import apps
from django.utils.cache import patch_vary_headers
from django.utils.six.moves.urllib.parse import urlparse
from .compat import MiddlewareMixin
from .conf import conf
from .signals import check_request_enabled
ACCESS_CONTROL_ALLOW_ORIGIN = 'Access-Control-Allow-Origin'
ACCESS_CONTROL_EXPOSE_HEADERS = 'Access-Control-Expose-Headers'
ACCESS_CONTROL_ALLOW_CREDENTIALS = 'Access-Control-Allow-Credentials'
ACCESS_CONTROL_ALLOW_HEADERS = 'Access-Control-Allow-Headers'
ACCESS_CONTROL_ALLOW_METHODS = 'Access-Control-Allow-Methods'
ACCESS_CONTROL_MAX_AGE = 'Access-Control-Max-Age'
class CorsPostCsrfMiddleware(MiddlewareMixin):
def _https_referer_replace_reverse(self, request):
"""
Put the HTTP_REFERER back to its original value and delete the
temporary storage
"""
if conf.CORS_REPLACE_HTTPS_REFERER and 'ORIGINAL_HTTP_REFERER' in request.META:
http_referer = request.META['ORIGINAL_HTTP_REFERER']
request.META['HTTP_REFERER'] = http_referer
del request.META['ORIGINAL_HTTP_REFERER']
def process_request(self, request):
self._https_referer_replace_reverse(request)
return None
def process_view(self, request, callback, callback_args, callback_kwargs):
self._https_referer_replace_reverse(request)
return None
class CorsMiddleware(MiddlewareMixin):
def _https_referer_replace(self, request):
"""
When https is enabled, django CSRF checking includes referer checking
which breaks when using CORS. This function updates the HTTP_REFERER
header to make sure it matches HTTP_HOST, provided that our cors logic
succeeds
"""
origin = request.META.get('HTTP_ORIGIN')
if request.is_secure() and origin and 'ORIGINAL_HTTP_REFERER' not in request.META:
url = urlparse(origin)
if not conf.CORS_ORIGIN_ALLOW_ALL and not self.origin_found_in_white_lists(origin, url):
return
try:
http_referer = request.META['HTTP_REFERER']
http_host = "https://%s/" % request.META['HTTP_HOST']
request.META = request.META.copy()
request.META['ORIGINAL_HTTP_REFERER'] = http_referer
request.META['HTTP_REFERER'] = http_host
except KeyError:
pass
def process_request(self, request):
"""
If CORS preflight header, then create an
empty body response (200 OK) and return it
Django won't bother calling any other request
view/exception middleware along with the requested view;
it will call any response middlewares
"""
request._cors_enabled = self.is_enabled(request)
if request._cors_enabled:
if conf.CORS_REPLACE_HTTPS_REFERER:
self._https_referer_replace(request)
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 request._cors_enabled and conf.CORS_REPLACE_HTTPS_REFERER:
self._https_referer_replace(request)
return None
def process_response(self, request, response):
"""
Add the respective CORS headers
"""
origin = request.META.get('HTTP_ORIGIN')
if not origin:
return response
enabled = getattr(request, '_cors_enabled', None)
if enabled is None:
enabled = self.is_enabled(request)
if not enabled:
return response
# todo: check hostname from db instead
url = urlparse(origin)
if conf.CORS_ALLOW_CREDENTIALS:
response[ACCESS_CONTROL_ALLOW_CREDENTIALS] = 'true'
if (
not conf.CORS_ORIGIN_ALLOW_ALL and
not self.origin_found_in_white_lists(origin, url) and
not self.origin_found_in_model(url) and
not self.check_signal(request)
):
return response
if conf.CORS_ORIGIN_ALLOW_ALL and not conf.CORS_ALLOW_CREDENTIALS:
response[ACCESS_CONTROL_ALLOW_ORIGIN] = "*"
else:
response[ACCESS_CONTROL_ALLOW_ORIGIN] = origin
patch_vary_headers(response, ['Origin'])
if len(conf.CORS_EXPOSE_HEADERS):
response[ACCESS_CONTROL_EXPOSE_HEADERS] = ', '.join(conf.CORS_EXPOSE_HEADERS)
if request.method == 'OPTIONS':
response[ACCESS_CONTROL_ALLOW_HEADERS] = ', '.join(conf.CORS_ALLOW_HEADERS)
response[ACCESS_CONTROL_ALLOW_METHODS] = ', '.join(conf.CORS_ALLOW_METHODS)
if conf.CORS_PREFLIGHT_MAX_AGE:
response[ACCESS_CONTROL_MAX_AGE] = conf.CORS_PREFLIGHT_MAX_AGE
return response
def origin_found_in_white_lists(self, origin, url):
return (
url.netloc in conf.CORS_ORIGIN_WHITELIST or
(origin == 'null' and origin in conf.CORS_ORIGIN_WHITELIST) or
self.regex_domain_match(origin)
)
def regex_domain_match(self, origin):
for domain_pattern in conf.CORS_ORIGIN_REGEX_WHITELIST:
if re.match(domain_pattern, origin):
return origin
def origin_found_in_model(self, url):
if conf.CORS_MODEL is None:
return False
model = apps.get_model(*conf.CORS_MODEL.split('.'))
return model.objects.filter(cors=url.netloc).exists()
def is_enabled(self, request):
return (
re.match(conf.CORS_URLS_REGEX, request.path) or
self.check_signal(request)
)
def check_signal(self, request):
signal_responses = check_request_enabled.send(
sender=None,
request=request,
)
return any(
return_value for
function, return_value in signal_responses
)
|